CC 用久了你会发现,同一个任务今天跑出完美结果,明天给你一坨垃圾。不是模型退化了,是你在裸跑。五层工程化配置,把成功率从 70% 拉到 95%。
同一个提示词,昨天跑出来的代码直接能用,今天跑出来的编译都不过。
你开始怀疑是不是模型变笨了。不是。是你在"裸跑"------没有分层约束、没有验证闭环、没有跨会话记忆。CC 不是聊天机器人,它是个需要工程化配置的 Agent。配好了,稳定输出;没配,看天吃饭。
我花了几个月踩坑,摸出一套五层配置体系。不用一次全上,按需叠加就行。
第一层:CLAUDE.md 分层------规则写对地方
你的 CLAUDE.md 是不是已经 200 行了?技术栈、代码规范、禁止事项、模块约定全塞一个文件里。结果 CC 该遵守的不遵守,不该管的瞎管。
问题不在规则多,在于没分层。CC 读一个 200 行的文件,注意力会被稀释------上下文膨胀会直接降低推理质量。
我的做法是三层:
objectivec
~/.claude/CLAUDE.md → 个人习惯(全局生效)
项目根目录/CLAUDE.md → 项目级约束(团队共享)
子模块目录/CLAUDE.md → 模块级细节(精准命中)
具体怎么分:
全局层 (~/.claude/CLAUDE.md)------放永远不变的个人偏好:
markdown
- commit message 用 conventional commits 格式
- 代码注释用中文
- 不要生成 @author 注解
项目层 (项目根 CLAUDE.md)------放"什么不能做":
markdown
- 禁止 @Autowired 字段注入,必须用构造器注入
- 禁止 System.out.println,用 Slf4j
- Controller 必须返回 ResponseEntity<T>
- 所有 REST 接口必须有参数校验注解
模块层 (比如 order-service/CLAUDE.md)------放"怎么做":
markdown
- DTO 转换使用 MapStruct,不要手写 BeanUtils.copyProperties
- Repository 方法命名遵循 Spring Data 规范
- 金额字段统一用 BigDecimal,精度 scale=2
原则就一条:越靠近代码的层级越具体,越靠近全局的越抽象。 项目层管"禁止什么",模块层管"怎么做"。CC 进入 order-service 目录时会同时读三层,但模块层的具体规则权重最高。
翻车记录:不同层级写了矛盾规则时,CC 的行为不确定。比如全局写了"用 Lombok @Data",模块层写了"禁止 @Data 用 @Getter/@Setter"------CC 会随机选一个。解法:层级之间不要有矛盾,上层只管抽象原则。
第二层:SubAgent 拆任务------复杂度可控
一个大任务丢给 CC,它跑了 10 分钟,改了 30 个文件,最后你发现第 3 步就跑偏了,后面全白干。
这不是 CC 的问题,是你把 10 个需求塞进了一个 prompt。你不会把 10 个需求塞进一个方法,凭什么塞进一个对话?
工程化做法:拆成多个 SubAgent,每个有明确边界和退出条件。
比如"重构 order-service 的支付模块",我会这么拆:
bash
第一步(分析):分析 payment 包下的代码结构,输出类依赖关系和调用链,
写到 /tmp/payment-analysis.md
第二步(重构):基于 /tmp/payment-analysis.md 的分析结果,
重构 PaymentService,只动 payment 包下的文件,
改完跑 mvn compile -pl order-service 验证
第三步(测试):为重构后的 PaymentService 补充单元测试,
跑 mvn test -pl order-service,失败就修到绿灯
每一步单独开一个对话(或用 Agent tool 派发 SubAgent)。关键原则:
- 限定文件范围:"只动 payment 包下的文件"------防止 CC 顺手改了 common 模块
- 明确退出条件:"编译通过 + 测试绿灯"------不是 CC 说 done 就是 done
- 串行不并行:SubAgent 之间改同一批文件会冲突,老老实实一个接一个
那 SubAgent 之间怎么传递信息?它们没有共享上下文。我的土办法:让上一个 Agent 把结论写到文件里,下一个 Agent 读这个文件。 简单粗暴但有效。
翻车记录:SubAgent 执行时间越长越容易漂移。一个子任务超过 10 次 Tool Use 还没完成,大概率已经跑偏了。解法:任务粒度再切小,宁可多拆一步也不要让单个 Agent 跑太久。
第三层:Memory------跨会话不失忆
每次新开会话,CC 又忘了你上次确认的架构决策、踩过的坑、选型的理由。你反复解释同样的上下文,烦得想摔键盘。
CLAUDE.md 解决的是"规则"问题,Memory 解决的是"决策记忆"问题。
适合存 Memory 的东西:
markdown
# 架构决策
- 缓存选了 Redis 而不是本地 Caffeine,因为多实例部署需要共享
- 消息队列用 RocketMQ,不用 Kafka,因为运维团队只维护 RocketMQ
# 踩坑记录
- MyBatis-Plus 3.5.3 和 Spring Boot 3.2 有兼容问题,必须升到 3.5.5+
- Redisson 分布式锁在 cluster 模式下 watchdog 续期有 bug,用 3.27.0+
# 团队约定
- 所有 API 必须走 gateway,不允许服务间直连
- 数据库变更必须走 Flyway migration,禁止手动 DDL
不适合存的:代码结构(直接读代码就行)、临时任务状态(用 TodoList)、git 历史(git log 更准)。
实操上,我会在关键决策确认后直接跟 CC 说:"把这个决策存到 Memory,下次会话要能想起来。" CC 会自动写入 memory 文件。
翻车记录:Memory 会过期。三个月前存的"用 Spring Boot 2.7"现在已经迁移到 3.2 了,CC 还在按旧记忆行事。解法:把 Memory 当文档维护,定期清理过时条目。每次大版本升级后花 5 分钟扫一遍。
第四层:Hooks 验证闭环------CC 说 done 不算数
CC 改完代码跟你说"已完成",你信了,push 上去 CI 红了。
问题在于:CC 的"完成"标准是"我觉得改对了",不是"编译通过了、测试绿了"。你需要用 Hooks 强制它在关键节点自动验证,绕不过去。
jsonc
// .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "cd $(git rev-parse --show-toplevel) && mvn compile -q -pl $(basename $(pwd)) 2>&1 | tail -3"
}
],
"Stop": [
{
"command": "cd $(git rev-parse --show-toplevel) && mvn test -q -pl $(basename $(pwd)) 2>&1 | tail -10"
}
]
}
}
这套配置的逻辑:
- 每次改文件后(PostToolUse):自动跑编译。编译不过 CC 立刻能看到报错,当场修------不让错误累积到最后
- 任务结束前(Stop):跑单元测试。测试不过就不算完成,CC 会继续修
关键细节:-q 静默模式 + tail 只取最后几行。Hook 太重会拖慢 CC 的迭代速度------你不想每改一行就跑 3 分钟的全量测试。编译用静默模式秒级反馈,测试只跑当前模块。
翻车记录:Hook 里的命令如果本身有 bug(比如路径写错),CC 每次改文件都会收到一堆无关报错,然后开始"修复"这些根本不存在的问题。解法:Hook 配置好后先手动跑一遍确认没问题。
第五层:Prompt 模板------输入标准化
每次写提示词都从零开始,质量全看当时的状态。上次写得好的提示词,下次想不起来了。
工程化做法:把高频任务的提示词存成 Custom Command,一键触发。
markdown
# .claude/commands/new-feature.md
---
description: 生成完整的 CRUD 功能模块
---
参考 $ARGUMENTS 的写法,新增指定实体。
要求:
1. 生成 Entity(JPA 注解 + Lombok)
2. 生成 Repository(Spring Data JPA)
3. 生成 Service + ServiceImpl(构造器注入)
4. 生成 Controller(RESTful + 参数校验)
5. 生成 Request/Response DTO
6. 生成后跑 mvn compile 验证编译通过
用的时候一句话:/new-feature Order.java,CC 就会参考 Order 的写法生成一整套新模块。
再来一个 review 模板:
markdown
# .claude/commands/review-api.md
---
description: API 安全与性能审查
---
审查当前模块的 Controller 和 Service 层:
1. 检查是否有缺失的权限校验(@PreAuthorize)
2. 检查 JPA 查询是否存在 N+1 问题
3. 检查 Entity 是否直接暴露到了 API 响应
4. 检查事务注解是否合理(只读方法加 readOnly=true)
列出问题并给出修复建议
模板的原则:约束"必须做什么",不约束"怎么做"。 你告诉 CC 要生成哪些文件、要通过什么验证,但不要规定它用什么算法实现------留出灵活性。
团队里多人用 CC 的话,这些模板提交到 git 仓库。所有人用同一套模板,CC 的输出质量就有了基线保障。
五层金字塔:按需叠加
markdown
┌───────────────┐
│ Prompt 模板 │ ← 输入标准化
┌┴───────────────┴┐
│ Hooks 验证闭环 │ ← 输出有保障
┌┴─────────────────┴┐
│ Memory 跨会话记忆 │ ← 上下文不丢
┌┴───────────────────┴┐
│ SubAgent 拆任务 │ ← 复杂度可控
┌┴─────────────────────┴┐
│ CLAUDE.md 分层架构 │ ← 规则有层次
└───────────────────────┘
不用一次全搭。我的建议:
先搞底下两层:CLAUDE.md 分层 + Hooks 验证闭环。这两个 ROI 最高,10 分钟配好,立刻见效。CC 的输出质量能从"时灵时不灵"变成"大部分时候靠谱"。
等你发现"CC 老是忘事":加 Memory。把反复解释的架构决策和踩坑记录持久化。
等任务越来越大:加 SubAgent 拆分。一个任务超过 5 个文件的改动,就该拆了。
等团队开始用:加 Prompt 模板。统一输入质量,新人也能用出老手的效果。
从偶尔惊艳到稳定输出,中间差的不是运气,是工程化。