公司动态
下篇:LangChain Agent 智能体从入门到实战(二)—— 记忆管理、中间件与最佳实践
让 Agent 记住对话、压缩历史、接受人工审核最终成为可靠的智能助手。上篇我们学会了 Agent 的概念、工具定义和 MCP 协议接入。但目前的 Agent 每次调用都是独立的——它不记得上一轮对话说了什么。同时长对话会导致消息列表无限膨胀Token 消耗剧增。本篇将解决这些问题通过Checkpointer实现记忆通过中间件实现历史压缩和人工审核并总结最佳实践与常见问题。四、记忆管理让 Agent 记住过去4.1 失忆问题默认情况下Agent 每次invoke都是一次独立的“感知→推理→行动”过程上一次的对话内容不会自动带入下一次。python# 第1次调用 agent.invoke({messages: [{role: user, content: 我叫张三}]}) # Agent: 你好张三 # 第2次调用默认无记忆 agent.invoke({messages: [{role: user, content: 我叫什么名字}]}) # Agent: 抱歉我不知道你叫什么名字。 ← 失忆了4.2 Checkpointer 机制LangChain 通过Checkpointer实现记忆。每次调用结束后自动保存本次对话的所有消息下次调用时自动加载历史消息拼接到新输入前面。使用方式只需两步pythonfrom langgraph.checkpoint.memory import InMemorySaver # 1. 创建 checkpointer checkpointer InMemorySaver() # 2. 创建 Agent 时传入 agent create_agent( modelllm, toolstools, checkpointercheckpointer, # ← 就这一行 )4.3 Thread ID多会话隔离一个 Agent 通常服务多个用户需要为每个用户维护独立的会话历史。通过thread_id区分python# 张三的对话thread_id user_zhangsan agent.invoke( {messages: [{role: user, content: 我叫张三}]}, config{configurable: {thread_id: user_zhangsan}} ) # 李四的对话thread_id user_lisi完全独立 agent.invoke( {messages: [{role: user, content: 我叫李四}]}, config{configurable: {thread_id: user_lisi}} )相同thread_id的调用共享历史不同thread_id互不干扰。4.4 完整示例pythonimport datetime from langchain.agents import create_agent from langchain.chat_models import init_chat_model from langgraph.checkpoint.memory import InMemorySaver llm init_chat_model(modelgpt-4o-mini, model_provideropenai) checkpointer InMemorySaver() agent create_agent(modelllm, tools[], checkpointercheckpointer) # 第1次调用 for chunk in agent.stream( {messages: [{role: user, content: 今天北京天气怎么样}]}, config{configurable: {thread_id: abc123}} ): print(chunk, end\n\n) # 第2次调用相同 thread_id → 有记忆 for chunk in agent.stream( {messages: [{role: user, content: 我刚才问你什么了}]}, config{configurable: {thread_id: abc123}} ): print(chunk, end\n\n) # Agent 会回答你刚才问了北京今天的天气 # 第3次调用不同 thread_id → 无记忆 for chunk in agent.stream( {messages: [{role: user, content: 我刚才问你什么了}]}, config{configurable: {thread_id: xyz789}} ): print(chunk, end\n\n) # Agent 会回答这是我们第一次对话你还没有问过任何问题4.5 记忆的代价随着对话轮次增加保存的消息列表越来越长第 1 轮2 条消息第 10 轮20 条消息第 100 轮200 条消息每次调用都要把所有历史消息发给 LLM导致Token 消耗剧增甚至可能超出上下文窗口限制。解决方案就是下一节的中间件。五、中间件在关键节点“拦截”处理5.1 中间件概念中间件是一种插入 Agent 执行流程中的“拦截器”可以在以下位置介入介入位置时机典型用途before_model消息发给 LLM 之前压缩历史、注入额外上下文after_modelLLM 返回结果之后记录日志、过滤敏感内容wrap_tool工具执行前后人工审核、权限控制使用方式创建中间件实例通过middleware参数传入create_agent。pythonagent create_agent( modelllm, toolstools, middleware[middleware_a, middleware_b], # 列表按顺序执行 )5.2 消息压缩中间件SummarizationMiddleware解决长对话中消息无限增长的问题。当消息量超过阈值时自动用 LLM 将旧消息压缩成一段摘要。pythonfrom langchain.agents.middleware import SummarizationMiddleware from langchain_openai import ChatOpenAI summary_middleware SummarizationMiddleware( modelChatOpenAI(modelgpt-4o-mini), trigger(messages, 100), # 消息数量达到100条时触发压缩 )压缩效果示意压缩前100 条消息[用户你好AI你好用户天气AI晴天...用户最新问题]压缩后2 条消息[系统以下是摘要用户询问了天气、订单状态...用户最新问题]trigger支持三种策略触发策略写法含义按消息数量(messages, 100)消息数达 100 条时压缩按 Token 比例(fraction, 0.5)Token 数达上下文窗口 50% 时压缩按 Token 绝对值(tokens, 3000)Token 数达 3000 时压缩5.3 人工审核中间件HumanInTheLoopMiddleware某些高风险操作转账、删除数据、发送邮件即使 LLM 决定执行也需人工确认后再真正执行。pythonfrom langchain.agents.middleware import HumanInTheLoopMiddleware hitl_middleware HumanInTheLoopMiddleware( interrupt_on{ transfer_money: True, # 转账 → 需要审核 delete_record: True, # 删除 → 需要审核 get_weather: False, # 查天气 → 不需要审核 } )执行流程Agent 决定调用transfer_money中间件拦截暂停执行返回“等待审核”状态人工通过界面查看并做出“批准”或“拒绝”决定将决定作为Command(resume...)传回Agent 继续执行或放弃。完整示例代码见文档 5.3 节实际开发中需结合前端交互来实现审核界面。5.4 中间件叠加使用多个中间件可以同时使用按列表顺序依次执行。例如pythonagent create_agent( modelllm, toolstools, middleware[summary_middleware, hitl_middleware], )六、Agent 最佳实践6.1 工具设计五原则原则为什么重要正面示例反面示例单一职责LLM 更容易理解功能明确的工具get_weather、get_forecast各做一件事handle_all一个工具做太多事描述清晰LLM 完全依赖描述决定何时用、怎么用“获取指定城市今天的实时天气”“查天气”参数具体减少 LLM 猜测参数格式的可能date: str Field(description格式YYYY-MM-DD)date: str无格式说明错误友好LLM 可根据错误信息调整策略返回“城市‘北精’无法识别是否指‘北京’”抛出KeyError: 北精幂等安全避免重试时产生副作用get_user(id123)多次调用结果相同create_order()多次调用会创建多个订单经验法则如果一个工具的 docstring 超过 3 句话才能说清功能说明它承担了太多职责应该拆分。6.2 系统提示词优化好的系统提示词应包含角色定位、工作流程、约束条件、输出格式。好示例text你是一个专业的数据分析助手。 工作流程 1. 理解用户分析需求 2. 使用 search 工具获取数据 3. 使用 calculate 工具进行计算 4. 用简洁语言呈现结果 注意事项 - 计算结果保留2位小数 - 如果数据不足主动告知用户 - 不要编造数据差示例“你是一个AI助手帮助用户解决问题。”太模糊6.3 调试三层次层次方法适用场景第一层开启日志logging.basicConfig(levellogging.DEBUG)快速定位调用参数第二层LangSmith设置环境变量启用追踪可视化完整执行轨迹第三层流式输出用stream替代invoke观察每一步中间过程经验大多数 Agent 问题根源可归为三类工具描述不够清晰 → LLM 选错工具系统提示词引导不足 → 执行顺序混乱工具返回值格式不规范 → LLM 无法解读结果6.4 性能优化问题优化方法效果响应慢只加载当前任务必需的工具减少 LLM 决策时间Token 消耗高使用SummarizationMiddleware压缩历史消息工具调用次数多优化工具返回值一次返回完整信息减少循环轮次吞吐量不足使用ainvoke异步调用支持并发处理七、课程总结与常见问题7.1 知识回顾章节核心问题学到了什么Agent 介绍Agent 是什么和 Chain 的区别Agent LLM 自主决策 工具调用工具定义怎么让 Agent“做事”tool定义create_agent组装MCP 接入怎么接入外部工具MCP 协议统一接入对 LLM 透明记忆管理怎么让 Agent 记住对话Checkpointer thread_id 实现多会话记忆中间件怎么压缩历史、人工审核SummarizationMiddleware、HumanInTheLoopMiddleware7.2 常见问题 QAQ1Chain 和 Agent 如何选择任务流程确定时用 Chain简单可靠任务需要动态判断时用 Agent灵活但复杂。两者可以结合——Agent 内部的某些子任务可以用 Chain 实现。Q2RAG 和 Agent 可以结合吗可以而且非常常见。典型做法是把 RAG 检索封装成一个工具Agent 在需要时自主调用它。例如将向量数据库检索包装为query_knowledge_base工具Agent 就可以在回答专业问题时自动检索相关知识。Q3如何优化 Agent 的响应速度四个方向只加载必需的工具减少 LLM 决策开销用SummarizationMiddleware压缩长对话减少 Token使用异步调用ainvoke支持并发优化工具返回值格式减少循环轮次Q4什么时候需要 LangGraph当你需要多个 Agent 协作、复杂的条件分支和循环逻辑或比create_agent更精细的流程控制时就需要 LangGraph。它是 Agent 的进阶编排工具。7.3 下一步建议动手实践选择一个实际场景如个人知识库问答、自动化数据分析用本课知识构建一个 Agent。深入 LangGraph学习状态图、条件边、多 Agent 协作构建更复杂的工作流。关注 AI 生态MCP 社区正在快速发展关注社区动态可以快速扩展 Agent 的能力。