
图 1:上下文不是把资料拖进窗口,而是一次受策略约束的组装过程。图中的连线会展示来源经过闸门进入 Context Packet,再交给 Agent。
1. 先区分 Prompt、Context 与 Context Architecture
这三个词经常被混在一起。
Prompt:这一次怎样向模型表达任务
Prompt 通常包括系统指令、用户问题、示例和输出要求。它回答的是:
Prompt Engineering 仍然重要。目标含糊、约束冲突、输出格式不清,后面的 Context 再完整也救不回来。
Context:这一次推理时模型实际能看到什么
Anthropic 对 Context Engineering 的定义重点不在“写一句更好的话”,而在为下一步推理选择和维护合适的信息集合。一次调用里的 Context 可能包括:
这里的关键是“当前可见”。数据库里有一条正确规则,不等于模型这一步能看到它;一段历史曾经出现过,也不等于它应该继续占用当前窗口。
Context Architecture:谁在何时、按什么规则组装 Context
当 Agent 开始跨多轮运行,问题就不再是手写一段 Prompt,而是:
-
哪些来源允许进入; -
如何判断资料是否过期; -
怎样处理同一规则的多个版本; -
什么数据受权限限制; -
预算不足时保留什么; -
长历史怎样压缩和恢复; -
选错上下文时怎样复现。
因此可以把三者的关系写成:
2. 当前上下文、Session、Memory 和外部来源不是一回事
另一个常见误区,是把 Agent 知道过的所有东西都叫 Memory。

