1. 前言

上一篇文章中,我们深入剖析了 Tool System 的设计——Agent 如何定义、注入、执行和回写工具调用。如果说 Agent Loop 是 Agent 的"心跳",Tool System 是 Agent 的"双手",那么 Context Management(上下文管理)就是 Agent 的"记忆系统"——它决定了 Agent 能记住什么、忘记什么、以及如何在有限的上下文窗口中高效组织信息。

1.1 从 Prompt Engineering 到 Context Engineering

过去几年,应用 AI 领域的焦点一直是 Prompt Engineering——如何写出更好的 prompt,让模型产出更好的结果。但随着 Agent 系统从单轮对话演进为多轮、多工具、长生命周期的自主运行,一个更根本的问题浮现了出来:不只是 prompt 写得好不好,而是进入模型上下文窗口的每一段信息,是否都值得占据那有限的注意力预算。

Anthropic 在其 2025 年的工程博客中正式提出了 Context Engineering 这个概念,将其定义为 Prompt Engineering 的自然演进1

Prompt Engineering 解决的是"怎么写 prompt",Context Engineering 解决的是"什么信息该进入上下文窗口,以最大化达成目标行为的概率"。

这个转变的核心原因是:一个在 loop 中运行的 Agent,每轮都在产生越来越多的数据——tool result、思考过程、中间决策、用户反馈——这些数据都有可能对下一轮推理有用,但不一定都值得放进有限的上下文窗口。Context Engineering 的本质,就是从不断膨胀的信息熵中,反复筛选出那组最小的高信号 token 集合。

1.2 上下文窗口没有免费午餐:Context Rot

这个筛选之所以必要,根源在于 LLM 架构层面的一个基本约束。Anthropic 的研究指出,LLM 存在 上下文衰减(context rot) 现象:随着上下文窗口中的 token 数量增加,模型准确回忆其中信息的能力会下降1

原因来自 Transformer 架构的注意力机制:每个 token 都需要关注上下文中的其他所有 token,形成 n² 对配对关系。上下文越长,这种注意力就越分散。此外,模型在训练时见过的短序列远多于长序列,对长距离依赖的处理能力相对较弱。因此,上下文窗口并不是"越大越好"——每新增一个 token,都会消耗模型的注意力预算(attention budget),增加模型在关键信息上"失焦"的风险。

这就引出了 Context Engineering 的指导性原则:找到最小的一组高信号 token,使其最大化目标行为的概率。 注意"最小"不代表"最短"——你仍然需要给 Agent 足够的信息来建立正确的行为模式——但它一定意味着:放进上下文的每一条信息,都必须经过有意识的筛选。

1.3 为什么这个工程难题被低估了

有了上面的理论框架,再来看为什么 Context Management 在工程中被严重低估。LLM 的上下文窗口(context window)虽然从 GPT-3.5 的 4K token 一路膨胀到如今 Claude 的 200K、Gemini 的 1M token,但上下文管理的挑战不仅没有消失,反而变得更加复杂。原因有三:

第一,大窗口不等于无限窗口。即便窗口达到 200K token,一个真实编程场景中的长会话——几十轮 tool call、数百个文件读取结果、数万行代码变更——仍然可能轻易突破上限。而且窗口越大,推理成本越高,延迟越大,prompt cache 越难命中。

第二,tool result 是上下文膨胀的主要来源。与普通聊天不同,编程 Agent 的每一轮 tool 调用都可能返回大量内容:一次 grep 可能返回数百行匹配结果,一次文件读取可能包含数千行代码,一次 shell 执行可能输出数万行日志。这些 tool result 必须回灌到上下文,否则模型无法基于真实执行结果继续推理——但如果不加治理,它们会迅速占满整个窗口。

第三,上下文不是单一数据结构,而是多层信息资产的持续维护。System prompt 需要稳定以命中 cache,对话历史需要合法以通过 API 校验,工具结果需要清理以控制体积,关键知识需要从易失的短期历史迁移到稳定的长期记忆——这些不是独立的优化任务,而是一套协同运作的治理体系。

2. Context Management 的本质

2.1 从"把历史全发过去"到"上下文治理体系"

