Claude Code 最佳实践与避坑指南

12 阅读12分钟

Claude Code 最佳实践与避坑指南

本文汇总四个阶段中最容易踩的坑、最有价值的实践,以及快速自检清单。 建议每次遇到问题时先翻一翻这里。


一、最常见的 10 个坑

坑 1:改完就说"完成了",没有验证

症状:Claude 说"修改已完成",你就关掉窗口,结果第二天发现代码跑不起来。

正确做法

修复 bug 或实现功能后,必须执行验证命令:

前端:pnpm type-check && pnpm lint && pnpm test
后端:mvn test 或 gradle test
通用:git diff 确认改动范围符合预期

在 CLAUDE.md 中强制这个行为

## 禁止行为
- 禁止未运行以下命令就宣布任务完成:
  - 前端:`pnpm type-check`
  - 后端:`mvn test -pl 模块名`

坑 2:让 Claude 读整个目录或大文件

症状:问 Claude "帮我分析这个项目的结构",结果 Claude 读了几千行代码,token 耗尽,分析质量还差。

错误做法

> @src/ 分析这个项目的架构
> @src/services/OrderService.java  这个文件有什么问题?(文件 800 行)

正确做法

# 先用 Grep 定位,再精确读取
> 先列出 src/ 下的目录结构,然后找出核心 Service 类在哪里

# 读大文件时指定范围
> 读一下 OrderService.java 中 processOrder 方法的实现,
  先用 Grep 找到方法的行号

节省 token 的量化效果

直接读 800 行文件  → 3200 tokens
Grep(20行) + 精确读(60行) → 320 tokens
节省 90%

坑 3:对话超长不 compact,导致 Claude "失忆"

症状:对话进行到第 30 轮,Claude 开始忘记之前确认过的设计决策,给出和前面矛盾的方案。

判断标准

超过 20 轮 → 执行 /compact
超过 40 轮 → 考虑 /clear 重开,把关键结论带入新会话
超过 60 轮 → 任务应该被拆分为多个独立会话

带关键结论重开会话的方法

执行 /clear 前,先让 Claude 总结关键信息:
> 在我们 /clear 之前,列出这次会话的关键结论:
  1. 已确认的技术方案
  2. 已完成的文件改动
  3. 还未完成的任务

然后 /clear,重新开始时把这些结论粘贴进去。

坑 4:CLAUDE.md 写了但不生效

症状:在 CLAUDE.md 里写了某条规范,但 Claude 还是不遵守。

排查步骤

# 1. 确认文件位置是否正确(必须在当前工作目录或其父目录)
ls ./CLAUDE.md
ls ~/.claude/CLAUDE.md

# 2. 确认文件没有语法问题(@ 引用路径是否正确)
cat ~/.claude/CLAUDE.md | grep "@"

# 3. 验证 Claude 是否读取了配置
claude
> 你知道这个项目禁止使用哪些依赖吗?

常见原因

  • CLAUDE.md 放错了目录(不在项目根目录)
  • @引用 的路径不存在或有拼写错误
  • 配置内容太多,被截断了(超过 150 行建议拆分)

坑 5:一次让 Claude 改太多文件,失去控制

症状:Claude 一次改了 10 个文件,你不知道每个改动是否正确,出了问题也不知道回滚哪里。

正确做法

# CLAUDE.md 中设置门控
## 禁止行为
- 禁止在未出方案并等待用户确认的情况下修改 3 个以上的文件

# 执行时主动分批
> 先只修改 UserService.java,改完我确认后再改其他文件

大改动的分批策略

方案 A:按文件批次(每批 2-3 个文件)
方案 B:按功能层次(先改数据层,确认后改业务层,再改展示层)
方案 C:先写测试(TDD:先改测试文件,确认测试意图后再改实现)

每批改动后立即验证:不要等所有文件都改完再验证,每批改完立刻运行验证命令,确认没有破坏已有功能,再进行下一批。


坑 5.5:Claude 改错了,不知道怎么回滚

症状:Claude 修改了代码,但结果不对,想恢复到修改前的状态。

决策树:选哪种恢复方式

改动还没有 git commit?
    ├── 只改了 1-2 个文件,知道哪里错了
    │   → 直接告诉 Claude:
    │     > 你刚才改的第 45-60 行不对,请还原到修改前的逻辑
    │
    ├── 改了多个文件,想全部撤销
    │   → git checkout . 或 git restore .
    │     (撤销所有未暂存的修改)
    │
    └── 部分改动是对的,只想撤销某一个文件
        → git checkout -- src/services/OrderService.ts
          (只还原这一个文件)

改动已经 git commit?
    ├── 只想撤销最后一次 commit,保留文件改动
    │   → git reset HEAD~1
    │     (commit 消失,但文件改动保留,可以重新检查)
    │
    ├── 想完全回到 commit 之前的状态
    │   → git reset --hard HEAD~1
    │     ⚠️ 危险:文件改动也会丢失,确认后再执行
    │
    └── 改动已经 push 到远端
        → git revert HEAD(生成一个新的撤销 commit,更安全)