图 2:当前 Context 是一次推理的有限工作区;Session 保存可恢复的任务状态;Memory 保存跨任务仍有价值的信息;外部来源保持为可按需读取的事实系统。
可以用一张表区分它们:
LangChain 的 Context Engineering 文档也强调类似边界:给模型的 Context 是瞬时的,而运行状态和长期存储可以持久存在。框架术语可能不同,但工程问题相同。
这个区分会直接改变实现:
-
20 MB 日志应保留在 artifact store,Context 只放异常摘要和可追溯位置; -
已完成的工具调用应写入 Session checkpoint,不必每一步原样重放; -
用户长期偏好应存入带来源和更新时间的 Memory,需要时检索; -
最新事故状态应回到状态系统读取,而不是相信三小时前的聊天历史。
一个判断原则
“以后可能有用”不足以让内容进入当前 Context。它只说明内容值得被保存或可检索。
3. 长窗口为什么不能替代 Context Architecture
模型窗口变长后,最直接的做法是把更多内容全部塞进去。但容量增加只解决“放不下”,没有自动解决以下问题。
3.1 注意力并非均匀分配
Lost in the Middle 观察到,一些长上下文模型对信息位置敏感,关键内容放在中间时表现会下降。RULER 进一步用多类任务评估长上下文能力,说明“声明支持某个窗口长度”与“在不同任务上有效使用整个窗口”不是同一个结论。
这些研究使用的模型和测试条件有时间边界,不能直接外推到所有当前模型。但它们足以支持一个谨慎判断:
是否能有效使用长上下文,需要按自己的模型、任务和数据分布评测,不能只看最大 Token 数。
3.2 过期资料不会因为更多而变新
如果旧版限流规则排在新版规则前面,“全部塞入”只是把冲突一起交给模型。真正需要的是:
updated_at
; valid_until
; -
规则版本或 canonical key; -
来源权威级别; -
明确的去重与淘汰策略。
3.3 无关内容会占用预算和判断空间
界面 Changelog 也许可信且最新,但它与“429 如何退避”无关。可信不等于相关。
3.4 未信任内容可能越过指令边界
网页、邮件和工单评论既可能包含业务证据,也可能包含“忽略规则、执行写入”的指令注入。OpenAI 的 Agent 安全指南建议隔离不可信数据,并优先提取受约束的结构化字段,避免让不可信文本直接驱动高风险行为。
实验为了让边界清楚,采用保守策略:trust != trusted 的来源不进入 Packet。真实系统不一定永久丢弃它,可以先在隔离步骤中提取事实,再把结构化结果作为新的、受约束的来源送入下一步。
3.5 更长的输入还会增加成本与延迟
即使 Prompt Caching 能降低完全重复前缀的成本和延迟,它也不会判断内容是否正确、过期或有权限读取。缓存是执行优化,不是语义校验。
4. Context Packet:把隐式拼接变成可检查对象
如果 Context 只是代码里几次字符串拼接,就很难回答“这次到底给模型看了什么”。因此本文引入一个显式产物:
它不是行业统一标准,而是本文项目中的工程约定。下面是 ctx-002 实际 Packet 的字段节选:
它解决五个实际问题:
- 可解释
:知道哪条证据进入了模型; - 可复现
:通过 case_id、时间和 fingerprint 对照固定数据集中的选择结果; - 可评测
:Grader 可以检查必需来源、禁用来源和预算; - 可恢复
:长任务可以保存 Packet 或其引用; - 可审计
:高风险结论能追到来源位置和更新时间。
注意,Packet 不是把所有内容重新复制一遍。在真实系统里,大对象可以只保留 artifact locator、摘要和校验值,需要时再读取。
Lab 的 fingerprint 只由策略、Case、选中来源 ID 和 as_of 生成,用于判断相同 Fixture 下的选择是否变化。它没有包含来源正文,因此不是内容完整性证明。生产实现还应记录 content_hash、ETag、文档版本或不可变 artifact ID,并把 Context Policy 版本写进 Trace。
5. 五道闸门解决五种不同风险
一个来源被选中前,至少要回答五个问题。
这五项不能合并成一个“相似度分数”。
一份泄露的敏感文档可能与问题高度相似,但没有访问权;一份旧规则可能权威且相关,但已经失效;一段网页可能包含正确事实,但不应该被当成指令。
本文实验先做资格过滤,再在合格来源中做覆盖和预算选择:
这段代码很简单,却体现了一个重要次序:
不是先按相似度拿到 Top K,再祈祷里面没有越权或过期资料。
闸门的前提是元数据本身可信
Lab 中的
trust、topics、valid_until和sensitivity都是受控 Fixture。生产环境最难的部分之一,是确定谁能写这些字段、怎样验证采集器、默认值是什么,以及来源变化后怎样失效。若网页可以给自己标成trusted,再完整的五道闸门也只是虚假的安全感。
6. missing_topics:让“不知道”成为一等输出
Context Architecture 最有价值的字段,可能不是 selected,而是:
假设读者问“差旅报销住宿上限是多少”,当前候选来源只有一个后台界面 Changelog。系统有三种选择:
-
把 Changelog 给模型,让模型自由回答; -
返回空白 Context,却不说明缺什么; -
明确声明缺少 expense-policy,触发补充检索、询问或人工接管。
第三种才是可控路径。
它把模型最危险的一种自由度收了回来:在关键证据缺失时,用语言流畅度填补事实空白。
因此 Packet 的渲染内容也应把缺失证据放在显眼位置:
“明确缺失”不等于任务失败。它可能是一次正确的拒答、一次新的检索动作,或者一个可靠的人工交接点。
7. Write、Select、Compress、Isolate:Context 的四类操作
开源项目 langchain-ai/context_engineering 把常见策略归纳为 Write、Select、Compress 和 Isolate。这不是唯一分类,但很适合检查系统是否只会“检索后拼接”。

