聊天记忆
手动维护和管理ChatMessage是很麻烦的。 因此,LangChain4j提供了ChatMemory抽象以及多种开箱即用的实现。
ChatMemory可以作为独立的低级组件使用, 或者作为高级组件(如AI服务)的一部分。
ChatMemory作为ChatMessage的容器(由List支持),具有以下额外功能:
- 淘汰策略
- 持久化
- 对
SystemMessage的特殊处理 - 对工具消息的特殊处理
记忆与历史
请注意,”记忆”和”历史”是不同的概念。
- 历史保持用户和AI之间的所有消息完整无缺。历史是用户在UI中看到的内容。它代表实际对话内容。
- 记忆保存一些信息,这些信息呈现给LLM,使其表现得好像”记住”了对话。 记忆与历史有很大不同。根据使用的记忆算法,它可以以各种方式修改历史: 淘汰一些消息,总结多条消息,总结单独的消息,从消息中删除不重要的细节, 向消息中注入额外信息(例如,用于RAG)或指令(例如,用于结构化输出)等等。
LangChain4j目前只提供”记忆”,而不是”历史”。如果您需要保存完整的历史记录,请手动进行。
淘汰策略
淘汰策略是必要的,原因如下:
- 为了适应LLM的上下文窗口。LLM一次可以处理的令牌数量是有上限的。 在某些时候,对话可能会超过这个限制。在这种情况下,应该淘汰一些消息。 通常,最旧的消息会被淘汰,但如果需要,可以实现更复杂的算法。
- 控制成本。每个令牌都有成本,使每次调用LLM的费用逐渐增加。 淘汰不必要的消息可以降低成本。
- 控制延迟。发送给LLM的令牌越多,处理它们所需的时间就越长。
目前,LangChain4j提供了2种开箱即用的实现:
较简单的一种,
MessageWindowChatMemory,作为滑动窗口运行, 保留最近的N条消息,并淘汰不再适合的旧消息。 然而,由于每条消息可能包含不同数量的令牌,MessageWindowChatMemory主要用于快速原型设计。更复杂的选项是
TokenWindowChatMemory, 它也作为滑动窗口运行,但专注于保留最近的N个令牌, 根据需要淘汰旧消息。 消息是不可分割的。如果一条消息不适合,它会被完全淘汰。TokenWindowChatMemory需要一个Tokenizer来计算每个ChatMessage中的令牌数。
持久化
默认情况下,ChatMemory实现在内存中存储ChatMessage。
如果需要持久化,可以实现自定义的ChatMemoryStore, 将ChatMessage存储在您选择的任何持久化存储中:
1 | class PersistentChatMemoryStore implements ChatMemoryStore { |
每当向ChatMemory添加新的ChatMessage时,都会调用updateMessages()方法。 这通常在与LLM的每次交互中发生两次: 一次是添加新的UserMessage时,另一次是添加新的AiMessage时。 updateMessages()方法预期会更新与给定内存ID关联的所有消息。 ChatMessage可以单独存储(例如,每条消息一条记录/行/对象) 或一起存储(例如,整个ChatMemory一条记录/行/对象)。
请注意,从ChatMemory中淘汰的消息也将从ChatMemoryStore中淘汰。 当消息被淘汰时,会调用updateMessages()方法, 传入不包含被淘汰消息的消息列表。
当ChatMemory的用户请求所有消息时,会调用getMessages()方法。 这通常在与LLM的每次交互中发生一次。 Object memoryId参数的值对应于创建ChatMemory时指定的id。 它可以用来区分多个用户和/或对话。 getMessages()方法预期会返回与给定内存ID关联的所有消息。
当调用ChatMemory.clear()时,会调用deleteMessages()方法。 如果您不使用此功能,可以将此方法留空。
对SystemMessage的特殊处理
SystemMessage是一种特殊类型的消息,因此它的处理方式与其他消息类型不同:
- 一旦添加,
SystemMessage总是被保留。 - 一次只能保存一条
SystemMessage。 - 如果添加了具有相同内容的新
SystemMessage,它会被忽略。 - 如果添加了具有不同内容的新
SystemMessage,它会替换之前的消息。
对工具消息的特殊处理
如果包含ToolExecutionRequest的AiMessage被淘汰, 随后的孤立ToolExecutionResultMessage也会自动被淘汰, 以避免与某些LLM提供商(如OpenAI)出现问题, 这些提供商禁止在请求中发送孤立的ToolExecutionResultMessage。
案例:实现多用户会话记忆
1 | public interface Assistant { |
案例:实现多用户会话持久化
1 | public interface Assistant { |
