Skip to content

05. 状态、记忆与上下文工程 ​

版本:v1.2

最后更新:2026-07-09

1. 为什么这一章是 Agent 的分水岭 ​

很多 Demo 看起来能跑,但一进入真实任务就崩,核心原因通常不是模型不够强,而是:

  • 没有设计好状态
  • 没有设计好记忆
  • 没有设计好上下文传递

简单说:

  • 模型能推理
  • 但系统必须帮它“记住该记住的东西”

2. 状态是什么 ​

状态是 任务执行过程中持续存在并会变化的信息。

例如:

  • 当前任务目标
  • 已完成步骤
  • 当前轮次
  • 已调用哪些工具
  • 检索到哪些文档
  • 当前审批状态
  • 最近一次错误

如果这些信息只靠模型“自己记住”,长任务就会非常不稳定。

2.1 更像生产系统的状态,通常至少分成四层 ​

很多 Demo 只有一个大对象叫 state,里面什么都塞。

但真实系统里,更稳的做法通常是拆层:

状态层典型内容为什么要单独分层
orchestration state当前节点、下一步、分支判断、handoff 去向这是工作流控制面,不该和工具细节混成一团
execution state工具调用结果、重试次数、超时、最后错误这是执行面,决定是否继续、重试还是升级
evidence state检索证据、引用片段、摘要、草稿版本这是模型真正需要消费的内容来源
governance stateapproval、policy hit、risk level、人工接管点这是治理面,决定哪些动作能不能继续

拆开之后有几个直接好处:

  • trace 更容易读
  • checkpoint 更容易恢复
  • 不同层可以分别做持久化和清理
  • 某一层出问题时,不会把整个对象一起污染

3. 记忆是什么 ​

记忆更偏向:

  • 跨轮次
  • 跨任务
  • 跨会话

保留下来的信息。

例如:

  • 用户偏好
  • 历史项目背景
  • 常用领域术语
  • 历史成功处理方式

4. 短期状态与长期记忆的区别 ​

短期状态 ​

服务于当前这一次任务。

特点:

  • 生命周期短
  • 与执行过程强相关

长期记忆 ​

服务于未来任务。

特点:

  • 生命周期长
  • 与用户、组织、业务事实相关

不要把所有东西都塞进长期记忆,否则系统会越来越脏。

4.1 还有一层经常被忽略:可恢复会话状态 ​

很多团队只区分:

  • 当前轮状态
  • 长期记忆

但生产里通常还需要第三层:

  • durable session state

它既不是“一次请求内的临时变量”,也不是“永久记忆”,而是:

  • 为当前任务链路服务
  • 跨多轮、多工具、多审批点保留
  • 在任务结束或过期后可以清理

典型内容包括:

  • 当前计划版本
  • 已通过的审批点
  • 当前 artifact 引用
  • 最近一次成功 checkpoint
  • 等待中的外部回调

如果这层缺失,系统很容易变成两个极端:

  • 要么什么都不存,恢复不了
  • 要么什么都进长期记忆,越存越脏

5. LangGraph 给我们的一个很好的思路 ​

根据 LangGraph Persistence 文档在 2026-07-01 可访问的说明:

  • checkpointers 用于线程级、短期运行状态
  • stores 用于跨线程、长期数据保存

这个区分非常值得借鉴:

  • 当前任务的中间过程,放到运行状态
  • 未来仍然有价值的事实,再考虑放进长期存储

5.1 OpenAI Sessions 给出的另一个重要边界 ​

OpenAI Agents SDK 当前 Sessions 文档也非常值得一起看,因为它强调的是另一种常见需求:

  • 在多轮 agent runs 之间保留工作上下文

这提醒我们至少要分清三层对象:

对象更像什么适合保存什么
run一次具体执行当前工具调用、当前输出、当前中断
session一段持续交互多轮历史、连续任务上下文、当前工作记忆
memory store跨 session 的长期层稳定事实、偏好、可复用知识

如果这三层不分开,最常见的混乱就是:

  • 把本来只属于当前 run 的中间结论写进长期记忆
  • 把本来只需要会话保留的信息误当成永久事实
  • 以为“有了 session”就不需要显式状态和 checkpoint

更稳的理解通常是:

  • session 解决连续交互
  • state 解决可恢复执行
  • memory 解决跨任务沉淀

6. 为什么不能只靠聊天历史 ​

