ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code用不好?问题不在工具,而在两个关键误区

Claude Code用不好?问题不在工具,而在两个关键误区

一开始接触 Claude Code 的那两周,我几乎在每一个深夜都对着终端怀疑人生:让它重构一个类,它把同文件里另一段业务逻辑一并“顺带优化”了;让它补测试,它在测试用例里自作主张改掉了被测试函数的返回值;让它跑一次构建,它甚至会在提交信息里替我写下“修复多个潜在问题”这种我根本不敢直面的表述。

直到后来我请一位擅长结对编程的同事帮忙诊断同一个需求,对方看完我的操作之后只问了三个问题:改哪个文件?边界在哪?哪些东西碰都不能碰?那一刻我才反应过来——问题根本不在 Claude Code,而在我把它当成了一个“能读懂我心思的自动程序员”,而不是一个“需要你用工程化方式去协作的结对搭档”。

这篇文章不会有让人眼前一亮的魔法技巧,但如果你也正在被 Claude Code 的“不听话”折磨,或者刚打开它没几天就想卸载,我建议你先花十分钟看完这两个最常见的理解误区,应该能省下好几个晚上的折腾时间。

1. 误区一:你把它当“命令执行器”,只发指令不给上下文

很多人会用得很痛苦,是因为把 Claude Code 当成了 IDE 里的终端插件,指令越短越好:“把登录逻辑改一下”“这个报错处理一下”“把这个页面优化一下”。

短指令在传统工具面前没问题,但 Claude Code 是对话式编码代理,它根据你的上下文、工作区文件和模型自身对任务的推演来生成改动。你给它一个含糊的指令,它只能去猜——而它猜的方向,往往和你的心智模型不一样。

1.1 你以为的“对话式编程”,本质是“结对编程”

把 Claude Code 理解成“下面这个命令行里住着一位远程协作者”会更准确。真正的结对程序员不会在你只说一句“你把登录改一下”的时候就直接动手,他一定想搞清楚几个问题:

  • 是改前端登录页、后端登录接口,还是改鉴权中间件?
  • 是修 bug,还是做需求变更?
  • 旧行为是必须保留的,还是可以替换的?
  • 哪些相关联的模块也在影响范围内?

Claude Code 也一样。它不是全知全能的,它每次能确认的信息主要来自三块:当前会话里你说了什么、工作区里索引到的文件内容、以及模型自身训练时对通用代码的理解。你给它越精确的“任务边界”,它越不容易跑偏。

我有一个实操习惯:任何一条任务指令,至少包含“文件路径 + 目标行为 + 禁止改动项”三要素。比如:

在 src/services/AuthService.ts 中修改 login 方法的逻辑: 1. 保留原有 validatePassword 的调用顺序不变 2. 在 token 过期时返回 { needRefresh: true } 3. 不要动 AuthService 里的 refreshToken 方法 4. 不要动同目录下的 userRepository.ts

这种写法看起来啰嗦,但实际执行效率和准确度都高得多。因为“不要让工具猜”这件事,本身就是工程素养的一部分,就像你给团队新人派活一样。

1.2 缺失上下文导致的一连串“翻车现场”

我见过最典型的崩溃现场是这样:某次我让它“给订单列表页加一个筛选状态”,它很开心地把订单查询接口的参数改了,顺手把状态枚举也改了,还在类型定义里加了两个无关字段。

原因很简单:我只描述了页面效果,没有说清“筛选状态是前端本地过滤还是后端查询参数”,也没有说明“订单状态枚举在枚举文件里,其他地方引用很多,不能改”。它的补全逻辑只是基于“当前对话 + 文件索引”做最合理的猜测,而它猜测的“合理”,在你眼里可能就是灾难。

这类问题在真实项目里会被放大:因为项目越大,关联文件越多,它越容易从你觉得无关的地方“助攻”一下。

所以现在只要涉及跨文件改动,我都会在任务里明确写出影响范围,偶尔还会加一条“如果发现需要在 X 之外修改其他文件,请先停下来问我”。这是成本极低但收益极高的一条约束。

