Appearance
05. 状态、记忆与上下文工程
版本:
v1.2最后更新:
2026-07-09
1. 为什么这一章是 Agent 的分水岭
很多 Demo 看起来能跑,但一进入真实任务就崩,核心原因通常不是模型不够强,而是:
- 没有设计好状态
- 没有设计好记忆
- 没有设计好上下文传递
简单说:
- 模型能推理
- 但系统必须帮它“记住该记住的东西”
2. 状态是什么
状态是 任务执行过程中持续存在并会变化的信息。
例如:
- 当前任务目标
- 已完成步骤
- 当前轮次
- 已调用哪些工具
- 检索到哪些文档
- 当前审批状态
- 最近一次错误
如果这些信息只靠模型“自己记住”,长任务就会非常不稳定。
2.1 更像生产系统的状态,通常至少分成四层
很多 Demo 只有一个大对象叫 state,里面什么都塞。
但真实系统里,更稳的做法通常是拆层:
| 状态层 | 典型内容 | 为什么要单独分层 |
|---|---|---|
| orchestration state | 当前节点、下一步、分支判断、handoff 去向 | 这是工作流控制面,不该和工具细节混成一团 |
| execution state | 工具调用结果、重试次数、超时、最后错误 | 这是执行面,决定是否继续、重试还是升级 |
| evidence state | 检索证据、引用片段、摘要、草稿版本 | 这是模型真正需要消费的内容来源 |
| governance state | approval、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 个:
- 历史越来越长
- 噪音越来越多
- 关键信息不结构化
- 无法稳定恢复任务
真正的状态管理,应该是:
- 有结构
- 有字段
- 有边界
7. 上下文工程是什么
上下文工程可以理解为:
- 决定在当前这一步,到底要给模型看什么
这和“存了多少信息”不是一回事。
上下文工程要解决的核心问题是:
- 哪些信息必须给模型
- 哪些信息会干扰模型
- 哪些信息该由工具随取随用
- 哪些信息应该结构化而不是自然语言拼接
8. 上下文来源通常有哪些
- 用户当前输入
- 系统提示词
- 当前任务状态
- 历史对话摘要
- 检索出的文档片段
- 工具返回结果
- 本地上下文或运行依赖
根据 OpenAI Agents SDK define agents 文档在 2026-07-01 的可访问说明:
- 有些本地上下文应与模型上下文分开管理
- 比如认证用户信息、数据库客户端、日志器、辅助函数
这非常关键,因为:
- 不是所有运行上下文都应该发给模型
8.1 更像生产系统的上下文装配顺序
很多系统的问题不是“缺上下文”,而是“上下文装配顺序没有被设计过”。
一个更稳的装配顺序通常是:
- 固定策略层:system / developer 规则、输出契约、安全边界。
- 任务快照层:当前目标、阶段、最近决定、未决问题。
- 证据层:最新有效的检索结果、工具结果、引用材料。
- 动作层:当前允许使用的工具、schema、审批约束。
- 输出层:这一步到底要产出什么。
这个顺序的价值是:
- 让稳定规则不要被动态证据淹没
- 让模型先知道“自己在做什么”,再看“手里有什么”
- 让工具定义和输出约束始终贴着当前动作
8.2 不要把原始状态对象整包塞给模型
状态表设计得再漂亮,也不等于应该直接把整包 JSON 发给模型。
更稳妥的做法通常是:
- 应用内部保存全量状态
- 模型只拿当前决策需要的最小切片
- 高噪音字段先摘要化或转成人可读结构
否则常见后果是:
- 模型被内部字段名和无关标记干扰
- token 花在“系统自己看得懂、模型却不一定看得懂”的内容上
- 同一个状态对象一膨胀,所有步骤都一起变慢
9. 一个实用的上下文分层思路
可以把上下文分成三层:
第一层:必须发给模型的内容
例如:
- 当前任务目标
- 当前可用证据
- 输出要求
第二层:应用内部要知道,但不必发给模型的内容
例如:
- 用户 ID
- 权限信息
- DB 连接
- 调试标记
第三层:按需检索的内容
例如:
- 大量文档
- 历史案例
- 表结构
- 长对话归档
这三层分清楚,很多 Agent 稳定性问题会少很多。
10. RAG 在 Agent 里的作用
RAG 不是 Agent,但常常是 Agent 的重要组成部分。
Agent 中的 RAG 主要用来:
- 找事实
- 找依据
- 找可引用内容
一个成熟的 Agent 通常不会把所有知识都塞进 Prompt,而是:
- 先判断是否需要检索
- 再检索相关内容
- 再把结果带入当前步骤
11. 状态设计时最该保存什么
建议优先保存:
- 目标
- 当前步骤
- 已完成步骤
- 中间结论
- 证据引用
- 错误计数
- 审批结果
- 输出草稿版本
不建议盲目保存:
- 每一句自然语言思考
- 所有原始上下文全文
- 无区分的整段对话历史
11.1 checkpoint 最好保存“可恢复最小集”
真正能帮你恢复任务的,往往不是完整历史,而是一组最小可恢复字段。
建议 checkpoint 至少能回答:
- 当前 run / session 是谁
- 当前节点和下一步是什么
- 最近一次工具调用做到哪一步
- 哪个 artifact / draft 是当前生效版本
- 哪个 approval / policy 状态已通过
- 当前引用了哪些证据
如果恢复点里没有这些字段,系统经常会出现:
- 对话能续上,但副作用对不上
- 工具结果还在,草稿版本却丢了
- 审批 UI 还在显示待处理,执行层已经继续了
12. 长期记忆应该存什么
适合长期存的通常是:
- 用户偏好
- 组织规则
- 业务术语
- 已确认事实
- 历史成功模板
不适合长期存的通常是:
- 未验证推测
- 一次性中间过程
- 低质量工具输出
- 敏感临时数据
12.1 长期记忆写入最好走一条显式流水线
更成熟的系统通常不会让模型“觉得有用”就直接写入长期记忆。
更稳的写入流水线通常至少包含:
candidate:先把候选记忆提取出来。validate:判断它是不是事实、偏好、规则,是否经过验证。dedupe:和已有记忆做去重或合并。label:打上来源、置信度、敏感级别、owner、更新时间。publish:只有过门槛的内容才进入可检索记忆。
这条流水线的价值非常实际:
- 降低幻觉写入长期记忆的概率
- 让错误记忆更容易回滚
- 让不同来源的记忆可以做优先级治理
12.2 记忆不只是要“会写”,还要“会失效”
长期记忆最容易被忽略的问题,是失效和删除。
至少要提前设计:
- 哪些记忆有 TTL
- 哪些记忆需要定期再验证
- 哪些记忆跟随 source of truth 一起撤销
- 用户偏好和组织规则发生冲突时谁优先
否则系统很容易出现:
- 老偏好永久压着新偏好
- 已作废规则还在被召回
- 已被纠正的事实仍在影响后续任务
13. OpenAI 的状态续接能力,适合解决什么问题
根据 OpenAI Conversation state 文档在 2026-07-07 可访问的说明,Responses API 可以通过 previous_response_id 续接前一个响应链,这对多轮任务和 Agent workflow 很有价值,因为它允许你:
- 不必每一轮都手工回传全部历史
- 让模型沿着上一轮的状态继续生成
- 在需要时重新注入新的工具结果或上下文
但这项能力更像“上下文续接机制”,而不是“完整状态管理系统”。原因是:
- 它解决的是模型侧连续性,不自动等于业务状态已经持久化。
- 一旦历史对象不可用,应用层仍然要知道怎么回放或重建现场。
- 外部副作用、审批状态、租约和权限等对象,本来就应该由应用自己持久化。
所以更稳妥的落地方式通常是:
- 模型对话链负责保持推理连续性
- 应用状态表负责保存工作流真实状态
- 长期记忆层负责沉淀跨任务仍有价值的事实
这三层不要混成一层。
14. 上下文续接不等于 instructions 自动继承
OpenAI Conversation state 文档在 2026-07-07 可访问的说明里,还特别强调了一个容易被忽视的点:
previous_response_id不会自动继承instructions
这意味着如果你的 Agent 很依赖系统规则、输出约束或安全边界,就不能因为“续接了前一轮”而默认这些规则仍然存在。
更稳妥的做法是:
- 把稳定规则放进固定可重建的系统层模板。
- 每轮都显式补齐不可丢失的治理约束。
- 把会变化的状态字段和稳定的策略字段分开管理。
否则非常容易出现这种隐蔽问题:
- 任务看起来还在同一条链路上
- 但关键约束已经悄悄丢了
15. 长期记忆写入要有准入门槛
长期记忆最大的风险不是“没有记住”,而是“记住了不该记的东西”。
所以和数据库建表很像,长期记忆也应该有准入策略。建议至少问四个问题:
- 这条信息是否跨任务仍有价值。
- 它是事实、偏好还是临时推测。
- 它是否经过验证。
- 它是否会带来安全或合规风险。
可以把长期记忆粗分成三类:
| 类型 | 例子 | 是否建议长期保存 |
|---|---|---|
| 稳定事实 | 客户行业、系统约束、术语解释 | 建议 |
| 偏好信息 | 输出格式偏好、沟通语言、关注维度 | 谨慎建议 |
| 一次性痕迹 | 临时故障、未证实猜测、中间推理 | 不建议 |
LangGraph Memory overview 的思路也很值得借鉴:
- checkpointer 负责线程级短期状态
- store 负责跨线程共享与检索的长期数据
把这个边界想清楚,长期记忆污染会少很多。
12.3 长期记忆最好按“事实 / 偏好 / 过程痕迹”分槽
很多系统的长期记忆之所以越来越脏,一个原因是不同类型的信息都混在同一个桶里。
更像生产系统的做法通常会至少分成三槽:
| 记忆槽 | 典型内容 | 默认策略 |
|---|---|---|
fact memory | 稳定业务事实、术语、组织规则 | 可检索、可版本化、变更要覆盖旧值 |
preference memory | 输出格式偏好、语言偏好、关注维度 | 可更新、冲突时以最近验证值为准 |
trace residue | 单次任务中间痕迹、失败尝试、未证实猜测 | 默认不进长期记忆,必要时只进审计层 |
这样做的价值非常直接:
- 事实不会和偏好混在一起
- 偏好不会和一次性失败痕迹混在一起
- 删除和失效策略可以分开设计
如果不分槽,后面最容易出现的就是:
- 用户一次性要求被当成永久偏好
- 临时猜测被当成稳定事实
- 清理时不知道哪些能删、哪些不能删
12.4 长期记忆写入最好经过“提议 - 验证 - 写入 - 失效”流水线
长期记忆写入如果只是:
- 模型觉得重要,就直接写
那污染几乎是迟早的事。
更稳的写入流水线通常至少包含四步:
propose:先提出候选记忆validate:检查是否稳定、是否重复、是否合规commit:写入对应记忆槽expire / revise:过期、覆盖或撤销旧值
这条流水线的意义是:
- 把“模型感觉值得记”变成“系统确认值得记”
尤其在企业环境里,至少还值得额外检查:
- 是否含敏感信息
- 是否和现有事实冲突
- 是否需要 owner 或人工确认
- 是否需要带时间戳与来源
16. 上下文压缩不是“越短越好”,而是保留决策所需最小集
当任务变长之后,真正的问题通常不是“上下文有没有”,而是:
- 给模型看的内容里,哪些还在起作用
OpenAI 关于 conversation state 的说明、Anthropic 关于 context windows 的说明,以及 prompt caching 的建议,放在一起看会很有启发:
- 上下文窗口再大,也不等于应该把全部内容都持续塞进去
- prompt caching 解决的是重复传输成本,不会神奇地替你降低推理复杂度
- 需要保留的是对当前决策仍有影响的信息,而不是所有历史痕迹
一个更可执行的压缩顺序通常是:
- 保留当前任务目标和约束。
- 保留最近有效的工具结果与证据。
- 摘要化早期回合,只留下关键决定和结论。
- 把大块参考资料转成按需检索,而不是常驻上下文。
压缩做得不好,常见后果不是“模型忘了全部内容”,而是:
- 模型把次要信息当成重点
- 响应变慢
- token 成本快速上升
16.1 prompt caching 不是长期记忆,也不是状态治理
Anthropic 当前 Prompt caching 文档和 OpenAI 当前 Conversation state / Compaction 相关思路放在一起看,很容易得到一个很实用的判断:
cache解决的是重复传输和重复计算成本memory解决的是跨任务保留什么事实state解决的是当前任务如何继续
这三件事非常容易被混掉。
例如:
- 命中 prompt cache,不代表系统已经拥有长期记忆
- 能续接上一轮 response,不代表执行状态已经可恢复
- 把所有材料常驻上下文,不代表上下文治理做得好
所以更成熟的上下文设计通常会分开回答:
- 哪些前缀值得缓存
- 哪些事实值得长期记忆
- 哪些状态字段必须持久化
- 哪些证据应该按需检索
16.2 上下文压缩最好伴随“决策摘要”,而不是只做字数摘要
很多系统做压缩时只会把历史缩短成更短的一段话。
但对 Agent 来说,更有价值的往往不是“更短”,而是“更利于下一步决策”。
更实用的压缩结果通常至少包括:
- 当前目标
- 最近已确认的关键事实
- 尚未解决的问题
- 已尝试但失败的路径
- 下一步可行动作
这类摘要可以理解成:
decision summary
而不是普通聊天摘要。
因为 loop 真正需要保留的,不只是聊过什么,而是:
- 为什么会走到当前这一步
17. 本地运行上下文要和模型可见上下文分层
Agent 系统里有一类信息非常重要,但又不应该直接进入模型上下文,例如:
- 认证 token
- 数据库连接
- 原始日志器
- 内部调试标志
- 高权限系统句柄
OpenAI Agents SDK 关于 context 的文档在 2026-07-07 可访问的说明里,就明确把这类对象视作本地运行时上下文,而不是默认发给模型的消息内容。
这层分离的价值非常大:
- 能降低泄漏机密的概率。
- 能让工具执行层拿到运行依赖,但不污染模型推理。
- 能让相同 Agent 在不同宿主里复用,而不是把宿主细节硬编码进 Prompt。
如果系统里还没有这层分离,后面越做越大时很容易出现:
- 安全边界混乱
- 提示词越来越脏
- 工具调试越来越难
17.2 运行时上下文最好显式做脱敏与投影
“本地上下文不要直接给模型”这件事,不应该只靠开发者自觉。
更稳的做法通常是显式设计两层动作:
redactionprojection
也就是:
- 先把敏感字段、内部句柄、认证信息排除掉
- 再把模型真正需要的事实投影成可读、可控的上下文片段
例如:
- 模型不需要知道完整 token
- 但可能需要知道“当前用户属于哪个角色”
- 模型不需要知道数据库 client 对象
- 但可能需要知道“当前查询目标表有哪些字段”
如果没有这一步,你很容易得到一个两头都不好的系统:
- 要么什么都不给,模型决策缺关键事实
- 要么全都给,机密和噪音一起泄进去
17.1 副作用动作最好绑定到独立执行记录
很多 Agent 系统的问题,不是模型推理断了,而是:
- 模型说自己已经做了
- 实际工具并没有成功执行
所以更稳的做法通常是把高风险动作单独记录成 execution record,例如:
tool_call_idapproval_ididempotency_keyexecution_statusside_effect_scoperesume_token
这样恢复时才能分清:
- 模型只是计划过
- 工具已经执行过
- 工具执行失败但需要补偿
- 这一步必须人工重新确认
如果没有这层记录,长任务恢复几乎一定会遇到“到底做没做过”的混乱。
18. 常见失败模式
失败模式 1:状态没有字段,只靠自然语言描述
后果:
- 不可测
- 不可恢复
- 很难分支判断
失败模式 2:长期记忆污染
后果:
- 系统学到错误偏好
- 后续任务被脏数据影响
失败模式 3:上下文过载
后果:
- 模型抓不到重点
- 成本上涨
- 延迟上涨
失败模式 4:把本地机密上下文直接喂给模型
后果:
- 安全风险
- 权限边界混乱
失败模式 5:记忆写入没有准入和失效机制
后果:
- 错误事实被长期保留
- 旧偏好一直覆盖新偏好
- 组织规则更新后,旧规则还在影响输出
失败模式 6:checkpoint 能续对话,续不了执行现场
后果:
- 模型以为还在同一步
- 应用层其实已经切到了新状态
- 工具副作用、审批状态、草稿版本彼此错位
失败模式 7:上下文装配没有固定顺序
后果:
- 同一任务不同轮次看到的信息结构不断变化
- 规则、证据、工具约束互相覆盖
- 回归测试很难定位到底是哪一层变了
19. 重点官方资源
以下资源已按 2026-07-09 复核到当前正式入口;其中部分 OpenAI 页面对脚本访问会返回 403,但浏览器入口仍可正常打开:
- OpenAI Conversation state:https://developers.openai.com/api/docs/guides/conversation-state
- OpenAI Responses API guide:https://developers.openai.com/api/docs/guides/text
- OpenAI Conversation state compaction:https://developers.openai.com/api/docs/guides/conversation-state#compaction
- OpenAI Agents SDK context:https://openai.github.io/openai-agents-python/context/
- OpenAI Agents SDK sessions:https://openai.github.io/openai-agents-python/sessions/
- OpenAI Agents SDK results:https://openai.github.io/openai-agents-python/results/
- OpenAI Agents SDK guardrails:https://openai.github.io/openai-agents-python/guardrails/
- LangGraph Persistence:https://docs.langchain.com/oss/python/langgraph/persistence
- LangGraph Memory overview:https://docs.langchain.com/oss/python/concepts/memory
- Anthropic Context windows:https://docs.anthropic.com/en/docs/build-with-claude/context-windows
- Anthropic Prompt caching:https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
20. 这一章最值得落地的实践动作
你可以立刻做下面 6 件事:
- 为自己的 Agent 设计一份状态字段表
- 区分哪些信息属于长期记忆
- 区分哪些运行依赖不该发给模型
- 为一个知识库问答系统设计“检索前、检索后、生成前”的上下文结构
- 为高风险工具动作补一份 execution record 字段表
- 为长期记忆设计写入准入、失效和删除规则
只要这 6 件事做完,你的系统思路就会比大多数只会写 Prompt 的实现稳很多。