从0打造编码Agent 导读 4 课 + 2 条岔路 + 1 节实验课 ≈ 3 小时
A5 上下文:对话太长装不下怎么办? 章导读

上下文:对话太长装不下怎么办?

循环每转一轮,整段历史就要重发一次。这一章先把一轮请求拆开看清楚,再被真数字一步步逼着走:截掉最早的会丢掉读过的文件,裁工具输出会裁掉唯一关键的那一行,让模型写摘要会编出不存在的东西。最后落到现代做法:什么时候触发靠预留和真实 usage,压缩本身是给接手者写交接文档。全部数字来自本课项目的真实运行重放,四家的触发规则从 pin 源码移植进浏览器现算。
本章一问:对话太长装不下怎么办?

主线定位

🧭

上游(A1 循环、A2 岔路 B1):模型 API 不记得上一轮,harness 每一轮都把 system prompt、工具定义和到目前为止的全部消息整份重发;工具的结果回填进消息列表,下一轮一起发出去。
本章(A5 上下文):这份越滚越大的请求迟早撞上窗口。满之前怎么知道快满了、满了先丢什么、丢之前怎么把要紧的东西留下来。
下游(A6 记忆与会话):一个会话压完了还能接着干;可明天开一个新会话,它还记得这个项目的规矩吗?

下面是累计数据流,本章点亮「上下文管理」。它在每一轮循环里都要经过:发请求之前先看一眼,这一轮装不装得下。

累计数据流 · 一次任务在 harness 里经过哪些环节 已学本课新增还没学
每一轮循环都经过

本章问题链

每一课只回答一个问题;上一课的失败,逼出下一课的问题。

课这一课的问题朴素方案在哪个真数字上失败一句话
第 1 课上下文为什么会满?每一轮到底发了多少?原样重发:pd-v2-cap20-s1 从 947 涨到 2,618 token,只增不减;第 1 轮里工具定义就占 72%上下文从第一轮起就不只是对话:工具定义先占了大半,之后涨的主要是工具结果
岔路上下文越长,模型真的越差吗?先猜再看 NoLiMa:13 个模型里 11 个到 32K 时跌到自己短输入成绩的一半以下窗口是上限,不是有效长度;能少放就少放
第 2 课直接截掉最早的消息,行不行?按真实预算 1,800 从头删,删掉的头两条正是 system prompt 和任务说明;整轮截断丢了读文件那一轮,模型凭记忆改出 + 1 + 1先裁不要钱的,再花钱摘要;永远别把 tool 调用和它的结果拆开
第 3 课什么时候触发压缩?按百分比、按余量,还是按估算?CoreCoder v0.4.0 把一段 118 token 的中文估成 60;它的计数里连 system 和工具定义都没有估算只求不致命,安全边际来自预留;真实数字以 API 回报为准
岔路「Pi 少送 3 倍上下文」该怎么读?正文说「每轮」,图表量的是「每任务累计」;我们自己的运行里这两个口径方向相反先问数字的口径:每轮还是每任务、谁测的、能不能复现
第 4 课压缩成摘要、整个重置,还是写交接文档?17 份真实摘要里写下确切报错的 0 份,编出「timezone」的 16 份;第 10 轮模型把改对的一处改了回去压缩是写交接文档,不是写对话概要
实验课八条真实运行 × 四家触发规则 × 几种压缩策略—用自己的数据定阈值

演进地图

本章的「现代做法」是被一连串真实数字逼出来的。每一课都会用这张图标出「你在这里」。