1.3 把“帮我看一下”这种模糊请求变成可执行确认单

大多数新人爱说“帮我看一下这个报错”,然后贴一段日志。Claude Code 确实能读日志,但“看一下”本身不构成任务。我习惯把这类请求拆成“问题描述 + 我尝试过的排查 + 要求它输出的内容”三段式:

报错信息:构建时 Module not found: Can't resolve './config' 所在文件:src/App.tsx 第 3 行引入 我确认过:src/config 目录存在,且 index.ts 已导出配置对象 请帮我: 1. 检查 import 路径是否与实际文件路径大小写不一致 2. 检查 tsconfig 中 paths 别名配置是否有缓存或路径错误 3. 输出问题原因 + 最小改动方案,不要直接改代码,先给我方案

注意这里最后一条“先给我方案”很关键,这相当于把一个自动执行的工具,切换成了“先对齐、再动手”的协作模式。你把它当成需要确认清单的同事,它回馈给你的就是可预期的行为。

2. 误区二:你完全跳过了“上下文工程”,把它当成零门槛的 AI 程序员

第二个更大的误区,是以为 Claude Code 开箱就能“懂你的项目”。这是被通用聊天助手惯出来的直觉:跟聊天助手说话,它天然会写代码;那跟 Claude Code 说话,它不是应该更懂代码吗?

单次对话它确实懂代码,但对“你的业务为什么要这么写”“你的项目有哪些不能动的历史包袱”毫无概念。同一个getUserInfo,在你的项目里可能是返回加密后的脱敏数据,在另一个开源项目里可能就是直接查表。它默认按照通用最佳实践去猜,猜错了你还觉得它笨。

2.1 从来不建项目词典,却指望它理解业务规则

Claude Code 支持在工作目录里放CLAUDE.md,这本质上就是一份给代理看的“项目工作手册”。它不是给你写文档用的,而是为了让你在对话里只描述增量需求,把项目共识、编码规范、禁忌清单一次性固化进去。

我之前不愿意维护这份文件,理由是“多一层东西要同步”。直到连续两个新会话里它都把同一个常量改错了,我才真正花半小时把项目里最重要的约定写了进去。

一份真正有用的CLAUDE.md不需要长篇大论,它更像一份给临时工看的上岗须知:

# 项目约定 ## 后端 - 所有接口返回格式统一为 { code, message, data },禁止在业务里直接返回裸对象 - 数据库操作一律走 storage/ 目录下的 Repository 层,禁止在 service 里直接写 SQL - 不要修改 migrations/ 目录下任何已提交的文件,如需变更 schema,必须新增迁移文件 ## 前端 - 页面组件放 pages/,通用组件放 components/ - 状态管理禁止直接修改 state,一律通过 actions 提交 mutation - 常量命名使用全大写下划线,所有魔法数字必须提取到 constants/ ## 禁止事项 - 禁止在代码中引入新的全局样式 - 禁止把测试文件里的 mock 数据直接用于生产环境 - 禁止为了通过 lint 而关闭规则

写完之后,新会话里的行为稳定性提升非常明显:改错字段的次数少了,跨层写 SQL 的情况几乎绝迹,它甚至会主动在动手前引用CLAUDE.md里的约定来说明为什么不做某件事。

2.2 会话讲不清的“历史包袱”,每次都要重新喂

很多人忽略的一个重要现实:Claude Code 的每一次新会话,都像刚入职的第一天,它什么都不记得。你在上一个会话里反复强调过的“我们项目的 id 字段叫 uuid 不叫 id”,新会话里它照样会用id。

所以,凡是“每个任务都需要知道”的信息,都应该固化到CLAUDE.md或者工作区内的约定文件里,而不是靠每次对话灌输。灌输能解决单次任务,固化才能解决长期一致的协作问题。

