index

上下文窗口是一台只有一半的检索引擎

·40min

《深入理解 AI Agent:设计原理与工程实践》第 2 章「上下文工程」精读笔记

原书信息:李博杰著,第 2 章,p35–p77。全书 311 页,本章 43 页,是篇幅最大、作者自称”全书最关键”的一章。原书开源发布,配套代码仓库:

bojieliai-agent-book

--

-- -- --

阅读定位:本章是 Agent = LLM + 上下文 + 工具 公式里”上下文”这一支柱的完整展开。作者在引言里给的建议是——时间有限就只读第 1 章和第 2 章。

关于本文:逐页精读整理,所有引文逐字来自原文,页码为原书 PDF 页码。文中提到的”图 2-6""图 2-16”等编号指原书插图,本文未转载,需要看图请对照原书。文末有批判性分析,那部分是我的判断,不代表原作者观点。


一、一句话抓住这一章

上下文窗口是一台只有一半的检索引擎。(p64)

这句话是整章的枢纽。模型”检索”那一半极强——你问什么,注意力就能从上万 token 里把原始记录捞出来;但它缺”提炼”那一半——上下文里的东西从来不会被自动数一遍、建个索引、或就地总结成一条结论(p65)。

于是整章所有技术,本质上都在做同一件事:替模型把它自己算不出来(或算起来很贵)的那部分先算好,再放进上下文。 章末小结原样重复了这条纲领(p72 与 p76 出现两次):

不要让模型被动地在海量信息中检索,而要主动为模型提供经过提炼的结构化知识。


二、全章骨架:一张结构图 + 一条逻辑链

2.1 结构图:所有技术都挂在”静态前缀 + 轨迹”上

作者在 2.2.5(p45)给出了本章唯一真正的地基图:

┌─────────────────────────────────────────┐
│  静态前缀(每轮不变,KV Cache 缓存)      │  ← 2.3 KV Cache 约束
│  ├─ System Prompt                        │  ← 2.4 提示工程
│  └─ Tool Definitions                     │  ← 2.4.6 工具定义设计
├─────────────────────────────────────────┤
│  轨迹(随交互增长,可压缩)               │
│  user / assistant / tool / user / ...     │  ← 2.7 上下文压缩
│  ├─ Skill 元数据(末尾注入,emit-once)   │  ← 2.5 Agent Skills
│  └─ <agent_status>(末尾注入,每轮更新)  │  ← 2.6 Agent 状态栏
└─────────────────────────────────────────┘
                                   ↑ 模型从这里开始生成

记住一句话就能推导出全章大半结论:前面不能动,后面可以压。(p45 原话:“理解了这个结构,就能理解为什么’前面不能动、后面可以压缩’。“)

2.2 逻辑链:七节之间的因果关系

2.1 为什么上下文决定能力上限(动机)

2.2 上下文在 API 层长什么样(地基:messages 列表 + 静态前缀/轨迹)

2.3 这个结构在推理层的硬约束(KV Cache:前缀改一字节全废)

     ├─→ 2.4 静态前缀里放什么、怎么写(提示工程 + 工具定义 + 提示注入)
     │        ↓ 提示词膨胀 → 注意力稀释
     │   2.5 静态放不下了怎么办(Skills 渐进式披露:按需加载)

2.6 轨迹里模型看不见的东西怎么补(状态栏:把隐式状态显式化)

2.7 轨迹太长了怎么办(压缩;以及更彻底的方案:隔离)

注意 2.5 → 2.6 的衔接是作者刻意设计的:Skills 的”方式三”(元数据以 user 角色注入上下文末尾)就是状态栏机制的一个特例(p61、p64)。两节共用同一条注入通道。


三、逐节精讲

2.1 上下文:决定 Agent 能力上限的关键(p35–36)

核心主张:「模型本身的智力只是基础,上下文的质量才是 Agent 能力的真正上限。」(p36)

作者给了一个 Coding Agent 的三分法,说明”最低信息需求”是什么:

类别内容缺失后果
实时代码上下文目录结构、模块职责、数据结构、代码规范语法正确但风格格格不入,甚至引入架构冲突
流程规范Git 分支策略、提交规范、CR 流程、CI/CD可能直接往主分支提交未测试代码
环境信息开发环境配置、测试库地址、staging 部署、密钥管理本地跑通,测试环境立刻崩

这一节最值得注意的是一个”越界”的论断——作者把上下文工程从技术问题拔高到组织问题:

上下文工程首先是一个技术问题,但更根本的是一个组织问题。……如果团队本身就是一个信息黑洞,再好的 AI Agent 也无计可施。(p36)

所以构建 AI 原生团队,首先是一场文档化运动,而不只是部署新工具。(p36)

他举 Linux 内核为例:三十多年全球协作,靠的是”高度透明、文档驱动”,这种工作方式天然创造了对 AI 友好的环境。并引 OpenAI 研究员翁家翌:「人和模型一样,最重要的是 Context」「AI 短时间内无法取代人的最大原因也是 context——因为 AI 跟人并不在同一个环境里面」。

评注:这是全章唯一一处非技术论断,但它的隐含推论很强——远程友好度 ≈ AI 友好度。可以当成一个可操作的组织诊断指标:如果你们团队的关键决策只存在于会议口头和私聊里,那么无论买什么 Agent 产品,天花板都在那里。


2.2 API 的上下文结构(p36–46)——本章地基,别跳过

这一节看似”讲 API 基础”,实际上后面每一节都在回指它。四个必须内化的点:

① 四种角色(p36)

role谁写的作用
system开发者身份、规则、约束。模型视为最高优先级,通常只有一条、放最前
user终端用户待响应的请求
assistant模型之前的回复,含工具调用请求。原样放回让模型”看到自己的决策”
toolAgent 框架工具执行结果,靠 tool_call_id 关联

tools 字段是请求的独立字段而非消息——这个细节决定了它随请求一起进静态前缀。

② API 是无状态的(p41)

每次调用都是无状态的——模型不会”记住”上一次的对话,Agent 框架必须每次都把完整历史送回去。

③ 决策与执行分离(p40)

模型负责决策(调用什么工具、传什么参数),Agent 框架负责执行(实际调用 API、运行代码)。

④ Agent 核心循环就是一个 while(p43)

while True:
    response = client.chat.completions.create(model=..., messages=messages, tools=tools)
    msg = response.choices[0].message
    messages.append(msg)
    if not msg.tool_calls:          # 没有工具调用 → 完成
        print(msg.content); break
    for tc in msg.tool_calls:       # 执行工具,结果追加回 messages
        messages.append({"role": "tool", "tool_call_id": tc.id,
                         "content": execute_tool(tc.function.name, tc.function.arguments)})

作者在代码注释里埋了一条生产提醒:这里必须加 max_iterations 上限,因为 Agent 会陷入无限重复同一工具调用(后文 2.3、2.6 会解释为什么)。

一句话总结这一节:「Agent 框架的核心工作就是管理这个 messages 列表……本章后续所有的上下文工程技术,本质上都是在优化这个列表的内容和结构。」(p44)