一个最朴素的上下文管理,可以写成这样:

def build_prompt(history, tools):
    return system_prompt + tools + history

同样,这个朴素例子距离一个"能在真实产品中长期稳定运行的上下文系统"还有很大差距。真实场景需要回答的问题包括:

  • System prompt 如何组装,才能既完整又稳定命中 prompt cache?
  • 对话历史超过窗口限制时,如何压缩而不丢失关键决策信息?
  • 工具返回的巨量结果(数万行日志、数百个匹配)如何回灌而不撑爆上下文?
  • 历史中的 tool call 和 tool result 失去配对时,如何修复而不导致 API 400 错误?
  • 跨 session 的知识(用户偏好、项目约定、历史决策)如何持久化并在新对话中复用?
  • 图片、多模态输入在上下文中如何降级和清理?

这些问题的本质是:Context Management 不是"拼一段 prompt"那么简单,而是一套覆盖 prompt 构造、历史合法化、tool result 治理、多级压缩、长期记忆、prompt cache 稳定化的完整治理体系

更深一层看,Context Management 之所以必须从"拼字符串"升级为"治理体系",根本原因在于 上下文的注意力预算(attention budget)是有限的。Transformer 架构下每个 token 都关注所有其他 token,形成 n² 对配对关系。随着 token 数增长,模型的注意力被拉伸稀释,准确回忆能力下降——这就是 Anthropic 所称的 context rot。因此,上下文管理的目标不仅是"不超过窗口上限",更是"让有限窗口内的每个 token 都值得占据模型的注意力"。

2.2 三个根本问题

从 Context Engineering 的视角,上下文管理需要回答三个递进的根本问题:

  1. Agent 看到什么:Prompt 构造 + 历史管理——如何把当前会话的上下文,变成模型能理解、能推理的合法 prompt。核心原则是"找到最小的一组高信号 token"。
  2. 超出窗口时怎么办:多级压缩 + 长期记忆——如何在信息不丢失的前提下,把上下文压缩到窗口以内。核心原则是"先搬运,再丢弃"。
  3. 跨会话如何复用:长期记忆 + consolidation——如何把高价值信息从易失的短期历史迁移到稳定的长期存储。核心原则是"让记忆成为可导航、可纠错的持久资产"。

2.3 Context Management 的通用分层

尽管四个项目在具体实现上各有取舍,它们的 Context Management 共享同一套核心分层:

flowchart TD
    A["Prompt 构造层:system prompt 组装 + 动态注入"] --> B["历史管理层:合法窗口裁剪 + 消息归一化"]
    B --> C["Tool Result 治理层:回灌 + 截断 + 持久化 + 清理"]
    C --> D["多级压缩层:轻量剪枝 → 结构收缩 → 语义折叠 → 自动触发"]
    D --> E["长期记忆层:session memory + cross-session consolidation"]
    E --> F["Provider 适配层:cache marker + 格式兼容 + 重放合法性"]

3. 主流项目的 Context Management 设计

3.1 Claude Code2:分层治理与 prompt cache 优先

Claude Code 的 Context Management 体系化程度最高,核心思路是四层分别治理:prompt、transcript、compaction、memory

Prompt。 System prompt 拆成"静态前缀 + 动态尾部"。静态前缀包括 attribution header、CLI identity prefix、intro、system rules、tool usage conventions、tone and style——这是 Claude Code 的长期人格和工作协议。动态尾部包括 session guidance、memory prompt、env info、language、output style、MCP instructions、scratchpad、token budget 等。Prompt cache 以前缀匹配,头部稳定就能复用缓存。外加一层优先级合成——override > coordinator > agent > 自定义 > 默认 > append,不同模式看到不同 prompt 但共享同一套组装框架。

值得注意的细节是,Claude Code 还把"用户/仓库局部背景"(claudeMdcurrentDate)从 system prompt 中分离出来,通过 <system-reminder> 包裹后作为最前面的 meta user message 注入。这样 system prompt 本身更稳定,局部背景按消息语义处理,不必打碎 system cache。