我见过一个比较极端的例子:某开发者为了让代理正确理解“订单状态机的迁移必须经过 audit 日志”,每次都在对话开头贴一段说明。结果有一次赶上机器人短路,它直接改坏了状态迁移逻辑。后来他把这段约束写进CLAUDE.md,问题彻底消失。

这背后其实是一个简单工程道理:代理的“记忆质量”取决于你有多少知识沉淀在工作区文件里,而不是它的上下文窗口有多大。

2.3 把长上下文当免死金牌,只会让“假理解”更加严重

现在的模型上下文窗口越做越大,很多人下意识觉得“反正它都能记住,我一次性把所有背景都塞进去不就行了”。但注意,上下文窗口大,意味着它能“容纳”的信息多,却不代表它能正确“区分”哪些信息对当前任务真正重要。

当你在一个会话里塞入整个项目说明、五十个文件的内容、三天的讨论记录时,Claude Code 会把注意力分散在不同权重上,很容易优先采纳离当前编辑位置最近的相似代码风格,而不是你藏在第 37 条里的“禁止事项”。

长上下文的正确用法,是靠CLAUDE.md和项目内文档来做“信息抽屉”:它需要时去翻,翻不到才来问你。而不是你一次性把整个图书馆推到它面前。

3. 纠正理解之后,我的日常工作流变了

如果你看完上面两个误区,决定换个方式和 Claude Code 协作,那接下来的工作流是我目前在真实项目里一直用的,可以直接抄作业。

3.1 开工前先花 10 分钟“办入职”

每次开始一个有一定复杂度的功能之前,我不会直接说“开始做”,而是先执行一个固定动作:把任务相关背景写成一个简短的TASK.md或直接在对话里贴一段“入职说明”。

这段说明一般包括四块内容:

  • 项目结构:当前模块在哪个目录,依赖哪些相邻模块;
  • 关键文件清单:优先读哪些文件,不要碰哪些文件;
  • 业务规则:这个功能必须满足的约束条件;
  • 验收标准:代码写成什么样算完成。

举个例子,我要做一个“批量导出订单 Excel”的功能,我不会只说“帮我加个导出功能”,而是说:

任务:在 admin/src/pages/orders 下新增批量导出功能。 背景:订单数据来自 src/api/order.ts 的 fetchOrders 接口,支持分页参数。 约束条件: - 导出格式使用 xlsx,上限 5000 条 - 导出文件列头必须与页面表格一致 - 不新增后端接口,前端直接复用 fetchOrders - 不要改动 order.ts 现有函数签名 验收:点击导出按钮后,调用导出工具生成文件并自动下载,页面不卡死。

这个过程看起来很费时间,实际上比我之前边聊边改要快得多,因为它大幅减少了来回修正的轮次。总体上,花 10 分钟“办入职”,至少能省掉三十分钟的返工。

3.2 小步走:一次只让它动一个文件,给完就检查

我之前犯过的最严重错误,是让它一口气“把所有相关文件都优化一遍”。听起来很高效,结果它同时动了接口、页面、样式、测试、配置五个维度,出问题之后根本分不清哪些是预期改动,哪些是它自由发挥。

现在的做法是“一次一个改动单元”:

  1. 明确唯一目标,比如“把 utils/date.ts 里的 formatDate 方法改成支持传入 Date 对象和字符串两种入参”;
  2. 让它先给修改方案,不许直接动手;
  3. 方案确认后,限制“只允许改 utils/date.ts 这一个文件”;
  4. 改完立刻git diff检查,有意外改动就在下一个任务里要求回滚。

这个流程牺牲了一点“自动化感”,换回来的是每一步都可控、可回滚、可验收。

3.3 我负责决策,它负责执行和反馈

修正确实理解之后,我对 Claude Code 的定位其实变成了三个角色,缺一不可:

  • 快速打字员:帮我生成大量重复性代码、模板代码、类型定义;
  • 代码检索器:在我记不清某些调用链时,直接在项目里帮我翻出引用关系;
  • 初稿生成器:把复杂需求先写出一版可运行的粗糙实现,再由我做架构把关和边界修正。

