原文:Memory & State Management in LLM Agents(AgentEngineering.io,David Akuma,2026-03-27)。本文为中文翻译,插图来自原文。
无状态(stateless)的 LLM 能回答问题,但代理(agent)需要追求目标——跨多个步骤、可能跨多个会话,而且常常与其他代理协同。这需要记忆。
在代理系统中,记忆并非单一机制,而是一整套互补机制的堆叠,每种机制各有不同的作用范围、成本与检索延迟。为某个用例选错层级,是生产环境代理最常见的不可靠来源之一。本指南将完整呈现这幅图景:说明每个层级何时适用,并提供你今天就能落地的具体实现模式。
重要:本文直接建立在《What Is Agent Engineering?》一文介绍的架构概念之上。如果你还没读过那篇,建议先读——它确立了记忆所嵌入的感知→推理→行动(perception → reasoning → action)循环。
为什么记忆比上下文窗口大小更重要
一个常见的本能反应是:当代理的上下文不够用时,就去换一个窗口更大的模型。GPT-5 在其基础档位支持最多 128,000 个词元(token);Claude Opus 4.6 与 Claude Sonnet 4.6 各支持 200,000 个词元;Google 的 Gemini 2.5 Pro 则达到 2,000,000 个词元。这些窗口确实很大,但它们仍然有限、成本高昂(成本随词元数线性增长),而且转瞬即逝——每一次新会话都从零开始。
真正的问题不是”模型现在能看到多少上下文?“,而是”代理需要知道什么,又需要知道多久?”。这些是架构层面的问题,上下文窗口大小无法回答。
来自 DeepMind 与学术团体的研究已把这种直觉形式化。Cognitive Architectures for Language Agents(CoALA)(即”语言代理的认知架构”)框架(Sumers 等,2023)提出了一个与人类认知科学直接对应的四层记忆分类法:工作记忆、情景记忆、语义记忆与程序性记忆。这个分类法与下面四个实现层级一一对应。
记忆的四个层级
第 1 层:上下文内记忆(工作记忆)
它是什么: 当前加载进模型活动上下文窗口(active context window)的一切:系统提示词(system prompt)、对话历史、工具结果,以及任何注入的文档。
特点:
- 零检索延迟——模型直接对其加以注意
- 有硬性上限(模型的上下文限制)
- 会话一结束就完全丢失,除非被显式持久化到别处
- 推理时的成本随词元数增长
何时使用:
- 单次会话内即可完成的短期任务
- 必须被连贯地一起注意的信息(例如需要从头到尾审阅的代码文件)
- 作为中间推理步骤的临时草稿区(scratchpad)
实现模式——滑动窗口加摘要(sliding window with summarization):
MAX_HISTORY_TOKENS = 4_000 # reserve the rest of the window for tools + output
def trim_history(messages: list[dict], tokenizer) -> list[dict]: """Keep the system prompt, summarize older turns, keep recent turns verbatim.""" total = sum(len(tokenizer.encode(m["content"])) for m in messages) while total > MAX_HISTORY_TOKENS and len(messages) > 2: # Remove the oldest non-system message messages.pop(1) total = sum(len(tokenizer.encode(m["content"])) for m in messages) return messages这种做法的局限在于信息丢失:一旦某条消息被逐出,代理便再也无法回忆它。正是这个”逐出(eviction)问题”催生了下面两个层级。
第 2 层:外部记忆(检索/向量库)
它是什么: 存储在模型之外、为语义检索建立索引的信息。查询时,代理把查询转换为嵌入向量(embedding),在索引中搜索最相关的分块(chunk),再注入活动上下文。
这是**检索增强生成(Retrieval-Augmented Generation,RAG)**的基础——由 Lewis 等(2020)提出,如今已成为知识型代理的标准架构。
特点:
- 存储近乎无限
- 托管向量数据库的检索延迟约为 50–200 毫秒
- 质量受分块策略与嵌入模型质量制约
- 无需重新训练基础模型即可更新信息
何时使用:
- 体量大或频繁更新的知识库(产品文档、法律语料、代码库)
- 必须跨会话持久化的用户特定事实(偏好、既往决策)
- 任何全量加载会撑爆上下文窗口的信息
把检索当作一次工具调用:
与其把检索当作模型调用之前的预处理步骤,现代模式——与工具使用架构一致——是把检索暴露为代理可主动调用的显式工具:
tools = [ { "name": "search_knowledge_base", "description": "Retrieve relevant documentation chunks for a given query.", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "A focused search query. Be specific." }, "top_k": { "type": "integer", "description": "Number of chunks to return. Default 5.", "default": 5 } }, "required": ["query"] } }]这让检索在代理的推理轨迹中清晰可见,对调试与评估至关重要——本系列后续文章会专门讨论。
主流的向量库选型:
| 向量库 | 最适合的场景 | 托管方式 |
|---|---|---|
| Pinecone | 托管式、生产级规模 | 仅云端 |
| Weaviate | 混合(关键词 + 向量)检索 | 自托管或云端 |
| pgvector | 已在用 PostgreSQL 的团队 | 自托管 |
| Chroma | 本地开发、原型验证 | 嵌入式或自托管 |
| Qdrant | 高吞吐、Rust 原生 | 自托管或云端 |
对大多数团队而言,如果已经在跑 Postgres,pgvector 是通往生产环境摩擦最小的路径;当你需要一个与应用数据库独立伸缩的完全托管方案时,Pinecone 才是正确的选择。
提示:在检索与注入之间加一个重排器(re-ranker)。第一遍的嵌入相似度检索快但不精准。用一个轻量级交叉编码器(cross-encoder)重排器(例如 cross-encoder/ms-marco-MiniLM-L-6-v2)对前 20 个候选做重排,能以显著更高的精度挑出最相关的前 5 个分块——代价只是增加 10–30 毫秒的延迟。
第 3 层:情景记忆(事件日志)
它是什么: 代理所做事情的、结构化的、按时间排序的记录——发起的工具调用、收到的结果、做出的决策与用户交互。与上下文内记忆(它是活的工作集)不同,情景记忆是跨会话存续的持久日志(durable log)。
这个术语直接来自认知科学:情景记忆是人类回忆具体事件的方式(“我周二跑了一次数据库迁移”),而不是一般性事实(“PostgreSQL 必须有主键”)。
特点:
- 跨会话持久——存于数据库而非上下文窗口
- 可按需选择性检索(例如”这个代理昨天做了什么?”)或摘要
- 构成审计轨迹(audit trail),对调试与合规必不可少
- 可用于为后续会话预热(bootstrap),而无需重放全部历史
何时使用:
- 任何必须跨会话保持连续性的代理(个人助理、长时运行的工作流)
- 需要共享”每个代理做了什么”这一历史的多代理系统
- 审计轨迹属于合规要求的受监管行业
LangGraph 的检查点(checkpointer)模型:
LangGraph(本站介绍过的框架之一)以**检查点(checkpoint)**的形式实现情景记忆——在每个节点执行时对完整图状态做快照。这是头等特性,而非事后补丁:
from langgraph.checkpoint.postgres import PostgresSaver
# Every state transition is persisted atomicallycheckpointer = PostgresSaver.from_conn_string(os.environ["DATABASE_URL"])
graph = StateGraph(AgentState)# ... define nodes/edges ...app = graph.compile(checkpointer=checkpointer)
# Resume a prior run by thread_idconfig = {"configurable": {"thread_id": "user-abc-session-42"}}result = await app.ainvoke({"messages": [HumanMessage(content="Continue where we left off")]}, config)LangGraph 支持内存/SQLite(通过 MemorySaver——适合开发)与 PostgreSQL 作为主要检查点后端,另有 Redis 可用(通过 langgraph-checkpoint-redis 包)。
会话摘要模式:
对长时运行的代理,事件日志会无限增长。标准的缓解手段是渐进式摘要(progressive summarization):每隔固定间隔(例如每 20 轮或每小时),用一个摘要代理处理最早未经摘要的事件,将其替换为一段紧凑的摘要,并作为一条特殊的情景记录存储。
第 4 层:程序性记忆(微调/内化的知识)
它是什么: 通过预训练或微调直接编码进模型权重的知识。模型”知道”如何写 Python、知道 HIPAA 有什么要求、知道你内部 API 的结构——而无需在运行时检索这些信息。
特点:
- 推理时零检索成本
- 更新昂贵且缓慢——需要一次训练
- 没有”事实来源”链接——模型无法引用它据以学习的文档
- 最适合稳定、高频、否则会撑大每个上下文窗口的知识
何时使用:
- 检索延迟成为瓶颈的高吞吐生产代理
- 变动不频繁的稳定领域知识(法律定义、医疗编码标准)
- 应当无条件遵循的行为指令(语气、输出格式、安全规则)
何时不该用:
- 变动频率超过每月一次的知识——微调的节奏跟不上
- 需要溯源引用的客观知识——微调后的模型无法自我引用
- 开发早期——提示词的迭代周期是小时级,微调则是天级
警告:微调可能以意想不到的方式覆盖通用能力。为狭窄领域微调代理的团队,经常报告在相邻任务上性能下降。务必在每次微调前后维护一套回归评估(regression evaluation)套件。
选择正确的层级:一个决策框架
四个层级并非互斥——大多数生产代理会同时用到全部四层。要做出的决策是:某条信息该由哪一层负责。
| 问题 | 建议层级 |
|---|---|
| 这条信息是否需要被一次性连贯地一起注意? | 上下文内(in-context) |
| 这条信息是否太大、放不进上下文? | 外部检索(external retrieval) |
| 代理是否需要跨会话回忆自己做过什么? | 情景日志(episodic log) |
| 是否属于高频、稳定、且检索延迟不可接受的知识? | 程序性(微调) |
| 这条信息是否变动频繁? | 外部检索(绝不微调) |
| 是否需要审计轨迹? | 情景日志 |
对大多数团队而言,一个实用的起点是如下优先级:从上下文内记忆开始;上下文放不下时,加入外部检索;需要跨会话连续性时,加入情景日志;只有当事实证明检索无法满足延迟要求时,才考虑微调。
MemGPT 洞见:把操作系统当作代理记忆的模型
代理记忆架构中最有影响力的思想之一,来自 UC Berkeley 2023 年的一篇论文:MemGPT: Towards LLMs as Operating Systems(Packer 等,2023,NeurIPS 2023)。该系统现已更名为 Letta,它在操作系统记忆层级(L1/L2 缓存、RAM、磁盘)与 LLM 代理记忆之间建立了直接类比。
关键洞见在于:代理本身应当负责决定把什么换入、换出上下文。MemGPT/Letta 不借助外部控制器来管理记忆,而是授予代理工具,让它显式读写一个持久记忆存储,把上下文窗口当作一个受管缓存:
┌─────────────────────────────────────────────┐│ Context Window (RAM) ││ ┌──────────────┐ ┌──────────────────────┐ ││ │ System Prompt│ │ Working Memory │ ││ │ (fixed) │ │ (agent-managed KV) │ ││ └──────────────┘ └──────────────────────┘ │└─────────────────────────────────────────────┘ ↕ paging┌─────────────────────────────────────────────┐│ External Storage (Disk) ││ - Archival memory (vector store) ││ - Conversation history (episodic log) │└─────────────────────────────────────────────┘这套架构已经过生产验证
多代理系统中的状态管理
当多个代理协作时(见 Multi-Agent Orchestration 指南),记忆架构就成了一个协调问题。主要有两种模型:
共享状态(Shared State)
所有代理都读写同一个状态对象。编排框架(例如 LangGraph 的 StateGraph)通过归约器(reducer)管理并发访问——归约器规定来自不同代理的值如何合并:
from typing import Annotatedfrom operator import add
class SharedAgentState(TypedDict): messages: Annotated[list, add] # messages from all agents are appended research_notes: Annotated[list, add] # each agent contributes to the shared pool final_answer: str # last-writer-wins (no reducer)优势: 代理无需显式传递消息,就能看到彼此的工作。 风险: 写冲突与意外的状态覆盖。对任何会被多个代理写入的字段,都要使用归约器。
带交接的隔离状态(Isolated State with Handoffs)
每个代理维护各自的私有状态。当控制权从一个代理转移到另一个时,一条结构化消息(交接负载,handoff payload)只携带接收方需要的内容。这是 OpenAI Swarm 与 Pydantic AI 的代理交接 API 所用的模型。
优势: 更易推理,更易在隔离状态下单独测试各个代理。 代价: 交接负载必须精心设计——漏掉接收代理所需的上下文,是常见的 bug 来源。
提示:对大多数团队,从隔离状态加显式交接开始。共享状态在设计上显得优雅,但当两个代理写入相互冲突的值时,它很难调试。只有当代理确实需要对彼此的工作有实时可见性时,才改用共享状态。
常见陷阱
1. 把检索当作预处理,而非工具
在 LLM 调用之前先跑检索、再把结果盲目塞进上下文,意味着代理无法对检索质量进行推理。把检索暴露为工具,让代理自己决定何时调用、返回结果是否足够。
2. 忽视规模下的上下文窗口成本
以前沿模型约每 1K 输入词元 0.005 的价格计(截至 2026 年第一季度,GPT-5、Claude Sonnet 4.6、Gemini 2.5 Pro 的各档位),一个 50,000 词元的活动上下文窗口每次调用就要花 0.25。若一个代理每个任务调用 10 次、每月处理 10,000 个任务,仅上下文成本就达每月 25,000——还没算输出词元。记忆设计是一个成本优化问题。
3. 长时运行的情景日志没有压缩策略
没有渐进式摘要,情景日志会无限增长。活跃使用两周后,一个个人助理代理就可能积累 50 万+ 词元的历史。在上生产之前,就定好压缩(compaction)计划表。
4. 同时写入所有层级
有些实现在代理每一轮都向外部存储持久化。对高频代理,写入向量数据库或 PostgreSQL 检查点的延迟会成为瓶颈。在一致性要求允许时,批量写入或异步写入。
5. 调试时混淆记忆层级
当代理产出错误结果时,根因可能出在任意一层:向量库里的过期数据、损坏的情景状态、或是覆盖了预期提示词的微调行为。务必在你的可观测性(observability)体系里把每一层分开埋点。
关键要点
- 记忆是一套堆叠,而非单一机制。上下文内记忆、外部检索、情景记忆与程序性记忆各有独特作用。
- 上下文内记忆是缓存。快速且连贯,但有限且转瞬即逝。
- 外部检索(RAG)是长期存储。可扩展、可更新,代价是检索延迟与分块复杂度。
- 情景记忆是审计轨迹与连续性层。对多会话代理与受监管行业必不可少。
- 程序性记忆(微调)是最后手段。只有当检索延迟确实不可接受、且知识保持稳定时才值得动用。
- 多代理系统中的状态管理是一个协调问题。从隔离状态与显式交接开始;确有必要时才引入共享状态。
常见问题解答
什么是 LLM 代理中的上下文内记忆?
上下文内记忆就是当前加载进模型活动上下文窗口的一切——系统提示词、对话历史与注入的文档。它是代理的工作记忆:立即可访问,但受模型上下文窗口大小限制,并会在会话结束时丢失。
RAG 与上下文内记忆有什么区别?
上下文内记忆是模型当前所见的东西。RAG(检索增强生成)是一种为上下文填充内容的技巧:从外部向量库检索相关分块。RAG 解决的是规模问题:代理不必把整个知识库载入上下文,而是在查询时只检索最相关的片段。
LLM 代理如何跨会话记住事情?
跨会话持久的记忆需要一个显式的外部存储。最常见的模式是:(1) 情景日志——既往交互的数据库,可被摘要并注入未来的会话;(2) 外部键值或向量存储——代理把应当记住的事实写进去。LangGraph 的检查点 API 以及 MemGPT/Letta 这类架构,在框架层面实现了这一点。
何时该为代理微调模型,而不是用 RAG?
微调适用于:知识稳定(变动少于每月一次)、检索延迟是硬约束、且你有足够带标注的数据可用于训练。对大多数团队,RAG 是更好的起点,因为它更新更快、支持溯源引用,而且不需要训练基础设施。
代理记忆该用哪个向量数据库?
如果你已经在跑 PostgreSQL,从 pgvector 开始——它需要的新增基础设施最少。需要与应用数据库独立伸缩的完全托管方案,用 Pinecone。本地开发用 Chroma。需要混合关键词 + 向量检索时,评估 Weaviate。
多代理系统如何共享记忆?
两种主要模型:(1) 共享状态——所有代理读写由编排框架管理的单一状态对象(例如带归约器的 LangGraph StateGraph);(2) 带交接的隔离状态——每个代理维护私有状态,移交控制权时通过结构化消息传递上下文。从隔离状态开始——它更容易测试与调试。
接下来读什么
- RAG in Production: Chunking, Hybrid Search, and Agentic Retrieval——本系列(系列第 3 天)的下一篇,深入探讨面向代理检索负载的分块、嵌入与重排
- Multi-Agent Orchestration: Patterns and Trade-offs——协调模式如何与上文所述共享/隔离状态模型相互作用
- Tool Use in LLM Agents: Patterns, Pitfalls, and Best Practices——作为”检索即工具”之基础的调用模式
参考文献