
让Agent“记住”与“可控”记忆管理与中间件实战指南在前两篇博客中我们为Agent赋予了工具调用能力并通过MCP解决了工具接入的碎片化问题。一个能调用外部工具、自主解决问题的Agent已经初见雏形。然而当我们将Agent投入真实应用场景时两个问题会立刻浮出水面失忆症Agent处理完一次请求后就像金鱼一样完全不记得刚才聊了什么。在一场多轮对话中它会对你说过的信息“左耳进右耳出”。失控感Agent可能在一轮循环中生成数百条消息或是不假思索地调用高风险的“删库”操作缺乏有效的监管。记忆管理和中间件正是LangChain生态为解决这两个核心痛点而设计的“良药”。本文将深入探讨如何让Agent拥有健壮的“短期记忆”以及如何通过中间件实现对Agent执行过程的精细控制。1. 记忆管理让Agent告别“失忆症”在LangChain中Agent的记忆通过持久化Persistence机制实现其核心思想是将Agent在某次对话中的状态State保存下来以便在后续对话中恢复。1.1 “失忆”问题为什么Agent会忘记默认情况下每次调用agent.invoke()都是一个独立的、无状态的执行单元。当这次调用结束时Agent的所有内部状态如消息历史、中间步骤等都会被销毁。因此在下一次调用中它是一个全新的、没有任何“过去”的Agent。这种无状态特性在简单的问答中没有问题但在构建复杂的、需要上下文理解的应用时就成为了致命的短板。1.2 Checkpointer记忆的“存档点”LangGraph提出了Checkpointer检查点保存器的概念。它像一个游戏中的自动存档点在Agent执行的每一步之后自动将当前的状态包括所有消息、待办事项、临时变量等保存下来。当Agent再次被调用时Checkpointer会加载之前保存的“存档”让Agent从上次结束的地方无缝继续。Checkpointer有不同的实现以适应开发和生产环境。InMemorySaver: 用于开发和测试的内存型存储。Agent状态保存在RAM中一旦进程重启所有记忆将丢失。SqliteSaver: 用于本地开发的文件型存储。状态保存在本地的SQLite数据库中进程重启后记忆依然存在。PostgresSaver:生产环境推荐。使用PostgreSQL数据库存储状态支持高并发和水平扩展是构建生产级应用的基石。AWS用户也可使用AgentCoreMemorySaver集成Bedrock服务。1.3 Thread ID记忆的“房间号”有了Checkpointer这个“保险箱”我们还需要一把钥匙来区分不同用户的“记忆”。这把钥匙就是thread_id线程ID。想象一下每个thread_id都代表一个独立的对话“房间”。同一个用户或会话使用相同的thread_idAgent就能加载这个房间里的历史记忆不同用户使用不同的thread_id他们的记忆就完全隔离互不干扰。在代码中我们将thread_id作为配置参数传入config {configurable: {thread_id: user-session-123}} # 第一次对话Agent会创建并记住“user-session-123”这个房间的状态 agent.invoke({messages: [HumanMessage(content你好我叫小明)]}, configconfig) # 第二次对话通过相同的thread_idAgent能回忆起之前的对话 agent.invoke({messages: [HumanMessage(content我叫什么名字)]}, configconfig) # Agent会回答“你叫小明”1.4 记忆的局限Checkpointer不是万能的Checkpointer提供了强大的短期记忆Short-term Memory但它也有其局限性。它是线程范围的所有记忆都依附于特定的thread_id。如果用户开启了一个全新的会话生成了新的thread_idAgent将无法访问旧会话的任何信息。对于需要跨会话记忆的长期记忆如用户偏好、历史事实LangGraph提供了StoreAPI作为补充。存储空间会增长随着对话不断进行保存的状态会不断累积可能导致存储空间膨胀和性能下降。生产环境中需要配置合理的清理策略TTL或定期归档。是“快照”不是“流”Checkpointer保存的是状态快照适合回溯和恢复但不适合用于实时协作场景。1.5 完整示例为Agent装上记忆下面是一个完整的代码示例演示了如何使用InMemorySaver和thread_id让Agent具备记忆能力。from langgraph.checkpoint.memory import InMemorySaver from langgraph.prebuilt import create_react_agent from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage # 1. 初始化模型 model ChatOpenAI(modelgpt-4o) # 2. 创建Checkpointer checkpointer InMemorySaver() # 3. 创建Agent编译时传入checkpointer agent create_react_agent(model, tools[], checkpointercheckpointer) # 4. 定义一个thread_id config {configurable: {thread_id: conversation-001}} # 5. 第一轮对话 resp1 agent.invoke( {messages: [HumanMessage(content你好我叫Alice我住在伦敦。)]}, configconfig ) print(resp1[messages][-1].content) # 输出: 你好Alice很高兴认识你 # 6. 第二轮对话使用相同的thread_id resp2 agent.invoke( {messages: [HumanMessage(content我在哪个城市)]}, configconfig ) print(resp2[messages][-1].content) # 输出: 根据你之前说的你住在伦敦。注意如果是生产环境将InMemorySaver替换为PostgresSaver即可实现持久化。2. Agent中间件为“大脑”装上“控制面板”记忆管理解决了Agent的“失忆”问题让我们能够构建流畅的对话体验。中间件则解决了另一个核心问题如何让Agent的行为更可控、更安全、更高效。2.1 概念Agent执行流水线上的“过滤器”中间件Middleware是一种强大的设计模式它在Agent的执行循环模型调用 - 工具执行 - 模型调用 - ...中插入钩子Hooks允许我们在不影响Agent核心逻辑的前提下横切Cross-cutting地处理各种关注点如日志、限流、重试、提示词注入等。LangChain的create_agent函数支持通过middleware参数传入一个中间件列表。2.2 消息压缩中间件应对上下文窗口极限当对话轮次过多消息历史可能会超出模型的上下文窗口Context Window限制导致昂贵的长上下文费用或直接报错。SummarizationMiddleware消息压缩中间件正是为此而生。它的工作原理是当消息总长度或总轮数达到预设的阈值时自动触发一个摘要过程。它会将较早的消息压缩成一个简短的文本摘要用这个摘要代替原始消息从而保证对话上下文始终在模型处理能力之内。from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent create_agent( modelgpt-4o, tools[...], middleware[ SummarizationMiddleware( # 例如当上下文达到总容量的75%时触发总结 trigger(context_fraction, 0.75), # 保留最新的10条消息不进行总结以保证近期的细节不丢失 keep(messages, 10) ), ], )2.3 人工审核中间件为高风险操作按下“暂停键”对于一些关键或高风险操作我们往往希望在工具执行前加入人工审核环节这就是HumanInTheLoopMiddleware人工审核中间件。当Agent尝试调用被interrupt_on标记的工具时执行会暂停并生成一个待审核的请求。系统需要等待管理员通过接口批准、拒绝或编辑该请求后Agent才能继续执行。from langchain.agents import create_agent from langchain.agents.middleware import HumanInTheLoopMiddleware from langgraph.checkpoint.memory import InMemorySaver # 假设send_email是一个发送邮件的工具 agent create_agent( modelgpt-4o, tools[send_email, ...], checkpointerInMemorySaver(), # HITL依赖于Checkpointer来保存中断状态 middleware[ HumanInTheLoopMiddleware( interrupt_on{ send_email: { # 针对send_email工具 allowed_decisions: [approve, edit, reject], # 允许批准、编辑后执行、拒绝 } } ) ], )2.4 示例组合使用中间件在实际应用中我们常常会组合多种中间件以达到最佳效果。比如在一个金融咨询Agent中我们既需要通过SummarizationMiddleware控制长对话成本又需要通过HumanInTheLoopMiddleware保障涉及资金操作的安全性。from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware, HumanInTheLoopMiddleware agent create_agent( modelgpt-4o, tools[check_balance, transfer_funds, ...], middleware[ # 第一个中间件处理消息压缩 SummarizationMiddleware(trigger(tokens, 100000)), # 第二个中间件为关键操作加入人工审核 HumanInTheLoopMiddleware( interrupt_on{transfer_funds: {allowed_decisions: [approve, reject]}} ), # ... 可以添加更多中间件 ], )总结记忆管理和中间件是构建生产级AI Agent不可或缺的两大支柱记忆管理Checkpointer Thread ID让Agent拥有了连贯的对话能力它通过持久化状态解决了无状态Agent的“失忆”问题是实现流畅用户体验的基础。中间件Middleware则为Agent提供了强大的治理能力通过SummarizationMiddleware和HumanInTheLoopMiddleware等内置中间件我们可以灵活地控制成本、保障安全并增强系统的健壮性。掌握这两项技能意味着你不仅能让Agent“动起来”更能让它在你设定的轨道上“安全、高效地跑起来”。