最佳预防策略:在 Claude 大批量修改之前,先建立一个检查点:

# Claude 动手前,先记录当前状态
git stash        # 或 git commit -m "wip: checkpoint before Claude changes"

# Claude 改完,确认没问题
git stash drop   # 或继续正常提交

# 如果改错了
git stash pop    # 或 git reset --hard 到 checkpoint commit

坑 6:Hook 配置了但没有执行

症状:配置了 SessionStart Hook,但每次启动 Claude 都没看到 Hook 的输出。

排查步骤

# 1. 确认 settings.json 格式正确(JSON 不能有注释、尾逗号)
cat ~/.claude/settings.json | python3 -m json.tool

# 2. 手动测试 Hook 命令
bash -c "你的 hook 命令"

# 3. 检查脚本权限
ls -la ~/scripts/your-hook.sh
chmod +x ~/scripts/your-hook.sh

最小化可用 Hook 配置(先用这个验证机制是否工作):

{
  "hooks": {
    "SessionStart": [
      {
        "type": "command",
        "command": "echo 'Hook 测试成功'"
      }
    ]
  }
}

坑 7:MCP 连接了但 Claude 没有使用

症状:配置了 IDE MCP,但让 Claude 找函数定义时,它还是在用 Grep。

原因:Claude 不会自动偏好 MCP 工具,需要你明确要求。

正确的提问方式

# 不明确(Claude 可能用 Grep)
> 找一下 UserService 的 createUser 方法在哪里

# 明确要求用 IDE 工具
> 用 ide_find_definition 找到 UserService.createUser 方法的定义
> 用 ide_find_references 分析 validateToken 有多少个引用

什么时候值得明确要求用 IDE 工具

  • 需要语义级查找(不是文本匹配):定义、引用、实现类、调用链
  • 需要全局重命名(比 Grep+替换 更安全)
  • 想要 IDE 的实时诊断(类型错误、快速修复)

简单的文本搜索(关键词、注释、日志)直接用 Grep 就够,不必每次都用 IDE 工具。


坑 8:/compact 后 Claude 忘了重要信息

症状:/compact 之后,Claude 不记得之前已经确认的技术方案。

预防方法:/compact 前明确告诉 Claude 什么是重要的:

> 我要执行 /compact,请在压缩前确保保留以下关键信息:
  1. 我们决定使用 Redis 而不是本地缓存
  2. validateToken 的 bug 根因是并发竞态
  3. 还未完成:修改 TokenService.java 第 45 行

坑 9:permissions 配置没有生效

症状:deny 了某个命令但 Claude 还是执行了。

排查

# 检查 settings.json 是否被正确读取
claude --debug 2>&1 | grep "settings"

# 确认 deny 规则语法
# 正确:
"deny": ["Bash(rm -rf *)"]

# 错误(缺少括号内的内容):
"deny": ["Bash"]   # 这会禁止所有 Bash,不是只禁止特定命令

权限规则的优先级deny 优先于 allow。同一命令既在 allow 又在 deny 里,以 deny 为准。


坑 10:经验没有被有效沉淀

症状:每次解决问题后什么都不记录,下次遇到同类问题还是要从头摸索。

有价值 vs 无价值的知识对比

❌ 无价值(流水账):
"完成了用户登录功能的开发"

✅ 有价值(可复用):
## token 刷新竞态问题(通用模式)
现象:高并发下偶发 401 错误
根因:多个请求同时触发 token 刷新,第一个成功后其他请求拿到的旧 token 已失效
解法:前端用请求队列串行化刷新,后端 refresh 接口加锁防重复执行
适用范围:任何有 token 自动刷新逻辑的前后端项目

一个好的知识条目应该能让另一个人(或未来的自己)在 1 分钟内理解"什么情况下会触发、怎么解决"。

判断知识是否值得记录的三个问题

  1. 这个经验下次遇到类似问题能直接用吗?
  2. 这是一个不直觉的发现(反常识/踩坑)吗?
  3. 其他人会因为不知道这个而重复踩坑吗?

三个问题有 2 个"是",就值得记录到 learnings/ 目录。


二、坏习惯 vs 好习惯对比表

场景❌ 坏习惯✅ 好习惯
分析文件@src/ 分析整个目录先 Grep 定位,再精确读取
修改代码要求 Claude 一次改完所有文件分批改动,每批确认
对话管理对话 50 轮从不 compact每 20 轮执行 /compact
完成确认Claude 说"完成了"就信了运行验证命令确认
写 CLAUDE.md只写正面规范同时写"禁止行为"
使用 Skills跳过门控点,让 Claude 直接执行认真审阅每个门控点
经验积累任务完成就关掉会话记录有价值的发现到知识库
遇到错误让 Claude 重试同样方案让 Claude 换完全不同方向
搜索代码@大文件 让 Claude 找函数Grep "函数名" 直接定位
Hook 失效猜测原因先用 echo 测试 最小化验证

三、高价值配置检查清单

必备配置(每个项目都应该有)