这听起来好像很保守,但恰恰是这种定位,才让它在日常开发里成为真正省时间的工具。你不需要它替你思考整个系统的未来,你只需要它在明确的边界内快速执行,并且把所有它认为的“隐患点”反馈给你。

4. 真正踩过坑之后才理解的几条实战细节

这一节想聊一些官方文档不会告诉你、只有你真实跑过一段时间才能体会到的细节,算是个人踩坑笔记吧。

4.1 一次改太多文件,会出现“连锁塌方”

Claude Code 在拿到一个多文件任务时,倾向于按照它自己理解的顺序依次修改,但修改 A 文件时产生的假设,可能到修改 B 文件时已经变了。比如它先改了接口返回结构,然后又根据旧的类型声明去改前端调用,最后两者对不上,整个构建直接崩掉。

所以要严格限制改动范围。我自己常用的句式是:

只允许修改 src/order 目录下的 .ts 文件,其他目录下的文件如果有改动需要,先列出来给我确认。

如果它中途提出“发现 src/shared/button.tsx 也需要改”,那就停下来,先确认再继续。把这个习惯建立起来之后,崩溃概率直线下降。

4.2 让它“别碰什么”,往往比“做什么”更重要

有一次我让它优化某个文件的性能,它非常勤快地把里面一个被三处引用的公共函数改成了新的实现,结果另外两处调用直接行为不一致。原因就是我只说了“优化”,没有说“这个公共函数还被别人用着”。

从此之后,我的任务描述里会专门加一个“禁止事项区”。这一区甚至可以比正向描述更重要。你越清楚项目的雷区在哪里,就越要用文字明确标出来。毕竟,工具不会像老员工一样知道“这块代码当年为什么这么烂,别动它”。

4.3 养成 diff 洁癖,每次改动都要过一遍“变更审查”

我见过很多人对 AI 改代码极度信任,让它改完就直接提交了。这是灾难的根源。

我现在设置了三个动作,属于铁律,谁来了都不破:

git diff --stat # 看它到底动了哪些文件,有没有越界 git diff # 逐行看关键文件的具体变更,确认没有夹带私货 git log -1 --oneline # 提交信息是否出自你真实意图

如果要用 Claude Code 帮我写提交记录,我也只会让它“基于我指定的改动范围来写”,而不是让它看着所有 diff 自由发挥。

4.4 会话太长会“失忆”,该断则断

Claude Code 在很长的会话里,注意力更容易偏向最近的内容,早期提到的关键约束可能会在后面被稀释。如果你发现同一个需求来回改了四五轮,它还在反复提出同一类问题,那就别再硬撑着续这段对话了。

正确做法是:新开一个会话,把必要背景浓缩成一小段“入职说明”,接着做。不要觉得这是浪费,Session 是用来聚焦的,不是用来拼续航的。聚焦越强,它的表现越稳定。

5. 回归本质:它是一块“动力十足的引擎”,但方向盘始终在你手里

聊到这里,再回头看标题里的“理解错了”四个字,我想你大概也认同:Claude Code 确实不是不好用,而是很多人一开始就对它抱了错误的期待,误以为 AI 编程工具应该代替人做判断,结果自己放弃了上下文控制权,还把翻车归因于工具太蠢。

我个人的体会是,把它当“一个能力很强但完全不了解项目背景的试用期同事”来对待,是收益最稳的方式。你要给它清晰的工作手册,设定明确改动边界,在它动手前先让它给方案,在它动手后认真做 diff 审查。它负责把力气用在对的地方,你负责告诉它哪些地方是雷区。

如果你此刻正被它改得头皮发麻,不妨先停下操作,检查一下自己的任务描述是否写清了“文件路径、目标行为、禁止改动项”三要素,再检查一下项目根目录有没有CLAUDE.md。大部分所谓“不听话”,归根到底,都是这两件事没做到位而已。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进