上下文管理策略
7.1 节解决了"提示词怎么写",本节解决"提示词送进 AI 之后的世界"。再精妙的提示词也会被一个物理上限约束——LLM 的上下文窗口(Context Window)。Claude 系列的上下文窗口虽已扩展到 200K Token 量级,但这并不意味着"反正窗口够大、随便塞"。窗口越大,模型越容易出现"中间忽略"现象(Lost in the Middle);调用成本越高,延迟越长;而真实工作流里,长会话累积的"垃圾上下文"还会损耗模型的判断力。
本节的核心论点是:上下文管理不是工程师的可选技能,而是与 AI 协作时代的核心生产力杠杆——管理得好的工程师在同一会话中能完成 5 倍的工作量、保持 3 倍的输出质量;管理得差的工程师在第三次对话就开始遭遇"Claude 越来越不专注"的诡异现象。本节会把上下文管理拆成"窗口边界 → 内置机制 → 主动策略 → 反模式 → 缓存协同 → 角色协作"六部分,给出一份可以立即落地的实战指南。
需要先打破一个常见误解:上下文窗口大不等于"塞越多越好"。Anthropic、OpenAI、Google 多家公司近两年都做过类似的"长上下文 benchmark",结论一致——模型的有效注意力区间通常远小于物理上限。换句话说,一个 200K Token 的窗口可能只有约 80K Token 的"高质量利用区",剩余的 120K Token 即使被填满,对模型决策的贡献也很有限,甚至会引入"中间忽略"等副作用。
理解这一点后,"上下文管理"就不再是单纯的"省钱"问题,而是把有限的注意力配额配置在最有价值信息上的资源调度问题——和操作系统调度 CPU、数据库调度查询执行计划是同类的工程问题。本节后续所有策略都建立在这条认知基础之上:你不是在"塞数据",你是在"为 AI 安排注意力"。
一、为什么上下文管理是 AI 协作的核心约束
1.1 大模型上下文窗口的物理边界
Claude 模型家族的上下文窗口规格大致如下(以 2026 年初 Anthropic 官方文档为准):
- Claude Sonnet 4.6 / Opus 4.7:标准 200K Token,部分企业账户支持 1M Token 的扩展窗口。
- Claude Haiku 4.5:200K Token。
- 历史版本:Claude 3.5 Sonnet 也是 200K,Claude 2 系列是 100K。
200K Token 听起来很大——大约相当于 15 万英文单词,或者 30 万中文字符。换算到代码,差不多是一个中型项目(30-50 个文件、平均 200 行/文件)的全量代码。理论上"塞下整个项目"似乎可行。
但理论容量 ≠ 有效容量。Anthropic 官方给出的最佳实践建议——核心信息应放在前 20% 与后 20% 的区间内,因为模型的"注意力分布"在长上下文下并非均匀。这意味着 200K 窗口的"高质量利用区"可能只有 80K Token 左右。
Token 与字符的换算速查:
| 内容类型 | 1K Token 约等于 |
|---|---|
| 英文文本 | 约 750 词 / 4000-5000 字符 |
| 中文文本 | 约 500-700 字符(中文字符的 Token 密度更高) |
| 代码(TypeScript) | 约 30-50 行(含空白与注释) |
| 代码(Python) | 约 40-60 行 |
| JSON / YAML | 约 1000-2000 字符(取决于嵌套层级) |
| 日志(结构化) | 约 30-80 条 |
工程师在估算"我这次对话会消耗多少 Token"时,可以基于这张表做心算。例如让 Claude 读一个 300 行的 TypeScript 文件,约消耗 6-10K Token;让它处理 1000 条日志,约消耗 12-30K Token。养成"贴文件前先估 Token"的习惯,能避免大部分窗口溢出问题。
1.2 上下文成本曲线——长上下文的延迟、价格与质量损失
长上下文带来三重成本:
- 延迟成本:上下文越长,模型计算注意力的耗时越长。本人在多个项目观察到,10K Token 的对话首 token 延迟约 1-2 秒,100K Token 上下文后延迟可能升至 5-8 秒,200K 接近极限时延迟可能超过 10 秒。
- 价格成本:API 计费按输入 Token 量收费。一段在 50K Token 上下文中重复发送 20 次的对话,比 10K Token 上下文中重复发送的同等对话贵 5 倍。
- 质量成本:长上下文中模型的"注意力稀释"效应——它需要在更多内容中找到相关信息,错过细节的概率上升。这在涉及精确技术细节的任务(例如调试、代码审查)中尤为明显。
1.3 LLM 的"中间忽略"现象(Lost in the Middle)
学术界的一项著名研究(Liu et al., 2023, "Lost in the Middle: How Language Models Use Long Contexts")发现:LLM 在处理长上下文时,对开头和结尾信息的关注显著高于中间。具体表现:
- 当关键信息位于上下文的开头时,模型回答的准确率最高(约 75%)。
- 当关键信息位于上下文的中间时,准确率最低(约 50%)。
- 当关键信息位于上下文的末尾时,准确率次高(约 65%)。
这个 U 型曲线在多个模型(GPT-4、Claude、Llama)中都被观察到。它的实战意义:
- 重要信息要么放最前,要么放最后。
- 避免"夹心饼"格式——把核心需求埋在 200 行历史对话中间。
- 每次新会话开始时,主动重申核心目标与约束。
"位置效应"在长会话中的具体表现:
- 工程师在第 1 轮迭代设定的"必须用 TypeScript strict 模式",在第 50 轮迭代时可能被忽略——这条规则已经位于上下文的"中间深处"。
- 解决方案是把"持久性强约束"放进 CLAUDE.md,CLAUDE.md 在每轮迭代都重新注入到上下文最前端。
- 临时性约束("这一轮迭代不要改 src/order/")则放在最近一轮 prompt 的最前或最后。
用 prompt 结构对抗位置效应:在每次重要 prompt 中显式重申关键约束,例如:
**核心约束(请优先遵守)**:
- 不要修改 src/auth/,本轮只关心 src/user/
- 测试覆盖率必须 ≥ 90%
- 错误必须继承 BaseError
[详细任务描述]
**重要回顾(结尾再次强调)**:
- 严禁 try/catch 内静默吞错
- 任何 schema 变更需要 plan 模式审批
把核心约束分别放在开头与结尾,能利用模型的"首尾注意力偏好"形成"双重保险"。这种"sandwiching"策略是长上下文工作中行之有效的实战技巧。
二、Claude Code 的内置上下文机制
2.1 自动压缩(Compact)触发时机与原理
Claude Code 内置了"自动压缩"机制——当上下文接近窗口上限时,系统会自动压缩历史对话,把详细对话替换为摘要,腾出空间给新对话。
触发条件:
- 上下文累积到约 80% 窗口容量时进入预警。
- 累积到约 95% 时强制压缩。
- 工程师可以主动触发:
/compact。
压缩策略:
- 保留最近 N 轮完整对话(让 Claude 仍能记住"你刚刚要求做什么")。
- 早期对话压缩为关键决策摘要("你定义了 User 类型有 4 个字段、要求所有错误继承 BaseError")。
- 工具调用结果按需保留(最近的保留、远期的丢弃)。
注意事项:
- 压缩本身会消耗 Token(需要让模型生成摘要)。
- 压缩后的摘要可能丢失某些细节——重要决策应在压缩前主动写到
.claude/state.md或 CLAUDE.md。 - 频繁压缩说明"会话开太久了"——考虑结束本次会话、开新会话。
压缩前 vs 压缩后的质量对比:本人在多个项目里观察到,会话经过一次自动压缩后,Claude 的输出质量在以下方面会明显下降——
- 代码风格一致性:压缩前 Claude 严格遵守项目命名规范(例如 camelCase vs snake_case),压缩后偶尔混用。这是因为风格细节往往藏在早期"已被压缩"的具体例子中。
- 错误处理一致性:压缩前 Claude 记得"所有错误继承 BaseError",压缩后可能直接
throw new Error()。 - 测试结构一致性:压缩前 Claude 知道"测试夹具放在
__fixtures__/目录",压缩后可能放到错误路径。
应对方案是把"高频共识"主动搬进 CLAUDE.md——CLAUDE.md 在每次会话开始注入,不会被压缩。压缩损失的是"会话内积累",CLAUDE.md 沉淀的是"团队共识"。两者的角色不能混淆。
2.2 CLAUDE.md 的注入机制
CLAUDE.md 是 Claude Code 在会话开始时自动注入的"项目记忆"。注入规则:
- 仓库级 CLAUDE.md(项目根目录):每次会话开头注入。
- 用户级 CLAUDE.md(
~/.claude/CLAUDE.md):跨项目注入,先于仓库级。 - 嵌套 CLAUDE.md(子目录中):当 Claude 操作该子目录时按需注入。
Token 预算:
- CLAUDE.md 占据的 Token 直接吃掉上下文窗口。
- 一份 500 行的 CLAUDE.md 大约是 5K-10K Token——占 200K 窗口的 5%。
- 一份 2000 行的 CLAUDE.md 可能吃掉 20-30K Token——已是 10%-15%。
最佳实践:
- CLAUDE.md 控制在 200-500 行之间。
- 把"具体规则"放进来,把"教学性内容"放到外部 wiki。
- 每月做一次"CLAUDE.md 减法"——删除已被 Hook / settings.json 自动化的规则。
2.3 工具调用结果的截断与清理
Claude Code 会把每次工具调用的结果(Bash 输出、文件内容、grep 匹配)放进上下文。这些结果的大小不可预测——一次 cat large-file.log 可能瞬间塞入 100K Token。
应对策略:
# 反模式:直接读大文件
cat /var/log/app.log
# 正确:截取相关片段
grep "ERROR" /var/log/app.log | tail -50
# 或先聚合再读
awk '/ERROR/ {count++} END {print count}' /var/log/app.log
让 Claude 在读文件前先做"预聚合"——wc -l、head -20、tail -50、grep -c——避免一次性吞下全文。Claude 接收到聚合数据后再决定是否需要详细内容。
工具结果的"自适应裁剪":Claude Code 内部对超大工具输出会自动截断(通常截断到一定 Token 上限)。但截断本身可能损失关键信息——例如截断了恰好包含错误信号的那一行。最稳妥的做法是工程师在执行命令前就把输出限定在合理范围:
| 命令模式 | 反模式 | 推荐做法 |
|---|---|---|
| 看日志 | cat app.log | tail -100 app.log 或 grep ERROR app.log | tail -50 |
| 看依赖 | cat package-lock.json | jq '.packages | keys | length' package-lock.json |
| 看代码库 | find . -name '*.ts' | find . -name '*.ts' | head -50 或 find . -name '*.ts' | wc -l 先聚合 |
| 看 git diff | git diff | git diff --stat 先看摘要、再针对性 git diff <file> |
| 看进程 | ps aux | ps aux | grep node |
工程师把这些"裁剪习惯"内化为肌肉记忆后,工具调用的 Token 消耗能降到合理水平。
2.4 会话内 Plan 文件、Tasks、Memory 的角色
Claude Code 提供了几种"会话级持久化"工具,它们各自在上下文管理中扮演不同角色:
- Plan 文件(
.claude/plans/<plan-name>.md):长期任务的执行计划,可跨会话引用。 - Tasks(TaskCreate / TaskUpdate):当前会话内的任务追踪,会话结束后清空。
- Memory(
MEMORY.md):跨会话长期记忆,在新会话开始时自动加载。
用法对照:
| 信息类型 | 推荐工具 | 跨会话存活? |
|---|---|---|
| 当前要做的子任务 | Tasks | 否 |
| 多轮迭代的功能蓝图 | Plan 文件 | 是 |
| 团队约定 | CLAUDE.md | 是 |
| 用户偏好 | Memory | 是 |
| 临时上下文(本次重构涉及哪些文件) | .claude/state.md | 是(手动维护) |
合理使用这些工具能避免"把所有信息都塞在对话中"的窗口浪费。
2.5 /clear 与开新会话——边界判断
/clear 清空当前对话历史但保留会话进程。开新会话则完全重启——会重新注入 CLAUDE.md、重新计算 Memory。
何时用 /clear:
- 当前任务彻底完成、要切换到完全无关的下一个任务。
- 上下文中累积了大量调试日志、希望"清场"开始下一段干净对话。
- 已经触发了一次自动压缩、希望避免再次压缩损失细节。
何时开新会话:
- 工作目录改变(要去另一个项目)。
- 上一会话的"风格"已经偏离(例如本来在写代码,后来一直在闲聊)。
- CLAUDE.md / Skills 有更新——需要新会话才能加载新版本。
- 跨日工作的自然分隔点(每天上午/下午)。
三、主动的上下文管理策略
3.1 任务级别拆分
把"功能"拆成"故事"再拆成"任务",每个任务对应一次完整的会话。这与 6.3 节"多轮迭代"的策略一致——会话边界与迭代单元应当对齐。
错误示范:一次会话里写完整个用户管理模块(数据模型、CRUD、校验、测试、权限),然后调试 Bug,然后写文档。会话长度可能突破 100K Token,质量与速度都会下降。
正确示范:一次会话只做一件事——例如"为 User 类型加 phoneNumber 字段并补单元测试"。完成后开新会话做下一件。
任务拆分的"15 分钟原则":本人多年实战总结的一条经验——单次会话应当能在 15-90 分钟内完成主要任务。低于 15 分钟说明任务过小(开会话的固定成本不划算),高于 90 分钟说明任务过大(上下文开始累积、注意力开始稀释)。15-90 分钟是会话效率的"甜蜜区"。
如果某个功能预计需要 3 小时才能完成,应该把它拆成 3 段:
- 段 1(30-45 分钟):数据模型 + 核心 CRUD
- 段 2(30-45 分钟):业务规则 + 校验 + 错误处理
- 段 3(30-45 分钟):单元测试 + 集成测试 + 文档
每段独立一个会话,段与段之间通过 .claude/state.md 传递关键决策。这种拆分不是因为 Claude 做不了 3 小时的工作,而是因为人类工程师在 90 分钟后审查质量会下降——任务拆分本质上服务的是人类,而不是 AI。
3.2 上下文预算意识
每次会话开始时给自己一个"上下文预算"。例如:
- 小任务(5K Token 预算):单文件修改、补一个测试、修复一个简单 bug。
- 中任务(20K Token 预算):跨文件重构、新增一个 endpoint、补完整个测试套件。
- 大任务(50K Token 预算):实现一个完整功能、做一次大型重构。
任何超过 50K 的预算就应该警觉——很可能是任务边界没拆好。
预算意识的另一个表现是主动把"无关历史"清掉。例如调试到一半发现走错了方向,与其继续在错误路径上叠加更多对话,不如:
当前调试方向走偏了,让我重新开始。请忽略之前关于 X 的所有讨论,
回到 commit abc123 的状态。我重新描述需求:[简短重述]。
这种"软重置"虽然没真清空 Token,但 Claude 会把注意力聚焦到新描述上,远好于继续在错误路径上累加。
预算意识的"四道闸门":实战中可以设立四道渐进式的提示,确保自己不会在不知不觉中超预算——
- 第一道闸门:50% 预算消耗——警觉但继续。问自己"我的核心任务完成了一半吗?"。如果远未完成,说明任务边界估错了,需要主动收窄。
- 第二道闸门:70% 预算消耗——主动归档进度。把当前已完成部分的关键决策写入
.claude/state.md,避免后续压缩损失。 - 第三道闸门:85% 预算消耗——准备开新会话。让 Claude 输出"下一会话的接力清单"——具体到下一个动作是什么、需要什么前置条件。
- 第四道闸门:95% 预算消耗——立即结束。即使任务未完成,也应该结束当前会话、开新会话继续。继续硬撑会让接下来的对话质量急剧下降。
四道闸门的作用是让"上下文预算"从抽象目标变成可操作的检查点。每一道闸门都对应一个具体动作——警觉、归档、接力、结束——而不是模糊的"小心点"。
3.3 用 Skills 把高频信息固化
Skills 是 Token 效率的优化器。一个反复使用的 prompt 模板("写 CRUD repository、含校验、含测试")每次对话都重复输入,会无意义地消耗 Token。
封装为 Skill 后:
# 调用 Skill 只需一行
/crud-repository Order
# 而不是每次重写完整 prompt
"请为 Order 实体生成 CRUD repository,含 Zod 校验、含 Vitest 测试..."
Skill 的描述内容只会在 Claude 决定使用该 Skill 时才被加载到上下文,平时不占据 Token。这条机制让 Skills 既扩展了能力又节省了上下文——是 Claude Code 设计中最巧妙的取舍之一。
3.4 用 .claude/state.md 跨会话传递关键决策
复杂项目跨会话工作时,主动维护一份"状态摘要":
# .claude/state.md
## 当前工作焦点(更新于 2026-04-26)
- 正在做:用户管理模块的 6 轮迭代中的第 4 轮(补单元测试)
- 已完成:第 1-3 轮(类型、CRUD、校验)
- 下一步:第 5 轮业务规则、第 6 轮性能优化
## 关键决策(不要 Claude 重新讨论)
- User.email 必须唯一(基于业务方决定)
- 错误处理:所有自定义错误继承自 BaseError
- 测试框架:Vitest(不要切换到 Jest)
## 当前 Pending 项
- 待办:增加 actorRole 参数后,需要批量更新调用方(约 12 处)
- 风险:第 4 轮单元测试覆盖率目标 90%,目前 73%
新会话开始时让 Claude 读 .claude/state.md:
请先读 .claude/state.md 了解当前项目状态,然后开始第 4 轮迭代的剩余工作。
这种"工作状态外部化"让 Claude 不再需要从零理解上下文,会话效率显著提升。
state.md 与 CLAUDE.md 的角色分工:两者经常被混淆,但功能完全不同——
| 文件 | 角色 | 更新频率 | 适合内容 |
|---|---|---|---|
CLAUDE.md | 项目长期共识 | 月级别 | 团队铁律、命名规范、永久约束 |
.claude/state.md | 临时工作焦点 | 会话级别 | 当前 sprint 焦点、待办、风险 |
如果把会话级的临时信息写入 CLAUDE.md,会污染项目长期记忆;反之,把项目长期共识只写在 state.md,新人会找不到。两者各司其职、互不替代。一个健康的项目会同时维护两份文件,CLAUDE.md 半年才大改一次、state.md 每天都在更新。
3.5 子代理(Subagent):把局部探索隔离在独立上下文
Claude Code 提供 Agent 工具——派出一个独立的子代理处理某个子任务,子代理拥有自己的上下文窗口,结果汇总后才返回主对话。
适合场景:
- 探索性任务("帮我搜遍整个代码库找到所有调用 X 的地方")
- 局部研究("读一下 docs/ 目录下所有文档总结某个主题")
- 高 Token 消耗任务("分析这个 5 万行的日志找出错误模式")
通过子代理隔离,主对话保持精炼——Claude 只看到"子代理的结论"而不是"子代理的工作过程"。
子代理设计的"四原则":
- 任务边界明确:子代理的任务应当能用一句话描述,并且有明确的产出物(一份报告、一个文件、一组 ID)。模糊任务("帮我研究一下这个项目")容易让子代理产出冗长无重点的结论。
- 输入足够丰富:子代理不会自动继承主对话的上下文,需要在派遣时把所有必要信息写入 prompt。这反而是好事——它强迫工程师明确"这个任务到底需要什么背景"。
- 输出结构化:要求子代理返回 JSON / Markdown 表格 / 严格列表。结构化输出便于主对话直接消化,避免再让主对话花 Token "解读"子代理的散文式回答。
- 失败可观测:子代理偶尔会因 socket 错误、超时、误解而失败。主对话应当能识别这种失败并提供 fallback——例如"如果子代理 N 分钟内未返回,主对话亲自接手"。
子代理与主对话的 Token 经济学:
- 不用子代理:5 万行日志 × 估算 50K Token 直接进主对话,加上分析对话 = 约 80K Token。后续对话窗口紧张。
- 用子代理:子代理在它自己的 200K 窗口里处理 50K Token、返回 1K Token 的摘要给主对话。主对话只消耗 1K Token。节省 79K Token。
这条经济学在多个场景下都成立——大型代码库探索、跨多个文件的模式查找、长文档的总结提取——都应当优先派子代理处理。
四、典型上下文反模式与挽救
4.1 一口气贴大段日志/数据导致瞬间溢出
反模式:
[把 5 万行日志直接粘贴进 prompt]
请帮我分析为什么有错误。
后果:单次输入瞬间吃掉 50K+ Token,剩余窗口所剩无几,后续对话很快触发自动压缩。
挽救:
- 预聚合:先
grep ERROR | tail -100再贴。 - 派子代理:让 subagent 处理大日志、返回摘要。
- 分批分析:把日志拆成 5 个 1 万行的批次,每批独立对话分析。
实战示例:日志分析的"三步漏斗":
# 步骤 1:宏观聚合
grep -cE 'ERROR|WARN|FATAL' /var/log/app.log
# 输出:ERROR: 1247 / WARN: 5621 / FATAL: 3
# 步骤 2:按类型分组
grep -E 'ERROR|FATAL' /var/log/app.log \
| awk -F': ' '{print $3}' \
| sort | uniq -c | sort -rn | head -10
# 输出:342 Connection timeout
# 128 Database lock
# 89 OAuth token expired
# ...
# 步骤 3:拿最多的 ERROR 的 5 个具体样本
grep "Connection timeout" /var/log/app.log | head -5
把这三步的输出(合计可能不到 2K Token)贴给 Claude 让它分析。日志分析的有效信号往往集中在 1% 不到的内容里——其余 99% 是噪音,强迫塞给 Claude 反而稀释它的注意力。
4.2 长会话累积——Claude 已经搞混了
反模式:在同一会话里来回修改 src/user.ts、src/order.ts、src/billing.ts,几小时后 Claude 输出的代码开始混淆——把订单的字段写到了用户上。
挽救:
- 会话切换:每次主题切换主动开新会话。
- 强制状态摘要:让 Claude 每 10 轮迭代输出"我现在在做哪个文件、哪个功能、上一步是什么"。
- 善用 /compact:主动触发压缩,把早期"已完成的部分"摘要化,腾出空间给当前任务。
"主题混淆"的早期识别信号:当你看到以下任一信号,应该立即考虑切换会话——
- Claude 在新代码中引用了上一个文件的字段名(典型的"上下文串味")。
- Claude 重复定义已存在的类型/函数(说明它"忘了"早先的定义)。
- Claude 在工具调用前反复确认基本事实("Order 有 status 字段对吗?"——本应早已建立的共识)。
- Claude 输出的代码风格突然偏离项目惯例(CLAUDE.md 的位置效应失效)。
这四个信号都意味着"上下文不再可靠",硬撑下去只会浪费 Token + 降低质量。最佳响应是结束当前会话、写一份状态摘要、开新会话从干净状态继续。别舍不得"已经投入的对话历史"——更宝贵的是当下的判断力。
4.3 Plan 模式失效
反模式:在长会话末期切到 Plan 模式,发现 Claude 输出的 Plan 粗糙、漏了关键步骤。
根因:上下文已经被早期对话填满,Plan 模式可用的"思考空间"被挤压。
挽救:开新会话再启用 Plan 模式。新会话里 Claude 拥有完整的注意力配额。
4.4 工具调用结果占据过多 Token
反模式:让 Claude 跑一个返回 20K Token 的命令(例如 cat package-lock.json 或 npm outdated --json),结果直接吞掉一大块上下文。
挽救:
- 大命令前主动加
head -50/tail -100/grep过滤。 - 用
wc -l等聚合代替全文输出。 - 让 Claude 写脚本输出"摘要文件",再读摘要而非读全文。
"摘要文件"模式的实战示例:当需要让 Claude 分析一个超大文件(例如 50MB 的 package-lock.json),最稳妥的流程是——
# 步骤 1:让 Claude 写一个摘要脚本
cat <<'EOF' > .claude/scripts/summarize-lock.sh
#!/bin/bash
echo "## package-lock.json 摘要"
echo
echo "### 总包数"
jq '.packages | keys | length' package-lock.json
echo
echo "### 直接依赖(30 个)"
jq -r '.packages."" | .dependencies | keys[]' package-lock.json | head -30
echo
echo "### 重复依赖(潜在 dedupe 机会)"
jq -r '.packages | keys[]' package-lock.json | awk -F'/node_modules/' '{print $NF}' | sort | uniq -c | sort -rn | head -10
EOF
chmod +x .claude/scripts/summarize-lock.sh
# 步骤 2:跑摘要脚本,输出到中间文件
.claude/scripts/summarize-lock.sh > .claude/summaries/lock-summary.md
# 步骤 3:让 Claude 读摘要文件而非原文
# Read .claude/summaries/lock-summary.md
整个流程把 50MB 的原始文件压缩成 2-5KB 的摘要,再让 Claude 基于摘要做分析。如果摘要里发现某个具体包需要深入查看,再针对性地 jq '.packages."xxx"' package-lock.json 拿单个包的详情。"先聚合、再放大"的两阶段策略适用于几乎所有大数据分析场景——日志、配置、报告、数据集——都可以套用这个模板。
4.5 用"上下文摘要 + 新会话"挽救濒临溢出的会话
当会话已经接近上下文上限、自动压缩频繁触发时,主动结束会话比"继续硬撑"更好:
我们的会话已经接近上下文上限。请输出本次会话的"状态摘要":
1. 已完成的工作(带文件路径与 commit hash)
2. 仍未完成的任务清单
3. 关键决策与约束
4. 下一会话需要继续的具体动作
输出后我会开新会话,让新会话基于这份摘要继续。
把摘要写入 .claude/state.md,下次会话开始时读取。这条流程把"无意义的压缩损耗"换成了"有意义的状态外部化"。
摘要输出的"金字塔结构":好的摘要应当遵循金字塔原则——最重要的信息放最前,让下一会话即使只读前 100 字也能知道大概。建议格式:
## 会话状态摘要 — 2026-04-26 14:30
### TL;DR(一句话)
正在做 user-management 的第 4 轮迭代(单元测试),已完成 7 个用例,剩余 3 个待补。
### 关键决策(3-5 条,下一会话不要重新讨论)
1. User.email 必须唯一(业务方决定 2026-04-25)
2. 错误处理:所有自定义错误继承 BaseError
3. 测试框架用 Vitest,不要切换到 Jest
### 已完成(带 commit hash)
- ✅ 类型定义(commit a1b2c3d)
- ✅ 内存版 CRUD(commit e4f5g6h)
- ✅ 输入校验(commit i7j8k9l)
- ✅ 7 个测试用例(uncommitted)
### 待办(按优先级)
1. 补 deleteUser 异常路径测试
2. 补 updateUser 部分字段测试
3. 整体跑覆盖率 → 目标 ≥ 90%
4. commit 单元测试 + push PR
### 已知风险
- 性能测试还没做,不知道在 1k 用户量下表现
- updateUser 的并发测试还没设计
这种结构化摘要在下一会话读入后,Claude 能在 30 秒内重建完整工作上下文。摘要的写作时间投入(约 2 分钟)远小于在新会话中"从零重建"的时间(5-10 分钟)——是上下文管理中投资回报率最高的一项习惯。
五、上下文与 prompt cache 的协同
5.1 Prompt Cache 的工作原理
Anthropic 的 Prompt Cache 机制允许"缓存"上下文中的稳定部分(如 system prompt、CLAUDE.md),下次请求时如果前缀匹配,直接复用缓存而不需要重新计算。
命中条件:
- 缓存的内容必须精确匹配(一个字符的差异都会导致 miss)。
- 缓存有 TTL(默认 5 分钟,可延长至 1 小时)。
- 缓存有最小 Token 阈值(小于阈值的内容不会被缓存)。
收益:
- 命中后,被缓存部分的 Token 价格降至 1/10 左右。
- 命中后,模型计算注意力的延迟显著降低。
Cache 命中链路的"前缀原则":Cache 是前缀匹配的——只要"上下文的前 X Token 完全一致"就能命中前 X Token 的 cache,X 之后即使变化也不影响前面的命中。这意味着应当把"会变的部分"放在 prompt 末尾、把"不变的部分"放在 prompt 开头:
[系统提示,永不变 — 5K Token] ← 全程命中
[CLAUDE.md,每次会话注入 — 8K Token] ← 全程命中
[本会话历史对话 — 累积变化] ← 部分命中(早期对话稳定后命中)
[当前用户输入 — 每次都新] ← 不命中
理解这条机制后,工程师可以主动设计 prompt 结构以最大化 cache 收益——哪些放最前、哪些放中间、哪些放最后,都不再是随手安排,而是基于"命中率最大化"的工程决策。
5.2 把 CLAUDE.md / 系统提示词放进 cache 的最佳实践
CLAUDE.md 是天然的 cache 候选——它在会话期间几乎不变。把它放在上下文最前面,能让 cache 在每次对话中都被命中。
反例:
[历史对话 ... 30K Token]
[当前 prompt]
[CLAUDE.md ... 5K Token] ← 放在末尾,cache 命中率低
正例:
[CLAUDE.md ... 5K Token] ← 放在最前
[历史对话 ... 30K Token]
[当前 prompt]
Claude Code 默认会做这个排序,但工程师在调用 API 时也应当遵循同样原则。
5.3 cache 命中率监控与成本对比
通过 Anthropic API 的 response 中的 cache_read_input_tokens 与 cache_creation_input_tokens 字段可以监控 cache 表现:
// 简化版监控逻辑
const response = await client.messages.create({...});
const cached = response.usage.cache_read_input_tokens || 0;
const created = response.usage.cache_creation_input_tokens || 0;
const total = response.usage.input_tokens;
const hitRate = total > 0 ? cached / total : 0;
console.log(`Cache hit rate: ${(hitRate * 100).toFixed(1)}%`);
console.log(`Saved approx: ${cached * 0.9} Token-equivalents`);
健康团队的 cache 命中率应当在 50%-80% 之间。低于 30% 说明 cache 被频繁失效(CLAUDE.md 改动过频繁,或会话频繁切换)。
5.4 cache 失效时机:避免无谓重新计费
cache 失效场景:
- CLAUDE.md 内容变更(即使只改了一个空格)。
- 上下文中早期某条消息被压缩或删除。
- 会话间隔超过 TTL(默认 5 分钟)。
- 不同账户之间不共享 cache。
避免无谓失效的实践:
- 不要"调试性"频繁修改 CLAUDE.md——把临时调试规则放在临时文件里。
- 长会话保持连续工作,避免长时间挂起再回来。
- 多人协作时,每个工程师的 cache 互相独立,不要期待"队友的 cache 我也能复用"。
Cache 命中率优化的"三招":
- CLAUDE.md 分层:把"几乎不变"的内容(团队铁律、命名规范)放在最前面;"偶尔会调整"的内容(当前 sprint 的临时关注点)放在末尾。即使末尾内容变化,前面的部分依然能命中 cache。
- 模板化系统提示:在 API 直接调用场景中,把系统提示设计成
[固定模板] + [变量部分],固定模板放最前。变量在末尾,即使变量天天变,固定模板依然命中。 - 批量任务的 cache 链路:如果有 100 个相似任务要处理(例如批量翻译、批量代码审查),让所有任务共享同一份系统提示与 CLAUDE.md。第一个任务付全价创建 cache,后续 99 个任务命中 cache 享受 1/10 价格。100 个任务的总成本约等于 11 个任务的成本——这是 Cache 在批处理场景下的最大杠杆。
Cache 成本测算示例:假设系统提示 + CLAUDE.md 合计 10K Token,单次任务追加 1K Token 用户输入:
| 场景 | 单次输入成本 | 100 次累积成本 |
|---|---|---|
| 无 cache | 11K Token × 100 = 1100K Token | 1100K Token 全价 |
| 有 cache(命中率 99%) | 第 1 次 11K Token,后 99 次约 1K Token + 10K cached | 11K + 99 × 1K + 99 × 10K × 0.1 = 209K Token-equivalent |
数据计算公式中 cached 部分按 1/10 计费。100 次任务的实际成本从 1100K 降至约 209K Token——节省约 80%。这条收益在批处理、CI/CD 自动化、Agent 调用场景中尤为显著。
六、PM 与工程师的上下文管理风格
6.1 PM 视角:用结构化文档代替散乱描述
PM 经常要把需求传达给 Claude(例如让 Claude 翻译为技术任务)。常见反模式是把多个相关需求杂糅在一段散文中——Claude 提取信息时可能漏掉关键约束。
正例:把需求拆成结构化文档:
## 功能:批量导入用户
### 输入
- CSV 文件,最大 10 MB
- 字段:姓名、邮箱、手机号
### 业务规则
- 邮箱必须唯一
- 手机号可重复
- 姓名长度 2-50 字符
### 性能要求
- 1 万条记录 30 秒内完成
- 失败记录不阻塞成功记录
### 错误处理
- 单条记录失败:跳过、记录日志
- 系统错误:整体回滚
### 验收标准
- 导入成功率 ≥ 99%
- 失败原因可追溯
让 Claude 基于结构化文档生成代码,远好于散文式描述。
结构化文档的"信息密度优势":把同一份需求用散文表达,可能需要 800-1500 字符;用结构化清单表达,往往只需 300-500 字符。信息密度高 2-3 倍意味着 Claude 在更少 Token 内获得同等清晰度——这是 Token 经济学最直接的体现。
PM 团队可以围绕这条规则建立"标准需求模板"——所有传给 Claude 的需求都按统一模板组织,包括但不限于:功能说明、输入输出契约、业务规则、性能/容量约束、错误处理路径、验收标准、不在范围("什么不做")。模板化的另一个好处是 Claude 解读速度快——它在数千次类似格式的训练数据中学过这种结构,能精准提取每一栏的信息,不会因为表述风格不同而产生歧义。
6.2 工程师视角:用文件路径代替粘贴代码
错误示范:
[贴 5000 行 src/user.ts 全文]
请重构 createUser 函数,让它支持异步初始化。
正确示范:
请重构 src/user/factory.ts 的 createUser 函数,让它支持异步初始化。
背景:当前 createUser 是同步的,但我们需要在创建用户时异步调用 sendWelcomeEmail。
请先读 factory.ts 了解当前实现,再提议方案。
让 Claude 自己 Read 文件——它会读取最新版本,而你贴的版本可能已经过时。
6.3 跨角色协作:让 Claude 在角色间转译时保留关键上下文
PM 与工程师协作时,让 Claude 充当"转译层":
PM 写了以下需求:[贴 PM 的需求文档]
请把它翻译为:
1. 工程任务清单(带预估工时)
2. 依赖识别(前后依赖关系)
3. 风险点(PM 没明说但工程师需要警惕的部分)
转译过程中,请保留 PM 的所有约束(不要简化掉)。
转译输出后让 PM review——确保 Claude 没有遗漏任何业务约束。
转译过程中常见的"信息损耗模式":让 Claude 做角色转译看似省事,但实际操作中容易出现以下三类损耗——
- 业务约束被省略:PM 说"批量导入失败时不阻塞成功记录",Claude 转译为"批量导入有错误处理"——这种"概括式简化"丢掉了关键的语义。对策:在 prompt 中强调"逐条保留 PM 的所有约束,禁止概括"。
- 非功能需求被忽视:PM 关心可观测性("我们要能在仪表板上看到导入成功率"),但 Claude 容易把它当成"附加功能"而非"核心需求"。对策:在转译模板中显式列出"非功能需求清单"——性能、可观测性、可维护性、可扩展性。
- 隐性假设被丢失:PM 说"用户名长度 50 字符",但 PM 心里假设的是"中文 50 字符 = UTF-8 150 字节"。Claude 转译时可能直接写成"VARCHAR(50)"——数据库层就出了问题。对策:在转译完成后做一次"假设核对"——让 Claude 列出它的隐性假设,让 PM 逐一确认。
转译不是"压缩"。好的转译会把 PM 的散文式需求结构化,但不会简化。结构化与简化是两码事——前者让信息更易被工程师消化,后者会丢失业务关键性。这条区分需要 PM 与工程师在使用 Claude 转译时反复练习才能内化。
6.4 团队级"上下文卫生"约定
把上下文管理写进团队约定:
## 团队上下文卫生公约(v1.0)
1. 单次会话不超过 60-90 分钟,超过则结束、写状态摘要、开新会话
2. 不在 prompt 中粘贴大段日志/数据——预聚合再贴
3. CLAUDE.md 控制在 500 行以内,每月做减法
4. 大文件的修改用"读+精确编辑"而非"粘贴重写"
5. 切换主题时主动开新会话,而非延续旧会话
6. 高频任务封装为 Skills,减少重复 prompt
新人入职第一周读这份公约。半年后所有人都默会这套节奏,整个团队的"AI 协作 Token 效率"会显著高于不做约定的团队。
公约执行的"自检清单":把公约的每条规则转化为可观测的指标,每月在团队周会上 review——
| 公约规则 | 自检指标 | 健康基线 |
|---|---|---|
| 1. 会话长度 ≤ 90 分钟 | 单次会话平均时长 | < 60 分钟 |
| 2. 不贴大段数据 | 单次 prompt 平均长度 | < 5K Token |
| 3. CLAUDE.md ≤ 500 行 | CLAUDE.md 行数 | 200-400 行 |
| 4. 精确编辑 | Edit/Write 调用比 | Edit > 70% |
| 5. 切主题开新会话 | 单次会话主题数 | < 2 个 |
| 6. Skills 复用 | 每月 Skill 调用次数 | > 团队人数 × 10 |
每月输出一份"团队上下文健康报告",把指标可视化、把异常公开化。透明的指标比模糊的口号更能塑造行为——当工程师知道"我的会话平均长度本月超过 90 分钟"时,下个月他会自觉缩短会话;当 CLAUDE.md 行数膨胀时,团队会主动安排清理。
公约的"零成本启动法":很多团队在引入公约时陷入"完美主义陷阱"——花一个月起草、再花一个月讨论、最后无疾而终。建议改用"零成本启动法":
- 第 1 周:把 1-2 条最关键的规则贴在团队 wiki,不需要全员讨论。
- 第 2-4 周:观察实际效果,每周一次 5 分钟例会反馈。
- 第 2 个月:基于真实使用经验补充更多规则、淘汰不适用的规则。
- 第 3 个月:公约稳定,全员签字、贴上 wiki 第一页。
这种"小步快跑"的引入方式比"一次性完美起草"成功率高得多——因为公约的真正价值是"被真的执行",而不是"被设计得完美"。
总结
上下文不是"反正窗口大就够用"的资源,而是工程师必须主动管理的核心约束。本节给出的"窗口边界 → 内置机制 → 主动策略 → 反模式 → 缓存协同 → 角色协作"六部分,目标只有一个——让团队在 Claude Code 协作中保持稳定的高质量输出,避免落入"上下文塞满 → 注意力稀释 → 输出退化"的恶性循环。
最朴素的一条心法:上下文管理不是技巧问题,而是自律问题。一个习惯于"长会话乱塞"的工程师,无论给多大的窗口都会撑爆;一个习惯于"小任务、清边界、勤摘要"的工程师,即使在 32K 窗口的旧模型上也能高效协作。本节给出的所有工具与策略,都只是把这条自律变得更容易实践。
学习曲线的真实样貌:本人在多个团队推广这套方法论时观察到,工程师对上下文管理的接受度有一条相对一致的曲线——
- 第 1 周:抵触。"我以前直接贴日志一直这样工作,没出过事,何必学这套规则?"
- 第 2-4 周:被动遵守。规则贴在 wiki 上、PM 偶尔提醒,工程师勉强跟做但不情愿。
- 第 2 个月:开始体验收益。会话效率明显提升,自己开始主动应用部分技巧。
- 第 3 个月:主动倡议。开始在团队会上推荐"我发现这条很有用",从被动接受者变成主动布道者。
- 第 6 个月:内化为习惯。完全不需要 wiki 提醒,所有动作都符合上下文卫生规范。
这条曲线对每个人都成立,差异只在于"第 2 个月开始体验收益"是否真的发生——而这取决于团队是否在前 4 周给了他足够的"练习场"。学习上下文管理的最佳方式不是读文档,而是在压力相对小的真实任务中反复尝试。建议团队 leader 在新人入职第 1 周就让他们用 Claude Code 完成 2-3 个小任务,期间故意设置一些"会触发上下文问题"的场景(例如让他读大文件、写长会话),让新人亲身感受问题,再引导他们应用解决方案。这样形成的肌肉记忆远比死记硬背规则更牢固。
下一节 7.4 是"心法层"的最后一节——Boris Cherny 的 9 条实战心法。这 9 条心法是 Anthropic Claude Code 团队多年沉淀的精华,涵盖从提示词到上下文、从权限到协作的全方位智慧。把 7.1、7.2、7.3 与 7.4 四节合起来,就构成了"AI 协作时代的工程师心法体系"。
留给读者的两个习题:
- 在你当前项目里,给自己设定一个"上下文预算"——下一次会话前明确写出"这次会话最多 20K Token"。完成后回看,看实际用了多少。
- 给团队写一份"上下文卫生公约",至少包含 5 条规则。在团队会议上讨论后正式签字、贴进 wiki。
这两个习题做完,你会发现"上下文管理"从抽象概念变成了团队的肌肉记忆。
延伸阅读
- Anthropic Claude Code 官方文档 — 上下文窗口、自动压缩、Skills 全览
- Anthropic Prompt Caching 官方文档 — Prompt Cache 工作原理与最佳实践
- Lost in the Middle: How Language Models Use Long Contexts (Liu et al., 2023) — 长上下文中模型注意力分布的经典研究
- Anthropic: Contextual Retrieval — RAG 与上下文检索的最佳实践
- LangChain 官方文档:上下文管理 — LangChain 在上下文工程中的实践
- OpenAI: GPT-4 长上下文白皮书 — GPT-4 在长上下文下的能力评估
- Pinecone: Vector DB 与长上下文 — 向量数据库辅助上下文管理
- Sanjay Krishnan: Token-efficient AI applications — 学术界关于 Token 效率的研究
- Anthropic Trust & Safety — Claude 系列的隐私与上下文保留政策
- Boris Cherny: Claude Code 工程心法(YouTube 公开演讲) — Anthropic 内部实践分享
- Awesome Claude Code — 社区维护的 Claude Code 资源集
- Hugging Face: Long Context Benchmarks — 长上下文模型的开源 benchmark