✅ 项目 CLAUDE.md
□ 技术栈声明(框架、版本、主要依赖)
□ 禁止引入的依赖列表
□ 代码风格约定(命名、分层)
□ 验证命令(类型检查、测试、lint)
□ 禁止行为列表(至少 3 条,用"禁止"开头,不用"应该")
□ 目录结构说明

✅ 全局 ~/.claude/settings.json
□ 危险命令的 deny 规则(rm -rf, git push --force 等)
□ 模型设置(可选)
□ 环境变量(API Key 等)

✅ Hooks(强烈推荐)
□ SessionStart:同步团队配置或打印环境信息
□ Stop:提示记录本次会话的新发现

推荐配置(提升效率)

🔵 MCP 服务器
□ chrome-devtools(前端项目必装,用于 UI 验证)
□ IDE 插件 MCP(代码导航,用 ide_find_definition 等)

🔵 团队配置
□ 团队共享 CLAUDE.md(通过 @引用 加载)
□ SessionStart Hook 自动同步共享配置

四、CLAUDE.md 反模式(不要这样写)

反模式 1:过于宽泛,没有约束力

❌ 不好的写法:
## 注意事项
- 请写好代码
- 注意代码质量
- 遵守规范
✅ 好的写法:
## 禁止行为
- 禁止使用 any 类型,使用 unknown 代替
- 禁止 console.log,必须使用 src/utils/logger.ts 的 logger
- 禁止修改 3+ 文件不先出方案

反模式 2:太长,导致每次 token 消耗巨大

原则:CLAUDE.md 控制在 150 行以内
超出部分使用 @引用 外部文件,按需加载

反模式 3:只有正面规范,没有禁止行为

大量实践证明:明确的"禁止"比模糊的"应该"更有效

# 效果差(Claude 会灵活解释"最好")
## 规范
最好使用组件库而不是自己写 UI

# 效果好(没有歧义空间)
## 禁止行为
- 禁止自己编写 UI 组件,必须优先使用项目已有的 UI 库
- 如果组件库没有所需组件,在引入前先咨询用户

五、任务开始前的快速检查(30 秒自检)

开始一个新任务前,问自己:

□ 这个任务预计改动多少文件?
  → 3+ 文件:先出方案,等确认再动手

□ 需要探索多少代码?
  → 3+ 文件:考虑委派子 Agent(Sonnet)探索

□ 对话已经多少轮了?
  → 20+ 轮:先 /compact

□ 项目文档或 README 里有没有相关信息?
  → 先查文档,再读代码

□ 这个任务完成后有可复用的经验吗?
  → 任务结束后记录到 learnings/

六、当 Claude 给出错误结果时

诊断流程

1 步:确认问题是"理解错误"还是"执行错误"
  - 理解错误:Claude 做了你没有要求的事
  - 执行错误:Claude 理解正确,但代码有 bug

第 2 步:针对性处理
  - 理解错误 → 用更明确的语言重新描述要求
    (检查 CLAUDE.md 是否有相关规范)
  - 执行错误 → 提供错误信息,让 Claude 重新分析

第 3 步:如果同一类错误出现 3 次
  → 停止尝试同类方案
  → 寻求完全不同的方向
  → 或者咨询同事/查文档

第 4 步:解决后
  → 这个错误是否是个"坑"?
  → 如果是,加到 CLAUDE.md 的禁止行为里
  → 记录根因到 learnings/

七、新手最常见的提问误区(及正确写法)

误区 1:问题太宽泛

❌ > 帮我优化代码
❌ > 这段代码有什么问题?
❌ > 帮我看看项目

✅ > 帮我优化 src/payment/calculator.ts 中 calculateTotal 函数的性能,
    现在它在列表渲染时被调用了 1000 次,感觉很慢
✅ > @src/auth/middleware.ts 第 45-80 行有没有并发安全问题?
    特别关注 token 验证的部分
✅ > 帮我理解 src/order/ 模块的架构,
    重点关注订单状态流转的逻辑

误区 2:没有提供错误信息

❌ > 代码报错了,帮我看看

✅ > 代码报错了,错误信息如下:
    TypeError: Cannot read property 'id' of undefined
    at OrderService.createOrder (src/services/order.ts:89:23)

    相关代码在 src/services/order.ts 第 85-95 行

误区 3:要求 Claude 一次改太多

❌ > 把整个订单模块重构成最佳实践

✅ > 先分析 src/order/ 模块的问题,
    给我一个重构方案(不要直接动手),
    等我确认方案后再分步骤实施

误区 4:不说清楚约束条件

❌ > 帮我实现分页功能

✅ > 帮我实现分页功能,要求:
    - 复用 src/components/Pagination 已有组件
    - 分页参数格式参考 src/api/order.ts 里的 getOrderList 接口
    - 不要引入新的依赖库
    - 改动只限于 src/pages/ProductList.tsx 文件

误区 5:Claude 说完成后不验证

❌ 看到"修改完成"就关掉会话

✅ 每次改完代码必须执行:
    git diff               → 确认改了什么
    pnpm type-check        → 确认类型没问题
    pnpm test              → 确认没破坏已有功能