拓冰建站拓冰建站
首页 / 资讯中心 / 正文

从提示词收藏到Agent Skills:构建可复用AI技能库的工程化实践

说个最近一直在琢磨的事。我也是被 Andrej Karpathy 在公开分享里反复提到的那个观点“真正重要的不是某个 prompt 写得有多精巧而是你能不能把一次成功的工作方式沉淀成可复用的能力”反复敲打最后彻底掉进了 Agent Skills 这个坑。这一年多我从最开始收藏一堆提示词到后来被 Claude Code、Codex、OpenCode 这些工具带着走再到自己动手写 SKILL.md、设计技能包的目录结构、甚至给团队内部的技能库做回归测试整个思路发生了很大的变化。这篇文章不打算写成什么标准教程而是从我自己的踩坑和复盘讲起把“skills”究竟是什么、它的底层结构怎么设计、实际开发中哪些环节最容易翻车完整地拆给你看。无论你是刚开始接触 agent 开发的新手还是已经上手了几个工具想在工程化上更进一步这篇应该都能给你一些能直接落地的参考。1. 从“提示词收藏夹”到“Agent 技能库”一次方法论迁移我最早用大模型干活的方式大概率和你差不多在聊天窗口里把背景信息、需求、约束条件一股脑贴进去然后一边调整措辞一边祈祷生成结果靠谱。遇到有价值的长 prompt就存到收藏夹或者网盘里下次干活再复制出来改改。这套玩法在单轮对话、任务边界清晰的时候是没问题的可一旦涉及到多文件项目分析、持续集成、批量代码重构这类复杂任务就会发现两个特别要命的问题第一同样的 prompt 在不同的上下文窗口里表现极不稳定稍微多贴几段日志它就“忘了”前面的规则第二所谓经验只存在于聊天记录里换个人、换个项目、换台机器一切都要从头再来。Karpathy 有一句被我摘进笔记的话大意是“我们不该训练模型去匹配提示词而应该让执行环境去承载一部分智能”。这句话我一开始没太当回事直到后来接触到 Claude Code 的 skills 目录和 Codex 的 skill 机制才反应过来skills 本质上就是把“一次性对话”升级成了“可挂载的工程资产”。它不是一个提示词而是一个自包含的目录里面装着任务说明、示例、脚本、约束文件甚至还有一组用来验证结果是否达标的测试用例。Agent 在启动任务时按需加载这个目录相当于给模型外挂了一套“操作手册 工具集”。为什么偏偏是这个时间点 skills 突然火起来两个原因。一是模型本身的上下文窗口虽然变大了但“上下文质量”并没有等比提升给得越多注意力越分散结构化、局部化的指令反而更可控二是 agent 类应用的执行链路变长了单靠自然语言已经没法约束住模型的自由度必须把一部分“约束”下沉到文件层、脚本层和校验层。所以 skills 不是一个锦上添花的功能而是 agent 工程化的必然产物。1.1 为什么“skills”比“精心设计的 prompt”更进一步很多人第一次看到 SKILL.md 文件时的反应是这不就是把提示词写进 markdown 吗我一开始也这么想直到真正上手才意识到差别很大。普通 prompt 是给模型看的“一次性输入”只有文本本身而一个技能包是给模型和解释器共同看的“多文件工程”除了指令文本它还包括了文件读取、脚本执行、结果校验等多个环节。举个例子我写过一套“Git 仓库变更分析”技能目录长这样git-change-analysis/ ├── SKILL.md ├── scripts/ │ ├── collect_diff.py │ └── detect_risk.py ├── references/ │ └── common_mistakes.md └── tests/ ├── case01_input.txt ├── case01_expected.txt └── run_tests.shSKILL.md 里只写了这个技能在什么场景下使用、应该按什么步骤执行、必须调用 scripts 下哪个脚本、结果的输出格式是什么。而真正的“智能”有一部分落到了 collect_diff.py 和 detect_risk.py 里——脚本负责过滤无效 diff、计算文件变更热度、标记可能存在安全风险的改动点。模型只是个调度员它调用脚本拿到结构化结果再基于结果生成结论。这比“请仔细分析以下 git diff”可靠得多因为脚本的确定性是模型不具备的。1.2 技能、工作流、MCP 工具到底有什么区别概念混乱是刚接触 skills 时最大的阻碍。我梳理了自己实际用下来后的理解三者区别如下维度技能Skill工作流WorkflowMCP 工具核心载体SKILL.md 引用文件 脚本多步骤编排定义文件独立功能性接口解决的问题教会模型“怎么做一类任务”规定“任务按什么顺序执行”提供“模型可调用的外部能力”是否包含代码可以包含脚本和测试通常是配置文件如 YAML/JSON是独立服务/函数粒度任务级偏“方法论”流程级偏“流水线”原子级偏“动作”生命周期随着经验迭代相对稳定按需部署简单说技能是“做一件事的方法包”MCP 是“能用的工具”工作流是“串起多个动作的剧本”。一个技能在运行过程中可以调用多个 MCP 工具也可以触发一个工作流反过来一个工作流也可以在不同步骤加载不同技能。理解了这层关系再去设计自己的技能库就不容易搞混。2. 拆解一个完整 Skills 包SKILL.md、脚本资源与工具绑定要真正掌握 skills最直接的办法就是找一个成熟的开源技能库拆开看。我一开始用的是社区里比较知名的几个仓库把里面的结构从头到尾过了一遍后来自己也仿照这个体系搭了一套。下面我把一个标准技能包的各个组成部分以及它们各自的作用讲清楚。2.1 SKILL.md 的构成Frontmatter、指令体、示例区SKILL.md 是整个技能包的入口。Agent 加载技能时首先读取的就是这个文件所以它的结构会影响模型对整个技能的“第一印象”。一个完善的 SKILL.md 通常分三块--- name: frontend-code-review description: 用于前端项目代码审查重点关注组件性能、可访问性、状态管理设计适用于 React/Vue 项目提交 MR 前的自检阶段。 license: MIT metadata: version: 0.3.1 priority: high --- # 前端代码审查技能 ## 适用场景 - 提交 MR/PR 前对本次改动做一轮系统检查 - 针对组件重复渲染、useEffect 依赖缺失、无障碍属性遗漏等问题进行定位 ## 执行步骤 1. 读取目录下的 CHANGES.diff 文件若不存在则运行 git diff --staged 生成 2. 运行 npx eslint --format json 获取静态检查结果 3. 调用 scripts/analyze_components.py 解析变更涉及的组件文件 4. 按【输出模板】输出审查结论不要输出与结论无关的内容 ## 关键约束 - 只关注变更文件本身不展开全项目的技术债 - 不修改任何源代码只输出审查报告 - 对严重问题用「严重」「建议」「可选」三级标记 ## 示例输出 - 审查报告输出格式见 references/report_example.mdfrontmatter 里的 description 字段会在模型做“技能选择”的时候被读取所以这段话必须写得精准说清楚“什么时候用”“处理什么类型任务”“有什么边界”别写“这是一个非常好用的技能”这种废话。指令体部分要遵循“少而准”的原则尽量用可检查的动词来驱动模型比如“读取”“运行”“解析”而不是“仔细分析”“认真核对”——后者的自由度太大输出质量很难收敛。示例区往往是最容易被忽略的部分实际上它的作用比指令还大。模型本质上是模式匹配机器给它一个完整的高质量输出示例效果远好于用十句话描述“你应该输出什么”。我在设计前端代码审查技能时把一份真实的、标注完整的审查报告放进了 references/report_example.md模型照着这个模板输出的结果直接就可以拿来发给开发同事。2.2 技能如何调用脚本与外部工具技能包里的脚本承担的是“确定性智能”的角色。模型擅长归纳总结但不擅长精确计算、批量文件操作、格式校验这类事。与其让模型用自然语言去“模拟”计算结果不如写一个 Python 或 Node 脚本把脏活累活接过去。我习惯把一个技能包里的脚本分成两类分析型脚本和校验型脚本。分析型脚本负责从原始输入中提取结构化信息比如从一个 git diff 里提取变更函数列表、从日志文件里统计错误码频次校验型脚本负责检查模型生成的输出是否符合预期比如检查生成的 JSON 是否合法、字段是否齐全、引用的文件路径是否存在。举一个我在“数据血缘分析”技能里的实际例子。一开始我让模型直接读 SQL 建表语句自己推断字段之间的血缘关系。结果是字段一多模型就开始胡编关联关系。后来我在技能包里加了一个参考脚本专门解析 CREATE TABLE 语句并生成表字段树模型只需要基于这棵树的 JSON 输出来做间接推理正确率一下就上来了。这说明一个道理技能包里能确定的东西尽量不要留给模型自由发挥。2.3 同一份技能在不同 Agent 之间的适配差异Claude Code、Codex、OpenCode 等工具对 skills 的支持并不完全一致这是我在迁移技能时踩过最多坑的地方。下表是我自己实际迁移后的经验总结能力点Claude CodeCodexCLIOpenCodeSKILL.md 自动发现支持放在.claude/skills目录支持通过配置文件声明支持项目级和全局级分开脚本执行许可需要用户授权支持白名单支持需注意沙箱策略支持命令可配置变量插值如输入路径支持支持支持技能间互相引用有限支持支持有限支持测试钩子skill 内调用测试可通过命令执行支持支持最需要注意的一点是“脚本执行许可”。在 Claude Code 里技能包中的脚本不一定能自动运行首次执行时往往需要用户确认而在 Codex 里如果沙箱策略设置不当技能包内的 Python 脚本可能根本无法读取某些路径。我自己的做法是在技能包内放一个 bootstrap.sh专门负责检查环境变量和权限如果脚本没法执行就给出明确的提示说明避免模型傻乎乎地反复重试同一个失败命令。3. 从零开发自己的技能边界拆分、指令设计与回归测试聊完了结构接下来是这门手艺的核心怎么从零开发一个真正好用的技能。开发技能和写代码有点像前期需求分析做得越透后期返工越少。下面是我的完整工作流。3.1 第一步把任务拆成可验证的“输入-输出”开发技能最容易犯的错是贪多。想在一个技能里覆盖所有分析场景最后写出来就是一个啥都管但啥都管不好的巨型指令。正确做法是先把任务拆成“最小可验证单元”。我当时复盘能力强检技能的思路是这样从“学习前端项目代码”这个宽泛需求中拆出“组件重复渲染检测”“复杂条件表达式可读性评估”“事件监听内存泄漏风险排查”“样式类命名与设计规范一致性”四个子任务。然后只针对第三个子任务做第一版技能因为它边界清晰输入是一份包含组件创建与销毁逻辑的 JS/TS 文件输出是一个危险点列表每一项需要指出风险位置、泄露对象、触发路径。判断一个子任务适不适合做成技能我有一个很笨但有效的标准如果人类专家在没有上下文交流的情况下拿着你写的说明文档就能完成这个子任务那么这个子任务就是合格的。如果还需要反复追问细节说明任务边界根本没拆清楚。3.2 指令怎么写才不会让模型过度发挥指令撰写阶段我的核心原则是“把边界写进约束把标准写进示例”。约束部分一定要使用否定句明确指出哪些事情不允许做。比如我这套“内存泄漏排查”技能里写了三条硬约束不得仅凭 class 名称猜测组件生命周期必须在代码中定位到对应生命周期方法。不得将第三方库内部逻辑作为风险项报告除非它被项目代码显式调用。对无法确认的依赖关系统一标注为“待确认”不得使用“可能存在风险”这类模糊表述。这些否定式约束的本质是给模型设置“停止信号”。大模型生成文本时是逐个 token 往外蹦的如果没有明确的禁止项它很容易顺着最自然的语言惯性继续写下去写到最后自己都不知道自己在说什么。有了停止信号模型在语义相似处会更倾向选择“更安全”的表达。另外一个容易忽略的细节是“输出长度控制”。我通常会在指令里给出明确的章节上限比如“每个风险项的描述不超过 80 字”。否则模型会写出一大段绕圈子的话看似信息丰富实际对后续阅读者毫无价值。对细节的颗粒度控制比多写十句鼓励性提示词都有用。3.3 用测试用例做回归把技能当成小型软件工程技能也是会回归的——模型升级、依赖变化、示例改写任何一个环节变了同一份技能的输出质量都可能抖动。所以我把测试用例当成技能开发中不可省略的环节。我的测试策略是准备一组“固定输入”。拿刚才的前端代码审查技能举例我会准备三个 case一个包含明显重复渲染问题的 React 文件、一个只有轻微风格问题的 Vue 文件、一个故意制造边角条件比如未安装依赖的坏输入文件。测试时我把每个 case 的原样输入喂给技能对照期望输出看模型是否按照约束执行了。刚开始这套测试靠人肉看输出效率非常低。后来我写了一个测试 runner 脚本直接把技能生成的报告和期望报告做两个层面的对比一是结构化字段的缺失检查比如是否包含“风险等级”字段、是否包含“代码行号”二是语义相似度打分低于阈值就标记为疑似回归。虽然语义打分还不能做到完全准确但至少能快速筛掉那些非常离谱的输出。试验了多个版本的指令措辞之后一个很意外的发现是示例对测试结果的影响最大。有一次我只是在示例报告里增加了一个“影响范围”子字段所有测试 case 的语义相似度都明显提高。这说明模型非常擅长模仿示例的结构所以在示例上花时间打磨性价比远高于在指令描述上反复堆词。4. 搭建个人技能库命名、依赖、上下文预算与版本管理当技能数量超过十个之后管理成本就开始显现了。技能不是写完就完事它需要被维护、被组织、被升级这背后其实是一套知识工程问题。4.1 技能的命名与层级设计让它能被快速复用我先说命名这件事。前面提到 Agent 会读取技能包里的 description 字段来做技能路由。这个字段和技能目录名一起决定了模型在面临一个新任务时能不能找出这个技能。我最开始用的是类型化命名比如“前端技能”“后端技能”“数据分析技能”听起来很整洁但实际上模型经常把它们混淆——因为任务类别的边界本来就模糊。后来我换成了“场景 动作”命名比如“react-mr-review”“sql-lineage-analyze”“error-log-triage”。这套命名有两个好处一是模型的语义搜索能更精准匹配二是人回头看目录时一眼就清楚这个技能是干嘛的。对于有多个子能力的技能包我会在技能内部做能力标签而不是拆成多个目录。比如“react-mr-review”技能里同时覆盖了性能检查和可访问性检查我会在 frontmatter 里定义tags: [react, performance, accessibility, mr-review]这样模型可以在技能内部按需选择执行路径又不会让技能目录爆炸。4.2 上下文窗口是硬约束如何控制技能加载体积另一个真实存在的隐患是上下文被技能包撑爆。技能包里的 SKILL.md 写得太长参考文件贴得太多AI Agent 在加载技能后还没开始干活上下文就已经消耗了三分之一。我的经验是控制技能包体积遵循“三级原则”第一级SKILL.md 本体控制在 150 行以内只放最关键的行为指令和输出模板。第二级references 目录存放详细规范、示例报告、领域术语表模型按需读取。第三级scripts 与 tests 目录存放代码文件这些不会全部进入上下文只有执行时才被读取。三级各自的目标是“核心指令要让模型一次读懂扩展知识要能按需取用代码和测试则不要占用模型的注意力”。通过这个设计即使是一个功能很复杂的技能模型在加载时消耗的上下文也保持在可控范围内留给真正任务处理的窗口就多了很多。还要提醒一句关于版本管理。技能包实际上是一份可执行的“知识源码”它应该跟代码一样做版本管理。我现在的要求是每个技能包必须带 version 字段修改行为逻辑时务必要同步更新测试用例发布技能时写上 CHANGELOG哪怕只有一句话也行。这个习惯帮我避过好几次“技能怎么突然不听话了”的坑——查版本记录发现原来是自己上次调整示例时引入了格式不一致。5. 我在真实项目里踩过的技能坑与排查链路就算你把前面所有原则都做到了实际跑起来还是会出幺蛾子。这一节我整理了几个我自己的翻车案例每个都附上完整排查链路。这些坑很有代表性你可以当成一份避坑清单来用。5.1 坑一技能被当成“万金油”什么任务都往里塞现象我的前端技能包在手头三个项目里都跑得很好到第四个项目时就疯了。明明是个用 Angular 的老项目模型却按照 React 的组件模式对它做代码建议给出的方案几乎全都要推翻重构。排查过程先检查技能包里的 description发现只写了“适合前端项目”没有写“React 为主”也没有声明“可选支持 Vue 基础暂不支持 Angular 特殊语法”。继而检查 references 里的现有项目样例发现样例全是我平时维护的 React/Vue 项目没有任何 Angular 专属代码作为对比。最终定位技能没有设置明确的项目框架识别前置门槛也没有针对不支持框架的输出“停止信号”。解决方案分两步第一在 SKILL.md 最前面增加“适用条件”和“不支持范围”两个小节并把“非 React/Vue 项目不要执行”写进约束里第二在技能包内增加一个frameworks.py检测脚本进入分析前先读取项目配置文件识别出项目用的是什么框架如果不是支持范围就打印提示并直接退出流程。这个补丁之后技能就老老实实识别自己不认识的框架了。5.2 坑二技能输出格式漂移同一天上下午两个版本现象上午生成的分析报告结构很规范下午同一份技能在同一个仓库里输出的报告格式全变了章节顺序被打乱字段名也对不上。排查链路看模型日志发现上午的调用带进了“项目 README 中的表格风格”下午的调用则带进了“某篇代码注释中的描述语气”。定位问题根源不是技能变了而是技能执行期间 Agent 还有别的上下文导入模型把上下文里的其他格式习惯“转移”到了技能输出上。处理方式在示例区把输出模板改成了不可辩驳的“代码块式模板”并给模板文件增加了 JSON Schema 版本在技能执行完最后一步之前强制调用一次validate_output.py格式不对就修正后输出。教训技能输出不能只靠模型自觉。越关键的输出越需要外部校验来“兜底”。格式问题虽然不致命但会极其影响下游自动化流程。5.3 坑三依赖了不存在的命令技能在 CI 环境直接挂掉现象集成到 CI 流水线后技能包里的脚本调用系统命令jq但 CI 基础镜像里根本没装 jq结果下游步骤拿到的 JSON 全是错的。排查链路在本地环境复现一切正常——因为本地开发机装了 jq。检查 CI 镜像发现是精简版缺少一系列基础工具。解决办法有两个我最后两条都做了一是在技能包中增加 dependency_check.sh在执行初期检查核心命令是否存在缺失时给出安装命令二是把对 jq 的依赖直接从脚本中移除改用 Python 自带的 json 模块解析从根源上消除环境差异。这提醒我在设计技能脚本时的基本原则尽量用 Python 标准库或者项目里明确声明的依赖来实现数据处理逻辑避免依赖外部 shell 工具。做一个能在极端环境里跑起来的技能比做一个“在你电脑上完美运行”的技能重要得多。6. 那些真正长期有用的“技能”来源与持续迭代建议最后分享一点关于技能库整体运营的判断。网上已经有不少开源 skills 仓库质量参差不齐。我的选择标准有三个看它有没有 Programmatic API 式的脚本看它有没有明确的适用边界看它是否附带测试或验证用例。三个都满足才值得拖进本地作为起点缺任意一个就作为参考看看思路自己再重写一版。从我的实际使用经验看最值得自己动手开发的技能往往不是那些通用性很强的“代码生成”“代码解释”类而是那些和你的具体工作场景强绑定的技能。比如我写过“周报自动生成技能”它读取我这周提交的 commit、合并的 MR、处理的 issue按公司要求的格式生成周报初稿再调用校验脚本确保不包含敏感项目代号。这类的技能官方仓库基本不会给你但对个人效率的提升是实打实的。持续迭代的方法上我现在遵循的是“再多一版就停”原则。技能生命周期里最常见的失败不是没人用而是作者陷入无限优化循环——改一版示例跑一次测试再改一版指令再跑一次测试迟迟不给技能“封版”。给技能定一个明确的发布迭代节奏例如每月只做一次版本迭代剩下的时间集中在收集实际使用中的失败案例比每天微调语言表达要高效得多。只有把技能开发当成知识资产的长期管理而不再是写一次性脚本才能真正体会到这套体系的威力。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门