图 3:四类操作可以组合使用。写入让状态落盘,选择控制当前可见内容,压缩回收窗口,隔离避免不同任务和信任域互相污染。
Write:把状态写到窗口之外
适合保存:
-
当前计划与完成步骤; -
文件 diff 和测试报告位置; -
工具返回的 artifact; -
已确认的事实和来源; -
等待人工审批的动作参数。
写入不是 Memory 的同义词。Session checkpoint、artifact store 和长期 Memory 都是不同的写入目标。
Select:只把当前步骤需要的信息取回来
选择可以来自:
-
规则匹配; -
关键词或向量检索; -
图关系; -
最近状态; -
任务类型; -
权限和来源过滤; -
模型路由。
模型可以参与选择,但资格边界和高风险限制最好由确定性代码控制。
Compress:缩短内容,但保留恢复能力
压缩可能是:
-
工具结果摘要; -
对话 compaction; -
代码 diff 而不是完整文件; -
日志异常窗口而不是完整日志; -
子 Agent 的结构化交接。
OpenAI 的 compaction 文档强调,压缩后的状态用于后续轮次继续推理。工程上还需要额外保存原始 artifact 或 locator,避免摘要成为无法追溯的新事实源。
Isolate:把噪声和风险留在独立边界
适合隔离:
-
外部网页中的不可信文本; -
大型日志分析; -
多个子任务的独立工作区; -
含敏感数据的工具结果; -
只需要结构化结论的子 Agent 过程。
隔离不是简单“开更多 Agent”。它的目的,是让一个步骤只返回经过约束的交接对象,而不是把整个工作历史灌回主 Agent。
8. Preload 还是 Just-in-time:不要把选择题做成口号
Anthropic 在 Context Engineering 实践里强调 Just-in-time 检索和 progressive disclosure:Agent 先看到高层索引,需要时再展开具体内容。但这不意味着所有信息都应延迟加载。
我更倾向于使用这条判断:
前者优先保证安全和任务完整性,后者优先控制噪声、成本和新鲜度。
9. 稳定前缀与 Prompt Caching:优化执行,不替代选择
OpenAI 的 Prompt Caching 最佳实践建议把静态、重复内容放在前面,把动态和用户特定内容放在后面,因为缓存依赖精确前缀匹配。
这对 Context Architecture 有两个启发:
Manus 的 Context Engineering 实践也提到保持前缀稳定、尽量 append-only,以及把文件系统当作可恢复的外部 Context。这里应把它看成一个具体 Agent 产品的工程经验,而不是所有模型和 Provider 都必须照搬的标准。
更重要的是,缓存命中不能证明输入正确:
-
旧规则也可能被高效缓存; -
无关内容也可能复用前缀; -
敏感内容仍然需要权限判断; -
缺失证据仍然需要显式输出。
所以先保证 Context 的语义正确和边界正确,再优化它的缓存形状。
10. 跑起来:复现 Context Reliability Lab
本篇代码在 GitHub 仓库 RalfNick/ai-agent-learn 的固定 commit 05a30ff。固定 commit 很重要:主分支以后继续演进,本文命令仍应得到同一组结果。
先运行测试:
预期结果:
再运行 Context Eval:
成功时命令退出码为 0,并生成:
仓库根目录中也保留了本次文章核验使用的固定报告:
context-comparison.jsoncontext-failures.mdcontext-packets.jsonl
11. 这 8 个案例究竟在测什么
实验没有调用模型,因为它先回答一个更窄的问题:
给定任务、候选来源和预算,组装器能否稳定产出符合合同的 Packet?
8 个合成案例分别覆盖:
这组案例故意集中在上下文常见失败模式上,不代表生产流量分布。dump-all-v1 也只是一个透明、可解释的朴素基线,不是对成熟 RAG 系统的概括。
基线仍在三个直接案例上通过,这一点很重要:实验不是为了证明“只要全部塞入就必然失败”,而是观察它遇到冲突、权限和预算时怎样失败。
12. 拆开 ctx-002:过期规则是怎样被挡住的
ctx-002 问:
候选来源按顺序是:

图 4:相关性不是唯一标准。旧策略主题相关但已经失效;Changelog 可信且最新但与问题无关;只有当前限流策略进入 Packet。
dump-all-v1 从候选列表头部开始装入,直到预算切断。它选中了过期策略和无关 Changelog,当前策略反而没有进入 Packet。
context-packet-v1 的路径是:
最终 Packet 不只保存了选中的规则,还保存了两个排除原因。这样即使最终回答错误,也能先判断错误是否来自 Context 选择。
13. 实验结果:改善的是组装合同,不是模型准确率
在固定 commit、Python 测试通过的条件下,报告结果如下:

图 5:Context Packet 在本组装测试中保留了全部可用必需证据,并消除了禁用和无关来源。Token 是项目内确定性估算,不是 Provider tokenizer 的真实计费数。
context-packet-v1 相比基线改善了:
没有出现案例级回归,因此本实验的发布 Gate 通过。
但这个结果只能支持:
它不能支持:
下一步应把真实失败样本加入 Dataset,再比较最终模型回答、工具行为和任务 Outcome。
14. 评测 Packet,而不是只看渲染后的文字
Grader 直接检查结构化 Packet:
每一项分别回答:
这种评测有两个优点:
-
不需要等待模型回答,组装层回归可以快速定位; -
模型答错时,可以把问题分成“上下文没给对”和“给对后仍推理错误”。
不过不能只停在这里。生产链路至少需要两层 Eval:
如果只测 Layer 2,失败定位很慢;如果只测 Layer 1,又无法证明最终任务价值。
实验 Dataset 中还有一个字段:
它是 Eval 作者事先标注的 Gold Label,只用于判断组装器是否正确识别缺口。生产 Packet 不会预先知道“正确答案应该缺什么”,它只会根据任务合同和当前可用来源计算 missing_topics。这两个字段不能混为一谈。
15. 故意把预算降到 10:正确失败比勉强通过更重要
再做一次失败注入:
在 PowerShell 中也可以写成一行:
这次预期退出码为 1,Gate 不通过。预算小到连必要来源都放不下时,Context Packet 不会编造一份“精简证据”来获得通过。
实验结果中,两种策略都只通过 2 / 8 个案例,可用必需证据覆盖率为 0%。这不是 Packet 设计失效,而是门禁正确暴露了:
生产系统此时可以:
-
申请更大预算; -
把任务拆成多个步骤; -
先读取摘要,再按需展开; -
转交拥有更合适工具的流程; -
明确拒绝并请求人工补充。
不应做的是静默丢掉证据,然后让模型继续生成确定语气的答案。
16. Token 估算器为什么故意写得很朴素
Lab 使用一个确定性估算器:
它的用途是让测试跨环境稳定,不依赖某个 Provider 的 tokenizer。报告字段因此明确叫:
而不是 tokens。
这带来一个必须保留的限制:66.38 -> 50.25 只能比较本实验内部的相对输入规模,不能拿来计算真实账单。
接入生产模型时,应替换或补充:
-
当前模型对应的 tokenizer; -
API 返回的实际 input/output usage; -
cached 与 uncached 输入; -
工具调用和重试造成的总成本; -
Context 组装耗时与检索耗时。
可复现测试和真实计费可以同时保留,不必让其中一个冒充另一个。
17. 怎样把实验接入真实 Agent
从 Lab 到真实系统,可以拆成五个适配层。
17.1 Source Adapter:统一不同来源
把仓库、数据库、工单和 API 返回统一为:
不要让每个检索器直接拼最终 Prompt。
17.2 Policy Engine:资格和选择分开
确定性策略负责:
-
权限; -
有效期; -
信任域; -
强制预载规则; -
最大预算; -
禁止来源。
检索或模型排序负责:
-
主题覆盖; -
语义相关; -
多样性; -
在合格来源中挑选更高信号内容。
17.3 Packet Builder:输出结构化快照
Packet Builder 生成:
selected
; excluded
; missing_topics
; budget
; fingerprint
; -
最终 rendered_context。
高风险任务还可以保存策略版本和调用主体。
17.4 Provider Adapter:渲染成具体模型输入
不同 Provider 对 system、developer、user、tool result 和 compaction 的表达不同。Context Packet 不必等同于 API 消息格式,应该由 Adapter 映射:
这样更换 Provider 时,来源和策略合同不必全部重写。
17.5 Trace 与 Eval:保存选择证据
每次运行至少记录:
随后把生产失败转成新的 Context Case。例如:
这时 Context Engineering 才进入持续改进,而不是一次性的 Prompt 整理。
18. 哪些场景暂时不需要独立 Context 层
并非每个模型调用都需要完整的 Packet 系统。
当以下问题开始反复出现时,再把 Context Architecture 独立出来:
-
同一任务经常拿到冲突或过期资料; -
来源包含不同信任域和权限; -
窗口预算导致关键内容被截断; -
长任务需要压缩、恢复和交接; -
团队无法解释某次回答依据了什么; -
改完检索策略后无法证明没有回归。
工程化的目的不是让每次调用更复杂,而是把已经出现的复杂性放到可管理的位置。
19. 45 分钟练习:为自己的 Agent 做第一版 Context Packet
不需要先接入向量数据库。选一个真实任务,用静态 JSONL 就能开始。
第 0-10 分钟:列出 Context 边界
写四列:
把现有 Prompt、历史、工具返回和知识库内容放进对应列。
第 10-20 分钟:定义 Source Schema 与五道闸门
至少加入:
选一个过期来源、一个无关来源和一个未信任来源作为失败样本。
第 20-30 分钟:输出第一份 Packet
要求同时包含:
不要只输出最终拼好的字符串。
第 30-40 分钟:写 5 个 Context Case
建议包括:
-
正常成功; -
新旧规则冲突; -
必要证据缺失; -
权限不足; -
预算不足。
为每个 Case 写确定性 Grader。
第 40-45 分钟:做一次失败注入
把预算减半,或把当前规则改成过期,确认:
-
命令返回非零退出码; -
报告指出具体失败 Case; -
Packet 没有静默改写缺失事实; -
修复后历史 Case 仍然通过。
完成这一步,你得到的不是一段更长 Prompt,而是一条可以持续回归的 Context 管道。
20. 收藏清单
设计或 Review Agent Context 时,可以逐项确认:
-
[ ] 已区分 Prompt、当前 Context、Session、Memory 和外部来源; -
[ ] 当前任务与成功标准始终可见; -
[ ] 每条动态证据保留 locator、更新时间和有效期; -
[ ] 未信任内容不能直接改变系统行为; -
[ ] 权限检查发生在内容进入模型之前; -
[ ] 相关性排序不会绕过信任、权限和有效期; -
[ ] 预算不足时会显式失败、拆分或按需读取; -
[ ] missing_topics是结构化输出,而不是模型自行猜测; -
[ ] 压缩结果仍能追到原始 artifact; -
[ ] 稳定前缀和缓存只作为执行优化; -
[ ] Token 估算与 Provider 实际 usage 明确区分; -
[ ] Context Assembly Eval 与 Agent Outcome Eval 分层运行; -
[ ] 每次策略变更都能列出 improvement、regression 和失败样本; -
[ ] 生产失败可以沉淀成新的 Context Case。
21. 这篇真正建立了什么
这一篇没有试图找到“最好的上下文长度”,而是把问题换成了更可执行的形式:
Context Packet 不是终点。它仍要交给模型,模型仍可能误读证据;检索器也可能根本没有找到正确来源。但现在至少能把失败拆开:
能区分这些失败,才有资格谈下一步的自动恢复和持续改进。
下一篇进入 Harness Engineering:模型、Context、工具、Session、Sandbox 和审批分别由谁负责?我们会在同一个 GitHub 项目里,把目前分散的组装、执行和评测代码收进一个最小 Harness,并测试超时、重试、停止和恢复边界。
参考资料
官方与一手工程资料
-
Anthropic:Effective context engineering for AI agents -
OpenAI:Compaction -
OpenAI:Prompt caching -
OpenAI:Safety in building agents -
LangChain:Context engineering in agents -
Manus:Context Engineering for AI Agents
研究与开源实现
-
Lost in the Middle: How Language Models Use Long Contexts -
RULER: What’s the Real Context Size of Your Long-Context Language Models? -
langchain-ai/context_engineering -
HumanLayer:12-Factor Agents,Own your context window -
Datawhale Hello-Agents:上下文工程
本文代码与证据
-
Agent Reliability Lab 05a30ff -
本篇完整 commit
订阅智宅客
AI / 技术 / 数字生活方式,新文章第一时间送到邮箱。









