上下文窗口一旦被填满,最危险的不是”报错停摆”,而是输出质量悄悄变差——模型开始忘记早先读过的文件、复述已经讨论过的决策、对边缘条件含糊其辞。在 Claude Code 这类以工具调用为主的编程助手场景里,窗口同时承担系统提示、用户消息、模型回复、文件读取、Shell 输出五路输入,是最稀缺的运行时资源,也是最容易被低估的工程约束。
一、200K 窗口并不是”很大”
以 Sonnet 4、Opus 4 为例,单次会话窗口 200K token。听起来不少,但实际工程会话吃窗口的速度远超直觉。常见的几路消耗大致如下:
| 输入来源 | 单次典型 token 量 | 触发频率 |
|---|---|---|
| 系统提示与工具 schema | 约 16K-20K | 每次会话首轮 |
CLAUDE.md / 项目说明 |
约 1K-8K | 每次会话首轮 |
| MCP 服务器定义 | 每个约 2K-5K | 每次会话首轮 |
| 文件读取(每文件) | 约 0.5K-15K | 按需 |
| Bash / 测试输出 | 约 0.1K-5K | 高频 |
| 模型推理与回复 | 约 0.2K-2K | 每轮 |
| 检索 / 搜索 / 差异 | 约 1K-8K | 中频 |
一轮跑下来 30K-50K token 是常态。10-15 轮后窗口就接近上限。代码库稍大、命令稍多,15-20 分钟就能打满。
二、填满之后的三类后果
后果按可观测性从”看得见”到”看不见”排序:
- 自动压缩触发。窗口使用率到阈值(公开资料里常见说法是 83% 左右,不同模型有差异)时,Claude Code 会自动调用压缩:让模型把历史摘要成短段落,丢掉原文细节,腾出空间继续。官方明确”压缩不可配置、不可关闭”。
- 硬上限锁死。如果自动压缩仍不够,再继续追加会触发硬上限——主循环停摆,必须人工
/clear才能恢复,期间会弹出”resume”对话让用户二选一(继续或重开)。 - 质量静默退化。这是最危险的一种。窗口还没硬满、但已超载时,模型会更倾向于给含糊的答案、复述已问过的信息、重新读它已经读过的文件——表面看像”模型变笨了”,本质是它已经看不到完整上下文了。
三、为什么这是”最重要的资源约束”
相比订阅级的速率限制(5 小时窗口、周上限),上下文窗口是”单次会话级”且”与技术质量强绑定”的硬约束。三个原因让它比配额更值得关注:
- 速率限制可以”等”,上下文一旦被错误尝试污染,事后清理成本很高;
- 上下文不可购买:再贵的套餐也不能给单次会话扩到 1M token;带 1M 窗口的模型也仍是同一窗口,仍存在”上下文腐烂”问题;
- 上下文决定可解释性:审计、回溯、教学都依赖窗口里能还原的事实;压缩一旦发生,具体行号、精确错误信息、约束原话就会消失。
四、自动压缩的隐藏代价
压缩并不是”无损瘦身”,而是把 167K token 压到 2K-4K token 的摘要。公开资料反复提到三类典型丢失:
- 精确信息:行号、栈帧、字段名、错误信息原文几乎都进不了摘要;
- 中间状态:多步骤重构里某一轮得到的”精确函数签名”、端口号、临时分支名常被丢掉;
- 约束原话:会话早期写下的”不要改 /legacy/ 下任何文件”这类硬约束,容易被摘要改写成”避免修改遗留代码”。
压缩触发后模型的注意力也最差(业界俗称”上下文腐烂”),这也是为什么官方建议”在 1M 模型里也要主动 /compact 而不是等自动压缩”。
五、案例:两小时无人值守的崩塌路径
无人值守场景里,窗口填满引发的连锁反应比交互场景更糟:
- 模型持续工作 2-4 小时,窗口使用率越过阈值;
- 自动压缩触发,摘要生成后模型继续,但具体行号、栈帧等关键信息丢失;
- 跑着跑着进程进入 resume 弹窗(”Yes/No”二选一);
- 无人应答,进程既不退出也不超时,外部看像”还在跑”,实际已经停摆;
- 早上来检查,发现任务卡在 8 小时窗口里、原地未动。
六、可执行的防护步骤
- 每次会话开始先跑
/usage或/cost,确认基线; - 触及 60% 窗口预算时主动
/compact,并加引导词指明要保留什么、丢弃什么; - 长任务用
/clear切分,跨任务前用/rename命名方便回溯; - 大量工具输出用管道截断(如
npm test 2>&1 | tail -50),别让几 MB 的日志直接进窗口; - 把”模型从代码推断不出的硬约束”放
CLAUDE.md,避免在会话内反复复述消耗窗口。
七、与速率限制的边界
| 维度 | 上下文窗口 | 速率限制 |
|---|---|---|
| 范围 | 单次会话 | 跨会话、按套餐 |
| 触发后表现 | 输出质量下降或自动压缩 | 整段拒绝服务或冷却 |
| 恢复方式 | /clear 或 /compact |
等待或升级套餐 |
| 决定性因素 | 工具调用与文件读取量 | 累计 token 用量 |
| 工程重点 | 治理与隔离 | 排程与升级 |
八、用一行命令随时观察窗口占比
最直接的做法是把 npm test 这类长输出截断后再让模型看;下面给一个把 bash 长输出按行数截断、再喂回 Claude 的小工具脚本,挂在项目的 package.json 就能复用。
#!/usr/bin/env bash
# scripts/ctail.sh - 截断长输出,避免一次性吃光上下文
# 用法: ./scripts/ctail.sh <行数> <命令...>
LINES="${1:-50}"; shift
"$@" 2>&1 | tail -n "$LINES"
调用时把命令包一层:./scripts/ctail.sh 80 npm test。这样 Claude 看到的是 80 行总结而不是几兆字节的完整日志,窗口预算就被保住了。
常见问题(FAQ)
Q1:上下文满了 Claude Code 会报错吗?
一般不会报硬错,而是先自动压缩、然后质量下降,严重时才停摆等待 /clear。
Q2:自动压缩能用配置关掉吗?
不能,公开资料明确压缩不可配置、不可关闭,只能用主动 /compact 或 /clear 替代。
Q3:1M 窗口就不会撞墙了吗?
1M 仍受”上下文腐烂”影响,长会话里同样需要主动压缩与子代理隔离。