chat - 聊天会话的记忆与持久化
大语言模型的接口是无状态的服务,如果需要形成有记忆的会话窗口。需要使用“多消息”提示语,把历史对话都输入。
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));
}
}
}
}
}