聊天机器人要记住上一轮用户说了什么,否则每句都当新会话。把 messages append 到 list 可以,但多 session、多用户时要自己管 dict 键。ChatMessageHistory 抽象「按 session 读写 message 列表」,为 RunnableWithMessageHistory 提供后端。
段末注释:ChatMessageHistory = 按会话存储
BaseMessage列表的可插拔后端;Memory(记忆)在 LangChain 中指对话上下文持久化机制。
1. 一句话定位
| 维度 | 内容 |
|---|---|
| 角色 | 能力层 会话存储:session → list[BaseMessage] |
| 输入 → 输出 | add_message / add_user_message;读取 messages 属性 |
| 典型调用入口 | history.add_message(HumanMessage(...))、history.messages |
| 与 LangGraph | 长期记忆用 checkpointer + store;短会话 history 仍可用于简单链 |
2. 实现逻辑
1 | 1. history = InMemoryChatMessageHistory() |
字段级变形:
1 | messages = [] |
3. 原理说明
3.1 BaseChatMessageHistory
BaseChatMessageHistory(抽象类,langchain_core.chat_history)
功能:按会话读写 list[BaseMessage]。实现有内存、Redis、Postgres 等。
add_message(message)(方法)
最小输入:1 条 BaseMessage。
add_user_message(message: str) / add_ai_message(message: str)(方法)
内部包成 Human/AIMessage。message 建议非空。
clear()(方法)
清空当前会话。无参数。清空后 messages 长度为 0。
messages(属性)
类型 list[BaseMessage],默认 []。最小可读:0 条;多轮对话至少 2 条(human+ai)。
1 | history.add_message(HumanMessage(content="你好")) |
勿直接 mutate 该 list,用 API。
3.2 InMemoryChatMessageHistory
InMemoryChatMessageHistory(数据类)
功能:进程内 list,重启丢失,适合测试。构造无必填参数。
数据结构:内部 messages: list[BaseMessage] = []。
最小维度:空 history 合法。
1 | from langchain_core.chat_history import InMemoryChatMessageHistory |
多 session:dict[session_id, ChatMessageHistory],session_id 非空 str。
3.3 与 v1「Memory」类
旧版 ConversationBufferMemory 在 langchain-classic。挂到 LCEL 上的 RunnableWithMessageHistory 已弃用(≥1.3.3);新项目用 LangGraph checkpointer(thread_id)。BaseChatMessageHistory 本身仍可用作存储抽象。
3.4 工具轮次
带工具的历史须完整保存 AIMessage(tool_calls) 与 ToolMessage。最小合法工具轮:human + ai(tool_calls len≥1) + 等量 ToolMessage。缺 id 则下轮 invoke 非法。
4. 最小可运行示例
1 | pip install -U langchain-core |
1 | from langchain_core.chat_history import InMemoryChatMessageHistory |
重要配置参数
| 参数(API 名) | 类型 / 默认值 | 功能说明 | 作用与影响 | 参考起点 | 配置指导 |
|---|---|---|---|---|---|
session_id |
str(外层 dict 键) | 把不同用户/会话的消息列表隔开 | 共用一个 id 会串话;多 worker 内存后端会丢 | UUID | 多租户用 tenant:user |
messages |
list,只读属性,默认 [] |
读取当前会话已保存的 BaseMessage 序列 | 直接 mutate 可能不同步 | — | 增删一律走 add_message / clear |
| 持久化后端 | 实现类 | 历史存在内存、Redis 还是 SQL | InMemory 重启即丢、多进程不一致 | 生产选型 | InMemory 仅 dev |
clear() |
方法 | 清空该会话全部消息 | 不可恢复;合规「忘记我」用 | 用户触发 | GDPR 场景必暴露 |
| 历史长度上限 | 应用层 | 送进模型前截断或摘要到最近 N 轮 | 防超窗;截太狠丢上下文 | 最近 N 轮 | 可截断或摘要 |
| TTL | Redis 等 | 会话键自动过期时间 | 过短用户感觉失忆;过长占存储 | 7~30 天 | 按合规要求 |
5. 易踩坑
- 只存 user/ai 不存 tool 消息:Agent 多轮必崩。
- 多 worker 共享 InMemory:请求打到不同进程,历史不一致;生产用 Redis/DB。
- 直接修改 history.messages list 引用:部分实现不保证同步,用 API 方法。
小结
- ChatMessageHistory 管 session 级 messages 列表。
- 原型用 InMemoryChatMessageHistory;生产换持久化实现。
- v1 与 RunnableWithMessageHistory 组合挂到链上。
- 工具对话须存 完整 message 类型序列。