
最近复盘团队里一个很有意思的对比同样用AI编程Agent干活有人半天生成三个功能模块代码却让review的同事直挠头有人半小时产出一个小工具从目录结构、依赖声明到Git提交信息都规规矩矩。差距不在模型也不在提示词写得有多华丽而在你有没有给Agent装上工程纪律。GitHub Skills系统解决的就是这件事——它把工程师日常遵循的规范、流程、检查项做成Agent能识别、能加载、能按步骤执行的操作规程。这篇文章我会从它解决的问题讲起拆开一个Skill包的内部构造聊清楚工程纪律到底是怎么被编码进Agent行为的最后给出一条可以直接上手的装配路径和一个完整的手写示例。1. AI编程Agent的有手无脑困境代码生成不等于工程交付1.1 大模型不缺能力缺的是交付出可维护代码的行为约束很多人第一次接触AI编程Agent时最大的冲击是它写代码太快了。一个登录接口、一个数据同步任务、一套CRUD页面几秒钟就能给你吐出来。但真正在真实仓库里跑上几轮之后你会发现问题不在能不能写出来而在写出来的东西能不能融入现有工程体系。我见过太多次这样的场景Agent接到一个给用户模块增加导出功能的任务直接在一个已有三千行代码的文件末尾追加了一个函数没有复用里面已有的工具方法没有考虑异常分支也没有碰任何测试。代码语法上没问题但放进项目里review的人得花十分钟理解它破坏了哪些隐式约定。类似的情况还包括擅自升级了某个传递依赖的版本、绕过了项目现有的日志规范、生成了和仓库风格完全不一致的命名。这些问题本质上不是模型能力问题是行为规范问题。大模型擅长的是从海量数据中学到一般情况下的代码长什么样但它看不到你的仓库里特约了哪些规矩。于是它默认按通用套路来而通用套路在这种已经有了几年积累的工程代码库里经常就是那个不太对劲的东西。1.2 工程纪律不是束缚是稳定的质量下限如果说创造力决定了代码的上限那工程纪律决定的就是下限。在人类组成的团队里下限靠什么兜住靠Code Review文化、靠PR模板、靠CI流水线里的测试和lint、靠README和架构文档里写清楚的约定。这些东西的共同特点是它们都在代码被合入主线之前设置了一道闸门。但到了AI编程Agent这里闸门很多失效了。Agent不会主动去翻你那份五十页的团队规范文档也不会因为你没在提示词里写记得跑测试就去跑测试。它的默认行为是尽量高效地完成你直接要求的事情而那些你没说但团队约定俗成的东西一律不在它的考虑范围内。这就出现了一个很尴尬的局面人类成员约定俗成的纪律在Agent面前因为不可见而等于不存在。工程纪律要真正约束Agent必须换一种形态——从给人读的文档变成给Agent执行的操作规程。1.3 Skills系统把说给人听的规范翻译成给Agent执行的操作规程GitHub Skills系统提供了一套规范化、结构化的方式来解决这个问题。简单说Skill就是一个自包含的技能包里面用一份带格式约束的说明文档SKILL.md说清楚什么场景用、按什么步骤做、有哪些硬性规定同时可以附带脚本、模板、参考资源让这些规定可以真实执行、可验证。你可以把它理解成给Agent发了一本员工手册以前是口头交代Agent听不听全看运气现在是它在每次动手前都会主动查看的操作规程并且里面的检查项有脚本兜底不是一张空头支票。更关键的是Skill是文件它可以放进Git仓库做版本管理团队里每个人、每个CI节点拿到的都是同一份纪律定义。这套思路落地之后工程纪律不再依赖每个工程师在提示词里的临场发挥而变成了代码库自带的基础设施。下面我拆开一个Skill包看看它内部到底长什么样。2. Skills包的内部构造一份给Agent的职业规范手册2.1 SKILL.mdAgent真正逐字阅读的那几页纸一个Skill包的核心是SKILL.md。这听上去像一个普通的Markdown文档但它有别于普通文档的地方在于Agent会把它当成指令来源而不是仅供参考的背景信息。这意味着文档里的每句话都可能转化为Agent的动作所以写作逻辑和写给人看的文档完全不同。典型的SKILL.md会包含一段frontmatter用来声明技能名称和描述。描述字段尤其关键因为它决定了Agent在什么情况下会把这个Skill拉出来用。描述写得太宽Agent会在跟技能不相干的场景里频繁误触发写得太窄Agent该用时又找不到它。比较合适的写法是在描述里明确适用范围和不适用范围两件事。正文部分则通常包含这个技能的目标、适用的输入、执行步骤、硬性约束、完成后的验收标准。这些内容越具体越好。比如检查代码风格这种表述就不合格合格的是运行仓库根目录下的npm run lint确认所有通过后在提交信息中附上lint结果摘要。2.2 scripts与resources让约束可执行SKILL.md里的自然语言写得再详细Agent的执行仍然可能出现偏差。真正的兜底是脚本。一个规范的Skill包通常会带一个scripts目录里面放可执行的检查脚本。Agent按SKILL.md的指示去调用脚本脚本返回通过或失败的结果失败时还会附带具体的错误信息Agent再根据这些信息修改代码。这个设计非常像人类团队里的CI光靠Code Review时说请你注意规范是不够的得有一个跑起来就会红灯的检查工具。对Agent来说脚本给了它一个明确的外部反馈信号而不必完全依赖模型自己感觉行不行。resources目录则存放模板、配置样例、参考文档。比如一个生成新组件的Skillresources里可以放组件目录的标准结构和一份符合团队风格的示例代码。Agent在创建新组件时直接参照这些资源比让它凭空发挥稳定得多。2.3 发现与加载Skill是怎么被找到的Skills的存放遵循一套约定。不同AI编程工具对目录路径的命名略有差异但逻辑相通可以放在用户级别的全局技能目录也可以放在仓库内部的.local/skills或.skills这类目录里。放在用户级目录意味着所有项目都能用适合放通用的、跨仓库的技能放在仓库目录则只对该仓库生效适合放高度定制化的工程规范。加载机制通常是Agent在启动任务时扫描这些目录读取每个Skill的frontmatter描述把它纳入自己的可用工具集合。之后当用户提的需求与某个Skill描述的场景匹配时Agent就会在回复中自动加载并遵循该SKILL.md中的流程。这个按需自动发现的机制决定了Skill描述质量的优先级非常高——你在SKILL.md里写不清楚的边界Agent就会用它的自由意志替你决定而它替你做的决定常常就是产生工程混乱的起点。3. 工程纪律的三大编码机制约束、编排与反馈闭环3.1 显式约束禁止做什么比应该做什么更容易被执行我早期写过一批Skills一开始通篇都是应该句式应该写测试、应该更新文档、应该遵循现有风格。实际跑下来发现效果有限因为Agent天然倾向于完成用户可见的功能而那些应该往往属于不可见的质量项优先级天然靠后。后来我把大量应该改成了禁止和必须效果立刻不一样。比如这样一段禁止修改package-lock.json或yarn.lock禁止在src之外的目录创建新文件所有对外接口必须保持向后兼容如果需要破坏性变更必须先在方案中说明并等待用户确认。这类显式约束在SKILL.md里优先级最高Agent在每一步动作前都会拿它对照一遍违反后会停下来说明情况。人类团队里这叫红线Agent的Skill里同样需要红线而且必须写得非常明确不给解释空间。有个经验是一条约束如果不能用一条命令或一个静态检查来判断是否违反那它大概率执行不到位。所以凡是能用脚本验证的约束一定要配合脚本使用这才是真正的可执行纪律。3.2 流程编排用checklist接管模糊任务工程纪律的另一层含义是流程顺序不能乱。人类工程师拿到一个任务会先看需求、再探索现有代码、然后设计方案、写代码、自测、提交。但Agent如果没有任何流程约束它经常跳步骤还没看现有实现就开写写完不跑测试就提交。所以我在Skill里会强制编排流程。一个典型的实现类任务被拆成了六个阶段理解需求、探索相关代码、输出实现方案、编写代码、运行验证、整理提交说明。每个阶段都有一个明确的输入和输出并且要求Agent在当前阶段完成之前不得进入下一阶段。这个设计模仿的是飞行员的checklist文化。飞行员起飞前会逐项检查仪表不是因为每检查一次飞机就更安全一点而是因为人类在熟悉任务中容易跳过关键步骤。Agent的越熟练越自信问题更严重因为它生成代码的过程几乎不带自我怀疑。流程编排等于在它的默认行为模式外面加了一层轨道让它必须按顺序走。3.3 反馈闭环执行-检查-纠错取代差不多就行Agent在生成长段代码时最大的问题是缺少一个诚实的自检信号。它不会自己感觉到这段代码可能有隐患——模型的输出是基于概率生成的不是基于验证的。所以必须在Skill里内置反馈机制。具体做法是在SKILL.md的每个关键节点嵌入检查指令写完模块后先运行单元测试看到输出结果后如果有失败项就要定位失败原因并修复再重新运行直到全绿才能继续。这个循环强调Agent必须读取脚本输出并基于输出行动而不是运行一下脚本然后忽略结果。真正执行起来你会发现加了这样一个反馈闭环Agent的代码质量提升非常明显。原因不复杂大模型其实知道很多代码问题但它默认不会主动去检查一旦Skill强制它把检查结果纳入下一步的考量它能识别和修复大量前面蒙着眼写出来的问题。纪律在这里起到的作用就是逼它把已知的验证知识派上用场。4. 从能跑到靠谱给Agent装配Skills的实操路径4.1 装配前先盘点你的仓库缺哪条纪律在动手配置Skills之前建议先花半小时盘点自己的仓库当前最缺哪种纪律。方法很简单翻最近十个合并的PR看看review里面最常见的评论集中在哪几类。如果评论总是这个改动影响到了其他使用方缺少测试提交信息不规范那这几件事就是你的Agent首先需要被约束的方向。用最小的投入解决最痛的问题。这个思路在引入工程纪律时要特别强调。你有可能会想一口气把文档、测试、风格、安全、提交规范全部塞给Agent但这样的Skill包多半会被Agent选择性忽略——因为它要遵守的东西太多了反而没有一个是强约束。与其这样不如先挑一个最痛的点把它做成一个完整的Skill跑顺了再加下一个。4.2 一套最低成本的角色纪律配置结合我的实践一个新建仓库如果要用Agent持续开发最低限度应该配备以下几类Skills。这里我用表格列出方便对照自己的情况选择。场景推荐Skill核心约束推荐脚本提交前检查代码变更规范跑lint、跑测试、确认无残留调试日志lint脚本、test脚本提交信息Conventional Commit规范校验提交信息格式、scope必须与变更模块对应commit-msg校验脚本文档同步README/API文档更新对外接口变更时同步更新文档文档完整性检测脚本依赖管理依赖变更审批禁止擅自升级依赖版本必须说明升级理由依赖diff检查脚本新文件生成模块创建规范新文件必须放置到约定目录遵循命名规范目录结构校验脚本配置的方式很简单把写好的SKILL.md和脚本放进仓库的.skills目录或者用户级技能目录然后在Agent的对话里直接要求它在处理任务时自动加载对应Skill即可。多数工具都支持在启动时扫描本地Skills目录甚至可以在项目根目录加一个说明让进入项目的Agent主动加载。4.3 我踩过的三个坑描述过宽、约束过载、缓存滞后第一个坑是Skill描述写得过宽。我给一个仓库写了仓库规范Skillfrontmatter里的描述是适用于这个仓库的所有开发任务。结果Agent在几乎每个任务里都会加载它导致每次响应都先输出一大段规范摘要反而拖慢了主流程。后来我把描述改成适用于涉及src目录下公共模块改动的任务触发频率立刻正常了。经验是描述里最好写清楚什么类型任务不需要使用本Skill负向排除对Agent的帮助比正向描述更大。第二个坑是单份SKILL.md里堆了超过二十条硬性约束。这种Skill看起来非常严谨但Agent实际执行时记不住那么多经常捡了前面几条丢了后面几条。后来我做了拆分一份Skill只聚焦一个行为主题比如依赖管理规范只处理依赖变更的审批流程代码提交规范只处理提交信息的检查。多个主题用多个Skill文件比一份大而全的文件有效得多。第三个坑是缓存问题。有些工具会缓存已加载的Skill列表修改SKILL.md后可能不会立即生效。我自己就遇到过改了描述但Agent还在用旧版本的场景排查半天才意识到是缓存没刷新。现在每次调整Skill内容后我都会重启会话或者主动触发一次重新扫描确认加载的是新版本再继续。5. 团队级技能治理让Skills成为团队的工程公约5.1 把Skills放进仓库克隆即获得工程公约如果Skills只停留在个人层面那它解决的是你个人用Agent的体验要让整个团队受益最直接的办法是把Skills作为仓库的一部分进行版本管理。新成员克隆仓库后本地工具自动扫描到仓库级Skills从第一天起就会受到同样的约束。这比让新人自己去看团队文档然后凭理解执行要可靠得多。把Skills放进仓库还有一个额外的好处它随着PR一起演进。任何一个Skill的修改都可以走代码评审流程。以前改团队规范要起草文档、发公告、等大家自觉执行现在改一个SkillPR合并之后所有用Agent开发的成员自然就切到了新流程。规范升级从靠人传话变成了改代码、合代码。这类仓库里建议至少包含三层内容Skill定义文件本身、配套的校验脚本、以及一个简短的使用说明。说明里不需要写过程流程只需要告诉使用者这个仓库自带哪些Agent技能、放在哪个目录、遇到问题找谁。5.2 与CI形成双闸门Agent预检流水线终审Skill的存在并不能替代CI正确的姿势是形成一个双闸门机制。Agent在本地开发时通过Skill做预检尽可能在提交之前把问题拦掉CI流水线在代码推到远端后做终审跑完整的测试、构建、安全扫描。两道闸门各管一段Skill负责帮Agent写对CI负责确认代码确实没问题。这个机制在实际运行中对开发节奏的改善很明显。以前Agent生成的PR经常在CI阶段红灯然后要来回提交好几次才能过现在Skill里已经内置了提交前必须本地跑过测试的约束很多基础错误在Agent阶段就被修正了CI红灯数量大幅下降人也轻松很多。需要注意的是Skill脚本和CI脚本尽量复用同一套检查核心避免两边规则不一致。如果Skill里说禁止修改lock文件而CI里没有对应检查那这条纪律就是软约束时间长了Agent还是会越界。把同一套规则做成一个脚本Skill调用它CI也调用它才能保证口径一致。5.3 治理纪律Skills本身也需要被维护Skills不是写完就一劳永逸的。随着仓库结构变化、依赖升级、团队规范调整Skill内容也会逐渐过时。最常见的腐化现象是仓库已经改用新测试框架了Skill里还写着旧的测试命令或者团队早就废弃了某个目录Skill还在强制生成文件到那里。维护Skills的最省力方式是给它设一个定期体检的节奏。我实践下来比较有效的方法是每个迭代周期结束时顺手把Agent在这期间犯过、且被CI拦下的错误类型整理一次看哪些错误是因为Skill覆盖不到导致的哪些是因为Skill描述不准确导致的。把这些结论沉淀回Skill更新里形成一个小闭环。另外Skill的变更记录最好和代码一样留痕。在仓库的release note或CHANGELOG里加一行更新了提交信息校验规则成本很低但能避免很久以后大家对着一个Skill文件不知道它为什么长成这个样子。6. 从零手写一个最小可用的Skill完整过程复盘6.1 明确边界给规范提交信息写一份操作规程前面讲的都是框架这一节用一个能直接上手的例子走完整流程。假设团队的痛点很具体Agent生成的PR提交信息格式混乱有的不写scope有的没按Conventional Commits来。我们来做一个规范提交信息的Skill。先明确边界这个Skill只负责一件事就是在Agent生成提交信息之前先校验提交信息是否符合团队约定的格式。不涉及代码风格、不涉及测试目的是让Skill足够聚焦触发起来更精准。6.2 完整的Skill目录与SKILL.md首先建立目录结构放进仓库的.skills目录下.skills/ └── conventional-commit/ ├── SKILL.md └── scripts/ └── check-commit-msg.shSKILL.md的内容大致长这样--- name: conventional-commit description: 在生成Git提交信息时使用。适用于编写或修改提交信息、PR标题和PR描述的场景。不适用于代码实现、代码审查或问题排查。若提交信息已符合Conventional Commits规范且包含正确的scope则无需使用本Skill。 ---# Conventional Commit 规范 本Skill确保Agent生成的Git提交信息严格遵循Conventional Commits格式。 ## 使用步骤 1. 先查看最近的提交历史了解仓库正在使用的scope命名约定。 2. 分析本次变更的模块归属选择最贴近的scope如果现有scope都无法覆盖使用*并说明原因。 3. 按以下格式生成提交信息( ):type必须是以下值之一feat、fix、docs、style、refactor、perf、test、build、ci、chore。 scope必须从仓库已有的scope列表中选取。 subject使用祈使句、不超过80个字符、首字母小写。 ## 硬性约束 禁止生成没有scope的提交信息。 禁止使用feat之外的type描述非功能性改动。 禁止在subject中使用中文标点。 禁止在提交信息正文中出现协作者姓名或邮箱。 ## 验收标准 提交信息必须通过scripts/check-commit-msg.sh的校验。脚本返回非零退出码时根据错误输出修正后重新生成。这份文档的关键是把禁用情况写进了描述又通过验收标准把必须通过脚本校验固化为强约束。仅靠自然语言时Agent可能觉得得写个scope大概差不多就行有了脚本兜底过不了就是过不了。6.3 一个可执行的commit-msg校验脚本配套脚本的作用是把SKILL.md里的验收标准变成可以执行的检查。下面是一个简单的bash脚本示例它做的事情是读取提交信息文件用正则检查格式输出错误并返回失败退出码。#!/usr/bin/env bash COMMIT_MSG_FILE${1:-/dev/stdin} MSG$(cat $COMMIT_MSG_FILE) TYPE_PATTERN^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)\( SCOPE_PATTERN^[a-z][a-z0-9-]*\): SUBJECT_PATTERN^[a-z0-9].{0,80}$ if ! grep -qE $TYPE_PATTERN $MSG; then echo 错误type必须是 feat/fix/docs/style/refactor/perf/test/build/ci/chore 之一并且必须带scope括号。 echo 示例feat(user-service): add email verification exit 1 fi if ! grep -qE ${TYPE_PATTERN}${SCOPE_PATTERN} $MSG; then echo 错误scope只能包含小写字母、数字和中划线且必须以右括号结尾。 echo 示例fix(auth): handle token expiry exit 1 fi if ! grep -qE : [a-z0-9] $MSG; then echo 错误subject必须以小写字母或数字开头。 exit 1 fi if ! awk NR2 { exit } /^.{81,}$/ { print \错误subject不能超过80个字符\ \/dev/stderr\; exit 1 } $MSG; then exit 1 fi echo 提交信息格式校验通过 exit 0这个脚本不需要多复杂关键是它给Agent提供了一个确定性的通过标准。当SKILL.md里写了必须通过脚本校验时Agent就会去调用这个脚本拿到失败输出后修改提交信息再重新跑直到退出码为0。6.4 实测、反例与迭代写完SKILL.md和脚本之后我在测试仓库里放了几条典型的错误提交信息来验证效果。第一条是fix login bug因为缺少scope被脚本拦下Agent根据错误提示改成了fix(auth): correct login redirect。第二条是FEAT: 新增接口type大小写和中文标点都不符合Agent也通过脚本反馈修正了。真正有价值的验证不光是看Skill能不能拦截错误还要看Agent在完全没被提示的情况下会不会自动加载它。我在一个干净会话里直接要求Agent提交刚才的改动发现它扫描仓库后主动将conventional-commit纳入执行流程说明Skill的自动发现机制是通的。这个小而完整的示例可以直接扩展成一套团队纪律库。比如再写一个测试先行Skill强制Agent每次新增功能前先补齐测试用例再动手实现再写一个变更日志Skill要求Agent在涉及对外接口变更时自动更新CHANGELOG。每个Skill独立演进聚合起来就是一棵完整的纪律树。我在实际项目中跑通这套流程之后的体会是GitHub Skills系统真正解决的不是让Agent写出更强的代码而是让它在无人盯守的情况下也按同一个稳定的标准把事情做完。模型的能力用户在持续提升但工程纪律不会自动伴随能力提升出现——它需要被显式定义、结构化承载、持续维护最终才能成为团队默认的工作方式。对任何把AI编程Agent放在真实生产仓库里的团队来说这件事的优先级应该排在更换更强模型之前。