上下文窗口由系统提示、项目级 CLAUDE.md、会话记忆、用户消息、工具调用与工具返回结果、模型输出六部分共同组成,按”固定层 + 动态层”两层模型拼接;容量逼近时主循环触发自动压缩(compaction),把历史折叠成结构化摘要并腾出空间,让长任务得以继续跑。理解组成与压缩触发点,是控制 token 成本与避免”context rot”的前提。
一、上下文窗口的两层结构
Claude Code 沿用 Anthropic 主流大模型的”固定系统段 + 动态对话段”拼接模型。每次发往 API 的请求都包含两段,固定段由系统提示、CLAUDE.md、Hooks 注入内容、会话记忆等组成,每轮开销几乎一致;动态段随对话轮次线性增长,最终会触顶。
| 组成部分 | 类别 | 大致 token 量级 | 能否压缩 |
|---|---|---|---|
| 系统提示与工具定义 | 固定 | 约 3K | 否 |
| CLAUDE.md(项目级) | 固定 | 数百到 8K | 否(可手动瘦身) |
| Hooks 注入与 Memory | 固定 | 数百到 2K | 否 |
| 会话历史(用户+助手) | 动态 | 随轮次线性增长 | 是 |
| 工具调用与返回结果 | 动态 | 单次可达数千 | 是(压缩时折叠) |
| 当前用户消息 | 动态 | 单次数十到数百 | 否 |
固定段每轮相同、靠 Prompt Cache 复用计费,动态段才是真正吃光窗口的主因。读一个大文件、跑一次 npm test、让子代理返回一段总结,都会把上千 token 塞进动态段。
二、容量在什么阈值会触发自动压缩
Claude Code 主循环(Master Loop)持续监控当前上下文占比,到达阈值后会执行一次自动压缩,把旧的会话历史折叠成摘要,丢弃冗长的工具返回,保留任务进度、关键决策、已读文件路径等结构化要点。
- 监控阶段:每次请求前后,主循环对比当前 token 数与窗口上限;
- 触发阶段:达到容量阈值时,调度一次额外的模型调用做”自摘要”;
- 替换阶段:原始对话历史被摘要覆盖,文件读取与命令输出细节丢失;
- 续跑阶段:下一轮请求基于摘要继续,工具结果按需重新读取。
2.1 容量阈值的分级参考
业界对长上下文窗口的容量管理有共识的分级:0–50% 推理最稳;50–70% 出现轻微精度损失;70–90% 注意力被稀释、模型开始遗忘早期规则;90% 以上出现幻觉、规则被忽略。Claude Code 遵循类似分级,自动压缩落在后段触发。
2.2 一次会话的 token 累积形态
把上下文当作”可花钱的预算”会更直观:第 1 条消息 5K,第 3 条 4K(累计约 18K),第 5 条 3.5K(累计 35K),第 8 条 4K(累计 65K)……每条新消息都要把历史全部重发一次,token 增长呈典型累积曲线。
三、压缩触达后会发生什么
自动压缩不是”扩窗口”,而是”换摘要”,因此有可见代价。
- 缓存失效:压缩改变了消息前缀,Prompt Cache 必须重新生成,下一轮成本上升;
- 信息不可逆:被压缩的旧文件内容、命令输出、调试日志永久消失,需要时只能重新读;
- 工具结果被截断:长 bash 输出、测试日志往往最先被折叠成几行总结。
需要让压缩保留”前情提要”时,可用 /compact 手动触发并附指令,例如 /compact focus on the auth refactor, drop the test debugging,把摘要聚焦到主题上。
四、四种主流的容量管理动作
压缩只是兜底,更稳的做法是把窗口管理前移到工作流里:
/clear:彻底重置对话历史到 0 字节,切换任务或模型开始胡言乱语时使用;/compact:触发结构化摘要,保留关键决策与文件路径;- 子代理(Subagent):把读大文件、跑日志分析等重活外包给独立上下文,主体只接收摘要;
- 渐进式披露:通过 Skills、MCP、路径作用域规则按需加载,避免一次性塞满。
实战中常见组合是”主会话压缩 + 子代理隔离 + 路径作用域规则”,三者叠加能把一次长任务稳稳控制在安全水位。
五、把容量控制在安全水位的具体做法
把窗口管理拆成可执行步骤,比靠”感觉”省事:
- 启用
/status与/context实时观察Ctx(u)占比与 token 分布; - 命中黄色区间(50–70%)后,改用 Grep 精确定位文件行号,避免整文件读取;
- 进入橙色区间(70–90%)立即
/compact一次,给摘要加上”保留哪些决策、丢弃哪些调试”的指令; - 触及红色区间(90% 以上)执行
/clear并写一份交接简报给新一轮会话; - 重型读取(架构总览、依赖图)通过 Task 工具交给子代理,主会话只拿结论。
六、压缩机制的局限与替代
压缩对”事实性回忆”很弱,对”决策与方向”很强。如果一项关键决策(接口约定、命名约束、模块边界)被压缩丢掉,下一轮模型会从摘要里”再发明”一套,造成隐性偏移。生产环境里,更稳的姿势是把它写进 CLAUDE.md 这样的固定层——固定段即使压缩也不会被覆盖。
子代理是另一个常被低估的方案:把”读懂这个 50 万行仓库”这种重活丢给子代理,主体只接收结构化结论,相当于把预算压力转嫁出去。
七、用脚本预估上下文是否装得下
写一段粗略的 token 估算脚本,能在执行大批量文件读取前预警。下面这段 Python 用字符/4 估算 token 数,能识别”快要装不下了”的批操作。
# estimate_tokens.py —— 粗略 token 预算检查(字符/4 近似)
import os, sys, pathlib
def est_tokens(text: str) -> int:
# 中英文混合按字符数 / 4 估算;实际请用 tiktoken
return max(1, len(text) // 4)
def scan(root: str) -> dict:
total = 0
by_file = []
for p in pathlib.Path(root).rglob("*"):
if not p.is_file():
continue
# 跳过二进制与大文件
if p.suffix in {".png", ".jpg", ".pdf", ".zip"}:
continue
try:
content = p.read_text(encoding="utf-8", errors="ignore")
except Exception:
continue
t = est_tokens(content)
total += t
by_file.append((str(p), t))
by_file.sort(key=lambda x: -x[1])
return {"total": total, "top": by_file[:10]}
if __name__ == "__main__":
root = sys.argv[1] if len(sys.argv) > 1 else "."
budget = int(sys.argv[2]) if len(sys.argv) > 2 else 200_000
r = scan(root)
print(f"总 token 估算: {r['total']:,}")
print(f"窗口预算: {budget:,}")
print(f"占比: {r['total']/budget:.1%}")
print("Top 10 大文件:")
for path, t in r["top"]:
print(f" {t:>8,} {path}")
跑法示例:python3 estimate_tokens.py ./src 200000。占比超过 70% 就该考虑分批读取或交给子代理,避免一次性把上下文塞爆。
常见问题(FAQ)
Q1:上下文窗口到底指什么?
模型生成下一条回复时能”看见”的所有 token,包含系统提示、会话历史、工具输入与结果。
Q2:自动压缩会丢东西吗?
会。被压缩的旧消息、工具返回细节永久丢失,只保留结构化摘要与关键决策。
Q3:怎么判断该不该手动 /clear?
当模型开始忽略 CLAUDE.md 规则、重复犯同样错误或要求重读已读文件时,立刻 /clear。