我之前带过一个项目第一版Agent跑得很顺第二周就开始翻车。同样一句帮我整理这份会议纪要模型今天记得把待办事项单独列出来明天就把所有内容铺成流水账。后来我复盘的时候发现问题根本不在模型而在我的Agent压根没有一套可复用的技能库——它每次干活都是在临时听我口述该怎么干而不是调用一个已经被验证过无数次的固定作业流程。agent-skills这个概念字面意思是智能体的技能但它跟普通的prompt模板完全是两个物种。它把任务知识、执行步骤、参数约束、输出校验和失败处理全部封装成一个完整的能力单元让Agent不是会聊天而是能稳定交付结果。这篇文章我想从一个干活的人的角度把技能库怎么拆、怎么写、怎么建、怎么测、怎么迭代原原本本讲一遍。适合正在做Agent应用产品化、或者团队里想把AI能力沉淀成资产的开发者参考。1. 先想明白Agent缺的不是会对话是能独立干活的技能包1.1 技能和提示词模板差的不是一点半点提示词模板解决的是怎么把话说清楚技能解决的是怎么把一件任务稳定做完。这中间的差距我用一个真实例子说明。你让模型帮我写一封催款邮件。如果只是丢一句话给它它可能写得彬彬有礼但毫无杀伤力也可能列出一堆法律条款搞得像律师函警告。而如果我把客户催款封装成一个技能技能内部会强制规定先读取客户账单里的逾期天数参数逾期小于7天走第一版温和措辞逾期超过30天自动切换成强硬版并抄送主管邮件里必须包含付款链接、发票编号、截止日期输出之前还要过一遍自检清单确认客户名称没有被拼错。同样的目标一个靠临场发挥一个靠流程保障。技能存在的意义就是把这些只有做得好的人才知道的细节固化下来让弱模型不至于跑偏太多让强模型每次都能稳定发挥。我做Agent落地这半年最深的一个体感是模型能力确实重要但真正决定项目生死的是任务定义的颗粒度。颗粒度太大Agent无从下手颗粒度太小技能库变成一场灾难。而技能就是那个最合适的中间层。1.2 技能和Function Calling怎么分工不少同学会把技能和Function Calling混在一起聊其实它们是上下级关系。Function Calling解决的是模型怎么调用一个外部函数定义的是函数名、参数、返回值。技能解决的是模型怎么完成一项完整任务它内部可能调三四个函数每个函数的返回结果都要做逻辑判断哪一步失败了要重试哪一步最后还要按指定格式输出。打个比方Function Calling是一把螺丝刀技能是换轮胎操作手册。操作手册会告诉你先用千斤顶把车顶起来再按对角线顺序拧松螺丝换好新轮胎后还要检查胎压。里面的每一步都可能用到螺丝刀但只有螺丝刀是远远不够的。很多团队第一版只做了工具调用觉得够用了等任务复杂到需要多步决策时就卡住了。原因就是缺了技能这层编排。工具是死的技能是活的它把工具调用、规则判断、质量检查、异常兜底全部编排进了一次完整交付。2. 技能划分的粒度决定Agent能力的天花板2.1 三个粒度原子工具、任务技能、工作流模块我在实际搭建技能库的时候会把能力拆成三个层级原子工具、任务技能、工作流模块。拆错粒度是新手最容易犯的错所以先用一个表格把它们的区别摆清楚。粒度典型例子适用场景常见风险原子工具发送邮件、查询数据库、调用外部API单一、无状态、可重复执行的操作太零碎Agent需要编排大量步骤任务技能撰写周报、生成催款邮件、提取会议待办高频复用、有明确输入输出、可独立验收描述不清晰导致误触发或漏触发工作流模块客户投诉全流程处理、月度经营分析多步骤、跨系统、有分支判断的完整业务链路太重一次改动影响面过大原子工具是最底层的手任务技能是一个熟练工种工作流模块是一条生产线。我的建议是刚开始搭技能库时不要一上来就设计工作流模块先把高频复用的任务技能做扎实。工作流可以等业务跑通了再编排。2.2 判断该不该拆成一个技能的三个问题我每次决定要不要把某个能力沉淀成技能时会问自己三个问题是否高频复用如果这个任务一个月才遇到一次不值得做成技能。做成技能意味着后续还要维护、评测、迭代低频任务用普通prompt临时处理就行。是否有明确的输入和输出技能必须要有清晰的参数契约。如果输入是帮我处理一下这个输出是看着办那说明任务本身还没想清楚这时候做成技能只会把混乱固化下来。是否可以独立验收这个技能干得好不好能不能用一套用例去衡量如果答案是只能靠人主观感受那说明验收标准还没定技能的边界也无法收敛。我见过一个反面教材有人把一个叫帮我做事的大技能写进系统里面既包含查资料、写代码又包含发邮件、安排日程。结果Agent经常在应该写代码的时候跑去查资料在应该发邮件的时候开始安排日程。原因很简单这个技能本身不是一个任务而是一堆任务的集合边界完全失控。2.3 用技能边界清单防止技能之间互相抢活技能一多一定会遇到互相覆盖的问题。比如写周报和总结工作进展两个技能触发条件高度重叠Agent到底该调哪个我的做法是给每个技能维护一份边界清单里面明确写清三件事这个技能管什么、不管什么、什么情况下应该去调用另一个技能。举个例子写周报技能的描述里会写本技能负责将团队本周工作内容整理为周报格式按团队模板输出如果用户要求的是总结某个项目的阶段性进展请勿使用本技能应调用项目进展总结技能如果用户只是想记录一条工作日志请勿使用本技能直接回复即可。这套边界清单一开始看起来很啰嗦但实际跑起来能少踩很多坑。LLM有一个特点给它足够的约束它就能表现得很好给它模糊的空间它就发挥给你看。边界越清晰技能被误调用的概率越低。3. 让大模型一调就准技能描述与参数契约的写法3.1 技能描述决定模型对你的技能有没有感觉技能描述是整座技能库最容易被低估的地方。很多人写技能描述就是一句话写周报。结果模型根本不知道什么时候该用这个技能更不知道用完之后应该交付出什么。我总结了一套技能描述模板分四个部分用途说明、触发条件、典型场景示例、禁止事项。下面是一个示例name: weekly_report_generator description: | 用途根据团队成员的原始工作记录生成符合团队模板的周报正文。 触发条件用户要求撰写周报、汇总本周工作、提交周报内容时使用。 典型场景 - 帮我写一下这周的周报 - 把这几条工作内容整理成周报 - 周报模板要点是什么 禁止事项 - 用户要求的是日报或月报时不要使用本技能。 - 不要自行编造未提供的工作内容信息缺失时请明确询问。 - 不要输出Markdown以外的格式除非用户明确要求。用途说明和禁止事项这两段尤其重要。我见过很多技能被误调用不是因为模型笨而是因为描述里没有把什么时候不要用写清楚。大模型很擅长从文本里找倾向性你给了它明确的否定清单它就会特别老实地绕开。3.2 参数契约JSON Schema里的几个关键设计技能描述解决什么时候用参数契约解决用什么数据干活。参数设计得越规范后面的执行步骤就越不容易崩。我的参数设计通常遵循几个原则参数个数能少就少、类型尽量明确、必须给示例值、能设默认值就设默认值。下面是一个实际的会议纪要技能参数定义{ type: object, properties: { meeting_topic: { type: string, description: 会议主题用于生成纪要标题, examples: [Q3产品路线评审] }, participants: { type: array, items: { type: string }, description: 参会人姓名列表, minItems: 1 }, attendee_email: { type: string, default: , description: 参会人的企业邮箱用于后续自动发送纪要 }, include_action_items: { type: boolean, default: true, description: 是否从会议记录中提取待办事项 } }, required: [meeting_topic, participants] }这里有个细节我把attendee_email设计成非必填并给了默认空值而不是把它直接去掉。原因是在实际中同一个技能可能被多个场景复用有些场景确实有发送纪要到邮箱的需求。参数可以少但不能让技能失去扩展性。3.3 输出的可校验性给模型一张自检清单技能的最后输出不能是一段看起来不错的内容而应该是可以通过自动校验的内容。我通常会给每个技能设计一个自检清单让模型在输出前自己检查一遍。还是以会议纪要技能为例它的输出要求是必须包含会议主题参会人关键结论待办事项四个区块待办事项里每一项必须有负责人和截止时间如果输入材料里没有提到负责人或截止时间必须在输出中标注待确认不允许编造。这听起来像常识但实际操作时模型经常会在细节上偷懒。有了自检清单相当于给模型的输出加了最后一道质量闸门。我在自检清单里还会让模型输出一个has_warnings的布尔字段如果检测到输入材料里有明显缺失信息就返回告警而不是硬着头皮生成一份看起来漂亮但其实不可用的纪要。4. 从零搭建技能库目录结构、注册机制与实操步骤4.1 一套可以直接抄作业的技能库目录结构理论讲多了上点实操。下面是我现在项目里正在用的一套技能库目录结构不算复杂但组织得很清晰skills/ ├── skills.json # 技能注册总表记录所有技能的元信息 ├── meeting_minutes/ # 每个技能一个独立目录 │ ├── SKILL.md # 技能描述与边界清单 │ ├── schema.json # 输入参数契约 │ ├── execute.py # 技能执行主逻辑 │ ├── validator.py # 输出校验逻辑 │ └── examples/ │ ├── happy_path.md # 正常用例示例 │ └── edge_case.md # 边界用例示例 ├── weekly_report/ │ ├── SKILL.md │ ├── schema.json │ ├── execute.py │ └── validator.py └── tests/ ├── test_meeting_minutes.py └── test_weekly_report.pySKILL.md负责告诉模型什么时候用、怎么用、注意什么schema.json负责收拢参数execute.py负责真正的业务逻辑validator.py负责检查模型输出是否达标examples/里的用例是给开发者和模型做Few-shot参考用的。我见过一些团队把技能定义全部塞进数据库里结果写文档的人、写代码的人、测模型的人各看各的一改需求就乱套。用目录方式组织最大的好处是每个技能自成一个仓库改动范围可控出问题也好回溯。4.2 技能的注册与调度为什么不要用if-else硬编码技能多了之后下一个问题就是Agent怎么知道该用哪个技能。最笨的办法是在代码里写一堆if-else比如判断用户输入里有没有周报两个字有就调周报技能。这种做法的问题在于用户不可能每次都用同样的话描述需求自然语言表达变化太多规则根本无法穷尽。我现在用的是一种混合策略每个技能在skills.json注册表里记录描述文本当用户输入到达时先把描述文本和用户输入做语义匹配召回排名前几的候选技能再让模型在候选技能里决定最终调用哪一个。这个过程中技能的描述质量直接决定了召回的准确率所以前面说的SKILL.md不能随便写它是会被检索系统直接拿去用的。skills.json 结构示例 [ { id: meeting_minutes, name: 会议纪要生成, description: 用于将会议记录整理为结构化的会议纪要并提取待办事项, tags: [会议, 纪要, 提炼, 待办], version: 1.2.0 }, { id: weekly_report, name: 周报生成, description: 用于将本周工作记录整理为周报正文按团队模板输出, tags: [周报, 工作汇总, 月报], version: 0.9.0 } ]tags字段是给规则匹配兜底用的。当语义召回置信度低于阈值时我会用关键词规则做一次粗筛避免模型随机乱猜。这种语义为主、规则兜底、模型终选的调度方式目前在大多数场景下都够用。4.3 一个技能从建模到联调的完整过程我从零开始做一个会议纪要与待办提取技能时走的流程是下面这么几步基本适用于所有技能定义任务边界。明确这个技能只做会议纪要和待办提取不做会议安排、不做日程推送。输出给谁看、用什么格式、缺数据怎么办都要先写清楚。写SKILL.md和schema.json。先写描述和参数契约这一步会逼着我把任务想透。写参数的过程中如果发现字段太多说明任务还可以拆。跑一组种子用例。准备5到10条历史会议记录用现成的大模型先跑一遍看看输出质量和预期差距有多大。这一步能快速暴露出描述里我以为写清楚了但实际上没写清楚的地方。补执行逻辑和校验逻辑。把需要强规则保证的部分写进execute.py比如日期格式转换、参会人去重、邮箱格式校验。把需要模型自由生成的部分留在LLM调用里最后用validator.py做整体校验。嵌入Agent试运行。先把技能挂到测试环境用真实用户输入跑一周观察误调用率、输出达标率、用户手动改稿频率这些数据就是后续迭代的输入。这里面最容易翻车的是第4步。很多人把所有逻辑都交给模型结果模型输出格式不稳定又有人反过来了把逻辑全部写死在代码里结果技能失去了灵活性。我的原则是凡是能用规则确定的绝不交给模型凡是需要理解和生成的绝不强行写规则。5. 技能库上线后的迭代、评测和那些坑5.1 用回归用例集守住技能质量底线技能上线不是终点只是开始。我认为技能库必须配一套回归用例集每次改动技能描述、参数契约或执行逻辑时都把这套用例完整跑一遍。回归用例集至少要覆盖三类正常用例、边界用例、反例。正常用例验证技能在主场景下是否正常工作边界用例验证空输入、极端长文本、缺失必填参数时的表现反例验证那些不该调用本技能的情况是否被正确拒绝。我举一个具体数据我们的周报生成技能正常用例有8条覆盖本周工作内容较少工作内容非常多用户提供了结构化列表用户只给了一段流水账等场景边界用例有5条包括用户没提供任何工作内容用户提供的内容全是下月计划等反例有3条主要是用户问的是日报怎么写用户想生成季报。每改一版技能描述就全量跑一遍跑挂了就回到代码里查原因。这套用例跑下来最有价值的不是确认技能是好的而是能清楚知道这次改动到底有没有把别的场景搞坏。没有回归用例集的技能库就像没有测试的代码库改一次坏一次最后谁都不敢动。5.2 我踩过的几个坑描述过拟合、参数漂移、技能膨胀实践过程中我踩过几个典型的大坑拿出来给各位排雷。第一个坑描述过拟合。为了让技能在种子用例上表现好我在SKILL.md里不停地加细节越写越长最后描述都快赶上文档了。结果模型表现确实稳住了但召回的灵活性急剧下降用户换了个说法技能就识别不出来了。技能描述不是法律条文写得太多反而过拟合。后面我强制要求自己描述控制在400字以内能说清边界就行。第二个坑参数漂移。技能上线后业务方陆续提需求说能不能顺便支持按部门筛选能不能加个负责人字段。每次加字段都不算大改但加了七八轮之后schema.json变得无比庞大模型经常漏传参数执行逻辑里到处是兼容分支。最后我不得不做了一次大重构把技能拆成了两个。现在我对参数的态度非常保守加参数要回答一个问题——这个字段是真的每次都需要还只是某个场景里的特例特例就让调用方自己处理不要污染公共契约。第三个坑技能膨胀。这是团队层面最容易犯的错。随着项目推进大家会不停地把新能力塞进已有个别的技能里导致技能之间的边界越来越模糊。比如写邮件和写催款邮件和写客户感谢信被塞进同一个技能结果模型不知道该用哪套语气和格式。正确的做法是只要发现某个技能里出现了if branch特别多的情况第一反应就应该是拆技能而不是继续加规则。技能库的健康状态需要靠定期维护来保持这个定期维护不是可选项是必选项。5.3 技能库的版本管理与团队协作约定技能库本质上是一份代码资产理论上应该用版本管理的方式去维护。我目前采用语义化版本管理主版本号在技能边界、参数契约发生不兼容变更时递增次版本号在新增可选参数、补充描述、调整边界清单时递增修订版号则用于小修小补比如修正一个错别字、调整某个示例。每次改动技能我都会同步更新该技能目录下的一个CHANGELOG.md记录改了哪块、为什么改、影响范围是什么。团队成员之间定了一条规矩任何技能描述或参数契约的修改都必须由另一个同学做交叉评审不允许自己改完直接上生产。这套约定看起来给团队增加了不少流程负担但实际跑起来之后它帮我挡掉了非常多上线了又回滚改完A技能导致B技能误触发的问题。尤其是当技能数量超过20个之后没有版本管理和评审流程整个技能库就会变得失控。最后分享一个我个人的习惯每次模型输出异常我第一反应不是去换模型、调temperature而是先看一眼对应技能的描述文本是不是有过一次小改动。很多时候问题就出在那个顺手改个措辞的瞬间。技能库的稳定本质上靠的不是某一个天才设计而是一套严格的小步迭代纪律。