上下文管理的演进:每一代都被上一代的某个真数字逼出来
  1. A1 的循环(所有 harness 的底层事实:模型 API 不记得上一轮)
    解决了实现最简单,模型每轮都看得到全部经过。
    卡在pd-v2-cap20-s1 从第 1 轮的 947 token 涨到第 11 轮的 2,618;第 1 轮里工具定义就占 72%,到最后一轮工具结果占 44%。只增不减,总有撞墙的一轮。
  2. 本课项目 miniagent 的 truncate(整轮丢,保留 system 与任务)、learn-claude-code s08 的 snip_compact(中段存档)
    解决了零成本,还能保证 tool 调用与结果不被拆散(按整轮丢)。
    卡在pd-v2-truncate-s1 截断 2 次共丢 3 轮,读文件那一轮也在其中;第 7 轮模型凭记忆改,那一行变成 + 1 + 1,验收测试退出码 1。
  3. CoreCoder Layer 1、learn-claude-code micro_compact、OpenCode prune(默认关)、Anthropic tool result clearing
    解决了工具结果是最占地方、也最可再生的一块;裁它不用调模型。
    卡在按位置裁,不懂内容:分层运行里被裁过的 0 份测试输出,0 份丢了唯一关键的 AssertionError 行。另一头,本任务最长的工具输出 1,302 字符,CoreCoder 的 1,500 字符门槛一次都没碰到。
  4. CoreCoder 50 / 70 / 90%、Pi 窗口 − 16,384、OpenCode 窗口 − min(20,000, 最大输出)、Codex 90%
    解决了阈值定在撞墙之前,给压缩本身和下一次回复留出余地。
    卡在本地估算在中文上偏低:一段真实中文 118 token(录制模型的 tokenizer),CoreCoder v0.4.0 估成 60,按「字符数 ÷ 4」估成 45。只靠本地估算触发,就会晚。
  5. CoreCoder Layer 2、本课项目 miniagent L2
    解决了比截断保留更多:旧轮次不是消失,而是被压成一段话。
    卡在pd-v2-layered-s1 的 17 份摘要里,写下确切报错的 0 份,编出不存在的「timezone」的 16 份;第 10 轮模型把改对的一处改了回去。21 轮、73,168 token(摘要另花 11,832)才完成,是同组不压缩成功运行最少的 4.3 倍。
  6. Codex(交接摘要 + 保留用户原话)、Pi(结构化模板 + 文件清单)、OpenCode(五节模板)
    解决了把「必须留下什么」写进模板:目标、约束、进度、确切报错、下一步、相关文件;完整历史留在磁盘上。
    卡在仍然有损。Codex 每次压缩后提醒用户:「Heads up: Long threads and multiple compactions can cause the model to be less accurate. Start a new thread when possible to keep threads small and targeted.」→ 下一章:会话存在哪、明天还记得吗。
旁支 context reset:清空上下文,换一个新 agent 接手 作者已弃用
Anthropic《Harness design for long-running application development》(2026-03-24)
为治「context anxiety」(模型以为快满了就草草收尾)而设;同一篇文章写明:换到 Opus 4.5 后这种行为基本消失,作者把 reset 整个拿掉了。

数字口径:本课项目 miniagent 用 Qwen/Qwen3-8B-MLX-4bit 本机录制的真实运行(2026-09-26),每轮发出的消息由重放得到并与录制的压缩事件、服务端 usage 逐轮核对一致;估算器的输出由 CoreCoder、Pi 的原实现在 pin 源码上跑出(a05-context.json,2026-09-26)。耗时不作比较(本机有其他任务同时占用)。

贯穿任务:修好 test_parse_date

全课的贯穿任务是项目 04-实践项目/tasks/parse_date:让失败的 test_parse_date 通过,测试文件不许改。这一章给它的 trace 加上上下文轨:每一轮真正发给模型的是哪几条消息、各占多少 token,压缩在哪一轮发生、压完留下了什么。

三层交互

层本章里的组件在哪一课
概念动画演进地图(每一代卡在哪个真数字上);四份压缩提示词的要求对照每一课、第 4 课
算法模拟器(真算法、小数据)同一段 12 条真实历史交给六种删法 / 裁法,拖预算看留下什么、请求还合不合法;六个 token 估算器在 10 段真实文本上的误差;四家触发规则在同一条曲线上的触发轮次第 2、3 课
真实数据六条真实运行的逐轮上下文回放(分块 token 与服务端逐轮一致);分层运行 21 轮里每份摘要还剩什么、摘要模型当时看得到什么;长任务 T3 / T3b(预算 8,000)的逐轮回放与四家触发规则;学习者把自己的 Claude Code 会话拖进来,只在浏览器里解析;NoLiMa 公开数据的先猜后揭示第 1、4 课、实验课、岔路 B1

所有算法都在浏览器里现算,不联网。移植的部分都配了自检:CoreCoder 与本课项目用 Python 加载原函数跑出期望值,Pi 与 OpenCode 用 bun 在 pin 源码的切片上跑,Codex 用 rustc 编译 pin 源码的切片;组件右上角显示与原实现一致的条数。

项目推进:里程碑 M5 · 机械裁剪 + 触发阈值

对应 04-实践项目/MILESTONES.md 的「A5 · 上下文工程与压缩」。实现已经在 miniagent/context.py:截断(整轮丢,保留 system 与任务)与分层(L1 裁旧工具输出 → L2 模型摘要 → L3 截断,阈值为预算的 50 / 70 / 90%)。代码 AI 来写,决策你来做。

