1. 为什么我把“万能提示词”全部扔进了模板
我大概是在 Claude Code 刚火那阵开始重度使用终端的,最开始跟很多人一样,直接把需求一句句丢给它:“帮我看看这个文件哪里有问题”“给这段代码补个测试”。日常小任务还好,一旦涉及跨文件改动、架构评审、多轮重构,你会发现每次都得从头啰嗦一遍上下文、约束、输出格式,而且它每次的理解还不太一样——同一个需求,今天给的结果和昨天给的版本能差出一大截。
后来我认真琢磨了一件事:与其反复“调教”对话,不如把高频任务的处理逻辑固化成模板文件,让 Claude Code 每次启动都带着同一套规则、同一个工作流去干活。这就是我折腾 claude-code-templates 的起点。说白了,模板就是把“你希望 AI 怎么思考、按什么顺序做事、输出什么结构”这件事变成一份可提交、可版本管理、可团队复用的配置文件,而不是靠人肉记忆去维持一致性。
这篇文章把我从零搭建模板仓库的完整过程写出来,包括目录设计、system prompt 的写法、CLAUDE.md 的配合方式、hooks 动态注入,还有我踩过的几个大坑。适合已经在用 Claude Code、但觉得输出不够稳定的朋友,也适合打算在团队里统一 AI 编码规范的人。
先说结论:模板真正解决的,不是让 Claude 变聪明,而是让它每一次都“稳定地保持某个水平”。就像你请一位高级工程师来干活,你不会每次重新介绍一遍公司背景和代码规范——你给 Ta 一份 onboarding 文档。Claude Code 的模板,就是这份 onboarding 文档。
2. 模板仓库的文件结构设计与启动流程
2.1 模板放在哪里,是一门学问
我一开始很随意,直接在项目里建了个templates.md,结果发现 Claude Code 并不会自动读它——你必须通过某种方式把文件内容拼进 prompt 里。后来我整理出一套固定的放置方案,分两种情况:
- 个人全局使用:放在
~/.claude/或~/.config/claude-code/下,让所有项目共享同一套基础规则。 - 项目级使用:放在仓库根目录的
.claude/文件夹下,跟随代码库一起提交,团队其他人 clone 下来就有同样配置。
我的建议是两层都要:全局放“通用行为规范”,例如代码风格偏好、输出格式要求;项目级放“业务上下文”,例如模块结构、命名约定、测试要求。这样模板既不会因为塞太多项目细节而无法复用,也不会因为完全没有项目信息而显得空泛。
下面是我现在用的全局模板目录结构:
~/.claude/ ├── settings.json ├── system-prompts/ │ ├── review.md │ ├── refactor.md │ ├── test.md │ └── explain.md ├── scripts/ │ ├── collect-context.sh │ └── git-summary.sh └── CLAUDE.md项目级的建议放在.claude/下,结构类似,但侧重点是业务规则:
<repo>/.claude/ ├── settings.json ├── CLAUDE.md └── prompts/ ├── service-review.md └── migration-guide.md2.2 settings.json 是如何把模板“喂”给 Claude 的
Claude Code 的配置文件支持prompt字段,用来注入用户级或项目级的系统提示词。如果你像我一样把提示词拆成了多个 markdown 文件,两种办法:要么用脚本读取并合并成一个字符串再传给 CLI,要么直接在 settings.json 里写短片段,长内容用文件引用。我实际用的是后者,配合一次启动前的小脚本,把多个 md 拼成一个总 prompt。
伪代码大概是这个样子(我简化了逻辑,重点是思路):
#!/bin/bash # scripts/build-prompt.sh PROMPT_DIR="$HOME/.claude/system-prompts" OUTPUT="" for f in "$PROMPT_DIR"/*.md; do OUTPUT="${OUTPUT}$(cat "$f")\n\n" done claude --settings-file "$HOME/.claude/settings.json" \ --prompt "$OUTPUT" "$@"跑起来之后,Claude 每次启动都会先“读一遍”这些模板,相当于给自己定了规矩。同样,项目里的.claude/settings.json会覆盖或追加全局配置,具体规则后面会专门说。
2.3 拼接顺序至关重要:系统提示词、CLAUDE.md、用户消息
很多人的模板实践失败,是因为根本不理解 Claude Code 内部 prompt 的拼接顺序。我实测下来,大致是:系统提示词(system prompt)在最前面,然后是项目 CLAUDE.md 和全局 CLAUDE.md 的内容,再往后才是你跟它说的用户消息。
这个顺序决定了规则冲突时的胜出方——越是靠后的内容,越容易在生成时被模型强调。所以我通常把“铁律”类约束(比如禁止修改某些目录、必须输出中文注释)放在系统提示词里;把“背景知识”(比如当前模块的技术栈、过往决策记录)放在 CLAUDE.md 里。背景知识不需要每次当成命令执行,它更像参考资料。
3. 让 AI 稳定输出的系统提示词设计
3.1 模板不是“长篇大论”,而是“结构化指令”
我见过不少人把模板写成两千字的小作文,从 AI 伦理写到团队愿景。这不是模板,是噪音。系统提示词的有效设计应该遵循极简结构:身份定义、任务目标、工作流、输出格式、红线规则。
拿我做代码评审的review.md举例,核心内容就四块:
你是一名资深后端工程师,负责审查 pull request。 任务目标: - 发现潜在 bug、性能瓶颈和安全问题 - 检查是否违反项目既有约定 工作流: 1. 先阅读 diff,列出变更文件清单 2. 对每个关键文件给出风险评级 3. 汇总问题并标注严重程度 输出格式: - 用 markdown 表格列出问题:严重程度 | 文件 | 行号 | 问题描述 - 末尾给出一段 200 字以内的总体建议 红线规则: - 不评价代码风格偏好(除非项目有强制 lint) - 不为凑数量而提无意义 issue注意看,每一块都是可执行、可校对的条目,没有废话。AI 不是人类,它对“写得很有文采”的判断力有限,但对“明确的步骤编号”和“结构化的输出要求”特别敏感。
3.2 为什么结构化提示词能压制“自由发挥”
这个机制我后来想明白了:Claude 在生成文本时,本质上是在做概率预测——给它一段开头,它预测后面最可能的内容。如果开头是一堆抽象形容词,它就可能跟着抽象下去,越写越飘;如果开头是一二三四的清单,它更倾向于继续按清单式结构输出。模板的核心作用就是把模型“惯性的输出方向”扭到你想去的轨道上。
所以我写模板时特别讲究“决策点”的设置:比如“如果发现内存泄漏风险,请停止继续审阅并优先汇报”。这种指令实际上是在模型内部触发了一个分类决策——先判断是否存在高风险,再决定走哪条分支。结果就是它不会闷头把整个文件评完才告诉你最严重的问题在哪儿。
3.3 让模板具备“自检查”能力
这是我最喜欢的一招:在模板末尾加一段“自我检查指令”。比如要求 Claude 在输出前检查是否满足指定的 commit 规范、是否遗漏了编号、是否在回答中引用了具体文件行号。本质上就是让模型在生成后用另一段 prompt 再“看一遍自己写的东西”。
成本几乎为零,但效果极其明显。很多次它都会自我发现“我刚刚漏了一个约束”,然后自己修正。这比你在外面反复催它“注意细节”管用得多。
4. CLAUDE.md 作为项目级记忆:模板的暗线
4.1 全局模板管“怎么干活”,CLAUDE.md 管“这项目是什么”
很多文章把 CLAUDE.md 和模板混在一起讲,但其实它们分工完全不同。模板是“方法论”,CLAUDE.md 是“项目记忆”。打个比方:模板是外聘顾问的工作手册,CLAUDE.md 是公司内部的文档库。顾问不知道你们这个服务的架构图长什么样、哪个模块是新写的、哪段代码是为了兼容老接口而留的“疤痕”,这些只能写在 CLAUDE.md 里。
我见过最糟糕的 CLAUDE.md 写法,是把整个 README 复制进去,还贴了几百行 API 文档。模型确实能读,但它根本分不清哪些是“当前任务需要关注的重点”,哪些只是“历史背景铺陈”。CLAUDE.md 应该精简到只有三类内容:
- 技术栈和目录的关键事实
- 当前迭代中已知的问题或技术债
- 命令、脚本、代码生成约定
比如我某个项目的.claude/CLAUDE.md就写成这样:
# 项目简报 - 后端: Python 3.11 + FastAPI,核心代码在 `app/services/` - DB: Postgres 16,迁移文件在 `migrations/` - 当前已知问题: `payments` 模块存在死锁风险,禁止在该模块加异步嵌套锁 - 测试策略: 新功能必须有单测,关键路径需要集成测试 - 常用命令: `make dev` 启动本地环境,`make test` 跑全部测试看上去很简单,但 Claude 拿到这些信息后,回答质量是飞跃式的。它不会再绕着你的架构图乱猜,也不会建议你用项目里根本没装的工具。
4.2 CLAUDE.md 和 system prompt 冲突时的“优先级规则”
实际使用中一定会遇到冲突。比如我全局模板要求“所有代码注释必须用英文”,但某个项目的 CLAUDE.md 写的是“注释必须用中文并包含需求单号”。实测结果是,项目级的 CLAUDE.md 往往比全局 system prompt 更占上风,因为它是更贴近当前任务的上下文。
这个机制其实是可以利用的:用全局模板定死那些“绝对不能妥协”的底线,比如安全规范、敏感数据不得写入日志;用项目 CLAUDE.md 做灵活的项目级覆盖,比如注释语言、命名风格。如果发现覆盖结果不符合预期,就调整拼接顺序或者直接在 system prompt 中写“禁止填充内容来自项目 CLAUDE.md 的 XX 规则”。
4.3 别把 CLAUDE.md 写成一劳永逸的“圣旨”
项目是活的,CLAUDE.md 也应该跟着迭代。如果不维护,它会逐渐变成一堆过时指令,AI 拿着过时的技术栈信息给你出方案,比没有记忆还危险。我的习惯是:每次完成一个重要的架构决策或者踩坑修复,就顺手在 CLAUDE.md 里加两行;每次大规模重构,就重写一半内容。
模板和 CLAUDE.md 的关系,应该是:模板提供稳定的方法论框架,CLAUDE.md 提供流动的项目事实。
5. hooks、前置命令与状态注入:让模板从“静态”变“动态”
5.1 静态模板只是起点
固定模板的局限在于:它不知道你当前要处理的到底是哪个文件、当前分支上改了什么、测试跑没跑过。这些信息如果全靠手工描述,每次都会漏掉一部分,而漏掉的信息往往恰好是 AI 做判断的关键输入。
所以我给模板加了一个前置脚本层,思路就一句话:在把 prompt 交给 Claude 之前,自动收集当前仓库的状态信息,注入到模板里。这样每次启动时,它拿到的不是一份死模板,而是一份“当次任务的实时简报”。
5.2 一个动态模板的完整构成
下面是我为一个代码评审场景设计的完整配置。首先要有一个收集上下文的脚本collect-context.sh:
#!/bin/bash # scripts/collect-context.sh BRANCH=$(git branch --show-current) CHANGED_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null || git diff --cached --name-only) DIFF_STATS=$(git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --cached --stat) echo "## 当前分支: $BRANCH" echo "## 变更文件:" echo "$CHANGED_FILES" echo "## 变更统计:" echo "$DIFF_STATS"然后用一个启动器脚本拼接完整 prompt:
#!/bin/bash # scripts/review.sh CONTEXT=$(bash "$HOME/.claude/scripts/collect-context.sh") SYSTEM_PROMPT=$(cat "$HOME/.claude/system-prompts/review.md") claude --settings-file "$HOME/.claude/settings.json" \ --prompt "${CONTEXT}\n\n${SYSTEM_PROMPT}\n\n请对上述变更进行代码评审。"跑起来的效果是:Claude 一上来就知道当前分支是feature/payment-fix,改了哪些文件,换了哪些逻辑,而不是等着你去解释半天。实测下来,评审意见的准确率明显提升了,尤其在“这个改动会不会影响别的模块”这类问题上,因为模型终于能看到具体的变更边界了。
5.3 用 hooks 维持会话状态
前两种方案都是“启动时注入”,但实际工作时往往是一个会话要持续好几轮。我有段时间发现,聊到第 5 轮之后,Claude 会把最初给它的一些上下文“忘记”,比如偶尔忘了自己是“代码评审员”的身份。
后来我在 settings.json 里配了 hooks 功能,在每轮用户消息之前自动重新注入核心身份和关键约束。这样,只要对话还在继续,身份就不会丢。这个机制的原理类似于“每次对话都重新拉一遍确认”,代价是 prompt 变长,但好处是长会话的一致性有了保障。
6. 一份可直接落地的“全栈评审模板”实战
6.1 目标:让每次代码评审输出格式统一、发现问题有优先级
我在团队里推广模板时,最大的阻力不是 AI 不听话,而是大家看不懂 AI 的输出。每个人习惯不同,有人喜欢列 bullet,有人喜欢写长段落。所以我做了个决定:用模板把输出的结构强制统一成表格,并且给问题定性、定量。
这是完整的review.md模板内容,你可以直接抄走改成自己的:
# 代码评审规则 你是团队的技术负责人,请对给定的代码变更进行严格评审。 ## 评审步骤 1. 阅读所有变更文件,先理解业务意图再分析代码 2. 逐个文件检查以下维度:正确性、性能、安全、可维护性 3. 对每个问题给出文件路径、行号区间、严重等级 ## 严重等级定义 - P0: 可能引发线上故障、数据丢失或安全漏洞,必须立即修复 - P1: 明确的功能缺陷或性能瓶颈,应在合并前修复 - P2: 可维护性或潜在风险,建议修复但不强制 - P3: 风格或微小建议,不阻塞合并 ## 输出格式 ### 评审摘要 一句话说明本次变更的整体风险和是否建议合并。 ### 问题清单 | 等级 | 文件 | 行号 | 问题描述 | 修复建议 | |------|------|------|----------|----------| | P1 | `app/service.py` | L88-95 | ... | ... | ### 优点 列出一到三条做得好的改动,避免只报问题。 ## 自我检查 输出前检查: - [ ] 是否所有 P0/P1 问题都给出了修复建议? - [ ] 是否每条问题都包含具体行号? - [ ] 是否在摘要中明确表达了阻塞/不阻塞的意见?这份模板的实际效果是:不管项目里谁跑review.sh,产出的评审意见格式都是一样的,可以省掉大量解释时间。团队里新来的同事只要跑一遍,也能立刻看懂。
6.2 配合 settings.json 的完整配置
这套方案还需要一个配套的settings.json控制横纵配置:
{ "model": "opus", "permissions": { "allow": [ "GitDiff(*)" ] }, "hooks": { "PreToolUse": [ { "matcher": "GitDiff", "command": "bash ~/.claude/scripts/collect-context.sh" } ] } }这里有个设计意图要解释一下:允许模型使用 Git 命令不是为了让它随便跑 git,而是为了让它在面对模糊问题时,能自己去查代码仓库的当前状态,而不是瞎猜。配合上面的collect-context.sh,模板就从“启动时静态注入”变成了“运行时动态查询”,两者一起用,效果最好。
6.3 实际运行效果:一次标准的评审输出
我把这套配置跑在一个实际项目上,变更是一个支付模块的超时重试功能。Claude 的输出从一开始的“这个代码看起来不错,但有几个小细节可以优化”,变成了带有 P0/P1 分级、精确行号、修复建议的评审报告。它甚至捕捉到了我在代码里埋的一个“签名验证失败后吞掉异常只 return false”的问题,并且直接指出这会导致支付回调无法感知失败——这恰是我故意留的 bug。模板认真写和不认真写,AI 的表现完全不是一个量级。
7. 踩坑记录:模板不是写出来就完事的
7.1 模板太长导致 token 膨胀,连带成本翻倍
我第一次写的 review 模板洋洋洒洒 3500 字,想着“细节越多越精准”,结果实际用下来每次评审上下文的 token 消耗暴涨,成本翻了接近一倍,而且效果没有同比提升。原因很简单:模型对于长文本的注意力会分散,特别是指令之间出现冗余或重复时,决策点反而不清晰。
后来我把模板裁到 700 字左右,只保留步骤编号、严重等级、输出格式、红线,效果反而更好。核心原则是:模板里的每句话都必须能在 30 秒内读完整,否则就是冗余。
7.2 CLAUDE.md 和 system prompt 打架,Claude 直接懵了
有一段时间,我的全局模板说“不要输出中文注释,统一用英文”,但项目 CLAUDE.md 写着“公共函数必须有中文注释”。结果 Claude 的行为变得极其怪,一会儿英文一会儿中文,甚至在同一段代码里混合出现。排查之后确认是规则冲突了。
解决方案是给 CLAUDE.md 增加一条“以项目级规则优先,如与全局规则冲突,以本文件为准”,然后在全局模板里给规则设置一个“可覆盖”。更重要的是,我养成了一个习惯:写模板时明确哪个规则是“绝对不可覆盖”,哪个规则是“默认值”。
7.3 模板路径用了相对路径,换个目录就失效
这事说起来很蠢。我有一次在~/.claude/scripts/collect-context.sh里写了cd ./repo,结果从项目的子目录启动时,脚本直接找不到路径,Claude 拿到空的上下文,评审结果完全跑偏。
排查链路是这样的:先怀疑是模板内容问题,后来发现系统报错说找不到collect-context.sh,再一查才知道脚本里的相对路径依赖当前工作目录。解决方式是把脚本里所有涉及项目操作的路径都改成动态获取:
PROJECT_ROOT=$(git rev-parse --show-toplevel) cd "$PROJECT_ROOT"这是个特别基础的问题,但特别容易埋下定时炸弹。以后不管是谁跑脚本,它都会先找仓库根目录再干活,就不会因为启动位置不同而出现诡异行为了。
7.4 模板里引用文件列表,但没有过滤大文件
我还踩过一个坑:collect-context.sh会把所有变更文件列出来,包括一个 3MB 的 lockfile。Claude 为了“表现好”,试图去理解这个 lockfile 里的每一行依赖差异,直接把上下文撑爆了。
修法也很简单:在收集脚本里加一个过滤逻辑,超过阈值的大文件只保留文件名,不保留内容。这个经验放在其他场景也通用——在任何模板设计里,都要主动思考“哪些信息 AI 看了有用,哪些只是噪音”。
8. 我最终定型的一套增量式模板法
踩完这一圈坑之后,我的模板策略已经从“一次写个大而全”变成了“增量式、局部可替换”。现在我是这么组织 claude-code-templates 的:全局维护一套基准模板,每个项目用 CLAUDE.md 覆盖业务上下文,再用脚本收集实时状态,最后靠 hooks 维持长会话的一致性。这套结构跑了大半年,算是稳定下来了。
如果你准备照做,我的建议是别急着照搬全部,先做三件事:
- 找出你每周重复次数最多的 3 个任务(比如代码评审、写测试、解释老代码),针对这 3 个任务各写一份精简模板。
- 给模板仓库建 git,每次调整都提交一次,方便回溯“哪个改动导致输出变化”。
- 跑两周后,只保留真正提升了效率的规则,其余全部删掉。
模板系统真正有价值的不是“堆规则”,而是“沉淀决策”。每一条可靠的规则,背后都对应着一次踩坑或者一次团队讨论。把这些东西固化下来,AI 才能从一个“懂很多却经常跑偏的助手”,变成一个“虽然能力有限但每次都不掉链子的稳定协作者”。
如果有时间,我下一版模板里最想加的是一个自动更新模块——让模板根据项目最近的 git 历史自动调整部分上下文,省掉手动维护 CLAUDE.md 的负担。但目前这套方案已经足够解决我日常 80% 的痛点,剩下的,慢慢打磨就好。