先说结论:按这个顺序救,别一上来就 /clear
markdown
1. 退出进程 → claude --resume 重开(带上调小的输出预留)
2. 重开后立刻 /compact
3. 还是 400 → /clear,然后靠重建文档接续(会话 JSONL 不会丢)
下面是一次真实事故的完整复盘:报错原文、为什么 /compact 也救不了、怎么预防。
事故现场
跑着一个长任务的 Claude Code 会话,突然所有请求都挂:
vbnet
API Error: 400 This model's maximum context length is 1048576 tokens.
However, you requested 1058665 tokens (930665 in the messages, 128000 in the completion).
拆开看这行数字:
- 1048576 = 模型上限(deepseek-v4-pro,1M 上下文)
- 930665 = 消息本身
- 128000 = 预留给输出的空间
- 930665 + 128000 = 1058665 > 1048576,超了 1 万 token
关键是:超限之后,连 /compact 都报同样的 400。
为什么 /compact 也救不回来
很多人以为 /compact 是"本地截断"------不是。
/compact 的工作方式是:把整份对话记录发给模型,让它写一份摘要。上下文已经超限,这份"整份记录"同样发不出去,于是:
bash
请求超限 → 400
/compact 需要先发全量 → 也 400
→ 死锁
这就是为什么必须"先降需求,再压缩"------不能指望压缩自己跳出来。
根因是三个叠加的
| # | 原因 | 说明 |
|---|---|---|
| 1 | 模型硬上限 | 消息 + 输出预留 > 上下文上限,物理上发不出去 |
| 2 | 自动压缩没兜住 | 配置里把压缩窗口顶到了模型上限(1M),等于没留余量------压缩还没触发,墙先撞上了 |
| 3 | /compact 同病 | 它也要发全量,超限时一起失败 |
第 2 条最坑:压缩窗口设成 1M,看起来"最大化利用上下文",实际是把安全带拆了。
三步处置
第 1 步:退出重开 + 调小输出预留
环境变量只在进程启动时读取,所以在原会话里改配置没用。退出后用 --resume 重开:
bash
export CLAUDE_CODE_MAX_OUTPUT_TOKENS=65536 # 输出预留 128K → 64K
claude --resume
效果:930K 消息 + 64K 输出 < 1M,会话恢复可用。第一步不做别的,先让它能发出请求。
第 2 步:立刻 /compact
恢复后马上压缩,把上下文压回安全水位,然后正常继续。
第 3 步:还不行就 /clear(数据不丢)
如果 resume 后仍 400,/clear 清空。别怕丢东西:
- 会话 JSONL 完整保留在
~/.claude/projects/<project-slug>/ - memory 文件(
~/.claude/projects/<project>/memory/)不受/clear影响 - Claude Code 会自动重读
CLAUDE.md/AGENTS.md重锚
预防:两个配置就够
改 ~/.claude/settings.json(改前先备份):
json
{
"env": {
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "800000",
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "65536"
}
}
- 压缩窗口 1M → 800K:消息到 80 万就自动压缩,给输出留足余量
- 输出预留 128K → 64K:直接让出 64K 给消息
注意:env 只对新启动的进程生效,改完要退出重开。
改完的效果可以自己验证------/context 会显示类似:
makefile
Model: deepseek-v4-pro Tokens: 358.2k / 800k (45%)
分母从 1M 变成 800k,说明配置生效了。
爆了以后怎么快速重建上下文
这是比"救回来"更有价值的部分:让新会话靠文档重锚,而不是靠超长上下文。
① 从三处提取事实
memory/*.md:Claude Code 自己记的规则和结论- 会话 JSONL 尾部:最近的用户消息 + 工具调用
- 工作区文档:项目里已有的说明
② 写成一张"重建文档",固定五段
markdown
1. 身份与恢复路径
2. 必须遵守的规则
3. 刚完成的工作
4. 进行中的事与待回答的问题
5. 文档与记忆指针
③ 从 JSONL 里提取关键信息(脚本)
python
import json
path = "/home/zhms/.claude/projects/<project-slug>/<session-id>.jsonl"
users, tools, asst = [], [], []
with open(path, encoding="utf-8", errors="replace") as f:
for line in f:
try:
d = json.loads(line)
except Exception:
continue
t, msg = d.get("type"), d.get("message") or {}
c = msg.get("content")
if t == "user":
if isinstance(c, str):
users.append(c)
elif isinstance(c, list):
users += [p["text"] for p in c if isinstance(p, dict) and p.get("type") == "text"]
elif t == "assistant" and isinstance(c, list):
for p in c:
if not isinstance(p, dict):
continue
if p.get("type") == "text":
asst.append(p["text"])
elif p.get("type") == "tool_use":
tools.append((p.get("name"), json.dumps(p.get("input", {}), ensure_ascii=False)[:200]))
for u in users[-20:]:
print("-", u.replace("\n", " ")[:200])
for n, s in tools[-30:]:
print(f"[{n}]", s.replace("\n", " ")[:150])
for a in asst[-5:]:
print(">", a.replace("\n", " ")[:300])
这次事故的会话文件 18MB,里面有 156 条用户消息、2616 条助手回复、1113 次工具调用(光 Bash 就 783 次)------靠这个脚本能快速捞出"刚才在干什么"。
日常三个习惯
/context常看 :到 80 万就主动/compact一次,别等报错- 结论落盘 :长任务中途把结论写进
docs/或 memory,新会话靠文档重锚 - 定期清老会话 :
~/.claude/projects/**/*.jsonl会持续膨胀,确认 memory 已沉淀后清理
版本与时效性
| 项 | 值 |
|---|---|
| Claude Code 版本 | 2.1.308 |
| 事故日期 | 2026-11-02 |
| 模型 | deepseek-v4-pro(1M 上下文) |
| 提醒 | 上下文管理与压缩策略随版本变化,升级后先跑一次 /context 确认窗口数值 |