🧭
你要拍板的决策
  1. 阈值定多少,用百分比、余量还是二者结合?必须引用真实 trace 论证。本项目照搬了 CoreCoder 的 50 / 70 / 90%;第 3 课的数据:预算 1,800 时,工具定义 685 与 system + 任务 249 token 的固定开销就占了近一半,分层运行几乎每轮都在压。
  2. 估算器用哪种?本项目用录制模型自己的 tokenizer,但只数消息内容和工具定义,不含聊天模板的特殊 token:六条运行里比服务端 usage 少 81–198 token(中位数 110)。换成字符估算的话,第 3 课的中文段落上会低估一半以上。
  3. L1 放过最近几轮、按什么裁?本项目放过最近 2 轮,超过 400 字符就留头尾各 3 行。第 2 课的真实代价:测试输出唯一关键的 AssertionError 那一行正好在中间,被裁掉了。
  4. L2 什么时候不该做?第 4 课的重放发现两件事:只有 1 轮可摘要时,摘要比原文还长;第 4 轮刚写好的摘要,在同一次压缩里就被 L3 当成最旧的一轮丢掉了——花了一次模型调用,什么也没留下。

验收标准(全部可测):

坑与带走

本章拦截的误解
误解纠正在哪一课
上下文里只有对话第 1 轮 947 token 里,对话只有任务那 52 token;工具定义 685第 1 课
命中缓存的 token 不算上下文缓存省的是钱和时间,不省窗口;第 2 轮 990 token 里 989 命中缓存,照样全部占着窗口第 1 课
窗口标称多大就能用多大NoLiMa:标称 128K 的模型,在 32K 时多数已跌到自己短输入成绩的一半以下岔路 B1
50 / 70 / 90 是 Claude Code 的内部机制那是 CoreCoder 自选的设计值;它注释里对 Claude Code 的描述是作者的逆向说法,没有官方证实第 2 课
必须上精确的 tokenizerOpenCode 的 pin 源码里没有任何 tokenizer,估算只有「字符 ÷ 4」;它的触发看 API 回报的 usage,安全边际来自预留第 3 课
Pi 每轮都检查要不要压缩pin 版只在一次任务跑完后检查阈值;任务中途只在真的溢出报错时压缩并重试一次第 3 课
Pi 每轮少送 3 倍上下文原文正文说「每轮」,图表量的是「每任务累计」;Databricks 自报、不可复现岔路 B2
context reset 是长任务必备组件提出它的文章自己写明:换到 Opus 4.5 后就拿掉了第 4 课
压缩之后历史就没了被压掉的只是「发给模型的那份」;完整历史仍在磁盘上(本课项目的 trace、Pi 的会话文件、Codex 的 rollout)第 4 课
写代码时的坑
症状后果怎么办
超了就从头删先丢掉 system prompt 和任务说明;删在调用与结果之间,请求直接被拒保住开头;按整轮删,或像 CoreCoder _safe_split 那样把切点挪到调用之前
整轮截断丢掉读文件那一轮模型凭记忆改代码,改出 + 1 + 1先裁工具输出、保住源码;或者在说明里告诉模型「这些内容被删了,需要就重新读」
按行数裁工具输出关键的一行在中间,被裁掉裁之前先按内容保留(报错行、diff);或者只裁已经「用过」的输出
按「字符 ÷ 3 或 ÷ 4」估中文低估一半以上,压缩触发太晚分档估算,或以 API usage 为准、只估新增部分
摘要写成对话概要接手后丢掉确切报错、已完成的修改;还会编造用交接文档式模板,点名要保留的东西;给摘要模型的输入别先被截断
把 50 / 70 / 90 当标准照搬换个窗口大小就失效;预算小时固定开销就占一半用余量或 reserve 表达阈值,用自己的 trace 验证
把 context reset 当必备组件为已经不存在的问题付成本先确认手上的模型是否仍有 context anxiety

带走这些句子(各课「一句话」):

  1. 上下文从第一轮起就不只是对话:工具定义先占了大半,之后涨的主要是工具结果。
  2. 窗口是上限,不是有效长度;能少放就少放。
  3. 先裁不要钱的,再花钱摘要;永远别把 tool 调用和它的结果拆开。
  4. 估算只求不致命,安全边际来自预留;真实数字以 API 回报为准。
  5. 先问数字的口径:每轮还是每任务、谁测的、能不能复现。
  6. 压缩是写交接文档,不是写对话概要。

深入这一章

按你愿意花的时间选。每条都实际打开核对过(2026-09-26);站外链接都需要联网,离线包里只保留链接。

🎮 想更直观 10–30 分钟

