





















本文原始发布在: https://www.sunai.net/t/1407
本文使用 claude opus 4.8 协助编写
我身边不少人对 vibe coding 是有怨气的。模型已经够强了,Claude Code 这种工具也摆在面前,但他们的结论往往是:AI 写的代码不可靠,能跑但不敢上线,改一处崩三处,review 起来比自己写还累。
我自己用下来感受完全不一样。同样的模型、同样的工具,产出质量差距很大,差别基本不在模型,而在你有没有把"你这个人/你这个团队的工程判断"喂给它。大多数人把 AI 当成一个许愿池,丢一句话进去等结果;而真正能让 AI 稳定产出可上线代码的方式,是把你脑子里那套"什么叫写对了"的标准,固化成它每次都会读的东西。
这篇就讲我是怎么做的——核心是一个自己写的 code skill 。下面用的所有例子都来自我自己维护的 czl-code-skill 仓库。
skill 这个概念不复杂:一段带触发条件的、可被 AI 按需加载的规则文档。Claude Code (以及 Codex 、Gemini 这些支持同一套 skill-creator 标准的工具)会在合适的时机把它读进上下文,然后照着里面的规则干活。
它和你随手发给 AI 的一段 prompt 的区别在于两点:一是持久,写一次,之后每个会话、每个项目都能复用,不用每次重新交代;二是带路由,它不是一坨平铺的长文档,而是一个入口加一堆分领域的细则,AI 按当前任务只读相关的那部分。
那为什么要写"自己的",而不是用网上现成的规范?因为编程这件事根本没有放之四海皆准的标准。命名风格、目录结构、该不该用 go:embed、空数据返回 null 还是空对象、Cookie 还是 localStorage 做认证——这些每个团队的答案都不一样,而且很多答案是你踩过坑才定下来的。
AI 不知道你踩过哪些坑。它的默认行为是"统计意义上最常见的写法",而最常见的写法对你的项目往往恰好是错的。我写 skill ,本质上是在做一件事:把我脑子里那套隐性的工程判断显性化、文档化,让 AI 每次都按我的标准来,而不是按互联网平均水平来。
举个我自己的例子。我的 skill 里硬性规定了新项目根目录必须按端拆分成 server/ web/ desktop/,即使只有一个后端加一个前端也不许扁平化,不许在仓库根放 Go 源码。这不是什么通用真理,是我的偏好。没有这条规则,AI 十有八九会把 main.go 直接丢在根目录——因为大量开源项目就是这么干的。有了这条规则,它每次都拆得很整齐。
这是被问得最多的问题。Claude Code 本来就会读 ~/.claude/CLAUDE.md(全局)和项目根的 CLAUDE.md(项目级),把规则写那里不就行了?
不行,而且这俩根本不是一个东西。我是这么分工的:
项目级 CLAUDE.md 是"这个项目当前长什么样"的快照。 它写的是事实,不是规范:这个项目用什么架构、有哪些目录约定、对外接口的路径和错误码、哪些地方有反直觉的坑("该模块禁用 SSR 因为……")。它是给"未来接手这个项目的 AI 或人"看的说明书。我的 skill 里专门有一节约束它怎么写,第一条就是禁止写流水账——不许写"本次新增/本次修复",不许写日期戳加改动列表,不许堆 changelog 。判断标准我写得很直白:一句话三个月后读起来像考古笔记,就不该出现在 CLAUDE.md 里。同时限定项目级不超过 300 行,超了多半是塞了流水账。
skill 是"我这个人写代码的方法论",跨项目不变。 改动该大改还是小修怎么判断、动手前要穷举哪些边界、写完怎么自审、文件多长该拆、命名用哪种 case——这些和具体项目无关,是我对"什么叫写好代码"的定义。它们不该塞进每个项目的 CLAUDE.md 里重复一遍。
还有一个很现实的原因:体积。如果把我所有规范都堆进 ~/.claude/CLAUDE.md,那玩意会变成几千行的巨物,每个会话无脑全量加载,挤占上下文不说,还拖慢响应、稀释注意力。skill 的路由机制天然解决这个——主文件很小,细则按需读。这点下面专门讲。
一句话区分:CLAUDE.md 回答"这个项目是什么样",skill 回答"我写代码该怎么写"。 前者随项目走,后者跟着我走。
结构上就两层:
顶层一个 SKILL.md,是唯一带 frontmatter 的入口文件。 frontmatter 里写 skill 名字、描述和触发词——触发词很关键,它决定了 AI 在什么场景会想起来加载这个 skill 。我的触发词列得很细:"写代码、改 bug 、重构、新建项目、改 UI 、加 API 、改 CLAUDE.md 、Dockerfile 、命名规范、Go 包结构、PWA 、Service Worker 、拆文件、文件太长……" 列得越具体,命中越准。
SKILL.md 正文我只放三样东西:默认架构(新项目默认用什么技术栈)、规则优先级(用户要求 > 现有项目约定 > 领域规范 > 默认规则,冲突时照这个顺序来)、还有一张触发词到 references 的路由表。正文不展开任何细则,每条规则就一句话要点加一个指向 references 的链接。
references/ 目录放具体规则,每个文件一个领域,都是普通 Markdown ,不带 frontmatter 。 我现在拆成了这些:coding-standards.md(通用编程规范)、go-backend.md( Go 后端)、nextjs-frontend.md( Next.js )、frontend-design.md( UI 视觉,下面还按颜色/字体/布局/loader 再拆了子文件)、pwa.md、stripe-webhook.md 等等。
路由表长这样(节选):
| 任务关键词 | 必读 references |
|---|---|
| 通用规范 / 改动幅度 / 自审 / 命名 | coding-standards.md |
| Go 后端 / 包结构 / GORM / 时区 | coding-standards.md + go-backend.md |
| Next.js / static export / Shadcn | frontend-common.md + nextjs-frontend.md |
| PWA / Service Worker / manifest | pwa.md |
AI 接到任务,先读小小的 SKILL.md,从路由表查出该读哪几个 references ,再去读那几个。改 Go 后端就不会去加载一堆 UI 视觉规范。
有个写作上的硬约束我一直在坚持:skill 和 references 里只写规则和逻辑,不写代码块。 字段名、命令名、API 名用反引号标一下就够了,连反例正例都改写成自然语言描述。原因是代码块特别容易过期,而且会诱导 AI 去照抄那段具体代码而不是理解背后的规则。例外只有极少数确实需要"必须能直接复制"的东西——比如 PWA 那个 no-op service worker 的完整实现、品牌 loader 组件的完整实现,这种才允许放整段代码。
这是我觉得最反直觉、也最值钱的一条经验:skill 的质量上限,很大程度上由"拆得够不够细"决定,而不是"写得够不够多"决定。
很多人写规范文档的直觉是堆成一个大全。一个文件几千行,从命名到部署到 UI 到安全全在里面。这个东西的问题不是它"不全",而是它没法被精确加载。AI 要么全读(上下文爆炸、注意力稀释),要么不读(规则形同虚设)。
我的做法是反过来的:一个方向、一种特定要求,就单独一个文件。 颜色规范、字体规范、响应式规范、布局组件规范、loader 规范,我全拆开了。frontend-design.md 只是个主索引加全局 token 清单加自检清单,具体到配色去读 1-color.md,具体到布局组件去读 4-layout-and-components.md。
这么拆有三个好处,按重要性排:
1-color.md,不用在巨型文件里翻来覆去找。判断拆不拆,我用的标准和我对代码的标准是同一套——基于职责,不是基于行数。一个 references 文件只承担一个领域的规则。如果一个文件同时在讲后端错误处理和前端动画,那它就该拆,哪怕它才 200 行。反过来,一个讲 Go 后端完整规范的文件就算 500 行,只要它职责单一、删哪段都伤完整性,那就不拆。
顺带说,这条"按职责拆而非按行数拆"的原则,我同时也写进了 skill 里去约束 AI 写的代码。skill 里的硬规则是:单文件、单函数承担的独立职责不超过一个;行数(文件 400 / 组件 300 / 函数 80 )只是触发你停下来评估一次的信号,评估结论完全可以是"职责单一,不拆";但文件超 600 行 / 函数超 200 行还决定不拆的,必须在文件头注释里写清楚为什么不拆——写不出来就说明其实该拆。规则自己也遵守自己定的规则,这种一致性本身就让整套东西更可信。
把 skill 装到 ~/.claude/skills/czl-code-skill 只是第一步。装了不代表会被用——AI 有它自己的判断,可能觉得"这个小任务不用加载吧"就跳过了。我吃过这个亏:明明装了 skill ,它改个小文件时压根没读,产出还是默认风格。
解决办法是在 ~/.claude/CLAUDE.md 里显式下一道强制加载的指令,把"什么时候必须加载 skill"这件事本身也变成硬规则。我的全局 CLAUDE.md 里有这么一段(这里贴的是我实际在用的):
强制加载 czl-code-skill (硬规则)
违反本节属于硬错误,不是"风格问题"。本节优先级高于任何"任务太小""我已经知道了""快速回答"的自我判断。
触发条件:只要本次任务涉及"代码 / 项目 / 配置 / 工程文档"中的任何一项,必须通过 Skill 工具加载
czl-code-skill,由 SKILL.md 路由到对应 references ,然后才能继续后续动作。
关键设计有这么几点,每一点都是被实际问题逼出来的:
这一层是很多人漏掉的。光写 skill 不够,你得用更高优先级的全局指令保证它真的被读进去,否则写得再好也是摆设。
前面讲的都是结构和加载机制。但 skill 真正决定代码质量的,是里面装了什么规则。如果让我只保留三条,我会保留下面这三条——它们直接对应"AI 写的代码为什么不可靠"这个问题的根因。
AI 写代码有两个非常稳定的失误模式:一是只顺着你描述的那条正常路径写,边界和异常分支全靠运气;二是写完就交付,从不回看自己写了什么。这俩加起来,就是"能跑但不可靠"的全部来源。这三条规则就是专门治这两个病的。
动手前:穷举边界与分叉。 我在 skill 里要求,接到需求或 bug 后,先在脑子里(或 todo 里)显式列出六个维度的清单,再动笔。不是写注释,是逼它"想过":
清单不要求每条都写代码处理,但要求每条都明确表态——处理、显式忽略、还是不适用。选"忽略"或"不适用"的,要在交付说明里点出来让我能复核。这一条把"AI 顺着 happy path 开写"这个最大 bug 来源直接堵死了。
动手后:完工自审。 单个需求改完,不许立刻交付,先用 reviewer 的视角重走一遍。我列了九条,核心几条:
自审发现的问题当轮直接修掉,不许写进 TODO 留给下一轮(除非正交于本次需求、或依赖外部资源拿不到)。
还有一条我也归在这组里:改动幅度决策。 AI 有个很坑的默认倾向——把"最少行数变更"当成最安全的方案,结果就是绕开真正的痛点、在烂代码上继续打补丁。我在 skill 里明确写:"现有项目优先"指尊重既有架构,不是默认选最小改动。每次非平凡改动都要做一次幅度评估:先识别有没有结构性痛点(重复逻辑、错误抽象、修一处带一串),再评估"局部修补 vs 一次性重构"两条路,然后给出明确推荐而不是把两条路一摆让我选,最后由我拍板。同一段逻辑在三处以上重复、抽象已经和实际用法偏离、某模块反复出问题、用户描述的是"每次都要……"这种痛点——这些信号出现时,倾向推荐重构。
这三条(穷举边界、完工自审、幅度决策)是整个 skill 的灵魂。架构和命名规范决定代码长得好不好看,这三条决定代码可不可靠、敢不敢上线。如果你的 skill 里只来得及写三条,写这三条。
最后一条,也是最容易被忽略的:skill 不是一次写完就放那的,它是活的。
我的工作流是这样的:每次和 AI 协作中,只要冒出一个"值得落盘的东西",我就把它写进 skill 。什么叫值得落盘?标准很简单——这个东西换个项目、换个会话还会再遇到,而且我不写下来 AI 下次还会犯同样的错或者错过同样的判断。
几个真实例子,都是后来补进 skill 的:
go:embed 把前端产物嵌进二进制。我当时没说要这么干,它自作主张。我意识到这是个会反复出现的默认行为,就在 skill 里加了一条:Go 托管前端一律用 http.FileServer 挂 out/,禁止 go:embed,单二进制零依赖分发是唯一例外且要在 CLAUDE.md 记录。stripe-webhook.md,把"强制用 metadata.app 标记项目归属、入口处按归属过滤、验签和返回码语义、幂等"全写进去。下次任何项目接 Stripe 都不会再踩。每一条规则背后,基本都是一次真实的踩坑或一次真实的"AI 默认行为不符合我预期"。skill 的价值就在于:同样的坑我只踩一次,之后它替我记住。 这是它和一次性 prompt 最大的区别——prompt 是消耗品,skill 是资产,会复利。
具体怎么维护我也有约束,免得它自己也长成一坨流水账:加新规则前先判断属于哪个 references 文件,在已有小节里扩展,确实无法归入才新建文件;同类规则不在多个文件重复写,用相对链接交叉引用; SKILL.md 主索引保持精炼,详细规则下沉到 references 。改完一定要跑同步脚本推到各个工具的 skill 目录,否则本地实际加载的还是旧版。
把这七条连起来看,其实是一个很朴素的逻辑:
AI 不可靠,不是因为模型笨,是因为它不知道你的标准,也没有强制它对照标准的机制。skill 干的就是这两件事——把你的工程判断显性化成它每次都读的规则,再用全局指令强制它每次都读。
写自己的 skill ,按方向拆细、按需加载,把"动手前穷举边界、写完必自审、该重构就推荐重构"这几条灵魂规则装进去,再持续把每次踩的坑沉淀回来。做到这些,你会发现 AI 写的代码不仅快,而且是真的敢上线的那种可靠。
vibe coding 不是把脑子交出去,是把你脑子里那套标准,变成 AI 的标准。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。