Solon v3.2.0

chat - 聊天会话的记忆与持久化

</> markdown

大语言模型的接口是无状态的服务,如果需要形成有记忆的会话窗口。需要使用“多消息”提示语,把历史对话都输入。

1、原始形态的“多消息”提示语(有记忆的会话)

public void case3() throws IOException {
    //把对话记录到这里
    List<ChatMessage> messageList = new ArrayList<>(); 
    
    
    //1.
    messageList.add(ChatMessage.ofUser("hello")); //添加请求消息
    ChatResponse resp = chatModel.prompt(messageList).call(); //AI消息也会自动记录到 messageList
    log.info("{}", resp.getMessage())); 
    
    //2.
    messageList.add(ChatMessage.ofUser("Who are you?")); //AI消息也会自动记录到 messageList
    resp = chatModel.prompt(messageList).call();
    log.info("{}", resp.getMessage());
}

2、使用“聊天会话”接口(ChatSession)

ChatSession 可以记录消息,还可以作为提示语的参数使用。同时提供了序列化导入导出接口。

public void case3() throws IOException {
    //聊天会话
    ChatSession chatSession = new ChatSessionDefault("session-1"); //安排个会话id
    
    
    //1.
    chatSession.addMessage(ChatMessage.ofUser("hello")); //添加请求消息
    ChatResponse resp = chatModel.prompt(chatSession).call();  //AI消息自动记录到会话里
    log.info("{}", resp.getMessage())); 
    
    //2.
    chatSession.addMessage(ChatMessage.ofUser("Who are you?")); //添加请求消息
    resp = chatModel.prompt(chatSession).call(); //AI消息自动记录到会话里
    log.info("{}", resp.getMessage());
}

3、ChatSession 的持久化

  • 使用会话id与序列化导入导出接口
//保存
sessionService.save(chatSession.getSessionId(), chatSession.toNdjson());

//读取
String ndjson = sessionService.read(chatSession.getSessionId());
chatSession.loadNdjson(ndjson);
  • 通过定制直接同步数据(仅供参考)
public class ChatSessionImpl extends ChatSessionDefault {
    SessionService sessionService;
    
    public ChatSessionImpl(String sessionId) {
        super(sessionId);
        
        //初始化消息
        getMessages().addAll(sessionService.getMessages(sessionId));
    }
    
    @Override
    public void addMessage(ChatMessage... messages) {
        super.addMessage(messages);
        
        sessionService.addMessages(getSessionId(), messages);
    }
    
    @Override
    public void clear() {
        super.clear();
        sessionService.clearMessages(getSessionId());
    }
}

4、ChatSession 的接口字典

public interface ChatSession {
    /**
     * 获取会话id
     */
    String getSessionId();

    /**
     * 获取所有消息
     */
    List<ChatMessage> getMessages();

    /**
     * 添加消息
     */
    void addMessage(ChatMessage... messages);

    /**
     * 清空消息
     */
    void clear();


    /// //////////////////////////////////////

    /**
     * 转为 ndjson
     */
    default String toNdjson() throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        toNdjson(out);
        return new String(out.toByteArray(), Solon.encoding());
    }

    /**
     * 转为 ndjson
     */
    default void toNdjson(OutputStream out) throws IOException {
        for (ChatMessage msg : getMessages()) {
            out.write(ChatMessage.toJson(msg).getBytes(Solon.encoding()));
            out.write("\n".getBytes(Solon.encoding()));
            out.flush();
        }
    }

    /**
     * 加载 ndjson
     */
    default void loadNdjson(String ndjson) throws IOException {
        loadNdjson(new ByteArrayInputStream(ndjson.getBytes(Solon.encoding())));
    }

    /**
     * 加载 ndjson
     */
    default void loadNdjson(InputStream ins) throws IOException {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(ins))) {
            while (true) {
                String json = reader.readLine();

                if (Utils.isEmpty(json)) {
                    break;
                } else {
                    addMessage(ChatMessage.fromJson(json));
                }
            }
        }
    }
}