一次模型调用只能依据当前请求里真正提供的内容。项目里“有”最新日志、某轮对话里“提过”约束、数据库里“存着”用户偏好,都不代表模型这一次看到了它们。

读完这篇,你应该能回答:Context 最朴素的定义是什么?一条新测试结果怎样进入下一次模型调用?为什么保存、检索和最终可见是三件事?

资料说明:概念依据来自 Anthropic 与 OpenAI 的官方材料;实现案例核对了 2026 年 9 月 20 日的 Codex 公开源码,链接固定到核实版本。过滤器、TTL 和结构化 checkpoint 是本文的设计示例;下文会把它们与 Codex 已实现的历史整理、截断和压缩分开。模型窗口与服务端行为仍以目标 API 文档为准。

一、先用“工作台”故事看懂 Context

1.1 资料都在,为什么模型还是用了旧日志

继续看支付测试任务。系统里同时存在昨天的失败日志、刚生成的新日志、当前代码改动、完整聊天历史和项目文档。如果把所有内容都塞给模型,旧日志可能与新日志冲突,大量历史也会淹没当前问题;如果只给一句“继续修”,模型又缺少判断依据。

更合适的材料包很小:任务目标、不能修改公开 API 的约束、当前 diff,以及刚运行的支付测试结果。它们足以回答眼前的问题——“这次修改是否有效,下一步该做什么?”

Context engineering,就是为模型的下一步挑选、整理并更新此刻该看到的材料。这里的 Context 不只指聊天记录,而是本次模型调用实际能看到的规则、任务和证据。

1.2 用“资料室、候选架、工作台”建立直觉

可以把整个系统想成一间资料室。长期存储像书库,负责把可能以后有用的内容保存下来;检索像图书管理员,根据当前问题找出一批候选;Context 则是最后摆上工作台、真正交给模型的那一小包材料。

因此,Memory 负责保存,retrieval 负责找候选,Context selection 负责最后选择。保存成功不等于被选中,检索命中也不等于值得送给模型。

一份常见材料包会逐项考虑:稳定规则、当前目标和完成条件、任务正处在哪个阶段、最近得到的工具结果、按需取回的文档或历史,以及为模型回答预留的空间。每一项都要回答两个问题:下一步真的需要吗?它还是最新、可信、允许使用的吗?

这里也能看清它与上一篇的关系:Prompt 是材料包里较稳定的行为说明,Context 是这次模型能看到的整包材料。两者会重叠,但解决的问题不同;一个负责把要求说清,一个负责让要求与当前证据在正确时刻一起可见。

二、让正确材料进入下一步判断

2.1 从保存到可见,要经过三次选择

先区分三个集合:durable store 保存可能以后有用的事实;candidate set 汇集检索结果、最近消息和运行时状态;final input 才是这次真正序列化进模型请求的内容。写入存储只证明第一层有这条事实,不能证明模型这一次看得见。

长期存储中的资料经过筛选,成为本次模型请求的工作集
Context 是本次请求读取的一小部分资料,不是整个知识库。保存哪些内容与这次读取哪些内容需要分别设计。
材料适合长期保存?适合每轮携带?主要风险
稳定系统规则是通常是多份副本漂移
用户目标与 done 条件是通常是压缩时丢失约束
完整工具日志是,便于审计否,只带相关片段噪声挤占证据
当前文件内容可由仓库保存按任务选择快照过期
阶段性计划可 checkpoint当前阶段需要旧计划阻碍新证据
秘密与敏感数据按政策最小化默认否泄漏和权限扩大

2.2 一次 Context 是怎样装配出来的

Anthropic 把 context engineering 概括为在 agent 每一步维护最佳 token 集合。这里的“最佳”不是相似度最高,而是能支持当前决策:相关、足够新、来源可信、与目标一致,并且值得占用预算。

建议的上下文装配设计:任务目标指导候选材料的过滤、排序和预算装箱,再形成模型视图;检索是候选来源之一
建议的装配流程:检索只是候选来源之一,过滤、排序和预算决定最终输入。这不是 Codex 每次请求都执行的流水线。

先用一个建议的装配器设计继续支付测试任务。验证阶段的候选里同时有目标、旧错误日志、当前 diff、最新测试输出和完整聊天历史。装配器应先淘汰过期日志,再选择当前 diff 与最新测试输出;固定 instruction 和工具 schema 先计入输入成本,随后为输出预留空间,剩余预算才用于候选材料。

在这个设计中,Harness 完成测试后产生最新 observation;若需要完整审计日志,就由运行时另行保存原文,再把退出码、关键错误和日志引用加入候选。下一次装配优先选入新结果,并明确旧错误是否已被推翻。淘汰旧日志和保存完整日志都需要代码实现,不能从“用了 Context engineering”推导出系统已经具备这些能力。

