上个月我看一个团队把 Claude Code 的 1M context 当成「终于不用写文档」的理由。他们做的第一件事不是把 harness 结构补齐而是把仓库里所有 README、ADR、甚至几百 KB 的日志都喂进去试图让模型「一次看懂」。前三天很爽。第四天开始他们的产出变成了另外一件事不停地解释「我们刚才已经说过了」。再往后就是在每个关键转折点前先问一句「要不要 /compact」。这不是模型不够强是上下文工程没过关。context window 变大以后真正变贵的是什么很多人把 token 成本理解成「每次提问花多少钱」。但在 coding agent 里真正的成本结构是递归的上下文越大每一轮对话都会把更大的上下文重新读一遍你每多打一行字后面 N 轮都会为它付费。Claude Code 的官方文档把企业的平均成本写得很坦率在一些大规模部署里平均约是每个开发者每个活跃日 13 美元出处AnthropicClaude Code 文档《Manage costs effectively》。这不是「问了几次」的函数而是「你把多少东西长期留在上下文里」的函数。更关键的是context window 不是一个「能存多少」的容器而是一个「工作记忆」的舞台。舞台越大你越容易把无关的道具也搬上去。搬上去之后它们不会自动消失只会在每轮推理里持续消耗注意力。你会看到两个很稳定的失败模式第一类是「lost in the middle」。你把所有信息都塞满模型反而更容易忽略中间那一段关键约束。它不是不看是注意力预算被稀释了。第二类是「对齐成本爆炸」。当你把很多事实都留在历史对话里你实际上在逼模型不断地做一次隐形的 reconciliation这些事实彼此一致吗上一次的决定和这一次的改动冲突吗它当然会漏。Claude Code它不是让你无限堆上下文而是逼你会收拾Claude Code 文档里明确写了两件事它会用 prompt caching 降低重复内容的成本并且会在接近上下文上限时触发 auto-compaction把历史对话压缩成摘要出处AnthropicClaude Code 文档《Manage costs effectively》。这两点经常被误读成「你尽管塞Claude 会自动帮你优化」。但工程上更接近的事实是Claude 给你两把扫帚你得自己决定什么时候开始打扫。我更认可一个简单的经验法则复杂的多文件任务永远不要在「最后 20%」的上下文里做。你可以在尾部做一些低上下文密度的工作比如改一个小函数、补一段注释、整理 TODO但不要在那时做跨文件重构。原因很直白你在上下文的尾部做复杂任务等价于在一个已经堆满道具的舞台上排练一场大戏。你不但更容易忘约束还更容易让 compaction 在最不合适的时候发生。这里还有一个容易忽略的工程点compaction 是摘要不是压缩包。摘要的目标不是「信息无损」而是「让下一段工作还能继续」。所以你必须给它一个明确的「保留原则」。Claude Code 支持你在 compact 时附加指令告诉它「保留测试输出和改动」或者「保留 API 使用方式」——这个动作本质上是在做信息架构出处AnthropicClaude Code 文档《Manage costs effectively》。Gemini CLI开源世界把「压缩」做成了一个子系统你应该学的不是命令是架构Gemini CLI 的 release notes 里提到一个细节他们引入了 Context Compression Service用来「有效蒸馏对话历史」出处Gemini CLI 文档《release notes》条目Context Compression Service。这个表达非常工程化。它承认了一件事压缩不是一个 UI 命令而是一条管线。当压缩变成一个子系统你就会自然地问四个问题。第一什么时候触发压缩是按 token 百分比还是按对话阶段第二压缩的输入边界在哪里整个历史全丢进去还是只压缩某一段第三压缩的输出写到哪里只写回模型上下文还是落盘成一个可恢复的 artifact第四压缩是不是可插拔的我能不能在压缩前把重要状态先备份出来这些问题一旦问出来你会发现它们跟 harness 工程的五子系统是同一套思维你不是在「用一个工具」你是在「设计一个可持续的会话生命周期」。1M context 的正确打开方式把它当作缓存不要当作仓库我现在倾向于把大 context window 视为一种缓存层。缓存的第一条规则是命中率比容量更重要。你可以用更大的窗口提高命中率但如果你把它当成仓库把所有东西都丢进去你会得到一个很熟悉的结局缓存污染命中率下降真正需要的东西反而找不到。更工程化的做法是把上下文拆成三层。第一层是「开机即有」的稳定约束比如项目结构、命名约定、测试命令。这一层应该写进一份短小的 harness 指令文件让每个 session 都能快速恢复。第二层是「本 feature」的目标、Definition of Done、Out of Scope。这一层应该是机器可读的 scope 边界不应该靠对话历史维护。第三层是「临时推理」。这一层可以在对话里自然发生但必须默认会丢。只要你接受它会丢你就会更愿意把结论沉淀到前两层。如果你把这三层分开1M context 才会真正变成优势它让你在第三层推理时更少被打断但它不会替代第一层和第二层的结构化产物。这里我再补一个我踩过的坑把「长日志」当上下文会把你拖进一种慢性病。第一次你粘一段 CI log模型帮你定位到了某个依赖冲突看起来很值。第二次你把整份 log 粘进去模型开始在无关告警里游泳。第三次你发现你已经不敢再删 log 了——因为你不确定删掉的那行是不是关键。一旦到了这一步你的系统就不是在写代码而是在为上下文支付利息。真正的解法只有一个把日志变成结构化证据。把关键报错的 20 行摘出来标记发生条件落到一个可复用的排障条目里。下次遇到同类问题你喂的不是日志而是结论。一个能落地的「上下文预算」方法我现在给团队推一个很土的做法每个 session 开始前先写一张「上下文预算表」。不是给模型看是给人看。表里只有三列类别允许进入上下文的内容绝对不允许进入上下文的内容稳定约束目录结构、测试命令、代码风格、核心边界历史讨论、截图式的长日志、全量 README 合集任务目标Definition of Done、Out of Scope、风险点「顺便看看」这种开放式愿望清单临时证据当前报错栈、当前 diff、当前实验结论把整份 trace、整份 CI log 粘进来当背景你会发现一旦你把「什么不该进上下文」写清楚大家的使用方式会立刻变得更像工程。最后给一个很不讨好的结论大 context window 不是「不用写 harness」的理由恰好相反。窗口越大你越需要一套清晰的指令树、状态落盘、验证门禁、scope 边界和会话收尾。因为窗口让错误更晚暴露也让「看起来在进展」这件事更容易发生。我见过太多团队把上下文当成仓库然后把时间花在 compaction 上。最后他们会得到一个看似更强的模型以及一个更弱的工程系统。如果你不想走到那一步今天就做一件小事把你团队最常重复解释的那 5 条约束写下来放进一个每次 session 都能读到的地方。剩下的再慢慢拆。一个极简的「上下文工程」检查清单我现在判断一个团队有没有把上下文当工程做有一个很粗暴的检查他们能不能在 10 分钟内回答下面这五个问题。问题如果答不上来意味着什么你们把哪些信息放在「每个 session 必读」的指令里那份文件有多少行稳定约束没有分层所有东西都靠对话堆出来你们的 Definition of Done 是一句话还是一组可验证的断言目标不可验证最后只能靠「应该好了」你们有没有明确写出 Out of Scopescope 由模型自由发挥越界是必然你们是先跑验证再写结论还是先写结论再补验证证据链倒置会被自信幻觉反复坑你们的 compaction 触发点是策略还是碰运气会话生命周期失控最后都在追着 /compact 跑这张表不是为了让人背是为了让你把答案写进 harness。把话说得更直白一点如果你发现团队里最聪明的那个人最近的产出主要是「帮大家回忆我们之前说过什么」那不是他变忙了是系统在泄漏。上下文窗口越大这种泄漏越不容易被及时发现。你以为你省掉了文档实际上你把文档写进了一个每轮都要重新阅读、并且随时会被摘要改写的地方。这就是我说的那句话把 1M context 用满的人最后都在给 /compact 打工。