关于 vibe coding 如何提升代码效率和质量的技巧之 skill

查看 28|回复 3
作者:woodchen   

本文原始发布在: https://www.sunai.net/t/1407
本文使用 claude opus 4.8 协助编写

我身边不少人对 vibe coding 是有怨气的。模型已经够强了,Claude Code 这种工具也摆在面前,但他们的结论往往是:AI 写的代码不可靠,能跑但不敢上线,改一处崩三处,review 起来比自己写还累。
我自己用下来感受完全不一样。同样的模型、同样的工具,产出质量差距很大,差别基本不在模型,而在你有没有把"你这个人/你这个团队的工程判断"喂给它。大多数人把 AI 当成一个许愿池,丢一句话进去等结果;而真正能让 AI 稳定产出可上线代码的方式,是把你脑子里那套"什么叫写对了"的标准,固化成它每次都会读的东西。
这篇就讲我是怎么做的——核心是一个自己写的 code skill 。下面用的所有例子都来自我自己维护的 czl-code-skill 仓库。
一、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.md 了,为什么还要 skill
这是被问得最多的问题。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 怎么写——主 SKILL.md 加 references 目录
结构上就两层:
顶层一个 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 等等。
路由表长这样(节选):
[td]任务关键词[/td]
[td]必读 references[/td]
通用规范 / 改动幅度 / 自审 / 命名
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 质量——一个方向一个文件,避免长上下文
这是我觉得最反直觉、也最值钱的一条经验:skill 的质量上限,很大程度上由"拆得够不够细"决定,而不是"写得够不够多"决定。
很多人写规范文档的直觉是堆成一个大全。一个文件几千行,从命名到部署到 UI 到安全全在里面。这个东西的问题不是它"不全",而是它没法被精确加载。AI 要么全读(上下文爆炸、注意力稀释),要么不读(规则形同虚设)。
我的做法是反过来的:一个方向、一种特定要求,就单独一个文件。 颜色规范、字体规范、响应式规范、布局组件规范、loader 规范,我全拆开了。frontend-design.md 只是个主索引加全局 token 清单加自检清单,具体到配色去读 1-color.md,具体到布局组件去读 4-layout-and-components.md。
这么拆有三个好处,按重要性排:
[ol]
  • 按需加载,上下文干净。 AI 改配色时只加载颜色那个文件,不会被几千行无关规则淹没。上下文越干净,它对当前这条规则的执行越准。这是拆分最核心的收益——你不是在整理文档,你是在控制 AI 每次真正读进脑子的是什么。
  • 规则之间不打架。 同一类规则收敛在一个文件里,避免"命名规范在三个文件里各写一遍、还互相矛盾"。需要交叉引用时用相对链接指过去,不重复写。
  • 维护成本低。 改一条颜色规则,只动 1-color.md,不用在巨型文件里翻来覆去找。
    [/ol]
    判断拆不拆,我用的标准和我对代码的标准是同一套——基于职责,不是基于行数。一个 references 文件只承担一个领域的规则。如果一个文件同时在讲后端错误处理和前端动画,那它就该拆,哪怕它才 200 行。反过来,一个讲 Go 后端完整规范的文件就算 500 行,只要它职责单一、删哪段都伤完整性,那就不拆。
    顺带说,这条"按职责拆而非按行数拆"的原则,我同时也写进了 skill 里去约束 AI 写的代码。skill 里的硬规则是:单文件、单函数承担的独立职责不超过一个;行数(文件 400 / 组件 300 / 函数 80 )只是触发你停下来评估一次的信号,评估结论完全可以是"职责单一,不拆";但文件超 600 行 / 函数超 200 行还决定不拆的,必须在文件头注释里写清楚为什么不拆——写不出来就说明其实该拆。规则自己也遵守自己定的规则,这种一致性本身就让整套东西更可信。
    五、装好 skill 之后,怎么确保它真的被调用
    把 skill 装到 ~/.claude/skills/czl-code-skill 只是第一步。装了不代表会被用——AI 有它自己的判断,可能觉得"这个小任务不用加载吧"就跳过了。我吃过这个亏:明明装了 skill ,它改个小文件时压根没读,产出还是默认风格。
    解决办法是在 ~/.claude/CLAUDE.md 里显式下一道强制加载的指令,把"什么时候必须加载 skill"这件事本身也变成硬规则。我的全局 CLAUDE.md 里有这么一段(这里贴的是我实际在用的):

    强制加载 czl-code-skill (硬规则)
    违反本节属于硬错误,不是"风格问题"。本节优先级高于任何"任务太小""我已经知道了""快速回答"的自我判断。
    触发条件:只要本次任务涉及"代码 / 项目 / 配置 / 工程文档"中的任何一项,必须通过 Skill 工具加载 czl-code-skill,由 SKILL.md 路由到对应 references ,然后才能继续后续动作。

    关键设计有这么几点,每一点都是被实际问题逼出来的:
  • 判定靠任务实质,不靠关键词匹配。 我没写"看到'重构'两个字就加载",而是写"任何形式的读/写/改/删项目内源码、配置、文档都要加载"。因为 AI 很会钻空子,你列关键词它就只认那几个词。
  • 明确写出例外清单。 纯闲聊、纯翻译、纯查命令用法、操作目标完全在项目目录外——这几种才允许不加载。把例外写死,剩下的模糊场景一律加载。我还专门加了一句"模糊场景一律加载",堵掉它自己找借口的路。
  • 堵掉"任务太小"这个借口。 我特意写明"skill 内的各项规则对小改动同样适用,不存在任务太小可跳过"。AI 最爱用的偷懒理由就是"这么小的改动应该不用那么麻烦",必须显式禁掉。
  • 领域切换要重新查路由。 同一个会话里从写后端切到调 UI ,得重新去查 SKILL.md 的路由表按新场景加载,不能拿着后端的规则去改前端。
  • 给加载失败留兜底。 万一 Skill 工具不可用,退回 CLAUDE.md 里一段精简的兜底规范,并且要求 AI 在回复里显式说明"未能加载 skill ,使用兜底规范"——这样我一眼就知道这次产出可能没完全按标准来。

    这一层是很多人漏掉的。光写 skill 不够,你得用更高优先级的全局指令保证它真的被读进去,否则写得再好也是摆设。
    六、skill 里必须有这三条——动手前穷举边界、动手前自检、动手后必自审
    前面讲的都是结构和加载机制。但 skill 真正决定代码质量的,是里面装了什么规则。如果让我只保留三条,我会保留下面这三条——它们直接对应"AI 写的代码为什么不可靠"这个问题的根因。
    AI 写代码有两个非常稳定的失误模式:一是只顺着你描述的那条正常路径写,边界和异常分支全靠运气;二是写完就交付,从不回看自己写了什么。这俩加起来,就是"能跑但不可靠"的全部来源。这三条规则就是专门治这两个病的。
    动手前:穷举边界与分叉。 我在 skill 里要求,接到需求或 bug 后,先在脑子里(或 todo 里)显式列出六个维度的清单,再动笔。不是写注释,是逼它"想过":
  • 输入维度:空值、空数组、空对象、极值( 0 、负数、超大数、超长字符串、emoji 、换行、引号)、非法值、重复提交、并发写同一资源
  • 状态维度:未登录、登录了但没权限、session 过期、上游返回空、依赖资源被删、字段为 null 、多 tab 同时操作
  • 流程分叉:成功、业务失败、系统失败(超时、5xx 、数据库断连)、用户中途取消/刷新/后退、部分成功的回滚、重试是否幂等
  • 并发与时序:双击提交会不会写两条、多用户抢同一资源、异步回调到达顺序有没有被默认假设
  • 契约影响:这次改动有没有动接口字段/错误码/Cookie/表结构,已有调用方要不要同步改
  • 结构维度:先 Read 一眼目标文件,判断新逻辑该落在哪、当前文件是不是已经在做多件不相干的事、要不要先拆再写

    清单不要求每条都写代码处理,但要求每条都明确表态——处理、显式忽略、还是不适用。选"忽略"或"不适用"的,要在交付说明里点出来让我能复核。这一条把"AI 顺着 happy path 开写"这个最大 bug 来源直接堵死了。
    动手后:完工自审。 单个需求改完,不许立刻交付,先用 reviewer 的视角重走一遍。我列了九条,核心几条:
    [ol]
  • 重读 diff ,不靠记忆。 通读刚改的所有文件,抓多余调试代码、TODO 残留、注释掉的死代码、复制粘贴漏改、import 没清。顺手再按拆分信号回看一眼有没有往单一职责的文件里塞进不相干的东西。
  • 回放调用链。 从入口(路由/按钮/命令)一路追到底层(数据库/外部 API ),确认每一跳的入参出参符合预期,错误有没有被正确传播。
  • 回放动手前那张清单。 当时列的边界和分叉,现在代码里是不是真的处理了,而不只是"想过了"。
  • 错误路径、并发重入、回滚开关、对外契约、测试验证逐项过。
  • 复杂改动起子 agent 复审。 跨多文件、动了核心模块或对外契约的,自审完再起一个独立的 review subagent 看一遍,借"无上下文 reviewer"的视角抓自己看不见的盲点。
    [/ol]
    自审发现的问题当轮直接修掉,不许写进 TODO 留给下一轮(除非正交于本次需求、或依赖外部资源拿不到)。
    还有一条我也归在这组里:改动幅度决策。 AI 有个很坑的默认倾向——把"最少行数变更"当成最安全的方案,结果就是绕开真正的痛点、在烂代码上继续打补丁。我在 skill 里明确写:"现有项目优先"指尊重既有架构,不是默认选最小改动。每次非平凡改动都要做一次幅度评估:先识别有没有结构性痛点(重复逻辑、错误抽象、修一处带一串),再评估"局部修补 vs 一次性重构"两条路,然后给出明确推荐而不是把两条路一摆让我选,最后由我拍板。同一段逻辑在三处以上重复、抽象已经和实际用法偏离、某模块反复出问题、用户描述的是"每次都要……"这种痛点——这些信号出现时,倾向推荐重构。
    这三条(穷举边界、完工自审、幅度决策)是整个 skill 的灵魂。架构和命名规范决定代码长得好不好看,这三条决定代码可不可靠、敢不敢上线。如果你的 skill 里只来得及写三条,写这三条。
    七、skill 要持续更新——每发现一个值得落盘的东西就写进去
    最后一条,也是最容易被忽略的:skill 不是一次写完就放那的,它是活的。
    我的工作流是这样的:每次和 AI 协作中,只要冒出一个"值得落盘的东西",我就把它写进 skill 。什么叫值得落盘?标准很简单——这个东西换个项目、换个会话还会再遇到,而且我不写下来 AI 下次还会犯同样的错或者错过同样的判断。
    几个真实例子,都是后来补进 skill 的:
  • 有次 AI 给一个新项目的 Go 服务用 go:embed 把前端产物嵌进二进制。我当时没说要这么干,它自作主张。我意识到这是个会反复出现的默认行为,就在 skill 里加了一条:Go 托管前端一律用 http.FileServer 挂 out/,禁止 go:embed,单二进制零依赖分发是唯一例外且要在 CLAUDE.md 记录。
  • 处理 Stripe webhook 时踩过多项目事件串扰的坑——不同项目共用一个 Stripe 账户,回调互相收到对方的订单。这种坑非常隐蔽,我专门开了个 stripe-webhook.md,把"强制用 metadata.app 标记项目归属、入口处按归属过滤、验签和返回码语义、幂等"全写进去。下次任何项目接 Stripe 都不会再踩。
  • PWA 那块也是逐步沉淀的。一开始只是发现带 cache 策略的 Service Worker 在静态站点上会造成各种缓存问题,后来定下"默认只部署清缓存的 no-op SW + manifest"这个策略,连 no-op sw.js 的完整实现都放进了 skill ,确保每次都一致。

    每一条规则背后,基本都是一次真实的踩坑或一次真实的"AI 默认行为不符合我预期"。skill 的价值就在于:同样的坑我只踩一次,之后它替我记住。 这是它和一次性 prompt 最大的区别——prompt 是消耗品,skill 是资产,会复利。
    具体怎么维护我也有约束,免得它自己也长成一坨流水账:加新规则前先判断属于哪个 references 文件,在已有小节里扩展,确实无法归入才新建文件;同类规则不在多个文件重复写,用相对链接交叉引用; SKILL.md 主索引保持精炼,详细规则下沉到 references 。改完一定要跑同步脚本推到各个工具的 skill 目录,否则本地实际加载的还是旧版。
    写在最后
    把这七条连起来看,其实是一个很朴素的逻辑:
    AI 不可靠,不是因为模型笨,是因为它不知道你的标准,也没有强制它对照标准的机制。skill 干的就是这两件事——把你的工程判断显性化成它每次都读的规则,再用全局指令强制它每次都读。
    写自己的 skill ,按方向拆细、按需加载,把"动手前穷举边界、写完必自审、该重构就推荐重构"这几条灵魂规则装进去,再持续把每次踩的坑沉淀回来。做到这些,你会发现 AI 写的代码不仅快,而且是真的敢上线的那种可靠。
    vibe coding 不是把脑子交出去,是把你脑子里那套标准,变成 AI 的标准。

    SKILL, 标准, 可靠

  • zhqiang   
    正在开始学习 cc ,感谢分享
    tinyJoy   
    感谢分享,学习一下
    zhqiang   
    另外能 share 下这个 czl-code-skill 仓库么
    谢谢
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部