很多人一开始会把“状态管理”理解成:

  • 把所有历史对话拼进去

这通常不够,原因有 4 个:

  1. 历史越来越长
  2. 噪音越来越多
  3. 关键信息不结构化
  4. 无法稳定恢复任务

真正的状态管理,应该是:

  • 有结构
  • 有字段
  • 有边界

7. 上下文工程是什么 ​

上下文工程可以理解为:

  • 决定在当前这一步,到底要给模型看什么

这和“存了多少信息”不是一回事。

上下文工程要解决的核心问题是:

  1. 哪些信息必须给模型
  2. 哪些信息会干扰模型
  3. 哪些信息该由工具随取随用
  4. 哪些信息应该结构化而不是自然语言拼接

8. 上下文来源通常有哪些 ​

  1. 用户当前输入
  2. 系统提示词
  3. 当前任务状态
  4. 历史对话摘要
  5. 检索出的文档片段
  6. 工具返回结果
  7. 本地上下文或运行依赖

根据 OpenAI Agents SDK define agents 文档在 2026-07-01 的可访问说明:

  • 有些本地上下文应与模型上下文分开管理
  • 比如认证用户信息、数据库客户端、日志器、辅助函数

这非常关键,因为:

  • 不是所有运行上下文都应该发给模型

8.1 更像生产系统的上下文装配顺序 ​

很多系统的问题不是“缺上下文”,而是“上下文装配顺序没有被设计过”。

一个更稳的装配顺序通常是:

  1. 固定策略层:system / developer 规则、输出契约、安全边界。
  2. 任务快照层:当前目标、阶段、最近决定、未决问题。
  3. 证据层:最新有效的检索结果、工具结果、引用材料。
  4. 动作层:当前允许使用的工具、schema、审批约束。
  5. 输出层:这一步到底要产出什么。

这个顺序的价值是:

  • 让稳定规则不要被动态证据淹没
  • 让模型先知道“自己在做什么”,再看“手里有什么”
  • 让工具定义和输出约束始终贴着当前动作

8.2 不要把原始状态对象整包塞给模型 ​

状态表设计得再漂亮,也不等于应该直接把整包 JSON 发给模型。

更稳妥的做法通常是:

  • 应用内部保存全量状态
  • 模型只拿当前决策需要的最小切片
  • 高噪音字段先摘要化或转成人可读结构

否则常见后果是:

  • 模型被内部字段名和无关标记干扰
  • token 花在“系统自己看得懂、模型却不一定看得懂”的内容上
  • 同一个状态对象一膨胀,所有步骤都一起变慢

9. 一个实用的上下文分层思路 ​

可以把上下文分成三层:

第一层:必须发给模型的内容 ​

例如:

  • 当前任务目标
  • 当前可用证据
  • 输出要求

第二层:应用内部要知道,但不必发给模型的内容 ​

例如:

  • 用户 ID
  • 权限信息
  • DB 连接
  • 调试标记

第三层:按需检索的内容 ​

例如:

  • 大量文档
  • 历史案例
  • 表结构
  • 长对话归档

这三层分清楚,很多 Agent 稳定性问题会少很多。


10. RAG 在 Agent 里的作用 ​

RAG 不是 Agent,但常常是 Agent 的重要组成部分。

Agent 中的 RAG 主要用来:

  • 找事实
  • 找依据
  • 找可引用内容

一个成熟的 Agent 通常不会把所有知识都塞进 Prompt,而是:

  1. 先判断是否需要检索
  2. 再检索相关内容
  3. 再把结果带入当前步骤

11. 状态设计时最该保存什么 ​

建议优先保存:

  • 目标
  • 当前步骤
  • 已完成步骤
  • 中间结论
  • 证据引用
  • 错误计数
  • 审批结果
  • 输出草稿版本

不建议盲目保存:

  • 每一句自然语言思考
  • 所有原始上下文全文
  • 无区分的整段对话历史

11.1 checkpoint 最好保存“可恢复最小集” ​

真正能帮你恢复任务的,往往不是完整历史,而是一组最小可恢复字段。

建议 checkpoint 至少能回答:

  • 当前 run / session 是谁
  • 当前节点和下一步是什么
  • 最近一次工具调用做到哪一步
  • 哪个 artifact / draft 是当前生效版本
  • 哪个 approval / policy 状态已通过
  • 当前引用了哪些证据

