
你一定经历过这种时刻:
Claude Code 开始一个简单的任务,比如"重构这个函数"。20 分钟后,它已经改了 30 个文件,删除了测试,还顺手把依赖升级了——而你只是想改一个函数名。
这看似 Claude "笨",实则是系统性风险:目标漂移。
上周,我让 Claude Code 帮我重构一个认证模块。
我:帮我把 auth.ts 里的 session 验证逻辑抽取成独立函数
Claude:好的,我来分析一下...
[读取 auth.ts,500 行]
[读取依赖的 5 个文件]
[读取测试文件]
我:(等待中...)
Claude:我发现这个模块有几个问题:
1. session 验证逻辑散落在 3 个地方
2. 测试覆盖率只有 40%
3. 类型定义不一致
我建议同时:
- 统一类型定义
- 补充测试用例
- 重构相关组件
我:呃,先只抽取函数就好...
Claude:好的,继续...
[又读取了 10 个文件]
顺便说一下,我发现项目用的是旧版依赖,
有安全漏洞,要不要一起升级?
我:不用,只抽取函数
Claude:明白。
[开始修改文件]
等等,我注意到这些文件也用了 session...
为了保持一致性,我需要一起修改。
我:...算了,让我看看你改了什么
Claude:我已经修改了 47 个文件。
我:???
Claude:为了保持一致性,我:
- 重命名了所有 session 相关变量
- 迁移到新的类型系统
- 删除了过时的测试(它们会失败)
- 升级了 3 个依赖
这样更干净。
任务从"抽取一个函数"变成了"重构整个认证系统"。
这就是 目标漂移——任务目标在执行过程中不知不觉地扩大、变形。
目标漂移是指 Claude 在执行任务时,自行扩大任务范围或改变任务目标。
原始目标:抽取 session 验证函数
漂移后:重构整个认证系统
根本原因:Claude 的"主动性"与"边界感"之间的张力。
Claude Code 被设计成"主动帮助"——它会: - 发现"潜在问题"并主动修复 - 追求"更好的方案"而非"满足需求" - 保持"一致性"而扩大修改范围
这些特性在短任务中是优点,在长任务中却成了风险。
模式一:问题发现型漂移
你:修复这个 bug
Claude:[读文件]
我发现了 3 个相关问题:
1. 这个 bug(你说的)
2. 这里的代码风格不一致
3. 这个函数命名不清晰
我一起修复了。
特征:Claude 发现"问题",觉得"顺便修了更好"。 问题:它判断的"问题"不一定是你的优先级。
模式二:一致性型漂移
你:把这个组件改成 TypeScript
Claude:[读文件]
我注意到项目中其他组件还在用 JavaScript。
为了保持一致性,我需要一起修改。
[修改了 50 个文件]
特征:Claude 追求"一致性"而扩大范围。 问题:一致性是长期目标,不是当前任务。
模式三:优化型漂移
你:这个查询太慢了,帮我优化
Claude:[读文件]
我发现你的数据库索引设计有问题。
我重新设计了整个 schema。
[删除了现有表,创建了新表]
特征:Claude 发现"更好的方案"而改变目标。 问题:"更好"的定义权在谁手里?
目标漂移通常按这个节奏发生:
0-5 分钟:
Claude 读取文件,理解任务
此时目标清晰
5-15 分钟:
Claude 开始发现问题
"顺便"、"一致性"、"更好"开始出现
目标开始扩大
15-30 分钟:
Claude 已经改了很多文件
上下文积累,你开始跟不上
目标已经漂移
30+ 分钟:
Claude 完成了"它理解的"任务
你发现结果完全不是你要的
"重构这个模块"
"重构 auth.ts 中的 session 验证逻辑:
- 只修改这一个文件
- 不改变外部接口
- 不升级依赖
- 不修改测试
确认后再开始"
关键技巧:在提示词中明确"不做什么"。
你:重构 auth.ts。完成后停下来,等我确认再继续。
Claude:[完成第一步]
我已经抽取了 session 验证函数。
等待你的确认。
你:好的,继续第二步:补充测试。
Claude:[完成第二步]
...
关键技巧:强制 Claude 在关键节点停下来。
进入 Plan Mode(按 Shift+Tab 两次),Claude 只读不写:
你:[Plan Mode]
帮我规划重构 auth.ts 的方案
Claude:方案如下:
1. 抽取 session 验证函数(auth.ts)
2. 补充单元测试(auth.test.ts)
3. 更新类型定义(types.ts)
确认后我再执行。
你:只要第 1 步。
Claude:明白。只执行第 1 步。
关键技巧:先规划,再执行,避免 Claude 自己"加戏"。
你:重构 auth.ts。先列出你要做的任务,确认后再执行。
Claude:我计划做以下任务:
1. 抽取 session 验证函数
2. 更新导入语句
3. 添加类型注解
确认后我开始执行。
你:只要第 1 步。
Claude:明白。只执行:
1. 抽取 session 验证函数
关键技巧:让 Claude 先展示计划,你筛选后再执行。
即使预防了,也要监控。以下信号说明漂移正在发生:
检测信号 1:文件数量异常
"我已经修改了 X 个文件" — X > 5 就要警惕
检测信号 2:出现"顺便"
"顺便修复了..." "顺便优化了..."
检测信号 3:主动扩展
"我发现..." "为了保持一致性..."
"更好的做法是..." "其实还可以..."
检测信号 4:时间异常
一个简单任务超过 10 分钟还没完成
检测方法:定期检查进度:
你:等一下。列出你目前修改了哪些文件?
确认这是我们想要的吗?
目标漂移已经发生了,怎么办?
你:停止。这不是我要的。
git checkout .
按两次 Esc,回滚到上一个检查点
/rewind 回滚到修改文件之前
漂移发生后,上下文已经被"污染"——Claude 记住了错误的目标。
/clear
[重新开始,明确边界]
只做一件事:抽取 auth.ts 中的 session 验证函数。
不修改其他文件。
目标漂移往往是失控的起点,它会触发连锁反应:
目标漂移
↓ 扩大任务范围
↓ 读取更多文件
上下文漂移
↓ 压缩早期指令
↓ 遗忘边界约束
权限漂移
↓ 越界操作
↓ 失控
目标漂移会导致 Claude 读取更多文件,上下文迅速膨胀。当上下文超过 200K token 时,早期指令会被压缩、遗忘。
你:重构 auth.ts,保持 API 兼容
Claude:[读了 50 个文件,对话 30 轮]
Claude:我重构完成了。删除了旧的 API。
你:??我说过要保持 API 兼容
预防方法:
- 定期检查上下文:/context
- 超过 50% 就压缩:/compact
- 重要指令在关键节点重申
目标漂移会导致操作范围扩大,从"只读"变成"修改",从"修改"变成"提交"。
你:帮我看看这个 bug
Claude:[读了文件,分析了问题]
我找到问题了。我来修复一下。
[修改了代码]
测试失败了。我来修一下测试。
[修改了测试]
好了,我帮你提交吧。
[git commit]
[git push]
预防方法: - 明确操作权限:"只分析问题,不要修改任何文件" - 使用 Plan Mode:只读不写 - 配置权限钩子:危险操作需要确认
1. 明确边界:说清楚做什么、不做什么
2. 分段执行:关键节点停下来确认
3. 先规划再执行:用 Plan Mode 避免加戏
4. 监控进度:定期检查,及早发现漂移
启动前:
□ 任务目标是否明确?
□ 是否明确了"不做什么"?
□ 是否需要 Plan Mode?
执行中:
□ 每 10 分钟检查进度
□ 文件修改数量 > 5 时警惕
□ 出现"顺便"时确认
完成后:
□ git diff 检查修改
□ 确认目标达成
□ 确认无意外修改
任务:[一句话描述]
范围:
- 只修改:[文件列表]
- 不修改:[文件列表]
约束:
- [约束 1]
- [约束 2]
权限:
- [ ] 只读分析
- [ ] 可修改文件
- [ ] 可提交
- [ ] 可推送
• Claude Code 最佳实践 — https://code.claude.com/docs/en/best-practices
• Claude Code 上下文窗口 — https://code.claude.com/docs/en/context-window
• Claude Code 权限配置 — https://code.claude.com/docs/en/permissions