最终发给模型的请求由四部分构成:system blocks + tools schemas + messages + 请求级参数。静态进 system,动态进 user message,各归其位。

Transcript。 发 API 前做大量"语义不变、结构归一"的清洗,最关键的是 tool_use/tool_result 配对修复。取舍很明确:宁愿注入占位结果,也不让 transcript 进入模型不可消费的死状态——配对断裂 API 直接 400。

压缩。 四级递进:snip(投影视图,不改原 transcript)→ microcompact(清 tool result,区分 cache 冷/热——事前看间隔超 TTL,事后看缓存命中 token 是否下降)→ collapse(持久摘要视图)→ autocompact(优先 session memory 结构化压缩兜底)。

Memory。 Session Memory(中期,后台 forked agent 写 markdown)+ autoDream(跨 session,三道 gate,强调优先修旧而非新增)——维护一个可导航、可纠错的 memory corpus。

Prompt cache 作为隐形主线。 从静态拆分到 schema 缓存到 replacement 决策冻结到各类 header sticky latch——核心目标是不打乱服务端 cache。甚至有一整套 cache break detection 追踪 cache miss。不是"顺便优化",是一级工程指标。

3.2 Codex CLI3:稳态 diff 与双轨记忆

Codex 的 Context Management 是平台级的上下文状态机,核心:instructions 与 input 分离 + 稳态 diff + 长期记忆独立双阶段

Instructions/Input 分离。 发给 API 的请求分两块:instructions 承载 session 级稳定行为约束,input 承载每轮变化的环境/权限/app/skill。划分标准就一条:稳定的进 instructions,变化的进 input。具体来说:

  • 进 instructions:session identity / base behavior——“这个 Agent 是谁、长期如何工作”,生命周期最长
  • 进 input(developer message):运行权限与执行边界(sandbox、approval policy、cwd)、platform 附加约束(collaboration mode、guardian reviewer、git trailer)、能力发现信息(apps、skills、plugins、memory read-path)
  • 进 input(user message):用户态上下文(user instructions、环境 XML)
  • 按需注入:可变人格与状态提示(personality、realtime、model switch notice)

instructionsinput 直到发请求时仍然是两条独立通道,而不是先合成一段最终 system prompt 再整体发送。

稳态 diff。 Codex 最独特的设计:维护"上一轮已成功建立的上下文快照"作为基线,后续轮只发差异项。首轮全量 + 稳态 diff,减少前缀漂移、提升 cache 命中。

合法化。 ContextManager 保证三个不变量:每个 call 都有 output(缺了补 synthetic)、每个 output 都有 call(孤儿移除)、不支持图片时降级为占位文本。

压缩。 四级映射,autocompact 有三条触发路径——pre-turn(开局前先压)、model-switch(换小窗模型前借旧模型压缩)、mid-turn(超阈值且还要继续才压)。设计刻意:能不压就不压,本轮能正常结束就算超了也不压。compact 自己超窗时从最老项删保留后缀,为 preserve prefix-based cache。

长期记忆。 四个项目中最"重"的:Phase1 从 rollout 提炼原始记忆,Phase2 全局汇总,增量而非全量重建。进入 prompt 方式是"轻摘要 + 路由提示"而非全量回灌。

3.3 pi4:pipeline 式处理

pi 的 Context Management 最简洁,核心思路是:上下文不是内存数组原样发送,而是经过 Session tree 恢复 → 消息转换 → provider 合法化 → 压缩 → 缓存标记的多阶段流水线

pi 把上下文建模为三个独立部分——systemPrompt(稳定前缀)、messages(当前分支可重放会话)、tools(当前 turn 工具定义)。三者解耦,到发送请求时才合并。

System Prompt。 tool 对 prompt 有双层影响——结构化层(发给模型的 function schema)和非结构化层(写在 system prompt 里的使用说明)。这让模型即使 provider 不强依赖 tool schema 也能正确使用工具。

合法窗口。 pi 的 Session 是一个树结构而非扁平的 message list——从当前叶子回溯到 root,只取当前路径上的 entry,不在当前分支的历史天然不进入上下文。此外还有消息类型转换和 provider 格式兼容两层裁剪。所以"运行时消息"和"LLM 上下文消息"是两个不同的概念,真正送给模型的远比 session 里看到的干净。