如果恢复点里没有这些字段,系统经常会出现:

  • 对话能续上,但副作用对不上
  • 工具结果还在,草稿版本却丢了
  • 审批 UI 还在显示待处理,执行层已经继续了

12. 长期记忆应该存什么 ​

适合长期存的通常是:

  • 用户偏好
  • 组织规则
  • 业务术语
  • 已确认事实
  • 历史成功模板

不适合长期存的通常是:

  • 未验证推测
  • 一次性中间过程
  • 低质量工具输出
  • 敏感临时数据

12.1 长期记忆写入最好走一条显式流水线 ​

更成熟的系统通常不会让模型“觉得有用”就直接写入长期记忆。

更稳的写入流水线通常至少包含:

  1. candidate:先把候选记忆提取出来。
  2. validate:判断它是不是事实、偏好、规则,是否经过验证。
  3. dedupe:和已有记忆做去重或合并。
  4. label:打上来源、置信度、敏感级别、owner、更新时间。
  5. publish:只有过门槛的内容才进入可检索记忆。

这条流水线的价值非常实际:

  • 降低幻觉写入长期记忆的概率
  • 让错误记忆更容易回滚
  • 让不同来源的记忆可以做优先级治理

12.2 记忆不只是要“会写”,还要“会失效” ​

长期记忆最容易被忽略的问题,是失效和删除。

至少要提前设计:

  • 哪些记忆有 TTL
  • 哪些记忆需要定期再验证
  • 哪些记忆跟随 source of truth 一起撤销
  • 用户偏好和组织规则发生冲突时谁优先

否则系统很容易出现:

  • 老偏好永久压着新偏好
  • 已作废规则还在被召回
  • 已被纠正的事实仍在影响后续任务

13. OpenAI 的状态续接能力,适合解决什么问题 ​

根据 OpenAI Conversation state 文档在 2026-07-07 可访问的说明,Responses API 可以通过 previous_response_id 续接前一个响应链,这对多轮任务和 Agent workflow 很有价值,因为它允许你:

  • 不必每一轮都手工回传全部历史
  • 让模型沿着上一轮的状态继续生成
  • 在需要时重新注入新的工具结果或上下文

但这项能力更像“上下文续接机制”,而不是“完整状态管理系统”。原因是:

  1. 它解决的是模型侧连续性,不自动等于业务状态已经持久化。
  2. 一旦历史对象不可用,应用层仍然要知道怎么回放或重建现场。
  3. 外部副作用、审批状态、租约和权限等对象,本来就应该由应用自己持久化。

所以更稳妥的落地方式通常是:

  • 模型对话链负责保持推理连续性
  • 应用状态表负责保存工作流真实状态
  • 长期记忆层负责沉淀跨任务仍有价值的事实

这三层不要混成一层。


14. 上下文续接不等于 instructions 自动继承 ​

OpenAI Conversation state 文档在 2026-07-07 可访问的说明里,还特别强调了一个容易被忽视的点:

  • previous_response_id 不会自动继承 instructions

这意味着如果你的 Agent 很依赖系统规则、输出约束或安全边界,就不能因为“续接了前一轮”而默认这些规则仍然存在。

更稳妥的做法是:

  1. 把稳定规则放进固定可重建的系统层模板。
  2. 每轮都显式补齐不可丢失的治理约束。
  3. 把会变化的状态字段和稳定的策略字段分开管理。

否则非常容易出现这种隐蔽问题:

  • 任务看起来还在同一条链路上
  • 但关键约束已经悄悄丢了

15. 长期记忆写入要有准入门槛 ​

长期记忆最大的风险不是“没有记住”,而是“记住了不该记的东西”。

所以和数据库建表很像,长期记忆也应该有准入策略。建议至少问四个问题:

  1. 这条信息是否跨任务仍有价值。
  2. 它是事实、偏好还是临时推测。
  3. 它是否经过验证。
  4. 它是否会带来安全或合规风险。

可以把长期记忆粗分成三类:

类型例子是否建议长期保存
稳定事实客户行业、系统约束、术语解释建议
偏好信息输出格式偏好、沟通语言、关注维度谨慎建议
一次性痕迹临时故障、未证实猜测、中间推理不建议

LangGraph Memory overview 的思路也很值得借鉴:

  • checkpointer 负责线程级短期状态
  • store 负责跨线程共享与检索的长期数据

