使用 Claude Code 修复遗留代码时节省 80% 会话 Token 的隔离规则
当工作年限不满 1 年的独立开发者将 Claude Code 引入庞大的遗留代码库时,不到 1 小时 Token 预算就会见底。公司里没有资深前辈可以询问,在仅熟悉基础 CLI 命令的情况下打开终端,迎接你的将是源源不断的信用卡扣款提醒。
Claude Code 不会在服务器上保留对话状态。系统提示词、项目配置文件 CLAUDE.md、累积的对话历史以及工具调用结果会在每一轮对话中被打包成单个有效负载(Payload),重新发送给 Anthropic API。在会话开始后的第 12 轮,Token 数量通常维持在 15,000 左右,但当智能体(Agent)开始探索、读取构建产物或数万行日志时,有效负载瞬间就会膨胀到 80,000 Token。一旦超过 610 轮,每轮往返的 Token 就会达到 120,000 到 200,000 之间。这是一个按轮次以复利计费的结构。
查看 Anthropic 官方的提示词缓存单价,原因会更加清晰。如果保持相同的命名前缀上下文,只需支付基础输入 Token 10% 的费用。相反,如果智能体不规则地读取数万行代码导致缓存前缀失效,则会产生基于 5 分钟 TTL 的 1.25 倍新缓存生成费用。这就是为什么仅仅进行几次搜索,就会产生一笔个人难以承受的高昂费用。
.claudeignore 不起作用
许多开发者在根目录下创建 .claudeignore 文件后便安心下来。从结论上讲,Claude Code 官方的 CLI 引擎中并不存在这样的配置文件。如果在 CLAUDE.md 中写下“不要读取日志文件夹”,模型也会在它认为有必要时直接忽略。
要在引擎层面物理切断智能体对文件的访问,必须使用 .claude/settings.json 文件中的 permissions.deny 设置。
首先在项目根目录的 .claude/settings.json 中统一排除构建产物和安全文件。
json { "permissions": { "deny": [ "Read(./.env*)", "Read(./secrets/**)", "Read(**/node_modules/**)", "Read(**/dist/**)", "Read(**/build/**)", "Read(**/coverage/**)", "Read(**/target/**)", "Read(**/*.log)", "Read(**/*.map)", "Read(legacy-backups/**)", "Edit(**/dist/**)", "Write(**/dist/**)" ], "ask": [ "Bash(git push *)", "Bash(npm publish)", "Bash(rm -rf *)" ], "allow": [ "Read", "Edit", "Bash(npm test)", "Bash(npm run lint)", "Bash(git status)", "Bash(git diff *)" ] } }
为了防止在处理后端逻辑时顺便抓取前端代码,可以单独配置仅限本地的设置文件 .claude/settings.local.json。
json { "permissions": { "deny": [ "Read(apps/web/**)", "Read(frontend/**)", "Read(public/**)", "Edit(apps/web/**)", "Write(apps/web/**)" ] } }
还必须防止智能体通过 cat 或 head 等 Shell 命令将大型日志直接倾倒到终端中。可以在 .claude/settings.json 中挂载 PreToolUse 钩子来预先拦截命令。
json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/block-large-reads.sh"] } ] } ] } }
创建 .claude/hooks/block-large-reads.sh 文件并通过 chmod +x 赋予其执行权限。
`bash
#!/usr/bin/env bash
PAYLOAD=(cat)COMMAND=(echo "$PAYLOAD" | jq -r '.tool_input.command // empty')
if echo "$COMMAND" | grep -Eq '(cat|head|tail|less)\s+.*(.log|.map|.lock|dist/|build/)'; then
echo "检测到大文件的直接输出,已中止执行。" >&2
exit 2
fi
exit 0
`
当在操作系统进程级别返回退出码 2 (Exit code 2) 时,智能体的文件输出会立即停止。通过阻止不必要的文件扫描,可以将初始轮次的 Token 消耗量降低一半以上。
禁止完全重写文件,按函数单位传递
如果为了修改超过 1,000 行的遗留文件中的某个变量而允许重写整个文件,不仅会产生 Bug,还会浪费输出 Token。Claude Code 内部区分了用于覆盖文件的 Write 工具和仅替换特定字符串块的 Edit 工具。
必须将修改规则固化到项目根目录的 CLAUDE.md 中。
`markdown
Code Modification Constraints
- 绝对不要重新编写整个文件 (Write)。
- 必须仅使用 Edit 工具 (old_string -> new_string) 更改需要修改的最小单位。
- 修复 Bug 时,请勿随意更改周围代码的格式或空格。
- 在完成工作前检查 git diff,验证是否仅包含预期的更改。
`
与其将整个大型文件交给智能体,不如提取出目标函数。这是一个使用 AST 解析器工具 ast-grep 的 Shell 脚本 (extract-func.sh)。
`bash
#!/usr/bin/env bash
TARGET_FILE=1FUNCNAME=2
if [ -z "TARGETFILE"]∣∣[−z"FUNC_NAME" ]; then
echo "用法: ./extract-func.sh <文件路径> <函数名称>" >&2
exit 1
fi
if command -v sg &> /dev/null; then
sg run --pattern "function FUNCNAME($$$ARGS)$$$BODY""TARGET_FILE"
else
LINE_START=(ctags−x−−c−kinds=f"TARGET_FILE" 2>/dev/null | grep -w "$FUNC_NAME" | awk '{print 3}')
if [ -n "LINE_START" ]; then
sed -n "LINESTART,((LINE_START + 100))p" "$TARGET_FILE"
else
grep -n -A 60 "function FUNCNAME""TARGET_FILE"
fi
fi
`
仅将提取出的函数或已暂存的 git diff 通过无头模式 (claude -p) 传递并请求修改。
`bash
仅注入特定函数以提取修改后的代码
./extract-func.sh src/billing.js processRefund | claude -p "请仅输出用于修复上述函数计算错误的 Edit 专用替代代码块 (new_string)。"
仅验证已暂存的更改
git diff --staged src/services/OrderService.js | claude -p "请指出此 diff 中可能产生的并发缺陷或空指针引用风险。"
`
如果不输入整个源代码,而是只输入 50~100 行的切片(Slice),则可以将每轮的 Token 消耗量减少近 90%。
使用 HANDOFF.md 保存并清空会话状态
没有理由在一个会话中拖延太长时间。随着对话历史的累积,每轮必须支付的基础费用也会不断增加。当 Claude 模型达到约 967,000 个 Token 时,虽然支持自动总结对话历史的 /autocompact 功能,但在系统缩减代码的过程中,经常会丢失重要的参数或边缘情况(Edge Case)上下文。因此必须手动清空上下文。
在终端中使用三个内置命令来检查当前状态:
/context:查看系统提示词和对话历史所占用的内存比例。
/usage:检查会话 Token 使用量和套餐额度消耗率。
/cost:检查当前会话累计产生的实际美元费用。
如果 Token 超过 100,000 个或者某个具体的工作任务已经完成,请在关闭会话前指示 Claude Code 编写 HANDOFF.md。
text 请按照以下格式将当前会话的工作状态记录到项目根目录的 HANDOFF.md 中: Goal: 工作目标及目标模块 Current Progress: 已修改的文件及具体行号 What Worked: 已验证通过的逻辑及通过的测试 What Failed: 失败的方法及注意事项 Immediate Next Step: 下一个会话开始时应立即执行的单个任务
记录完成后,使用 /clear 命令清空上下文窗口。开启新会话,并仅传递上一个会话的摘要。
text 请阅读 HANDOFF.md 文件,并从 Immediate Next Step 项开始继续工作。请勿尝试之前失败的方法。
如果因为同一个错误无意义地打转超过 3 次,必须立即按下 Escape 键停止。如果在情况尴尬、难以完全清空会话时,可以使用 /rewind 返回到正常运行的上一轮。由于 /rewind 保留了已建立的系统前缀提示词缓存,因此可以返回到正常分支而无需支付额外的缓存写入费用。
各防御层级的控制水平
| 防御层级 |
设置位置 |
控制水平 |
实测 Token 节约效果 |
| 骨架文件过滤 |
.claude/settings.json (permissions.deny) |
CLI 引擎强制执行 |
阻止每会话 50%~80% 的初始扫描 Token |
| Shell 命令防火墙 |
PreToolUse Hook (block-large-reads.sh) |
操作系统进程拦截 (Exit 2) |
100% 防御日志及打包文件的大规模输出 |
| 上下文切片 |
ast-grep, git diff 流水线 |
输入范围限制 |
减少每轮文件分析与修改 90% 的 Token |
| 会话生命周期管理 |
/context, /clear, HANDOFF.md |
手动状态持久化 |
减少 60% 以上会话后半段累积的复利 Token 费用 |
通过 .claude/settings.json 阻止不必要的路径,并坚持只传递切片代码而非大型文件的规则,才能在一人开发环境中让 Claude Code 真正成为实用的开发工具。