[智能体-221]:RunnableWithMessageHistory 全详解,是对langchain LCEL 原始chain的包装,使得不具备记忆功能的原始chain具备了记忆功能。

发布时间:2026/6/4 22:20:14

[智能体-221]:RunnableWithMessageHistory 全详解,是对langchain LCEL 原始chain的包装,使得不具备记忆功能的原始chain具备了记忆功能。 RunnableWithMessageHistory是对langchain LCEL 原始chain的包装使得不具备记忆功能的原始chain具备了记忆功能被包装后的chain平等的参与后续chain的组合。一、核心定位与设计思想1. 本质定义RunnableWithMessageHistory是LangChain 基于 LCEL 协议实现的包装类属于装饰器模式应用目标对象任意标准 LCELRunnablePrompt LLM、普通 Chain、自定义 Runnable 等无原生记忆的链路核心能力无感追加对话历史记忆不修改原有链的代码与逻辑接口一致性包装后实例依然是标准Runnable完全遵循 LCEL 规范和原生链具备同等组合能力可使用|、RunnableParallel、RunnableBranch等任意 LCEL 语法拼接、嵌套、复用这正是该消息的强大之处2. 解决的痛点原生 LCEL 链是无状态的单次调用独立无法留存多轮对话上下文传统记忆组件ConversationBufferMemory和老版 Chain 强耦合难以适配 LCEL 流式、组合式的编程范式统一记忆逻辑与业务链逻辑实现记忆层与业务层解耦。二、工作原理1. 整体执行流程接收入参调用时传入业务输入 专属session_id会话唯一标识加载历史通过你定义的get_session_history函数根据session_id读取当前会话的历史消息拼接上下文将「历史对话 当前用户提问」自动整合注入到原始 Chain 的 Prompt 中执行原始链调用被包装的原生 LCEL 链路得到模型回复持久化历史把「当前提问 模型回答」追加到对应session_id的会话历史中返回结果输出模型响应整个过程对上层调用透明。2. 为什么能平等参与 LCEL 组合LCEL 的核心是统一 Runnable 协议所有组件Prompt、LLM、解析器、包装器都实现了invoke/stream/batch等标准方法。RunnableWithMessageHistory只是在标准方法内部增加了记忆读写逻辑对外暴露的接口、入参出参格式和普通链完全一致因此可放在链路任意位置用管道符|串联可并行、分支、嵌套组合支持流式输出、批量调用等 LCEL 全部特性。三、核心参数解析python运行RunnableWithMessageHistory( runnable: Runnable, # 必选被包装的原始LCEL链 get_session_history: Callable[[str], BaseChatMessageHistory], # 必选会话历史获取函数 input_messages_key: str input, # 用户输入字段名 history_messages_key: Optional[str] None, # 历史消息注入字段名 output_messages_key: Optional[str] None # 输出消息字段名 )runnable待增强的原始 LCEL 链纯业务逻辑本身不处理记忆。get_session_history回调函数入参为session_id返回一个消息历史存储实例。内置实现内存存储、文件、Redis、数据库等作用按会话隔离历史支持多用户、多对话并发。input_messages_keyPrompt 模板中接收当前用户输入的变量名。history_messages_keyPrompt 模板中接收拼接后的历史对话的变量名。四、完整实战示例分两种常用写法场景 1标准对话模板显式指定历史变量最规范写法手动在 Prompt 中预留历史消息位。python运行from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_openai import ChatOpenAI from langchain_community.chat_message_histories import ChatMessageHistory # 1. 构建无记忆的原始 LCEL 链 # MessagesPlaceholder 专门用来承载动态对话历史 prompt ChatPromptTemplate.from_messages([ (system, 你是专业助手根据上下文回答问题), MessagesPlaceholder(variable_namehistory), # 历史对话占位 (human, {question}) # 当前用户问题 ]) llm ChatOpenAI(modelgpt-3.5-turbo) # 原始链纯业务逻辑无记忆 raw_chain prompt | llm # 2. 定义会话历史获取函数内存版 def get_history(session_id: str) - ChatMessageHistory: return ChatMessageHistory() # 3. 包装为带记忆的链 history_chain RunnableWithMessageHistory( runnableraw_chain, get_session_historyget_history, input_messages_keyquestion, # 当前输入变量名 history_messages_keyhistory # 历史消息变量名 ) # 4. 调用测试同一个session_id 共享历史 session_cfg {configurable: {session_id: user_001}} # 第一轮对话 res1 history_chain.invoke({question: 我叫小王}, configsession_cfg) print(res1.content) # 第二轮对话自动带上历史 res2 history_chain.invoke({question: 我叫什么名字}, configsession_cfg) print(res2.content)场景 2极简写法自动推导字段适合简单对话框架自动处理消息拼接。python运行# 简化 Prompt prompt ChatPromptTemplate.from_messages([ (system, 友好聊天), (human, {input}) ]) raw_chain prompt | llm # 包装记忆链 history_chain RunnableWithMessageHistory( raw_chain, get_history, input_messages_keyinput ) # 继续 LCEL 组合包装后的链正常拼接解析器 from langchain_core.output_parsers import StrOutputParser final_chain history_chain | StrOutputParser() # 链式组合完全兼容 # 调用 print(final_chain.invoke({input: 今天天气如何}, config{configurable: {session_id:user_002}}))五、关键特性与进阶说明1. 会话隔离session_id不同session_id对应独立的对话历史天然支持多用户、多会话内存存储重启后历史清空生产环境建议替换为 Redis / 数据库持久化。2. LCEL 组合能力验证包装后的链 标准Runnable支持所有 LCEL 组合语法python运行# 并行组合示例 from langchain_core.runnables import RunnableParallel # 带记忆的链 和 普通链 并行执行 parallel_chain RunnableParallel({ chat: history_chain, summary: raw_chain }) # 正常调用 parallel_chain.invoke({question: 你好}, config{configurable:{session_id:s1}})3. 流式、批量支持原生stream/batch方法完全保留包装不影响流式输出等高级特性。4. 优势总结解耦记忆逻辑和业务链完全分离原始链可单独测试、复用通用任意 LCEL 链都可一键加装记忆无需改造原有代码兼容100% 适配 LCEL 生态组合、嵌套、分支不受限制灵活历史存储可自由切换内存、Redis、MySQL 等。六、和传统 Memory 的核心区别表格维度传统 Memory 老式 ChainRunnableWithMessageHistory LCEL耦合度强耦合代码侵入高装饰器包装零侵入组合性难以自由拼接、嵌套原生支持 LCEL 全组合能力状态管理链内部维护状态独立会话存储多会话隔离清晰适用范式旧版命令式编程LCEL 声明式、流式编程七、常见使用注意点必须通过config{configurable: {session_id: xxx}}传入会话 ID否则无法区分历史Prompt 中使用MessagesPlaceholder承载历史消息是最佳实践格式更标准内存版ChatMessageHistory仅适用于测试线上务必使用持久化存储包装顺序先构建业务 LCEL 链最后统一包装记忆逻辑更清晰。

相关新闻