把这个边界想清楚,长期记忆污染会少很多。

12.3 长期记忆最好按“事实 / 偏好 / 过程痕迹”分槽 ​

很多系统的长期记忆之所以越来越脏,一个原因是不同类型的信息都混在同一个桶里。

更像生产系统的做法通常会至少分成三槽:

记忆槽典型内容默认策略
fact memory稳定业务事实、术语、组织规则可检索、可版本化、变更要覆盖旧值
preference memory输出格式偏好、语言偏好、关注维度可更新、冲突时以最近验证值为准
trace residue单次任务中间痕迹、失败尝试、未证实猜测默认不进长期记忆,必要时只进审计层

这样做的价值非常直接:

  • 事实不会和偏好混在一起
  • 偏好不会和一次性失败痕迹混在一起
  • 删除和失效策略可以分开设计

如果不分槽,后面最容易出现的就是:

  • 用户一次性要求被当成永久偏好
  • 临时猜测被当成稳定事实
  • 清理时不知道哪些能删、哪些不能删

12.4 长期记忆写入最好经过“提议 - 验证 - 写入 - 失效”流水线 ​

长期记忆写入如果只是:

  • 模型觉得重要,就直接写

那污染几乎是迟早的事。

更稳的写入流水线通常至少包含四步:

  1. propose:先提出候选记忆
  2. validate:检查是否稳定、是否重复、是否合规
  3. commit:写入对应记忆槽
  4. expire / revise:过期、覆盖或撤销旧值

这条流水线的意义是:

  • 把“模型感觉值得记”变成“系统确认值得记”

尤其在企业环境里,至少还值得额外检查:

  • 是否含敏感信息
  • 是否和现有事实冲突
  • 是否需要 owner 或人工确认
  • 是否需要带时间戳与来源

16. 上下文压缩不是“越短越好”,而是保留决策所需最小集 ​

当任务变长之后,真正的问题通常不是“上下文有没有”,而是:

  • 给模型看的内容里,哪些还在起作用

OpenAI 关于 conversation state 的说明、Anthropic 关于 context windows 的说明,以及 prompt caching 的建议,放在一起看会很有启发:

  • 上下文窗口再大,也不等于应该把全部内容都持续塞进去
  • prompt caching 解决的是重复传输成本,不会神奇地替你降低推理复杂度
  • 需要保留的是对当前决策仍有影响的信息,而不是所有历史痕迹

一个更可执行的压缩顺序通常是:

  1. 保留当前任务目标和约束。
  2. 保留最近有效的工具结果与证据。
  3. 摘要化早期回合,只留下关键决定和结论。
  4. 把大块参考资料转成按需检索,而不是常驻上下文。

压缩做得不好,常见后果不是“模型忘了全部内容”,而是:

  • 模型把次要信息当成重点
  • 响应变慢
  • token 成本快速上升

16.1 prompt caching 不是长期记忆,也不是状态治理 ​

Anthropic 当前 Prompt caching 文档和 OpenAI 当前 Conversation state / Compaction 相关思路放在一起看,很容易得到一个很实用的判断:

  • cache 解决的是重复传输和重复计算成本
  • memory 解决的是跨任务保留什么事实
  • state 解决的是当前任务如何继续

这三件事非常容易被混掉。

例如:

  • 命中 prompt cache,不代表系统已经拥有长期记忆
  • 能续接上一轮 response,不代表执行状态已经可恢复
  • 把所有材料常驻上下文,不代表上下文治理做得好

所以更成熟的上下文设计通常会分开回答:

  1. 哪些前缀值得缓存
  2. 哪些事实值得长期记忆
  3. 哪些状态字段必须持久化
  4. 哪些证据应该按需检索

16.2 上下文压缩最好伴随“决策摘要”,而不是只做字数摘要 ​

很多系统做压缩时只会把历史缩短成更短的一段话。

但对 Agent 来说,更有价值的往往不是“更短”,而是“更利于下一步决策”。

更实用的压缩结果通常至少包括:

  • 当前目标
  • 最近已确认的关键事实
  • 尚未解决的问题
  • 已尝试但失败的路径
  • 下一步可行动作

这类摘要可以理解成:

  • decision summary

而不是普通聊天摘要。

因为 loop 真正需要保留的,不只是聊过什么,而是:

  • 为什么会走到当前这一步