def assemble(candidates, phase, window, fixed_input, output_reserve):
    usable = filter_by_scope_freshness_permission(candidates, phase)
    ranked = rank_for_current_decision(usable)
    budget = window - tokens(fixed_input) - output_reserve
    return pack_without_splitting_evidence(ranked, budget)

verify_candidates = [
    "goal", "old-error-log", "current-diff",
    "latest-test-output", "full-chat-history"
]
# selected: goal + current-diff + latest-test-output
设计伪代码:先决定当前阶段,再做确定性过滤、排序和预算打包;“与整个任务有关”不等于“对下一步有用”。

2.2.1 先问“下一步要做什么”

同一个任务在调查、编辑、验证三个阶段需要不同工作集。调查时需要入口文件与错误日志;编辑时需要目标符号、调用方和约束;验证时需要 diff、测试命令和失败输出。用整个任务的宽泛 query 检索,往往会得到“总体相关、当前无用”的材料。

2.2.2 再按来源和新鲜度过滤

相似度不能判断权威。正式 schema 比旧讨论更可靠,刚执行的测试比三轮前的猜测更新,工作区文件比模型记忆更接近当前事实。每个 context item 最好携带来源、时间/版本、作用域和敏感级别,装配器才能做确定性过滤。

  1. 产生事实:Harness 读取当前 payment.go,得到函数签名和工作区版本。
  2. 登记候选:Runtime 把正文或引用与来源、版本、作用域放入 candidate set。
  3. 检查候选:装配器确认它属于当前任务、仍然新鲜,而且当前模型有权看到。
  4. 放入请求:只有通过检查且预算放得下的 item 才进入本次模型请求;文件变化后,旧版本必须失效并重新读取。
{
  "item": "payment.go: validateRefund(...) signature",
  "source": "workspace_file",
  "version": "git:7ad12f + dirty",
  "observed_at": "turn:18",
  "scope": ["refund-fix"],
  "trust": "local-authoritative",
  "ttl": "until-file-change"
}
形状级示例:Context item 不只是一段文本,还要记录来源、版本和有效期,运行时才能判断它是否仍能使用。

until-file-change 不是文本自带的保证。Runtime 必须监听或比较工作区版本,在文件变化后使旧 item 失效;否则 TTL 只是一句无人执行的愿望。

2.2.3 真实实现还要保护调用与结果的配对

Codex 给出了另一种更具体的路径:每次采样前克隆当前历史并调用 for_prompt,而不是使用上面的通用候选排序器。工具结果写入历史时,按截断策略处理输出负载;准备请求时,再补齐缺失结果、移除没有对应调用的结果,并移除模型不支持的图像或音频。有名字的外部工具结果可以独立存在,不应套用普通调用结果的删除规则。

继续看支付测试:若历史中记录了“发起测试”,却没有对应返回,模型不应把缺失理解为测试通过。普通函数调用缺结果时会补一个 aborted 输出。这一步修复的是请求结构,并没有重新执行测试,也没有证明测试失败原因。

历史片段:function_call(call_id="test-4"),没有对应结果
请求片段:function_call(call_id="test-4")
          function_call_output(call_id="test-4", output="aborted")
下一步:重新确认测试状态,不能据此报告验证通过
简化的内部记录形状。调用与结果必须能对上,但结构完整不等于任务完成。

因此,调试旧日志问题时要分两层:先检查请求是否合法、结果是否完整,再检查事实是否过期。这里核实的历史整理函数没有提供任意文件的 TTL 失效,也没有承诺自动删掉所有旧日志;那些仍是需要独立实现的选择策略。

2.3 材料放不下时,先保护关键内容

简单地“超过 N tokens 就砍前面”会随机删掉关键限制。更稳的策略是先扣除 instructions、工具 schema 等固定输入成本,再为输出预留空间,余下预算按分区分配给稳定规则、当前目标、近期 observation、检索材料和历史摘要。预算可以动态变化,但优先级必须明确。

分区预算原则压力下的处理
稳定规则小而稳定,优先保留去重,不随意总结
目标与完成标准每轮可见结构化压缩并校验字段
当前 observation离决策越近越优先保留错误码、关键行和来源
历史过程只保留仍影响决策的状态总结、写入失效标记(tombstone)或不再放进下一次请求
候选文档按任务阶段打包降级、分批读取或再检索
输出空间调用前预留不能等输入塞满后再希望模型完成

三、进阶:让长任务可以压缩、恢复和追查

3.1 长任务需要压缩,但不能压掉任务状态