压缩。 只分两类:threshold(接近窗口上限时自动压缩,不 retry)和 overflow recovery(API 返回溢出错误后压缩并自动重试一次)。Cut point 策略很明确:不把 toolResult 从对应 turn 里单独切开,太大的 turn 拆成"历史总结 + turn 前缀总结 + 尾部保留"。

长期记忆。 没有独立 memory service——长期状态就是 session JSONL 中的 compaction 摘要、分支浓缩和 extension 自定义 entry。最接近 consolidation 的是 iterative summary update:拿到旧 summary 合并新消息做增量,而不是全量重算。这符合 pi 的设计哲学:核心框架只做最少抽象,高级能力留给 extension

3.4 nanobot5:学术级压缩

nanobot 的 Context Management 最学术化,五层协同:构造稳定 prompt → 维护 append-only 历史 → 运行时清洗 → token 驱动压缩 → provider cache 适配。

System Prompt。 按固定顺序拼接:identity → bootstrap files → long-term memory → skills。最关键的决策:时钟不进 system prompt——当前时间等高漂移信息包装进 user message,避免每分钟刷新 system 前缀。直接收益:provider prompt cache 更容易命中。

合法窗口与清洗。 合法窗口必须从 user turn 开始、无孤儿 tool result、每个 tool result 能找到对应的 assistant tool_call。Session 是 append-only 的,consolidation 通过指针前移标记"已沉淀"而非改写历史。写 session 前做一轮清洗:去空 assistant、截断过长结果(16K)、清 data URL、剥离 runtime context。核心思想不变:运行时"脏数据"转成可持续复用的历史表示

压缩。 Token 预算驱动,触发条件是 estimated >= budget,停止条件是 estimated <= budget/2——典型的滞回设计,避免每轮在阈值附近震荡。cut point 只在 user-turn 边界选择,优先语义完整性。

长期记忆。 双文件模型:MEMORY.md(长期事实,注入 system prompt)和 HISTORY.md(摘要日志,只用于 grep/search)。合并时 memory update 是完整重写而非增量 patch,让 LLM 一次性产出更一致的记忆视图。失败时降级到 raw archive——不丢数据。

3.5 四个项目 Context Management 总体横向对比:

维度Claude CodeCodex CLIpinanobot
System Prompt静态前缀 + 动态尾部,多级覆盖instructions/input 分离,六类职责固定骨架 + tool 双层注入identity + bootstrap + memory,时钟不进 prompt
历史模型统一消息流,compact boundary 截断ContextManager + 稳态 baselineSession tree,当前分支路径append-only,consolidation 指针
合法化消息归一化 + tool 配对修复补 output、清孤儿、降级图片三策略三层裁剪,回退合法状态孤儿驱逐 + 合法起点扫描
压缩层级snip → microcompact → collapse → autocompactsnip → microcompact → collapse → autocompactsanitization → compaction → branch summarycleanup → trim → consolidate → auto-trigger
压缩触发多策略叠加 + circuit breakerpre-turn + mid-turn + model-switchthreshold + overflow recoverytoken 预算 + budget/2 滞回
长期记忆Session Memory + autoDreamPhase1/Phase2 双阶段全局session-native summary + iterative updateMEMORY.md + HISTORY.md 双文件
Cache 策略静态拆分 + 冷热分离 + break detectionconversation_id key + 稳态 diff固定位置 marker + session affinity稳定 prefix + append-only + cache-control
整体风格重装备、体系化平台级、稳态机制轻量、干净、pipeline 式学术级、最小原则

4. Context Management 的关键设计维度

4.1 System Prompt 组装

四个项目的共识很明确:稳定部分和动态部分必须分离。策略各有侧重——Claude Code 用静态前缀 + 动态尾部(section-level memoize),Codex 用 instructions/input 分离(稳定进 instructions、变化进 input),nanobot 时钟不进 system prompt(高漂移信息进 user message),pi 从 active tool 集合动态抽取使用说明和指南。共通的目标:让 system prompt 前缀尽量稳定,最大化 cache 命中。