实验 2-1local_llm_serving)的结论很有意思:0.6B 的 Qwen3 在合理提示词下也能可靠完成工具调用,M2 芯片上 >100 token/s。作者的推论是「端侧 Agent 的时代比大多数人预期的更近」。


2.3 KV Cache 友好的上下文设计(p46–54)——全章技术密度最高

三条铁律(p47,作者说跳过原理也必须记住)

  1. 系统提示词和工具定义一旦确定就不要改。 任何改动,哪怕多一个空格,都会导致缓存全部失效。
  2. 动态信息永远追加到末尾——时间戳、用户状态作为新消息追加到对话末尾,而不是修改已有的系统提示词。
  3. 使用标准 API 格式,不要自行拼接消息。

第 3 条作者做了一个重要且容易被忽略的澄清:自行拼接 "USER: ... ASSISTANT: ..." 的根本问题不是缓存——“缓存只认 token 字节序列,只要拼出的前缀字节级稳定,照样能命中”——真正的问题是偏离了模型训练时见过的格式,削弱多步思考能力(p47、p52)。很多二手总结把这条讲错了。

开场那个事故(p46)

日均 10 万次对话的客服 Agent,工程师在系统提示词加了一行 Current time: {{now}}

  • TTFT:0.5 秒 → 3–5 秒
  • 月度推理账单:几乎翻倍

代码没问题、模型没换。这个例子的价值在于展示”无形成本”——一行看似无害的代码,让整条推理链路慢一个量级

原理(选读,但值得懂)

注意力机制三向量(表 2-1,p47):Query = 当前词的”搜索请求”,Key = 每个词的”标签”,Value = 每个词的”内容”。

实验 2-2(注意力可视化)揭示的四个模式(p49):

  1. 注意力储存池(Attention Sink):序列第一个 token 常吸收超过总注意力 70% 的权重。原因是 softmax 强制所有权重加起来 = 100%,模型无法表达”不关注任何东西”,于是把剩余权重倾倒到开头这个固定位置——「就像一个公共的回收站」。这是系统性现象,不是缺陷。
  2. 思考的三角形模式(<think> 内频繁回看之前思考与工具定义)
  3. 输出的三角形模式
  4. 位置偏好(Position Bias):开头和结尾回忆精度高,中间容易被忽略 → 关键信息放开头或结尾

为什么改前缀会全废(p51–52):大模型是数十到上百层 Transformer 串联,每层独立生成自己的 KV 缓存,且层间是流水线关系。改第 1 个 token → 第 1 层输出变 → 第 2 层输入变 → 逐层传导 → 所有层的缓存都必须重算

Chat Template(2.3.1)是被低估的一节。它是”信封格式”——把结构化 JSON 翻译成 <|im_start|>system ... <|im_end|> 这样的线性 token 流。两个实用价值:

  • 解释了为什么必须用标准格式:工具结果若被塞进 user 消息,Chat Template 会误判”用户换了话题”,清理掉之前的思维链——「相当于模型正算到一半,草稿纸被人收走了」(p50)。
  • 注意各家策略差异很大:DeepSeek 剥离全部历史思考;Claude 要求客户端在工具循环中把带签名的 thinking block 原样回传,新用户轮次后服务端才忽略历史 thinking。用前查模板文档。

实验 2-3:五种有害的上下文管理模式(p52)