历史持续增长并逼近可用窗口时,长任务可能需要压缩(compaction)。高质量压缩应保留目标、约束、已确认事实、已做变更、未解决问题、下一步和证据指针;可丢弃重复解释、完整低价值日志和已经被新事实推翻的猜测。摘要本身是有损变换,所以必须可追溯到原始记录。

普通请求使用当前历史,必要时压缩并替换历史,恢复从持久化检查点继续
普通请求与压缩是不同路径。压缩成功后替换当前历史并记录检查点;恢复读取检查点及其后的记录,不要求每轮先压缩。

3.1.1 用 checkpoint schema 保护关键状态

下面是一种形状级 schema,不是某个产品的固定字段:

  • Goal:当前任务与完成条件。
  • Constraints:不能丢的产品、安全和用户限制。
  • Confirmed:带来源的已验证事实。
  • Changed:文件、外部对象和副作用记录。
  • Open:未解决问题、失败尝试及原因。
  • Next:下一动作以及为什么。

自由文本摘要适合人读,结构化 checkpoint 适合恢复与校验。二者可以同时存在:结构保证不变量,叙述解释因果。

{
  "goal": "Fix refund_should_reject_expired_order",
  "constraints": ["Keep public APIs stable", "Run payment tests"],
  "confirmed": [{"fact": "expired-order guard is missing", "ref": "workspace:payment.go"}],
  "changed": ["payment.go"],
  "open": ["payment tests have not run"],
  "next": "run payment tests",
  "evidence_refs": ["trace:test-run-4", "workspace:payment.go"]
}
恢复检查:下一次 run 先验证文件版本;若引用已失效就重新读取,再执行 next。删除 constraints、open 或 evidence_refs,会分别让系统忘记允许范围、误报完成或无法找到原始结果。

3.1.2 压缩完成后,下一次请求从哪里继续

Codex 的自动压缩入口会按配置选择 token-budget 路径、远端压缩或本地压缩。这里跟随其中的本地摘要路径,不把它当成所有模型和提供方的统一实现。它调用模型生成摘要,然后构造替换历史;保留的用户消息从最近向前按预算选取,并按触发位置决定是否重新注入初始上下文。这不是把所有原始对话原样装回去,也不是上面六字段 checkpoint 的自动提取器。

摘要生成后还有一次明确的状态变化:replace_compacted_history把新历史写入内存,同时将带 replacement_history 的 Compacted 记录交给持久化路径。恢复时,先载入选中的压缩检查点,再重放其后的记录。所以要保存的既是“摘要说了什么”,也是“接下来用哪一组历史继续”。

压缩本身也可能放不进窗口。本地路径遇到 ContextWindowExceeded 时,在输入还有多项时移除最早历史项后重试;若已无法继续缩减则返回错误,其他可重试错误则受重试次数限制。这个兜底并不能保证目标和约束永远无损,因此关键状态仍需独立检查。压缩完成事件也只表示压缩步骤结束,不表示支付测试已经通过。

3.2 检索命中为什么仍可能是坏 Context

Memory 是持久化机制,retrieval 是找候选的机制,context 是本次调用的可见集合。一个事实写进 memory 后,仍需要检索、过滤和预算才能进入 context;一个工具结果即使不写 memory,也可能在当前回合直接进入 context。

Anthropic 的 contextual retrieval 展示了一个关键点:孤立的检索切片(chunk)可能丢失文档语境,为 chunk 补充来源上下文能改善检索。工程上还要继续往后走:检索命中只是候选,运行时仍需检查版本、权限、重复和与当前阶段的关系。

3.3 模型用错事实时,沿选择过程向前查

当 agent 用错事实,必须能回答:候选里有没有正确事实?它在哪一步被过滤?错误事实为什么排得更高?最终请求带了哪一版?压缩是否改写了含义?因此每次调用最好记录一份不含敏感正文的 context selection log。

  • item id、来源、版本与选择原因;
  • 确定性过滤原因、进入/淘汰阶段与排序分数,不只保留最终列表;
  • 每个分区的 token 用量和截断事件;
  • 摘要或压缩产物指向的原始证据;
  • 敏感材料的脱敏、授权与保留策略。

四、复盘:装配下一次 Context 的五个问题

评审问题要防的失败首选机制
模型此刻必须知道什么?缺关键证据按当前决策定义 working set
每条事实从哪里来、还新鲜吗?过期与错误权威provenance、版本、TTL
为什么它值得占窗口?噪声和 lost-in-the-middle分区预算、排序、去重
压力下哪些不变量不能丢?compact 后目标漂移结构化 checkpoint
下一次运行怎样重新取得它?把 session 当 memorydurable store + 可重放选择策略

Context engineering 的结果不是“塞得更多”,而是模型在每个决策点拿到正确的工作集。下一篇转向模型看不见却决定动作能否发生的部分:runtime harness。

官方资料与源码

延伸阅读