做了这么久的 Agent 相关项目,我收到最多的反馈其实是同一句话:“它聊得头头是道,我让它干活怎么就这么费劲?” 这不是模型不行,而是我们一直在用“聊天”的思路去要求“干活”。这个系列写到第八篇,前面聊过 Agent 的框架、上下文管理、工具调用,这篇终于轮到 Skill 技能系统——目前把 Agent 从“能说”推向“能干”最关键的一层封装。
这篇适合谁看?你正在用 Claude Code、Cursor、Codex 这类工具做自动化任务,或者自己在搭 Agent 应用,但发现 Agent 处理复杂任务时行为飘忽、结果不稳定、换一天跑同一个任务就变样。看完这篇文章,你会理解 Skill 和普通 Prompt、Function Calling 的本质区别,能独立设计一个可复用、可验证的 Skill,并且学会在实际开发中避开我踩过的那些坑。
1. Skill 技能系统入门:Agent 为什么需要“技能库”
1.1 聊天和干活,差的是一层“确定性”
先摆一个很常见的现象。你让 Agent 分析一份表格,第一次跑出来结果挺好,第二天同样的输入再跑一遍,它可能给出完全不同的结论。这不是偶然的 bug,而是 LLM 本身的概率属性导致的——同样的 Prompt、同样的模型参数,每次采样都可能落在不同的分布区域。聊天场景下这种发散是优点,同一个话题可以聊出千百种角度;但干活场景下发散就是灾难,因为任何一个重复性任务都要求行为可复现、结果可校验。
Skill 系统解决的就是这个“确定性缺口”。它把一段能力从“临时写在 Prompt 里的建议”升级成“工程上可加载、可触发、可验证的模块”。一个 Skill 不是一段更长的提示词,而是一个包含描述、步骤、脚本、参数定义和测试用例的完整单元。Agent 在任务中通过描述做检索匹配,一旦命中,就走固定流程:该用代码的地方用代码,该用模型判断的地方才把控制权交回给 LLM。这样一来,核心逻辑被钉死在代码里,模型只需要在少数开放节点上做决策。
我早期做过一个很蠢的尝试:把一系列操作步骤全写在一个大 Prompt 里,让 Agent“按部就班”执行。结果它前五分钟还很听话,聊天窗口一长,它就自己开始自由发挥,跳过步骤直接总结。后来我才意识到,这不是用户提示写得不够好,而是因为所有行为都挂在“模型的自觉”上,而模型没有自觉。Skill 的意义在于,把“自觉”换成“强制”——步骤里明确哪些动作是脚本执行,哪些输出需要结构化校验。确定性来自工程约束,不来自口头叮嘱。
1.2 Skill、Function Calling、Prompt、MCP:四者怎么分工
很多刚开始做 Agent 的同学喜欢把 Skill 和工具函数混为一谈。我在团队内部经常用一句话概括:Prompt 是“告诉模型要做什么”,Function Calling 是“让模型能做什么”,Skill 是“让模型知道什么时候做什么、怎么做对”,MCP 则更像“把工具变成标准化服务”的传输协议。四者不是替代关系,而是不同层级的分工。
用生活化类比来说,Prompt 像是你给一个新来的实习生口头交代“把这个报表整理一下”,说得再详细,也只是口头指令;Function Calling 是给他一台计算器,他得自己想清楚什么时候按哪个按钮;Skill 是给他一份完整的工作手册,里面有流程图、检查清单、异常处理办法,他照着走就能稳定产出;MCP 是把公司各个业务系统统一封装成标准接口,任何实习生进来都能按统一方式接入。
这个区分很关键,因为 Agent 的工程化难点从来不是“能不能调用工具”,而是“在什么条件下、用哪套流程、以什么标准交付”。Function Calling 只解决调用能力,调度逻辑还是模型临场发挥。Skill 则把调度依据前置,用描述和元数据给 Agent 提供决策支持,匹配决策是确定性的:描述配置得好,触发就精准;步骤配置得好,执行就稳定。
我还经常看到有人把 Skill 和 MCP 对立起来讨论。实际项目中它们常常配合使用:MCP 解决的是工具连接问题,让 Agent 能拿到外部系统数据;Skill 解决的是工作方法问题,定义处理这些数据的流程和产出标准。一个 MCP Server 可以提供搜索、数据库操作等原子能力,但“用这些能力凑成一份周报”的完整手艺,还是得靠 Skill 来编排。两者不是同一层的东西,放在一起比谁替代谁,意义不大。
1.3 工程化的分水岭:Skill 化程度
观察过不少 Agent 项目之后,我发现一个规律:早期项目都在堆 Prompt,把模型能力当万能牌,遇到问题就加一段描述;中期开始接入 Function Calling,模型终于能调外部工具;到了后期,真正能稳定落地的项目,基本都会沉淀出一套技能库。这个从“堆 Prompt”到“建技能库”的过程,就是工程化的分水岭。
这不是什么高深理论。做 Agent 项目,本质是在做一件事:把不确定性尽量压缩到模型最擅长的区域,把确定性的部分交给传统代码。Skill 系统就是这个压缩过程的载体。一个团队如果能把自己的核心能力写成几个高质量的 Skill,那么不同项目之间复用能力就变得非常便宜;反之,每次新项目都从头写 Prompt 调对话,相当于每次都重新发明一次轮子。
我也注意到社区里很多 Agent 教程都在讲“Agent 循环”:思考、调用工具、观察结果、再思考。这个框架没错,但它描述的是模型内部的运行过程。Skill 系统补的是产能侧的封装问题——如何把一次成功的实践固定下来,让 Agent 下次遇到同类任务时不需要重新摸索。换句话说,吴恩达那套 Agent 教程解决的是“Agent 怎么动起来”,Skill 解决的是“动完之后怎么沉淀下来”。两者结合,才是完整的 Agent 工程闭环。
2. 设计一个 Skill:目录、描述、入参与验证闭环
2.1 一个 Skill 的最小目录结构长什么样
我在实际项目中用过的 Skill 目录结构经过好几轮迭代,目前最顺手的是这样的:
skills/ meeting-minutes/ SKILL.md scripts/ parse.py format_output.py references/ template.md tests/ case_normal.json case_edge.json case_adversarial.json这个结构里,SKILL.md是 Agent 读到的说明书,scripts/放确定性执行脚本,references/放模板和参考材料,tests/放验证用例。每个目录都有明确职责,不混放。你可能会问,为什么需要references/?因为有些 Skill 需要引用固定格式模板或行业规范,与其把这些内容全部塞进 SKILL.md 里撑爆上下文,不如放在单独文件里,让 Agent 用到时再读取。这个设计能有效控制上下文窗口占用,尤其是 Skill 描述比较长的时候。
一个 Skill 的核心只有一个:让 Agent 在正确时机、用正确流程、产出正确结果。目录结构只是载体,真正的灵魂在SKILL.md和脚本的设计上。很多新手容易犯的毛病是把目录建得特别宏大,plan、analysis、report 建了一堆文件夹,结果内容都是空的。我建议从最小可用开始:一个 SKILL.md、一个脚本文件夹、一份测试用例,够用就行。后面扩展结构,一定是功能真的需要了才加。
2.2 SKILL.md 是写给 Agent 看的说明书
SKILL.md的定位很容易误解。它不是写给人类阅读的文档,而是给 Agent 的“操作规范”。这意味着它的写法要贴近模型的理解方式:结构清晰、语义明确、指令性强。我见过有人把 SKILL.md 写成大段散文,描述这个技能“旨在提升工作效率”,结果 Agent 看完根本不知道什么时候该用它。
一个有效的 SKILL.md,至少包含这些字段:
- name / version:技能名字和版本,用于检索和追溯
- description:一句话说明这个技能解决什么问题
- when_to_use:哪些场景应该触发、哪些场景绝对不能触发
- parameters:入参定义,字段名、类型、必填项、默认值
- steps:执行步骤,按顺序编号,标注哪些步骤跑脚本、哪些步骤用 LLM
- output_format:输出结构,最好有模板或示例
其中最容易写坏的是 description 和 when_to_use。description 写得好不好,直接决定 Agent 会不会在恰当的场景调用它。我举个对比:差的描述是“处理会议相关内容”,好的描述是“将会议录音转写后的纯文本整理为结构化会议纪要,提取决策、待办事项、负责人和截止时间,适用于会议时长小于三小时且包含明确议题的文本”。后者给了模型足够的匹配信号,触发准确率会高很多。
when_to_use 同样重要,而且要写“负面清单”。明确写“不要在文本缺少发言主体时强行推测归属”“不要对情绪化的聊天记录做结构化处理”,这能显著降低 Agent 在边缘场景的错误调用概率。模型对禁止项的理解往往比含糊的边界描述更可靠。
2.3 脚本层与“人机结合”:哪些部分交给代码
Skill 开发中最容易被忽视的问题是:没有正确划分“代码该做的事”和“模型该做的事”。我的原则是:凡是规则明确的、需要精确计算的、格式固定的,一律交给脚本;凡是语义开放、需要理解语境和判断取舍的,才交给 LLM。
拿会议纪要 Skill 举例。提取会议时间、统计参会人数、去重、格式化日期,这些都是规则性操作,应该用正则或日期解析库在脚本里做掉。它们不需要模型发挥,用 LLM 反而容易出幺蛾子——比如模型编造一个不存在的日期。而“这段对话里真正做出了什么决定”“这句话是结论还是疑问”这类语义判断,才值得调用 LLM。脚本负责确定性,LLM 负责歧义性,这是一个 Skill 稳定性的根本保证。
还有一点:脚本对 LLM 的输出要设立护栏。比如脚本里可以加一层断言,检查 LLM 返回的 JSON 是否包含必需字段、字段类型是否正确,不合规就直接重试或者报错,而不是把脏数据传给下游。这个习惯我是在吃了好几次“脏数据进入下一环”的亏之后养成的。Skill 不是把流程写好就完事,它必须有自我保护机制,保证任何一个环节失败时能尽早暴露,而不是带病运行。
2.4 验证闭环:Skill 必须自带“考试题”
做 Agent 工程和做普通脚本工程最大的不同,在于我们验证的不只是代码对不对,还包括“Agent 加 Skill 这个组合”能不能稳定完成任务。同一个脚本,面对不同的上下文扰动,Agent 的调用路径可能完全不同。所以 Skill 必须自带测试用例,形成验证闭环。
我的测试思路是设计三层用例:第一层是标准用例,覆盖技能的主要场景;第二层是边界用例,比如空输入、超长文本、缺字段;第三层是对抗用例,故意给一些不该触发技能的内容,看 Agent 会不会被误导。每一层都有不同价值:标准用例验证功能正常,边界用例验证鲁棒性,对抗用例验证触发阈值的准确性。
测试方式也很直接:把用例喂给 Agent,让它以该 Skill 的方式处理,然后核对输出是否满足断言。这个过程应该做成可重复的自动化回归,否则每改一次 SKILL.md 或者脚本就要手动试一遍,成本太高,也容易遗漏。一个 Skill 是否成熟,衡量标准就是它能不能通过自己的测试集——而不是“我今天试了一把感觉还行”。
3. 完整实操:从零开发一个“会议纪要与任务提取”Skill
3.1 定义边界:先想清楚这个 Skill 不做什么
很多 Skill 设计失败的起点,是功能边界没定清楚。一个技能又想整理会议纪要,又想处理翻译,又想分析情感,结果 Agent 遇到稍微偏一点的输入就把 Skill 调出来,流程一跑全是错的。我在设计任何 Skill 之前,第一件事是列“不做什么”清单。
以“会议纪要与任务提取”这个 Skill 为例,我定的边界是:只处理会议录音转写后的纯文本,且文本里存在明确的多方发言和议题讨论;不处理单句闲聊、不处理没有任何动作要项的文本、不对缺失的发言主体做猜测、不负责翻译或摘要改写。为什么要这么严格?因为触发精度要远比覆盖面重要。一个 Skill 偶尔漏触发一次,最多让 Agent 走回通用流程;但如果频繁误触发,下游就会持续收到错误结构的输出,这种污染比不触发更麻烦。
写完“不做什么”之后,我会把边界同步写进 SKILL.md 的 when_to_use 字段里,用负面清单的措辞明确禁止。实测下来,这种写法的效果立竿见影:Skill 的误触发率明显下降,因为模型在处理模糊任务时会优先排除边界外的场景,而不会硬着头皮套用。
3.2 把流程拆成五个可执行节点
边界定好之后,就开始拆流程。我设计的会议纪要 Skill 拆成五个节点:输入校验、文本清洗、结构化抽取、任务优先级判断、输出格式化。每个节点只做一件事,节点之间有明确的输入输出约定。
输入校验节点在脚本里实现,检查文本非空、长度在合理范围、包含至少两个不同发言主体,不满足直接返回错误码。文本清洗节点做去重、去无效行、修正标点和换行,这个也放在脚本里。结构化抽取是把清洗后的文本交给 LLM,让它按字段抽出议题、决策、待办、负责人、截止时间。任务优先级判断可以做成两个版本:简单版用规则(关键字匹配、时间紧迫度)在脚本里算;复杂版可以让 LLM 根据上下文判断紧急度,但我会要求它的输出必须是枚举值而不是自由文本,方便后续排序。最后输出格式化节点统一组装 JSON 或 Markdown。
这个拆分思路的核心是:每个节点要么是“纯代码”,要么是“LLM 做选择题”。越到后期,我越倾向于把 LLM 的输出收敛成选择题而不是简答题。比如“这个待办的优先级是 A/B/C 哪一档”,模型答对的概率远高于“请用一句话描述这个待办的紧迫程度”。不确定性在传输过程中会被逐级放大,收敛得越早,最终输出越稳定。
3.3 写描述和参数:让 Agent 看得懂、调得对
流程拆完,就要给 Skill 写“门面”——描述和参数定义。这是决定 Agent 会不会在正确时机调用你的 Skill 的关键环节。我在生产环境里反复调整过的经验是:描述要包含触发场景的具体信号词,比如“会议”“转写稿”“多人对话”“纪要”“待办”,同时明确输出形态。
参数设计上,我倾向精简。这个 Skill 只保留了三个入参:source_text,必填,待处理的会议转写文本;output_format,选填,支持json或markdown,默认json;include_summary,选填,布尔值,是否在纪要末尾生成一段简短总结。参数越少,Agent 在调用时越不容易拼错;参数越多,模型犯错的空间越大。不要把一个 Skill 设计成万能接口,什么都能传,最终就是什么都传不对。
参数类型也要尽量用明确的枚举或布尔值替代自由字符串。比如output_format写成枚举比让模型自己填一个“我觉得好看的格式”靠谱得多。我在 SKILL.md 里会给每个参数附带一个示例值,模型在生成调用时会模仿示例,这比冷冰冰的类型描述效果好很多。
3.4 测试用例三层:从正常到对抗
测试用例是 Skill 质量的第一道防线。我开发这个 Skill 时,测试用例设计遵循三层结构。第一层标准用例:给一段包含明确议题、决策和三项待办的会议记录,验证输出是否完整提取了全部字段,且格式符合 Schema。第二层边界用例:给空文本、只有一个人的独白、超过一万字的超长会议记录,看系统是优雅降级还是直接崩溃。第三层对抗用例:给一段朋友闲聊的微信对话,里面没有任何会议议题,验证 Agent 不会强行套用这个 Skill,而是返回“不适用”或者转交通用流程。
每层用例的价值不同,但第三层往往最容易被跳过。新手写测试都喜欢盯着“正常场景能不能跑通”,忽略了“不该跑的能不能拦住”。实际上在生产环境里,一个误触发造成的数据污染,远比十次漏触发的损失大。因为在编排链路中,错误的结构化输出会直接进入下游数据表,排查成本很高。对抗用例是给 Skill 上保险,这笔投入非常划算。
测试用例写完之后,我还会做一件事:用不同模型跑同一套用例,观察结果差异。同一份 SKILL.md,GPT 系和 Claude 系行为可能差别巨大。如果这个 Skill 要在多个模型间复用,就得在测试里记录各模型的通过率,针对偏差大的模型调整描述措辞。Skill 不是一次写死终生不变的,它需要跟着模型能力的变化做校准。
3.5 让 Agent 在实际环境中找到并触发 Skill
Skill 开发完成后,最后一步是把它挂到 Agent 的运行环境里。不同工具的做法有差异,但思路都是把skills/目录配置到 Agent 的可见路径下,让模型在任务开始时能检索到技能列表。我习惯在系统提示词里加一句“遇到与会议纪要、待办提取相关的任务,优先使用 meeting-minutes 技能”,同时在用户请求里也会自然触发描述匹配。整个过程等同于给 Agent 一个工作手册索引,而不是要求它靠记忆硬背。
挂载完之后,务必跑一个端到端验证:给出一段真实的会议记录,观察 Agent 是否主动选择这个 Skill、是否按流程执行、输出是否符合预期。很多 Skill 单独测试时样样都好,一挂到完整 Agent 环境里就出问题,通常是因为描述里缺少环境上下文,或者参数命名和 Agent 既有体系冲突。这一步验证不能省,它和单元测试是两码事。
我在 Cursor、Claude Code 和 Codex 里都试过类似的技能挂载逻辑,整体模式大同小异:目录要放在配置指定的技能根目录下,SKILL.md 的格式要严格对齐,脚本执行权限要给对。有个常见问题是沙盒环境默认不允许脚本执行,导致 Skill 里的 Python 脚本跑不起来。遇到这种情况,优先检查权限配置,再排查依赖是否安装,最后才是代码逻辑问题。
4. 实测中的坑与速查表
4.1 坑一:Agent 就是不调用 Skill
开发 Skill 初期,我遇到最崩溃的问题是:Skill 写好了,测试也过了,但真实使用时 Agent 完全不理它,宁愿自己靠记忆硬答也不用技能。一开始我以为是描述写得太含蓄,后来排查发现,是 Skill 列表压根没有进入模型上下文——Agent 根本不知道有这个技能存在。很多 Agent 工具默认只会把技能目录里的文件名加进索引,如果你的 SKILL.md 里没有足够强的检索信号,模型就“看不见”它。
解决办法分两步:第一步,把核心触发场景的关键词写进 SKILL.md 的开头段落,不要只放在某个偏僻字段里;第二步,在系统提示或者在关键任务节点,显式告诉 Agent“这类任务有专用技能可用”。实测下来,显式提示的效果立竿见影,但要注意不能让所有任务都靠提示硬指定,否则 Skill 系统就退化成了固定路由,失去了灵活性。
还有一种情况是模型压根不读 SKILL.md,只是看到目录文件名就自行发挥。这种问题一般出在 SKILL.md 格式不规范、结构不清晰、或者文件被放在脚本目录而不是技能根目录。我建议严格检查目录和文件命名,确保 SKILL.md 位于技能文件夹的根路径,而不是藏在scripts/子目录里。
4.2 坑二:Skill 能跑,但输出结果飘忽不定
另一个高频问题是:Skill 被触发了,流程也正常执行,但输出结果每次都不一样,而且不稳定。我把这类问题归结为“节点内自由度太大”。如果你的步骤里有一行写着“分析这段文本并提取相关信息”,这行指令就是自由度的源头——怎么分析、提取哪些信息、以什么格式输出,全部交给模型临时决定,结果自然飘。
修正方向是把开放性描述改成封闭性约束。比如“从文本中找出所有包含明确动词和负责人的句子,按 JSON 数组输出,每条记录包含 action、owner、deadline 三个字段,字段缺失填 null”。模型在封闭任务上的表现一致性会远高于开放任务。我在团队内部有个原则:Skill 里的每一步,要么是代码,要么是枚举选择题,原则上不出现“请总结”“请分析”这种开放式要求。每次出现这类要求,就是一次不可控因素注入。
此外,如果 Skill 输出会经过后处理脚本,务必在脚本里加 Schema 校验,所有非法输入统一拦截。很多不稳定问题不是模型造成的,而是模型输出的格式稍微变化,后处理脚本没有兼容,于是表现在结果上就是“时好时坏”。用 Pydantic 或者 JSON Schema 做一层强制性校验,能过滤掉绝大多数偶发问题。
4.3 坑三:参数冲突和上下文污染
第三个坑比较隐蔽,发生在 Skill 与其他系统组件协作时。我遇到过一个问题:Skill 的输出是一段很长的 Markdown 纪要,直接拼回主对话,结果后续几轮对话全被这段长文本带偏,模型开始“纪要口吻”说话。这就是上下文污染——Skill 的输出不应该无差别地流回主链路,应该做截断或结构化处理。
我现在的做法是:输出模块返回一个简短的执行摘要,完整结果写入文件或变量,只有摘要回填对话上下文。这样既保留了结果的可追溯性,又不污染模型对后续任务的判断。另外,Skill 之间的参数传递也要特别小心。多个 Skill 串联时,一个技能的输出字段和另一个技能的入参字段可能重名但含义不同,模型很容易把字段张冠李戴。解决思路是在参数命名上尽量加前缀区分,比如meeting_minutes_action_items,降低混淆概率。
还有一类问题是 Skill 内部使用的脚本依赖全局变量或环境变量,两个 Skill 同时运行时冲突。这种问题排查难度高,定位到之后也很沮丧。我的建议是 Skill 的脚本尽量做成无状态,输入全部从参数进、输出全部从标准输出或指定返回结构出,不要读写临时目录或环境变量。无状态是 Agent 技能库能够大规模并行的前提。
4.4 常见问题速查表
| 事故症状 | 可能原因 | 处理办法 |
|---|---|---|
| Agent 完全不调用 Skill | Skill 描述缺少触发信号、技能列表未加载 | 重写描述中的关键词和场景;显式提示可用技能 |
| 调用了但结果不稳定 | 步骤中开放式指令过多、模型自由度太大 | 把“请分析”改成封闭式选择题或枚举输出 |
| 输出偶尔断 JSON | 模型输出格式漂移、后处理校验缺失 | 脚本入口做 Schema 强制校验,非法输入拦截重试 |
| 后续对话被带偏 | Skill 长输出污染主上下文 | 只回填执行摘要,完整结果写文件或变量 |
| 脚本跑不起来 | 沙盒权限受限、依赖缺失 | 检查执行权限、安装依赖,先跑单测定位 |
| 多 Skill 串联时字段错乱 | 参数名冲突、字段语义混淆 | 加前缀区分命名,严格定义各自 Schema |
| 改了一版描述后效果倒退 | 触发关键词和真实场景失配 | 用测试集回归对比新旧版本通过率 |
4.5 进阶心得:Skill 不是越多越好
我在项目维护后期踩过一个大坑:技能库越建越多,维护成本爆炸,而且 Agent 的选择准确率反而下降。原因很简单,技能描述之间越来越相似,模型在召回阶段容易混淆。比如我建了“会议纪要”和“访谈纪要”两个 Skill,功能高度重叠,实际使用中 Agent 经常选错。最后我把它俩合并了,用参数区分适用场景,效果一下子稳定了许多。
这个教训让我意识到,Skill 系统的质量不在于数量,而在于每个技能之间的辨识度。技能库维护者应该定期检查现有技能,标记出功能重叠的部分,能合并就合并,能删除就删除。一个精而少、边界清晰的技能库,远比一个什么都往里塞的大杂烩可靠。另外,每个 Skill 最好指定一名负责人,技能更新要记录变更日志,避免多人同改一个文件导致版本混乱,这些管理细节看似和“技能开发”无关,但在长期项目中决定生死。
5. 从单个 Skill 到 Agent 工作流:编排与管理
5.1 编排思路:链式和路由式的平衡
单个 Skill 解决的是单个任务闭环,但真实 Agent 场景往往是多个 Skill 协作。我常用的编排模式有两种:链式编排和路由式编排。链式编排是指上一个 Skill 的输出是下一个 Skill 的输入,在数据处理管线里很常见;路由式编排是 Agent 根据任务意图选择一条技能路径,分流执行,更像企业里的工单分配系统。
两种模式各有代价。链式编排的缺点是错误会逐级累积放大,前一个环节的脏数据会污染后面所有环节,所以每个环节的校验特别重要;路由式编排的优点是模块独立性强,但要求路由决策足够精准,否则一个任务走错分支,后面全是白做。我目前的经验是:能并联就不要串联,能路由就不要链式,链条越短,出问题的概率越低。
在编排时还要考虑 Skill 之间的资源竞争。多个技能同时跑脚本时,注意依赖和超时设置。我之前踩过一个坑:一个 Skill 的 Python 脚本因为等待外部 API 响应挂起了整个流程,后续任务全部阻塞。后来我统一给所有脚本加超时和重试机制,才解决这个问题。Agent 工作流本质上是一个分布式系统,任何一环没有超时保护,整体可用性都上不去。
5.2 技能库的版本与质量治理
技能库壮大之后,版本管理就变成一个严肃问题。我见过不少团队的技能库处于“代码人都能改、改了没人测、加了没人删”的状态。解决这个问题的核心是给技能库建立简单的治理规则:每个 Skill 带 version 字段,更新要过测试集回归;变更记录写进 CHANGELOG;长期不用的技能标记为 deprecated 并定期清理。这套规则不需要很复杂,但要坚持执行。
质量治理的落地工具最好是自动化回归。我把所有技能的测试用例集中到一个脚本里,每次技能变更后跑一遍全量回归,任何一个技能通过率下降都能立刻暴露。这个机制让团队敢放心更新技能,不用每次改完都靠人工回归试。没有自动化验证的技能库,等于没有刹车系统的车,跑得越快越危险。
另外一个治理重点是技能的可观测性。每个 Skill 的调用记录应该被记录下来,包括:何时触发、用了哪些入参、输出结果是否通过校验、耗时多久。有了这些数据,你才能回答“这个技能到底有没有人用、用得对不对、和同类技能谁更好”这类关键问题。技能优化如果没有数据支撑,最终只会变成靠感觉拍脑袋。
5.3 我给新手的一句话:先跑通,再完善
最后说点我个人的实操体会。很多新手拿到 Skill 系统之后,容易陷入“设计完美框架”的陷阱,花大量时间在搭建目录结构、写规范文档上,迟迟不进入真实任务。我自己用过的最有效开发流程是:先用一段小脚本验证核心逻辑能跑通,再花半小时补一份能用的 SKILL.md,最后写几个测试用例把边界拦住。整个过程不追求一步到位,核心逻辑稳定之后,再回头优化描述、补充边界、完善测试。Skill 是要在真实任务里“喂”出来的,不是一次性设计出来的。
还有一个很务实的小技巧:新写的 Skill 先在单一 Agent 环境里试用一周,记录触发率、通过率、误触发次数,再决定要不要纳入正式技能库。这比在测试用例里自我感觉良好可靠得多。毕竟,技能库的价值最终体现在真实任务的成功率上,而不是文档写得有多漂亮。