先玩本章的组件;下面两个是外部最好的交互入口
15 min英文需联网 官方交互时间轴
可播放的时间轴:输入第一句话之前已经加载了什么,每次读文件、每个 hook 各占多少,子 agent 的独立窗口,/compact 之后哪些内容重新载入(system prompt、CLAUDE.md、记忆、最近改过的至多 5 个文件、调用过的 skill 正文;skill 清单不重载)。
对应第 1、4 课。本章第 1 课的回放是它的「真数据版」:它用的是页面自己说明的代表性数字,本章用的是我们项目的真实运行。先看它建立全貌,再回来看真实的一轮长什么样。
5 min英文需联网 2025-01-30
一个编码 agent 怎样把上下文用量画成进度条:输入、输出分开计,总长是模型窗口。
对应第 1 课。产品里最常见的上下文可视化;对照看它省略了什么(构成、缓存、预留)。

🔬 想吃透原理 1–3 小时

唯一必看:Anthropic《Effective context engineering for AI agents》。中文首选李宏毅的课
30 min英文需联网 2025-09-29
上下文是有限的「注意力预算」;context rot 的官方定义;压缩、结构化笔记、子 agent 三种长任务对策;压缩最轻的一步是清掉旧工具结果。
对应全章,尤其第 2、4 课。本章「先便宜后贵」「压缩是挑出该留的」两条主线,都能在这篇里找到出处;它也提醒过度压缩会丢掉细小但关键的上下文——第 4 课的真实摘要就是例子。
1 h 50 min中文需联网 2025-09-21(时长据 2026-09 调研记录)
从 prompt engineering 讲到 context engineering:上下文由哪些部分组成、怎样选择、压缩与隔离。
中文首选,对应第 1、2 课。概念讲得最系统的中文课;听完再看本章的真实回放,知道每一块对应课上的哪个概念。
25 min中文需联网 季逸超 · 2025-07-18
生产 agent 的经验:KV-cache 命中率是最重要的单一指标;输入与输出的 token 比约 100 比 1;把文件系统当成不受限的外部上下文。
对应第 1 课与 A8。第 1 课看到「每轮整份重发」,这篇讲为什么前缀要保持不变;「文件系统当上下文」也是第 4 课「完整历史留在磁盘上」的另一种说法。
20 min英文需联网 HumanLayer;2025-12-02(据调研记录)
主动压缩(intentional compaction)与 research → plan → implement 的工作流;讲者给出「上下文用到约 40% 就进入 dumb zone」的经验阈值。
对应第 3 课。机制讲得具体;注意 40% 是讲者的个人经验断言,不是实验结论,本章只把它当讨论素材。
57 min英文需联网 时长据调研记录
Chroma《Context Rot》作者之一讲实验方法:18 个模型、针与干草堆的相似度、干扰项。
对应岔路 B1。报告里的曲线是静态图,这个访谈讲清了每条曲线是怎么测出来的。

📄 想读原文 按需

报告、论文与 pin 源码;全部需联网
报告需联网 2025-07-14
18 个模型(含本课录制用的 Qwen3-8B)在六类实验里随输入变长的表现;复现工具包在 github.com/chroma-core/context-rot。岔路 B1。
论文需联网
问题与答案几乎没有字面重合的「针在干草堆里」;岔路 B1 的先猜后揭示用的就是它表 3 的数。本地 PDF 待统一下载。
长文需联网 2026-03-24
context reset + 交接文档的出处,以及作者换到 Opus 4.5 后把它拿掉的原话。第 4 课。
源码需联网
全文 9 行的压缩提示词:把压缩定义为「给接手的另一个 LLM 写交接摘要」。第 4 课。
源码文档需联网
触发公式、切点规则(永远不切在工具结果上)、split turn、结构化摘要模板、跨多次压缩累积的文件清单。第 3、4 课。
源码文档中文需联网
作者本人讲三层压缩「先便宜后贵」的中文文章;第 2 课的 CoreCoder 代码就是它讲的那 210 行。第 3 课的中文估算实验也取了它的一段。
🚫

我替你排除了什么:win4r/cc-notebook 的上下文压缩三篇(给出「167K 阈值」等细节,但基于逆向或泄露代码,未经官方文档核实)· baoyu.io 的 Manus 译本(本轮不可达,改用 Manus 官方中文版)· 把 Databricks 博客的「3x」当结论的转述文章(口径问题见岔路 B2)· 把 Dex Horthy 的「40%」当阈值依据的二手文章(个人经验断言)· Chroma 报告里各模型曲线的具体数值(静态图,没有转录,只链原文)· Drew Breunig《How Long Contexts Fail》(2025-06-22)归入岔路 B1 的正文引用,不另列:它的四种失败定义本章用到了一种,并配了我们自己 trace 里的真实例子。