17. 本地运行上下文要和模型可见上下文分层 ​

Agent 系统里有一类信息非常重要,但又不应该直接进入模型上下文,例如:

  • 认证 token
  • 数据库连接
  • 原始日志器
  • 内部调试标志
  • 高权限系统句柄

OpenAI Agents SDK 关于 context 的文档在 2026-07-07 可访问的说明里,就明确把这类对象视作本地运行时上下文,而不是默认发给模型的消息内容。

这层分离的价值非常大:

  1. 能降低泄漏机密的概率。
  2. 能让工具执行层拿到运行依赖,但不污染模型推理。
  3. 能让相同 Agent 在不同宿主里复用,而不是把宿主细节硬编码进 Prompt。

如果系统里还没有这层分离,后面越做越大时很容易出现:

  • 安全边界混乱
  • 提示词越来越脏
  • 工具调试越来越难

17.2 运行时上下文最好显式做脱敏与投影 ​

“本地上下文不要直接给模型”这件事,不应该只靠开发者自觉。

更稳的做法通常是显式设计两层动作:

  1. redaction
  2. projection

也就是:

  • 先把敏感字段、内部句柄、认证信息排除掉
  • 再把模型真正需要的事实投影成可读、可控的上下文片段

例如:

  • 模型不需要知道完整 token
  • 但可能需要知道“当前用户属于哪个角色”
  • 模型不需要知道数据库 client 对象
  • 但可能需要知道“当前查询目标表有哪些字段”

如果没有这一步,你很容易得到一个两头都不好的系统:

  • 要么什么都不给,模型决策缺关键事实
  • 要么全都给,机密和噪音一起泄进去

17.1 副作用动作最好绑定到独立执行记录 ​

很多 Agent 系统的问题,不是模型推理断了,而是:

  • 模型说自己已经做了
  • 实际工具并没有成功执行

所以更稳的做法通常是把高风险动作单独记录成 execution record,例如:

  • tool_call_id
  • approval_id
  • idempotency_key
  • execution_status
  • side_effect_scope
  • resume_token

这样恢复时才能分清:

  • 模型只是计划过
  • 工具已经执行过
  • 工具执行失败但需要补偿
  • 这一步必须人工重新确认

如果没有这层记录,长任务恢复几乎一定会遇到“到底做没做过”的混乱。


18. 常见失败模式 ​

失败模式 1:状态没有字段,只靠自然语言描述 ​

后果:

  • 不可测
  • 不可恢复
  • 很难分支判断

失败模式 2:长期记忆污染 ​

后果:

  • 系统学到错误偏好
  • 后续任务被脏数据影响

失败模式 3:上下文过载 ​

后果:

  • 模型抓不到重点
  • 成本上涨
  • 延迟上涨

失败模式 4:把本地机密上下文直接喂给模型 ​

后果:

  • 安全风险
  • 权限边界混乱

失败模式 5:记忆写入没有准入和失效机制 ​

后果:

  • 错误事实被长期保留
  • 旧偏好一直覆盖新偏好
  • 组织规则更新后,旧规则还在影响输出

失败模式 6:checkpoint 能续对话,续不了执行现场 ​

后果:

  • 模型以为还在同一步
  • 应用层其实已经切到了新状态
  • 工具副作用、审批状态、草稿版本彼此错位

失败模式 7:上下文装配没有固定顺序 ​

后果:

  • 同一任务不同轮次看到的信息结构不断变化
  • 规则、证据、工具约束互相覆盖
  • 回归测试很难定位到底是哪一层变了

19. 重点官方资源 ​

以下资源已按 2026-07-09 复核到当前正式入口;其中部分 OpenAI 页面对脚本访问会返回 403,但浏览器入口仍可正常打开:


20. 这一章最值得落地的实践动作 ​

你可以立刻做下面 6 件事:

  1. 为自己的 Agent 设计一份状态字段表
  2. 区分哪些信息属于长期记忆
  3. 区分哪些运行依赖不该发给模型
  4. 为一个知识库问答系统设计“检索前、检索后、生成前”的上下文结构
  5. 为高风险工具动作补一份 execution record 字段表
  6. 为长期记忆设计写入准入、失效和删除规则

只要这 6 件事做完,你的系统思路就会比大多数只会写 Prompt 的实现稳很多。