Anthropic 提出 system prompt 应保持 “right altitude”1——在两种极端之间:硬编码 if-else 的脆硬极端(脆弱难维护),和只有模糊高层指引的模糊极端(缺乏具体信号)。最优高度是足够具体以引导行为,又足够灵活给模型自主决策空间。实践中从最小可用 prompt 开始,用最好模型测试,按失败模式逐步补充,而非一开始就穷举边界情况。

4.2 历史合法化

所有项目都必须在发 API 前修复消息历史:Claude Code 缺了补 synthetic、pi 三层裁剪剔除 error/aborted、Codex 保证 call 有 output 且 output 有 call、nanobot 扫描并驱逐孤儿 tool result。共同取舍:API 合法性优先于信息完整性——一旦 400,loop 中断,连"可能丢了些信息"的机会都没有。

4.3 Tool Result 治理

tool result 是上下文膨胀主因。Claude Code 的大结果先落盘只回灌 preview 是最实用的设计,且同一个 tool_use_id 的 replacement 决策一旦做出就永久冻结——不仅省 token,更保证了模型每次看到同一结果时形态不漂移,维护 cache 稳定性。Codex 写入时即截断,nanobot 持久化时截断到 16K 并清 data URL,pi 在 summarization 阶段截断。共同的思路:写入前截断、持久化清洗、压缩时优先清理。

4.4 上下文检索策略:预加载 vs 即时加载

传统做法是预推理时从向量库检索相关内容注入上下文。但 Agent 从单轮 RAG 演进为多轮自主 loop 后,Anthropic 观察到即时加载(just-in-time)1 正在兴起:Agent 持有轻量引用(文件路径、查询、链接),运行时按需通过 tool 动态拉取数据,全程不把完整数据集加载到上下文。这模仿了人类借助文件系统和书签导航信息的认知模式。关键收益是元数据即信号(tests/test_utils.py vs src/core_logic/test_utils.py 仅路径就暗示不同用途)和渐进式信息披露(逐层探索、按需组装)。

Trade-off 是运行时探索更慢,且需要 Agent 有足够自主导航能力。实践中采用混合策略:稳定信息(如 CLAUDE.md)预加载,动态信息由 Agent 通过 glob/grep 自主即时检索。

4.5 多级压缩

四个项目不约而同采用四级递进:局部截断(不改对话结构,只把单个 item 变薄)→ 结构收缩(清低价值内容,不做语义总结,Claude Code 还区分 cache 冷热)→ 语义折叠(LLM 总结旧对话为摘要,cut point 绝不切断 tool batch)→ 自动触发(token 预算驱动、threshold + overflow、pre-turn/mid-turn/model-switch 三条路径等不同策略)。

工程上建议的顺序:先做好写入前截断(成本最低),再补语义压缩(不可或缺的兜底),然后上自动触发,最后才考虑精细结构收缩。

Anthropic 的调优建议很务实:先最大化 recall(确保捕获每段相关信息),再提升 precision(逐步去除多余内容)——因为过度压缩丢失的信息比冗余更危险。Tool result clearing 是"最安全、最轻量"的压缩形式。

4.6 长期记忆与结构化笔记

四个项目的长期记忆方案分两派:独立服务派(Claude Code 的 Session Memory + autoDream,Codex 的 Phase1/Phase2 双阶段)和 session-native 派(pi 的 summary entry,nanobot 的 MEMORY.md + HISTORY.md 双文件)。独立服务功能更完整但复杂,session-native 简单但跨 session 复用弱。务实建议:从 session-native 起步,有跨 session 需求时再引入独立 service。

Anthropic 还提出了一个介于两者之间的中间策略——Structured Note-taking1:Agent 自主定期将笔记写入上下文窗口外的持久化存储(如 NOTES.md),后续按需拉回。这是开销最小的持久记忆策略,Claude Code 的 Todo List 和 Claude 玩 Pokémon 实验中数千步的自主训练笔记都是典型案例。核心特质是 Agent 自主决定记什么,而非系统被动压缩。

4.7 Prompt Cache 稳定性

