4713 字
24 分钟
LLM 代理中的记忆与状态管理

原文: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 atomically
checkpointer = 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_id
config = {"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) │
└─────────────────────────────────────────────┘

这套架构已经过生产验证 的 ChatGPT 记忆功能(2024 年 2 月上线)实现了类似的模型——助理维护一个结构化的键值(key-value)记忆存储,并显式决定何时读取或更新它。

多代理系统中的状态管理#

当多个代理协作时(见 Multi-Agent Orchestration 指南),记忆架构就成了一个协调问题。主要有两种模型:

共享状态(Shared State)#

所有代理都读写同一个状态对象。编排框架(例如 LangGraph 的 StateGraph)通过归约器(reducer)管理并发访问——归约器规定来自不同代理的值如何合并:

from typing import Annotated
from 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.002–0.002–0.005 的价格计(截至 2026 年第一季度,GPT-5、Claude Sonnet 4.6、Gemini 2.5 Pro 的各档位),一个 50,000 词元的活动上下文窗口每次调用就要花 0.10–0.10–0.25。若一个代理每个任务调用 10 次、每月处理 10,000 个任务,仅上下文成本就达每月 10,000–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) 带交接的隔离状态——每个代理维护私有状态,移交控制权时通过结构化消息传递上下文。从隔离状态开始——它更容易测试与调试。

接下来读什么#

参考文献 等(2023)《Cognitive Architectures for Language Agents》,arXiv:2309.02427。Packer 等(2023)《MemGPT: Towards LLMs as Operating Systems》,NeurIPS 2023。Lewis 等(2020)《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》,NeurIPS 2020。

LLM 代理中的记忆与状态管理
https://tech.boboee.com/posts/agentengineering-memory-state-management-zh/
作者
boboee
发布于
2026-03-27
许可协议
CC BY-NC-SA 4.0