反模式危害
动态系统提示词(塞时间戳)缓存 100% 失效
动态用户配置(余额、剩余调用数写进前缀)同上
工具定义动态排序实验表明:固定顺序对工具选择能力几乎无影响,但性能提升显著
滑动窗口对话历史①破坏前缀一致性 ②丢失关键工具结果。实验中「使用滑动窗口的 Agent 经常陷入循环,反复执行相同的工具调用」
文本格式化(自拼 USER:/ASSISTANT:不是缓存问题,是模型能力问题

KV Cache vs Prompt Cache(2.3.3,p52)

KV CachePrompt Cache
层级模型内部 / 推理引擎API 服务层
作用加速单次请求内的 token 生成减少跨请求的重复计算成本
经济影响间接直接影响 API 计费

计费细节差异不小:Anthropic / DeepSeek 缓存读取约为首次计算的 1/10,OpenAI 约五折;Anthropic 需显式设 cache_control 断点(并非自动命中)、缓存写入有约 1.25 倍加价、最小 1024 token、TTL 默认约 5 分钟;OpenAI 是自动前缀缓存。

2.3.4 缓存作为架构约束——本章最有分量的一节

这一节是全章我认为最值得反复读的部分。作者用 Claude Code 的三个设计决策,论证了一个远超”性能优化”范畴的结论:

在设计 Agent 架构时,缓存经济性不是事后优化,而是前置约束。(p53)

提示词的排列顺序首先由缓存的经济性决定,其次才是语义逻辑。(p53)

三个具体表现:

  1. 提示词结构由缓存边界决定:系统提示词被一个缓存边界一分为二,之前可跨用户跨会话全局缓存,之后放用户/会话特定信息。每个运行时二值条件若放在边界之前,缓存键变体数翻倍——3 个条件(macOS/Linux × 普通/调试 × 中/英)就是 2³ = 8 种缓存键。提示词片段在类型层面被区分为”可缓存”和”会破坏缓存”,后者命名带显式警告标记。
  2. 子 Agent 必须与父 Agent 字节级对齐:提示词、工具定义、模型配置、消息前缀、思考配置逐字节匹配,才能命中同一份 Prompt Cache。这个约束从缓存层向上传导,影响了 Agent 的生成方式和参数传递机制。
  3. 工具结果的替换字符串首次出现即冻结:即使会话重启也用完全相同的替换串,保证恢复后的字节流与缓存一致。

评注:这是全章从”技巧”跃迁到”架构”的地方。它说的其实是一个反直觉的工程秩序——在有 Prompt Cache 的系统里,“字节稳定性”是一个和”正确性""可读性”并列的一等公民约束。第 3 点尤其极端:为了缓存一致性,宁可持久化一个可能已经过时的字符串。这在传统软件工程里几乎是坏味道,但在这里是刚需。

2.3.5 铁律其实可以松动(深水区选读,p53–54)

作者自己的研究(arXiv

.17107)给了一个反直觉观察:prefill 阶段模型其实在”做笔记”。读到”用户所在城市:北京”时,它并不是把字段原样缓存,而是把”这意味着什么”的结论写进了下游每一层的 KV 状态。测量发现,字段自身那几个 token 的 KV 对最终决策的贡献往往不到 1%

由此打开两种操作:

  • 编辑(Editing):改一个字段后,只要模型有显式 CoT,改动能顺着已缓存的思考传播,用约 1% 算力得到与整段重算一致的结果。(边界条件:没有 CoT 时孤立改字段会被忽略,因为结论早已烘焙进下游状态却没有思考路径去更新它。)
  • 组合(Composition):用 RoPE 重定位把预算好的”技能”缓存块直接拼进另一段上下文,O(L²) 重算 → O(L) 拼接。

vLLM 实测:p90 TTFT 最高降几十到几百倍,前缀命中率约 98.5%,跨 12 个模型 logit 余弦 0.90–0.999

作者自己划了界:这仍属研究阶段,前面三条实践结论在当前生产系统中依然是默认原则。


2.4 提示工程:优化系统提示词(p54–59)

总的检验标准(p54,我认为是本节最实用的一句):

大语言模型是一位聪明的新员工,能力出众,但对你们的具体工作流程和内部约定一无所知。如果一个聪明的新员工读完你的系统提示词还不知道该怎么做,Agent 也一样不知道。

五个维度:

小节维度关键结论
2.4.1语气与风格(“人格”)大写 NEVER do XPlease avoid X 更引起注意,但过度使用会稀释,保留给真正关键的约束
2.4.2结构化(“格式”)XML 标签名自带语义(<working_directory> 优于”当前目录:”);XML 负责机器可解析的精确语义,Markdown 负责人机共读的组织逻辑
2.4.3流程 vs 规则(“组织方式”)流程驱动(SOP)优于规则堆砌。模型能随时知道”我在哪一步”,而不是遍历所有规则找匹配项
2.4.4业务规则细化(“内容”)这不是技术问题,是产品设计问题
2.4.5Few-shot 示例何时给、给几个、放哪里

2.4.4 是本节的重头戏(p55–56)

作者用 Pine AI 的计费系统做案例。三种计费模式(按省钱提成 20% / 按服务收 tip / 特别难办的预收款),而模糊规则会导致行为不稳定:

  • “帮我退掉上个月买的衣服”——是”帮用户省钱”还是”取回本属于他的钱”?
  • “帮我取消 Netflix 订阅”——取消让用户未来不再付费,这算”省钱”吗?

必须细化到可执行:

NEVER use percentage_based_one_time for refunds and service cancellations.
Use fixed_fee instead.

以及:成功率按固定流程分步评估,高于 60% 用可退款模式、低于 30% 直接拒绝任务;通话每分钟 0.05、汇总后四舍五入到整美元;"节省"只基于现有账单计算——否则模型会想"不砍价明年涨到0.05、汇总后四舍五入到整美元;"节省"只基于**现有账单**计算——否则模型会想"不砍价明年涨到 180,我维持 150就省了150 就省了 30”,把避免未来涨价也算成省钱。

设计哲学(p56):

大语言模型的优势在于遵循复杂指令和从长上下文中提取信息,但不应该在业务规则制定上被赋予过多的自由裁量权。

组织含义(值得单独抄出来):

在优秀的 Agent 公司里,提示词一般由产品经理来设计……工程师的角色是将规则准确地编码到提示词中,确保格式正确、结构清晰,但不应擅自决定业务逻辑。

2.4.5 Few-shot:两个决策点(p56)

  1. 放哪里:放 system → 成为静态前缀,对所有请求生效;伪造一组 user/assistant 消息放首轮 → 适合按会话类型选不同示例集。
  2. 对缓存的影响:无论放哪,示例都在靠前区域,一旦确定就应字节级稳定。「如果按请求动态检索’最相关’的示例,等于每次都改写前缀,缓存会持续失效。」→ 生产系统为每类任务准备固定示例集,而不是逐请求挑选。

数量:「两三个精心挑选、覆盖边界情况的示例,通常胜过十个大同小异的示例。」

2.4.6 工具定义:一个重要的时效性更新(p57)

Claude Code 的工具描述包含四类内容:使用边界(NEVER invoke grep or rg as a Bash command)、具体示例(timezone: 'America/New_York')、性能提示(Batch your tool calls together)、工具间协作(Use the Read tool at least once before editing)。

但作者明确指出:“工具定义与系统提示词一起构成静态前缀”只是基础模式。 2026 年以来工具定义本身也在向 Skills 式渐进披露演进,而且已经是 API 层原生能力

  • OpenAI Responses API:tool_search + defer_loading: true,走 tool_search_call → tool_search_output
  • Anthropic:Tool Search(tool_reference blocks);Claude Code 对 MCP 工具默认延迟加载
  • Codex CLI:tool_search(BM25)不是可选特性,而是默认开启的架构

为什么追加到末尾不破坏缓存? 因果注意力决定每个 token 的 KV 只依赖它之前的 token,末尾追加不改变任何已缓存 token 的 K、V。这不是”预编译”,而是**“只增不改”的追加式注入**。

一个极易误解的点(作者专门澄清,p57):“追加到末尾”只发生在工具被发现的那一轮。此后 schema 块固定在轨迹原位置,成为普通历史消息,不是每轮被重新搬到最新末尾(真那样每轮都要重新 prefill,缓存就没意义了)。真正导致重算的只有两种:TTL 过期、修改/移除/重排已加载工具集。

约束:模型必须在训练中见过”工具定义出现在对话中间”这种模式 → 目前只有 GPT-5.4+、Claude 4.5 系列等较新模型支持。

实验 2-4:提示工程消融实验(基于 Tau-Bench,p57–58)

维度操作结果
语气与风格商务中立 / Trump 风格 / Casual 风格对任务完成率影响相对有限——模型风格适应能力强
信息组织保留全部规则内容,但打乱结构、去掉标题层次任务成功率下降 >30%,“先验证身份再处理退款”被拆散后 Agent 会跳过身份验证
工具描述保留签名和参数,移除描述性文本工具调用错误率 +45%

这印证了:对人类友好的信息组织方式,对模型同样友好。(p58)

作者自评:“消融实验的结论本身并不意外……更有价值的是方法论本身——当 Agent 表现不佳时,与其全面重写提示词,不如先做消融实验。这比凭感觉猜测要可靠得多。“

2.4.7 提示注入(p58–59)

本质:攻击者通过 Agent 处理的外部内容(网页、邮件、文档),将伪装成系统指令的文本混入上下文。

为什么比聊天机器人危险:聊天机器人最坏输出不当内容,Agent 拥有工具调用能力——可能删文件、发邮件、泄露数据,不可逆。攻击面随能力增长:每一个感知工具都是潜在注入入口(网页不可见元素、PDF 元数据、甚至图片 EXIF)。

上下文层三道防御

手段做法强度
来源标记<external_content source="webpage">...</external_content>
结构化角色严格用 system/user/assistant/tool 角色体系中——这也是”不要自行拼接消息”的又一个理由:把工具结果混入 user 消息,等于亲手抹掉了模型辨别来源的依据
输入清洗过滤”忽略之前的指令”等模式弱,容易被措辞变体绕过,只能作为辅助

作者特别警示:本章介绍的机制本身构成新的注入面。

  • Skills:「Skill 的本质是’把外部内容当作指令加载’的制度化形式」——第三方 Skill 以很高执行倾向进入上下文,比网页隐藏文本更直接。→ 安装来源不明的 Skill 前必须审查,如同审查将要执行的代码
  • 状态栏:状态栏信息被模型高度信任(这正是它有效的原因),一旦内容来自可被污染的数据源,这种信任就会被反向利用

清醒的结论(p59):

上下文层的防御……只是第一道防线,它只能降低攻击成功率,无法做到万无一失

执行层防御(权限控制、沙盒、独立审查)在第 4、5 章;检索投毒在第 3 章。


2.5 动态提示词与 Agent Skills(p59–63)

动机:提示词膨胀的两个代价(p60)

  1. 浪费 token:大部分内容与当前任务无关
  2. 注意力被稀释(后文以”上下文腐化”展开)

渐进式披露的三层结构(p60)

内容体积加载时机
SKILL.md 的 YAML frontmatter(name + description~300 tokens启动时全部注入
SKILL.md 正文(核心流程)~2K tokens模型判断需要时,通过专用 Skill 工具加载
子文档(html2pptx.mdreference.mdscripts/*.py不定按需选择性深入

比喻:「你不会把公司所有部门的操作手册都堆到新员工桌上,而是先给一份总目录,需要哪本再去取。」

description 的写法:本节最实操的一条(p60)

元数据中的 description 字段是路由决策的关键……写法要像路由条件而非功能介绍。 最直接的写法是”Use when / Don’t use when”加上几条反例反例不是可选项,而是 Skill 路由能否准确触发的关键。 描述太宽泛(如 “help with backend”)等于任何后端相关工作都能触发。 真正有效的描述是路由条件——“何时该用我”比”我能做什么”重要得多。

2.5.2 三种注入方式的三难(p61)——本节的技术核心

方式做法指令遵循KV Cache结论
追加进 system 消息最强(训练时大量使用该位置)每次加载新 Skill 都失效前缀✗ 频繁切换 Skill 时代价巨大
通用文件读取工具,内容落在上下文中间打折——模型可能只当成”参考”而非”指令”;Claude 因训练数据充足最可靠,其他模型差异很大完全不影响✗ 模型依赖强
元数据注入末尾 + 完整内容按需工具加载(Claude Code 生产实现)强——模型对”自己刚刚主动调用的工具的输出”有更强的执行倾向友好

方式三的两个巧思:

  1. 元数据以 user 角色的 meta 消息注入末尾,外层用 <system-reminder> 包裹。既不改 system(不破前缀),又在末尾(注意力最优)。采用增量发送:每个 skill 只在首次出现时发送,稳态下每轮元数据增量为零。
  2. 完整内容通过 Skill(skill: "pdf") 这样的专用工具加载,结果作为 tool result 落在轨迹中。

作者自己点出的一个诚实的局限(p61):

“末尾”的注意力优势只在注入的当轮成立——增量发送的元数据永久留在轨迹中,随着会话增长它会逐渐滞留到上下文中部,位置优势随之衰减。 这是**“只发一次、节省缓存”与”每轮置底、保住注意力”之间的权衡**,下一节状态栏讨论持久追加式更新时会再次遇到同一个取舍。

KV Cache 演化的实测(图 2-13,p62)

轮次内容本轮 cache_creation
Turn 1首次加载 PPTX skill≈ 2.5k tokens
Turn 2读取 PDF≈ 0.5k tokens
Turn 3写出 HTML≈ 0.4k tokens

必须厘清的误解(p63):

“对 KV Cache 友好”并非”零成本”——首次 emit 那几百到几千 token 终归要付一次写入代价(缓存写入还是加价计费的)。 它的准确含义是一次性写入、永久受益

对比方案(塞进 system prompt)每次更新会让其下游整条 trajectory 进入 cache_creation,量级是数万到数十万 token

一条容易被忽略的元原则(p61)

选择 Agent 交互模式时应对齐模型厂商的训练方法论。 基础模型公司推行的 Agent 用法,本质上是它们专门训练过的模式,这使得同一生态内的模型天然具有最优表现。


2.6 Agent 状态栏(p63–71)——本章最有原创性的一节

要解决的问题(p64)

系统提示词要求”拨打每个商家不超过 3 次”,但打了 3 次之后,Agent 经常数不清打了几次,又打了第 4 次,甚至陷入循环

根源:关于”已经打了几次”的知识没有被自动提炼出来,而是以原始通话记录的形式分散在 KV Cache 的向量表示中。模型每次决策都要花额外思考 token 去扫描重新统计——效率极低、错误率高,而且代价随上下文里堆积的内容量 N 一起涨

理论基础:那句核心论断(p64)

上下文学习更像检索而非推理——模型擅长从已有内容中查找信息,但不擅长主动归纳和总结。

作者做了一个重要限定,避免被误读:「这里说的是模型在单次前向传播中如何消费已经在上下文里的信息,并不否定模型可以通过生成思维链来完成多步思考。」

于是有了那个比喻:上下文窗口是一台只有一半的检索引擎——检索那一半极强(相当于把 RAG 内置进每次前向传播),但没有”提炼层”

两个作用机制

  1. 把隐式状态提炼为显式知识(p65):原始轨迹信息高度冗余,状态栏”以极低的额外 token 成本,呈现出原本需要扫描数千个 token 才能获得的信息”。
  2. 显式地操纵注意力分配(p65):结构化元信息放上下文末尾 → 空间上更接近即将生成的新 token → 获得更高注意力权重。作者称之为**“强制性的注意力引导”**。

大规模证据:上下文蒸馏基准(p65–66)

作者与合作者的专门基准(Distill, Don’t Retrieve):3 类任务(计数、规则归纳、状态跟踪)× 11 个模型(前沿 API 到笔记本可跑的 2B)× 近 2.4 万次评测

对象收益
弱模型准确率 +40 ~ +54 个百分点;一个 2B 本地小模型追平了不带状态栏的前沿大模型
强模型思考量 / 延迟 / 花费各降约一个数量级(思考 token 砍掉八九成以上)
最本质的变化不带状态栏时每次查询的思考量随上下文变长而持续增长;带上后基本恒定

一个格式细节:状态栏必须写成 衣物: 9 件(合格 7、次品 2) 这样能一眼定位的键值对,而不是散文——论文里散文版效果明显更差,因为模型还得先读一遍解析出来,等于又回到了”扫描”

三条可以直接照做的经验(p66)——本章最实用的一段

① 状态栏要用代码维护,别拿大模型去维护

一个自然念头是”叫一个 LLM 去读历史帮我总结状态栏”——结果恰恰相反

  • 一个 20 行的正则函数就能达到”标准答案”级准确度
  • 前沿大模型一次性读完整段历史吐出统计,反而在大多数格子上出错,把下游准确率拖得比”根本不用状态栏”还低

原因:“让 LLM 批量统计长历史,等于把’扫描整段上下文’这个原始难题原封不动搬了个家。”

替代方案:能用代码算就用代码算;实在要用 LLM,也要逐条抽取、再由代码汇总,绝不要让它一次性批量统计。

② 想删原始上下文之前,先确认状态栏覆盖了所有会被问到的维度

状态栏是对原始上下文的有损投影。极端测试:状态栏只存”两两组合”计数,却去问”三者交叉”——连 Claude 都从 100% 掉到 7.6%

一条看着很像样、实则答非所问的状态栏,会变成一个理直气壮把模型带偏的”假权威”

实践建议:把”新增一种问法”当成一次数据库改表结构来对待——要么先给状态栏加字段,要么这次就别删原文。

另有一类任务(如大段散文里的多跳推理)本就没有干净的结构化摘要,别指望状态栏提高准确率,它顶多帮你省点 token

③ 把状态栏的准确率当成一线生产指标

模型几乎无条件地相信状态栏——你写”打了 3 次”,它就当真是 3 次,既不会偷偷去核对,也不会自己重算

容错空间:数错 10% 以内收益还能保住大半,越过这条线,带着错状态栏可能比不带还糟。

深水区:状态栏为什么”根子上”有效(p66–67)

这是本章我认为思想密度最高的一段。作者提出:让模型变强通常有两条路——想得更久(更长 CoT)和试得更多(多采样挑最好)。但两条路有共同天花板:

它们都只在模型”自己的脑子里”打转,用的都是同一套固定权重和同一段固定上下文,因此变不出上下文里原本没有的新信息,只能把已有信息重新排列组合。

真正突破天花板的是第三条路:交互Interaction Scaling,arXiv

.11598)——让外部”仪器”去观察模型的产出在真实世界里的表现,再写回上下文。

关键在于,这个观察是模型光靠想想不出来的:代码到底有没有通过测试、网页渲染出来那个按钮有没有跑出屏幕、这一步操作后系统状态变成了什么样。

所以状态栏最有价值的,往往不是模型本可以自己数出来的东西(那只是替它省力气),而是它根本无从推断的外部事实。

状态栏把”闭卷考试”变成了”随时能查一眼真实世界”。

配套的一条附带发现,很尖锐:

衡量改进的”尺子”本身也必须扎根于真实观测:若用一个只瞄一眼截图的视觉模型来打分,它连自己刚修好的缺陷都测不出来,整个循环就会悄无声息地空转

这与业界”循环的瓶颈在验证器,而不在模型”是同一件事。

2.6.2 状态栏的四类内容(p67)

类型内容变化频率缓存友好性
任务规划TODO 列表动态需追加更新
事件侧信道信息精确时间、地理位置、距上次回复的间隔一经添加不再变友好
环境当前状态系统时间、工作目录、“该工具已被重复调用 N 次”动态需追加更新
可用能力清单已安装 Skill 元数据最低(仅安装/卸载时)友好

2.6.3 位置:一个重要的协议层澄清(p68)

状态栏在 API 层面是一条 user 角色的消息插入到上下文末尾,而不是修改 system。

这里的 user 角色只是 API 协议层面的技术选择,并不等同于第一章定义的”来自终端用户的输入”。Harness 是在借用 user 角色这个消息槽位,向模型注入由 Agent 框架自动生成的系统状态信息。

<agent_status> 标签包裹以便模型识别其特殊性质。

2.6.4 更新方式的两种实现(p69)

实现一:每轮替换实现二:持久追加
做法移除上一轮状态消息,末尾追加最新一旦注入永久留在轨迹,每轮末尾追加新的
优点上下文只有一份状态,永远最新、无歧义对缓存完全友好(只追加不修改)
代价移除旧状态使其后所有缓存失效(与”动态时间戳”是同一失效机制,只是范围限于最近几轮)陈旧状态累积:占 token,且要求模型自己关注”最新一条”
生产实例Claude Code 的 <system-reminder>

经验法则:状态更新频繁 + 轨迹很长 → 实现二;轨迹较短 or 单条状态消息很大(完整 TODO + 环境快照)→ 实现一

实验 2-8:五种状态栏技术(p69–70)

技术做法实测效果
时间戳跟踪[2025-09-14 10:30:45] 前缀加到 user 消息和 tool 响应(注意:不是加在系统提示词里,否则破坏 KV Cache理解时序关系,支持调试审计
工具调用计数器全局字典 + Tool call #3 for 'read_file'触发模式识别:一次失败查路径、两次列目录、三次主动放弃找替代。深层价值是隐式成本感知
TODO 列表管理借鉴 Manus”通过复述操纵注意力”;rewrite_todo_list / update_todo_status启用 15 次迭代完成;禁用需 21 次且常遗漏子任务
详细错误信息四层:错误类型描述 + 完整参数 JSON + 调用栈 + 针对性修复建议找到替代方案成功率 60% → 95%,从盲目重试转为分析性问题解决
系统状态感知时间、工作目录(执行 cd 后自动更新)、OS 类型、Shell、Python 版本支持平台相关决策(Linux 用 apt、macOS 用 brew)

涌现效应:单独用效果有限,组合起来超出预期。时间戳 + 计数器 → 理解操作频率与时间分布;TODO + 系统状态 → 按环境调整策略;错误信息 + 计数器 → 多次失败后不仅改变策略,还能理解失败原因

2.6.5 从读数到策略:时间感(p70–71)——本节最反直觉的发现

作者提出 Agent 缺失的一项能力:时间感(time sense),拆成三轴:

名称含义失败模式
预算轴紧迫度 urgency把投入的力气匹配到时钟上。双向的——低紧迫度不等于”少干点”,而是”别急着停,接着做”三分钟和三十分钟交出的东西没区别
终点轴坚持度 persistence分清真墙和假墙,也知道活儿干完了没有对着已 410 Gone 的接口重试五次;或搜了两次就断言”查无此信息”
监控轴警觉度 vigilance把时间异常升级成值得追查的假设本该 500ms 却跑了 5 秒;1 毫秒就”成功”返回但 body 为空

关键实验(4 种条件对照):

条件通过率
什么都不给一成出头
只给原始时间戳与什么都不给几乎没区别(差 2–3 个百分点)
时间戳 + “这些读数该怎么用”的操作手册+19 ~ +49 个百分点,拉到四五成

光把读数摆到模型面前,并不足以改变它的行为。……它缺的不是读数,而是拿这个读数该怎么办的策略。

这补上了前面留的缺口:工具计数器之所以只靠”第 3 次(3/3)“一行读数就能纠偏,是因为决策规则太显然——“到顶了就停”;而”力气该花多少""这堵墙要不要绕”这类判断规则并不显然。

一条真正管用的”节奏状态栏”,必须把读数(用了多久、这工具慢不慢、这墙撞了几次)和一小段操作策略(时间紧就交付、慢调用要诊断、真墙就绕开)成对地给出去,缺一不可

四个厂商家族六个模型(Claude / Gemini / GPT / Qwen)不加手册时通过率无一例外趴在一成出头的地板上——说明这是当前后训练普遍漏掉的一项控制,而不是某个模型不够聪明

(伏笔:第 7 章会看到一个对照——同样教这套节奏感,稀疏的结果奖励怎么都学不会,换成逐 token 的稠密信号才终于学会。)

2.6.6 设计哲学(p71)

  • 所有元信息人类可读,开发者随时可检查 Agent 拿到了什么、做了什么决定
  • 对模型无侵入性——不需要微调,任何模型上都能起效,可以一项项叠加尝试

2.7 上下文压缩策略(p71–76)

两个截然不同的动机(p71)

  1. 长度约束和成本约束——最直观:窗口有限、工具结果动辄数万字符、token 越多成本越高延迟越大
  2. 提升思考质量——「总结后的知识比原始形式更利于模型使用」。即使窗口足够大,把所有原始信息堆在上下文里也不是最优选择。

第二个动机是本节的灵魂:状态栏是把算好的结论加进上下文,压缩是把臃肿的原始记录换成算好的结论——「两者是同一枚硬币的两面,都在给那台’只有一半’的检索引擎补上缺失的’提炼’」(p72)。区别只在于:状态栏往往由代码每一步确定性维护,压缩则更多是用一次 LLM 调用把大段原文蒸馏掉。

100 只猫的例子(p72)

上下文里有 100 个笼子的巡查记录(90 黑猫、10 白猫),问”各有多少只”:

条件结果
不启用思维链很难直接给出正确答案——注意力擅长查找(“笼子 37 里是什么猫”),不擅长统计归纳
启用思维链能数对,但每次被问都要重新从头数一遍,产生大量思考 token
提前写入”当前统计:黑猫 90 只,白猫 10 只”立即检索到结论,无需重新思考

这就是压缩的第二个价值:把需要思考才能得到的结论变成可以直接检索的知识。

上下文腐化 Context Rot(p72)

溢出是”装不下了”,腐化是”装得下但找不到了”——后者更隐蔽,因为 Agent 表面上还在正常工作,只是决策质量悄然下降。

实践中最常见的失效模式不是窗口不够长,而是信息密度不对——偶尔才用到的知识每次都加载、稳定的规则和动态的状态混在一起。

Karpathy 的洞察(p72):模型的”记忆差”在某种程度上是特性而非缺陷——窗口有限性迫使模型从大量细节中抽象出一般性模式。

另一条理论支撑(p72):上下文学习更像快速适配机制而非真正的学习——「不是真的改变了模型参数,但效果类似于做了一次小小的专项训练」。这解释了 few-shot 为什么有效,也解释了为什么这种改善不会跨会话累积

2.7.3 压缩与 KV Cache:看似矛盾,实则互补(p73)

关键在于压缩发生的时机和位置——不是在单次 API 调用过程中改上下文,而是在两次调用之间由 Agent 框架预处理

  1. System Prompt 和 Tool Definitions 永远不动
  2. 压缩对象是对话历史中的 tool results——替换位置之后的缓存失效,之前的仍有效
  3. 这是一个有意识的权衡:不压缩就溢出、任务直接失败;压缩虽损失部分缓存,但长度可控、密度更高

推论:「压缩的频次需要权衡——频繁压缩会频繁破坏缓存,最好在上下文接近阈值时批量压缩,而不是每轮都压。」

实验 2-9:六种压缩策略(p73–74)

任务:追踪 OpenAI 联合创始人的职业状态。模型:Kimi K3,刻意把上下文预算限制在 128K 以触发压缩

策略机制结果
① 无压缩全量保留7 次工具调用累计约 367,000 字符(平均约 52,000/次),第 5 次迭代溢出,任务失败
② 个体摘要每个结果独立生成 2–3 段摘要成功,但信息碎片化——多页面重复描述同一事件
③ 组合摘要所有结果合并后生成综合摘要成功,但输入超长时必须截断,可能丢末尾信息
上下文感知压缩当前查询意图 + 已积累信息纳入压缩决策(Given the search query: {query} / Current context: {context}最优。一次压缩把 147,877 字符压到 1,963 字符(约 1.3%)仍保留关键信息
⑤ 感知 + 引用每条事实附带来源 URL有损压缩 + 无损索引的结合,可回溯
⑥ 自适应窗口超过窗口 80%(128K 即 102,400 token,实测约 135,600 触发)才批量压缩全部未标记工具结果,[COMPRESSED] 防重复总 token 大,但前几次迭代保持完整原始信息,初期信息收集灵活性最大

策略④成功的洞察(值得单独记):

多步骤任务中,不同阶段需要的信息密度和类型是不同的——初期需要广泛的信息收集,中期需要精确的事实核验,后期需要综合的信息整合。

注意 · 原文数据不一致:图 2-16/2-17 与正文的数字对不上。例如”上下文感知”图中为 25,198 token / 0.9% / 15 次迭代,正文写 40,157 token / 约 3.0% / 7 次迭代;“个体摘要”图中 123,205 / 6.8% / 24 次,正文 276,608 / 10.9% / 12 次。图注称 token 减少 77%,章末小结称 75% 以上(p76)。引用这组数字前建议以配套仓库实测为准。

2.7.4 生产级五层压缩(以 Claude Code 为参照,p74–75)

不同类型的信息有不同的保质期,压缩策略应当与信息的预期生命周期匹配。

机制特点
1工具结果预算控制大输出存磁盘,模型只看摘要预览;替换决策一旦做出就被冻结以保证缓存一致
2噪声直接删除低价值内容直接移除、不做摘要——对噪声做摘要只是在浪费 token
3API 层微压缩服务端从前缀移除指定工具结果,本地消息不变。零本地实现成本,但移除点之后缓存同样失效 → 适合在反正要付重建代价时用,不宜频繁触发
4归档式摘要逐轮结构化摘要——git log 那样保留每轮独立记录,而非像 git squash 合并成一条
5全量压缩LLM 驱动,最后手段。分两阶段(先压会话记忆,不行再全量),配连续失败熔断器——生产数据表明大量会话会困在反复压缩失败的循环中烧钱

排列顺序有意义:前三层实现成本最低、缓存扰动可控,优先使用;后两层成本高但效果强,作兜底。

2.7.5 四条设计原则(p75)

  1. 信息价值非均匀分布:关键决策点(人员名单)> 支撑性证据(新闻细节)> 冗余噪声(导航栏、页脚广告)
  2. 语义完整性:「Sutskever 于 2024 年 5 月离开 OpenAI」不能压成「Sutskever 离开」——时间和公司名不可丢
  3. 任务相关性:同样内容在”查找创始人名单”和”了解个人背景”下应产生不同压缩结果
  4. 压缩即理解:需要深层语义理解;且显式压缩的结果是可审查的、可跨会话复用的

保留优先级清单(p75–76)——建议直接抄进你的系统

压缩最容易丢失的不是细节本身,而是早期的架构决策、约束背后的理由和失败的路径——LLM 通常会优先删除那些看起来还可以重新获取的信息。

  1. 架构决策和关键约束:不得摘要
  2. 已修改的文件列表和关键变更记录:完整保留
  3. 验证状态(pass/fail):必须保留
  4. 未解决的 TODO 和回滚笔记:必须保留
  5. 工具输出:可以删除,仅保留 pass/fail 结论

另:UUID、hash、IP、端口、URL、文件名等标识符必须原样保留——「一旦把 PR 编号或 commit hash 改错一位,后续的工具调用就会直接失效」。

2.7.7 隔离优于压缩(p76)——本章的收束

压缩是在信息已经进入上下文之后做减法,而一个更釜底抽薪的思路是:让大体积的中间信息根本不进入主上下文

对比同一任务”在代码库中找到处理支付回调的函数”:

做法主上下文增量
主 Agent 亲自搜索十几个文件、数万 token 原始代码进入主上下文,绝大部分在找到目标后就沦为永久占据窗口的噪声
委派搜索子 Agent只增加两条消息:一条任务描述,一条结论(“函数位于 src/payment/callbacks.pyhandle_callback,另有两处调用点”)

这本质上是用隔离代替压缩:压缩是有损的、需要额外 LLM 调用的事后补救;隔离则让噪声从一开始就与主上下文绝缘,主 Agent 的 KV Cache 前缀也完全不受影响。

代价(作者诚实地指出):子 Agent 看不到主 Agent 的完整上下文,任务描述必须自包含、目标明确——「这又回到了本章的主题:上下文的质量决定能力上限,对子 Agent 同样成立。」

生产实例:Claude Code 的 Task 工具、各类 Deep Research 系统的检索子 Agent。


四、贯穿全章的三条暗线

读完之后回头看,会发现七节之间有三条反复出现的线索。

暗线 A:模型只会检索,不会归纳 → 所有”提炼”都要外置

出现位置表现
2.6.1状态栏的全部理论基础:「上下文窗口是一台只有一半的检索引擎」
2.7.2压缩的第二动机:「把需要思考才能得到的结论变成可以直接检索的知识」
2.4.5few-shot 有效的原因(上下文学习”像被临时定制过”),也解释了它不跨会话累积
2.8章末纲领:「不要让模型被动地在海量信息中检索,而要主动为模型提供经过提炼的结构化知识」

推论:状态栏(加法)和压缩(减法)不是两件事,是同一件事的两面

暗线 B:稳定前缀是前置约束,它反复制造同一个两难

同一个取舍在本章至少出现四次,作者自己在 p61 明确点名过一次:

位置两难的两端
2.4.5 few-shot动态检索最相关示例(效果好)vs 固定示例集(缓存稳)
2.5.2 Skills 注入”只发一次、节省缓存” vs “每轮置底、保住注意力”
2.6.4 状态更新每轮替换(无歧义)vs 持久追加(缓存友好)
2.7.3 压缩时机频繁压缩(长度可控)vs 批量压缩(少破缓存)

推论:这不是四个独立的工程选择题,是同一个约束在四个位置的投影。理解了 2.3.4 “缓存作为架构前置约束”,四道题的答案都能自己推出来。

暗线 C:一切进入上下文的外部文本,都是不可信输入

位置注入面
2.4.7网页、邮件、PDF 元数据、图片 EXIF
2.4.7Skills 本身——“把外部内容当作指令加载”的制度化形式,比网页隐藏文本更直接
2.4.7 / 2.6.1状态栏本身——正因为模型高度信任它,污染它的收益才最大

推论:本章介绍的每一个”提升能力”的机制,同时也是一个”扩大攻击面”的机制。作者反复强调上下文层防御只是第一道防线


五、工程规则速查表

可以直接当 checklist 用。

KV Cache

  • 系统提示词和工具定义定下就不改,一个空格都不改(p47)
  • 动态信息(时间戳、用户状态)永远追加到末尾,不改前缀(p47)
  • 用标准 API 格式,不自行拼接 USER:/ASSISTANT:(p47)
  • 不要动态排序工具定义——固定顺序对选择能力几乎无影响,对性能提升显著(p52)
  • 不要用滑动窗口裁历史——破坏前缀 + 丢关键工具结果 + Agent 陷入循环(p52)
  • 不要把工具结果伪装成 user 消息(毁思维链 + 抹掉来源辨别依据)(p50 / p58)
  • 把运行时二值条件全部归到缓存边界之后(N 个条件 = 2^N 种缓存键)(p53)
  • 子 Agent / 旁路调用的前缀与父 Agent 字节级对齐(p53)

提示工程

  • 检验标准:聪明的新员工读完还不知道怎么做,Agent 也不知道(p54)
  • 流程驱动(SOP)优于规则堆砌(p55)
  • 业务规则细化到可执行——由产品经理设计,工程师只负责准确编码,不擅自决定业务逻辑(p56)
  • NEVER 全大写保留给真正关键的约束,过度使用会稀释(p55)
  • few-shot:2–3 个覆盖边界情况 > 10 个大同小异;一旦确定字节级稳定,不要逐请求动态检索(p56)

Skills

  • description 写成路由条件(Use when / Don’t use when + 反例),不是功能介绍(p60)
  • 元数据注入末尾 + 完整内容按需工具加载(方式三)(p61)
  • 元数据增量发送:每个 skill 只在首次出现时发(p61)
  • 来源不明的 Skill 必须先审查,如同审查将要执行的代码(p58)
  • 交互模式对齐模型厂商的训练方法论(p61)

状态栏

  • 用代码维护,别拿 LLM 批量统计长历史(20 行正则 > 前沿大模型)(p66)
  • 写成键值对 衣物: 9 件(合格 7、次品 2)不要写成散文(p66)
  • 删原文前先确认状态栏覆盖了所有会被问到的维度;新增问法当成一次改表结构(p66)
  • 把状态栏准确率当一线生产指标盯(容错约 10%)(p66)
  • 信息越是来自对外部世界的真实观测,价值越高;绝不能来自可被污染的数据源(p67)
  • 读数 + 操作策略成对给出,光给读数模型不会改变行为(p70)
  • 更新方式:长轨迹高频更新 → 持久追加;短轨迹或大状态块 → 每轮替换(p69)

压缩

  • 接近阈值时批量压缩,不要每轮都压(p73)
  • 压缩决策纳入当前查询意图 + 已积累信息(上下文感知压缩效果最好)(p74)
  • 对噪声直接删除,不做摘要(p75)
  • 全量压缩配连续失败熔断器(p75)
  • 保留优先级:架构决策/关键约束不得摘要;验证状态、未解决 TODO 必须保留;UUID/hash/URL/文件名原样保留(p75–76)
  • 大体积中间信息优先考虑子 Agent 隔离而非事后压缩(p76)

六、批判性分析:这一章的强项、张力与可追问处

强项

  1. 理论—证据—工程三层闭合。 每个机制都给了”为什么有效”(注意力/缓存原理)、“多有效”(自建基准的量化数字)、“怎么做”(可照抄的规则)。这在 Agent 类书籍里不常见——多数只有第三层。
  2. 作者诚实地标注了自己论断的边界。 例如状态栏”只对有干净结构化摘要的任务有效,对大段散文多跳推理别指望”;KV Cache 可编辑”仍属研究阶段,三条铁律依然是默认原则”;“追加到末尾”的注意力优势”只在注入的当轮成立”。这种自我设限提高了可信度。
  3. 2.3.4 是全章的思想制高点。 “缓存经济性是前置约束而非事后优化”这个判断,把一个性能话题提升成了架构话题,并给出了三个具体的传导路径(提示词排序、子 Agent 对齐、替换串冻结)。

值得注意的张力

① “上下文学习是检索而非推理”这个论断,作者自己的限定和它的使用范围之间有轻微张力。

作者严谨地限定为”单次前向传播内消费已有上下文”,并明确”不否定模型可以通过生成 CoT 完成多步思考”。但整章从这个论断推出的工程结论(状态栏、压缩、蒸馏),实际隐含的是一个更强的版本:用 CoT 现算的代价高到不可接受。这个更强版本在计数、状态跟踪类任务上有 2.4 万次评测支撑,但推广到”所有归纳类任务”时证据就弱了。作者在思考题第 6 题(★★★)里其实自己抛出了这个问题。

② 状态栏与提示注入之间有一个未完全解决的循环。

状态栏之所以有效,是因为模型几乎无条件相信它(p66);而这恰恰是它作为攻击面最危险的地方(p58)。作者给的缓解是”信息要来自可靠的真实观测”——但在一个 Agent 要处理网页、邮件、第三方 API 的系统里,“可靠观测”和”外部输入”的边界往往并不清晰(比如状态栏里的”用户当前订单状态”来自一个第三方 API)。这一层防御的具体工程方案,本章没有给出,被推给了第 4、5 章的执行层防御。

③ 状态栏的”有损投影”问题,在生产中比作者呈现的更棘手。

“新增一种问法当成一次改表结构”这条建议在原理上正确,但它假设你能预先枚举会被问到的维度。在开放域 Agent 里这恰恰是最难的部分。“连 Claude 都从 100% 掉到 7.6%“这个数字应该被当成警告而非注脚——它意味着状态栏 + 删原文这个组合,在维度覆盖不全时是一个悬崖式失效,而不是平滑退化。保守做法应该是:除非任务维度封闭(计数、状态机跟踪),否则保留原文

④ 实验数据的图文不一致(p73–76)削弱了压缩一节的说服力。

这是全章唯一明显的编辑问题。六种策略的核心排序(上下文感知最优)在两版数据下都成立,所以结论不受影响,但具体数字不宜直接引用。

我认为最被低估的两段

  • 2.4.6 结尾关于”工具定义也在渐进式披露化”的更新(p57)。这段实际上宣告了”工具定义必须在上下文最前面”这条经典铁律的松动,且已是 API 原生能力(不是框架补丁)。很多人对 Agent 上下文布局的心智模型还停留在松动之前。
  • 2.6.5 的”读数 ≠ 策略”发现(p70)。“只给原始时间戳与什么都不给几乎没区别(差 2–3 个百分点)“这个结果,对所有做可观测性注入的人都是一记警钟:你往上下文里塞的指标,如果没有配套的”该怎么用”的说明,很可能完全没起作用而你还以为起了。

七、关键数据索引

数据数值出处
上下文窗口Qwen3 32K / Claude 200K / Gemini 2Mp35
客服 Agent 事故TTFT 0.5s → 3–5s,月账单近翻倍p46
Attention Sink首 token 有时吸收 >70% 注意力p49
0.6B 模型速度M2 上 >100 token/sp45
Prompt Cache 读取成本Anthropic/DeepSeek 约 1/10,OpenAI 约五折;写入约 1.25× 加价;最小 1024 token;TTL 约 5 分钟p52
缓存键组合爆炸3 个二值条件 = 8 种缓存键p53
KV Cache 可编辑约 1% 算力;p90 TTFT 降几十至几百倍;命中率约 98.5%;12 模型 logit 余弦 0.90–0.999p53–54
消融:信息组织打乱成功率下降 >30%p58
消融:移除工具描述错误率 +45%p58
Skills 体积元数据 ~300 tokens;SKILL.md ~2K tokensp59–60
Skills 缓存演化Turn1 ≈2.5k → Turn2 ≈0.5k → Turn3 ≈0.4k cache_creationp62
上下文蒸馏基准3 类任务 × 11 模型 × 近 2.4 万次评测p66
状态栏:弱模型准确率 +40 ~ +54 个百分点p66
状态栏:强模型思考量/延迟/花费各降约一个数量级p66
状态栏覆盖不全Claude 从 100% → 7.6%p66
状态栏容错数错 10% 以内收益还能保住大半p66
TODO 列表启用 15 次迭代 vs 禁用 21 次p69
详细错误信息替代方案成功率 60% → 95%p70
时间感:只给读数与什么都不给差 2–3 个百分点p70
时间感:加操作手册+19 ~ +49 个百分点p70
压缩实验:无压缩7 次调用约 367,000 字符,第 5 次迭代溢出失败p73
压缩实验:单次压缩比147,877 → 1,963 字符(约 1.3%)p74
自适应窗口阈值窗口 80%(128K → 102,400 token),实测约 135,600 触发p74

八、实验与思考题清单

9 个配套实验(代码仓库:https://github.com/bojieli/ai-agent-book

编号难度名称项目目录
2-1本地 LLM 服务部署与工具调用local_llm_serving
2-2注意力机制可视化attention_visualization
2-3★★常见的错误上下文管理模式kv-cache
2-4★★提示工程的消融实验prompt-engineering(基于 Tau-Bench)
2-5★★提示注入攻防实验
2-6★★用 Agent Skills 从论文生成 PPT
2-7★★注意力可视化验证状态栏效果attention_visualization
2-8★★五种 Agent 状态栏技术agent-status-bar
2-9★★★六种压缩策略对比

9 道思考题,其中最值得动手想的三道(★★★):

  1. 第 1 题:设计一种既避免信息丢失、又控制长度、且不破坏 KV Cache 前缀的策略。(提示:本章其实给了答案的两半——2.7.4 的分层压缩 + 2.7.7 的子 Agent 隔离)
  2. 第 6 题:若”上下文学习本质是检索而非推理”成立,当前所有基于”把更多信息塞进上下文”的优化方向都需要重新审视。怎么突破?
  3. 第 7 题:Skills 渐进式披露依赖模型判断”我需要哪个 Skill”——如果模型不知道自己不知道什么,就无法正确触发加载。这个”元认知”问题怎么解?

九、这一章通向哪里

本章埋的伏笔在哪展开
工具定义的设计原则第 4 章
子 Agent 作为协作工具的完整设计第 4 章
执行层防御(权限、沙盒、独立审查)第 4、5 章
检索内容的注入风险(知识库投毒)第 3 章
”仅需七个核心工具”的 Skill + 通用执行器模式第 5 章
时间感蒸馏进权重(稀疏 vs 稠密奖励的对照)第 7 章
Claude Code 的周期性离线记忆整合第 8 章
让 Agent 自己设计知识结构第 8 章
Loop 工程与多 Agent 上下文架构第 10 章

下一章(第 3 章)把上下文管理从窗口内延伸到跨会话持久化:用户记忆与知识库。


版权说明

本文为读书笔记,其中标注页码的引文逐字摘自李博杰《深入理解 AI Agent:设计原理与工程实践》第 2 章,版权归原作者所有。原书选择开源发布,配套代码见 github.com/bojieli/ai-agent-book

本文的结构梳理、暗线归纳、速查表与第六节的批判性分析为笔记作者整理,如与原书原意有出入,以原书为准。推荐直接读原书——本文再详细也只是索引。