Prompt cache 不是附带优化,而是一级设计约束。三个核心原则:前缀稳定(system prompt 头部尽量不变)、决策冻结(一旦某段上下文的表示被模型看过就锁定)、理解 provider cache 边界条件(前缀匹配、TTL、cache editing)。从 system prompt 组织到 tool result replacement 到 compaction 策略,都要过 cache 这一关。

  1. 前缀稳定:system prompt 的头部尽量不变,变化信息放到尾部或 user message
  2. 决策冻结:一旦某段上下文的某种表示被模型看到过,后续就锁定为同一形态
  3. 显式缓存的边界条件:理解 provider cache 的工作原理(前缀匹配、5min TTL、cache editing),在这个前提下去设计上下文结构

5. 设计共识

综合四个项目的工程实践和 Anthropic 的 Context Engineering 方法论,可以提炼出以下设计共识:

  1. 上下文是有限且衰减的资产。 指导性原则是找到最小的高信号 token 集合,最大化目标行为概率。Context Management 不是"拼 prompt",而是覆盖 prompt 构造、历史合法化、tool result 治理、多级压缩、长期记忆、cache 稳定化的治理体系。

  2. 稳定和动态分离。 System prompt 的静态部分放前缀以命中 cache,动态部分放尾部或 user message。保持"right altitude"——具体但不脆硬,灵活但不模糊。时钟不进 system prompt,变化信息进 user message。

  3. 历史合法化先于发送。 Tool call/result 配对完整性是硬约束。压缩在 user turn 边界截断,不在 tool batch 执行中途切开。Tool result clearing 是最轻量最安全的压缩形式,compaction prompt 先最大化 recall 再提升 precision。

  4. 预加载与即时加载互补。 稳定上下文(如 CLAUDE.md)预加载,动态信息由 Agent 通过工具自主按需检索。文件路径、命名规范等元数据本身就是上下文信号。

  5. 绕过窗口限制只有三条路:compaction(压缩旧上下文)、structured note-taking(Agent 自主写外部笔记)、sub-agent(独立窗口执行,只传精简摘要回主 Agent)。 长时 Agent 三者并用。

  6. Prompt cache 是一级设计约束,不是事后优化。 三个原则:前缀稳定、决策冻结、理解 provider cache 边界条件。

这些共识解决同一个问题:把上下文当作有限的注意力预算来管理,让 Agent 在约束下长期稳定工作。

6. 总结

Context Management 是 Agent 系统中"最不性感但最关键"的部分。它不像 Agent Loop 那样有清晰的循环逻辑,不像 Tool System 那样有明确的接口边界——它更像是一套贯穿始终的"基础设施维护系统"。但正是这套系统,决定了一个 Agent 能从"跑 10 轮就跪"进化到"跑 100 轮还行"。

构建 Agent 的核心挑战已经不再是"怎么写好 prompt",而是"如何持续筛选和维护最优的 token 集合"。每轮推理前,都需要从不断膨胀的信息宇宙中做出决策:什么该进、什么该压、什么该留、什么该丢。这个决策循环本身就是 Agent 工程化的核心。

Anthropic 的 Context Engineering 实践有三个关键视角:

  • 注意力预算:上下文的边际收益递减。每新增一个 token 都会消耗模型的注意力。Context Engineering 的目标是找到最小的高信号 token 集合。
  • 三种绕过窗口限制的技术路径:compaction(压缩旧上下文)、structured note-taking(Agent 主动写外部笔记)、sub-agent architectures(子 Agent 独立窗口 + 精简摘要回传)。真正有效的长时 Agent 三者并用。
  • 混合检索策略:预加载稳定信息 + 即时拉取动态信息。让 Agent 像人类一样借助文件系统、命名规范、目录层级等元数据来导航信息空间。

Context Management 的设计没有银弹,但核心原则已经清晰:把上下文当作有限的注意力预算来管理,把稳定和变化分离,在确定边界上做压缩,让每个 token 都值得占据模型的注意力。 下一篇,我们将深入探讨 Agent 的 子 Agent 系统(Subagent System) 设计——Agent 如何把复杂任务拆解、分发、监督和合并。

参考文献