从提示词到技能库:手把手搭建AI Agent可复用技能体系 先说明一下背景。过去大半年我一直在折腾各种Agent项目从早期的纯提示词工程到接各种工具调用再到最近半年开始认真研究并落地了一套自建的agent-skills体系。中间踩过的坑、推翻重来的次数比过去三年写业务代码加起来还多。今天不聊那些花里胡哨的概念包装就纯粹把我在实际项目里怎么设计、怎么搭建、怎么踩坑又怎么修复的过程完完整整拆给你看。如果你手头也有一个或多个AI Agent项目正被提示词越写越长但效果越来越不稳换个输入形式就翻车同一个操作逻辑换个场景全部重写这类问题困扰这篇文章应该能给你一套可以直接上手的解法。1. 先搞清楚Agent缺的从来不是聪明而是可复用的手艺1.1 提示词堆砌的终点一个真实的失控现场三个月前我接了一个内部工具项目做一个能自动整理项目周报的Agent。需求听起来很简单——把团队群里零散的周报信息收集起来按照固定模板输出一份Markdown周报。我早期做法和大多数人一样把要求全写在系统提示词里你要提取每个人的任务、你要判断任务状态、你要分类优先级、你要总结风险点、你输出的格式必须是……前前后后写了三千多字。测试当天效果惊人样例数据全过。然后就翻车了。同事把周报从微信聊天记录换成飞书文档截图Agent直接懵了提取逻辑全乱套。再换成语音转文字稿输出格式又变了。我花了大量时间在提示词里补充各种输入形态的可能性每加一种场景提示词就变厚一层而每变厚一层其他场景的准确率就掉一截。到最后那个Agent变成了一坨碰不得的代码——改一行崩三处。这段经历让我彻底明白了一个道理你把怎么做写进提示词Agent只是在背诵你把怎么做封装成技能Agent才开始掌握。1.2 技能的本质把方法从指令里剥离出来后来我重新设计这个周报Agent不再往提示词里堆细节而是换了一种组织方式把整理周报这件事拆成几个独立的技能每个技能负责一个环节——信息抽取、任务去重、优先级判断、Markdown格式化。每个技能内部有自己完整的操作方法、参考样例、处理规则Agent碰到对应场景时再把这套手艺调用出来。打个比方你就明白了。普通提示词式Agent像你给实习生交代任务你去把这份文件处理一下注意格式要好看数据要准确别漏了重点……——他听得懂但遇到具体细节全靠临场发挥。技能式Agent像你给实习生一本工作手册处理文件之前先看第一章的格式规范再翻第二章的数据校验清单最后按第三章的模板输出。——他不光听懂了任务还知道该调哪套标准动作。所以我对技能的定义就一句话技能是围绕某一类具体任务预先组织和验证过的输入识别方式、执行步骤、输出范式以及用到的工具与参考样例的完整封装。它和工具调用Function Calling的区别在于工具是手技能是手 方法 经验。Agent调用一个天气API那是工具Agent拿到一段会议录音后知道该先分段、再转写、再按发言人归并、最后生成摘要那是一整套技能。1.3 什么任务才值得做技能先用这四个标准卡一遍不是所有任务都值得做成技能。我踩过不少盲目技能化的坑最后总结出一个判断标准基本上四条全中的任务才值得做高频这活儿Agent每周、每天都可能碰到。一辈子碰不到一次的任务写成技能是纯浪费。可复现同样的输入预期的产出相对稳定不是那种这次这么写、下次那么写都行的开放式任务。有明确产出物最后的结果是一份文档、一段代码、一张表格这类能检验的东西。纯闲聊没资格做技能。有判断基准你能说清楚什么算好、什么算差否则后面评测迭代无从谈起。我那周的输入形态多变导致崩溃的周报整理任务完美命中这四条每周都做、产出物固定为Markdown周报、格式好坏一眼可判。唯一难的是可复现——输入来源太杂。但实际情况是输入形态杂不等于方法不能统一只要把是否属于周报内容和怎么提取分开来处理底层方法是可以稳定的。2. 技能库的模块设计让Agent看得懂、用得对、学得会2.1 一个技能 一个目录 一份SKILL.md 若干资源文件先上一份我现在在用的标准技能目录结构。整套基于文件系统来组织因为文件比数据库更透明Git可以做版本管理随时能diff谁改了什么。agent-skills/ ├── README.md # 技能库总览与设计约定 ├── _shared/ # 跨技能复用的共享资源 │ ├── templates/ # 输出模板 │ └── tools/ # 公共脚本或工具封装 └── skills/ ├── weekly-report/ # 技能根目录名字就是技能ID │ ├── SKILL.md # 技能的元信息与执行说明核心文件 │ ├── scripts/ # 可选的辅助脚本 │ │ ├── parse_input.py │ │ └── validate_output.py │ ├── examples/ # 参考样例Few-shot │ │ ├── success_case_1.md │ │ └── failure_case_1.md │ └── assets/ # 模板、字典等静态资源 └── meeting-minutes/ ├── SKILL.md ├── scripts/ └── examples/1.2 SKILL.md的灵魂description就是Agent的记忆索引SKILL.md是每个技能的核心里面记录了这个技能的元信息、适用条件、操作步骤、资源文件和注意事项。整个文件最关键的其实是开头的YAML front matter尤其是description字段。为什么这么说因为Agent面对一个任务时不会把所有技能的SKILL.md都读一遍——那是巨大的上下文浪费。它在主对话里会先根据当前场景去检索技能库的描述索引决定该调用哪个技能。description写得像没写Agent就想不起这个技能description写得有偏差Agent就会在错误的场景调错技能。我见过写得很差的description长这样name: weekly-report description: 整理周报。这种描述等于没有。Agent面对同事发来一段语音转写稿要我整理时根本不会把整理周报和语音转写稿关联起来。我现在的写法是name: weekly-report description: - 当用户需要把零散的团队工作信息整理成结构化周报时使用。适用输入包括 聊天记录微信群/钉钉/飞书、会议纪要文本、语音转文字稿、项目看板条目。 不适用于生成新周报无素材时、为单个人写个人总结报告。 输出为固定Markdown模板包含任务列表、风险项、下周计划三个区块。前后的差别在于后者不仅告诉Agent这个技能是什么还告诉了它什么时候该想起这个技能什么时候不该用。**触发条件的正例和反例都写清楚召回准确率会显著提升。**这个字段是技能库设计里性价比最高的投入我基本会花整个SKILL.md三分之一的时间来打磨description。2.3 SKILL.md内的三段式结构输入识别、执行流程、输出约束SKILL.md的内文我建议固定成三段结构不要自由发挥——标准化是为了让Agent稳定理解也是为了让你自己维护时不用每次重新猜结构。--- name: weekly-report description: - ... version: 1.2.0 tags: [report, weekly, team] --- # 周报整理技能 ## 1. 输入识别 - 允许的输入形态聊天记录原文、会议纪要、语音转写文本、看板导出 - 关键字段标记任务描述、负责人、截止时间、状态 - 禁止输入纯闲聊内容、与团队工作无关的信息 ## 2. 执行流程 1. 用 scripts/parse_input.py 将输入文本切分为有效工作信息和噪音 2. 对有效信息逐条抽取任务描述、负责人、截止时间、状态进行中/已完成/阻塞 3. 对任务进行去重相同任务以最新一条状态为准 4. 识别阻塞项和高风险项填入风险区块 5. 调用 assets/template.md生成最终周报 ## 3. 输出约束 - 必须使用 assets/template.md 的格式不得自创模板 - 输出语言中文 - 长度范围200-500字 - 不做推测素材中未提到的信息不得自行补充这样一份SKILL.mdAgent拿到之后可以按图索骥地执行不会觉得自己做完了而实际上漏了校验步骤。顺便说一句输出约束这一节很多人会漏掉但它恰恰是决定产出稳定性的关键。Agent默认倾向自由发挥你不在文件里写明必须用模板不许推测它就会给你加点它自己脑补的内容看着没问题实际上已经偏离了预期。3. 手把手搭第一个真实技能把周报整理变成Agent的肌肉记忆3.1 选场景为什么拿周报开刀最合适纸上谈兵没意思下面我带你完整走一遍第一个技能的搭建流程。就以我前面反复提到的周报整理为例。选它当第一个技能的原因很简单它高频、有明确产出物、结果可校验、而且失败模式清晰。对于第一次搭技能库的人来说这几点决定了你后面迭代时有抓手不会陷入也不知道写好没写好的混沌状态。另外周报是一个复合型技能它内部包含了信息抽取、分类、去重、格式化等多个子环节把这个技能打磨透你对技能设计的大部分要点就都过了一遍。3.2 从零写一个可用的SKILL.md逐段拆解下面是我为周报整理技能写的SKILL.md实际内容我逐段说明为什么这么写。--- name: weekly-report description: - 当用户需要把零散的团队工作信息整理成结构化周报时使用。适用输入包括 聊天记录微信群/钉钉/飞书、会议纪要文本、语音转文字稿、项目看板条目。 不适用于生成新周报无素材时、为单个人写个人总结报告。 输出为固定Markdown模板包含任务列表、风险项、下周计划三个区块。 version: 1.2.0 tags: [report, weekly, team] --- # 周报整理技能 ## 1. 输入识别 接受以下输入形态 - 多人聊天记录的纯文本导出格式不限但需要包含发言人标识或上下文可推断归属 - 会议纪要文本包含讨论事项、负责人、结论 - 语音助手转写后的文本稿可能含重复、语气词、口语化表达 - 项目看板导出任务卡片列表 每个输入的第一处理步骤统一执行python scripts/parse_input.py input.txt脚本会做三件事 1. 按行切分并过滤噪音行表情、纯语气词、广告 2. 识别潜在的任务描述行输出候选句列表 3. 统计输入中的负责人出现次数用于归属推断 ## 2. 执行流程 1. 运行 parse_input.py获得候选句与负责人列表 2. 对每条候选句判断是否为有效工作信息判断准则包含动作动词 / 包含具体交付物 / 包含时间节点三者至少满足两者 3. 抽取字段 - task: 任务描述保留不超过30字 - owner: 负责人聊天记录中出现的人名或代词对应的角色 - deadline: 截止时间如有没有则标注未明确 - status: 进行中 / 已完成 / 阻塞依据上下文判断语气词如搞定完了映射为已完成 4. 任务去重合并描述相似度超过0.85的任务对保留后出现且信息更完整的一条 5. 风险识别status阻塞 或 距截止只剩2天且状态仍为进行中 的任务列入风险区块 6. 渲染模板 assets/template.md填充三个区块 ## 3. 输出约束 - 严格使用 assets/template.md 中规定的Markdown结构 - 不得添加素材中不存在的负责人和任务 - 若输入为空或没有有效工作信息直接输出本周无有效工作信息可整理 - 不输出分析过程只输出最终周报你可能注意到了我在输入识别环节放了一个真实脚本的调用入口。**当规则比较机械行切分、候选句识别时与其让LLM凭感觉做不如交给一个确定性脚本把候选集压缩到一个很小的范围内再由LLM做语义判断。**LLM擅长的是模糊匹配和语义理解不擅长的是逐行翻几千行文本不遗漏——明确分工才能扬长避短。执行流程里我特别写了第2步的判断准则和第4步的相似度阈值——这些量化标准看着不起眼但它们是Agent执行稳定性的锚点。没有量化准则Agent的判断就会有较大的随机性今天觉得这句是任务明天觉得不是输出就上下飘忽。3.3 喂参考样例不是越多越好而是成功 失败成对喂很多人在技能里堆一大堆成功案例以为Few-shot越多越准。我的实测结论是成功案例3个以内足够了更重要的是每个成功案例配1个失败案例。失败案例的价值在于圈定边界。比如我给周报技能放了一个失败样例输入是今天天气真不错大家周末愉快期望输出是本周无有效工作信息可整理。Agent看了这个样例之后面对闲聊输入时就不会强行提炼出工作信息。成功案例的选取也有讲究。不要全放理想化的整齐输入至少留一个案例输入是带口语化、带错别字、带重复内容的语音转写稿让Agent学会真实世界的输入长什么样。目录结构就像这样examples/ ├── success_case_1.md # 标准聊天记录输入 标准周报输出 ├── success_case_2.md # 语音转写稿含语气词、重复句 标准周报输出 ├── failure_case_1.md # 纯闲聊输入 无有效信息输出 └── failure_case_2.md # 单条不完整信息 信息不足需补充输出3.4 接入主Agent声明加载、触发调用、拿到结果技能文件写好之后还需要让它能被主Agent加载和调用。目前主流做法是在主Agent的配置里声明技能库地址加载器会读取所有SKILL.md的描述索引形成一个技能清单。当主对话产生新消息时系统根据消息内容与技能描述做向量检索或关键词匹配选出可能相关的Top-N技能把它们的完整SKILL.md内容注入上下文Agent读完SKILL.md后决定是否采用。这个过程有一个必须注意的性能点不要每次对话都把所有技能的完整SKILL.md注入上下文。几十个技能文件全部塞进去几千上万tokens的上下文就没了主Agent反而消化不良。正确做法是两步走先只注入技能描述列表轻量索引几十个技能也就几百tokens命中之后再注入对应技能全文。我当时接入后的主Agent配置大概是这样的agent: skill_library_path: ./agent-skills/skills skill_index_enabled: true skill_selection_mode: auto # 可选manual / auto / hybrid max_skills_to_load: 3 skill_injection_threshold: 0.6 # 相关度阈值低于则不注入max_skills_to_load: 3是我调出来的合理值。一次加载超过3个技能主Agent的处理质量反而下降——它会在多个技能之间摇摆不知道该按哪个来。如果你发现某些任务确实需要多个技能配合那是上层任务编排的问题不应该靠一次性全量加载技能来解决而是应该再设计一个更高层的编排技能来依次调用子技能。4. 技能评测与迭代像给同事做代码评审那样打磨技能4.1 不能靠感觉好用必须建回归测试集技能写出来只是起点真正让它从能用变成可靠靠的是评测和迭代。而评测的第一前提是有一套稳定的回归测试集。我给周报技能建的回归测试集大概长这样用例编号输入类型输入特征期望输出评判要点WR-001聊天记录5人对话3条有效任务1条闲聊3条任务无闲聊混入精确率不产出多余任务WR-002语音转写含语气词、重复、结巴转写内容被正常处理召回率不遗漏真实任务WR-003混合输入聊天 看板导出混合去重后输出综合去重效果WR-004纯闲聊无任何工作信息无有效信息拒绝率不强行编造WR-005含有阻塞项任务卡在阻塞状态风险区包含该任务风险识别准确率这套测试集里的用例部分是当初让我翻车的真实输入部分是构造的边界情况。建议把历史翻车输入全部整理进回归集这是最有价值的资产。评测方式我建议分两层第一层是机器可判的客观指标有没有用模板、有没有产出预期区块、有没有包含无有效信息字样这些可以写成脚本自动跑第二层是需要人工看的语义指标任务抽取是否准确、风险判断是否合理这些我每次迭代后会自己过一遍前十来个用例。两层都过了再放出去跑真实数据。4.2 最常见的三个失败模式偏、漏、编迭代的过程中会遇到各种失败总结下来大多数跑不出这三个模式失败模式一偏检索到了但理解偏了。症状是Agent加载了技能但没有按技能执行流程走自由发挥。排查方向SKILL.md的执行步骤写得不够命令化建议把每一步都写成祈使句像必须执行不得跳过这种强制性措辞比建议执行要管用得多。失败模式二漏执行到一半觉得自己做完了。症状是跳过中间步骤直接输出结果。这是LLM的常见毛病尤其跳过的往往是有脚本校验的那一步。修复方法在输出约束里明确写未经脚本checksum校验禁止输出最终结果同时把校验失败时的兜底输出也写出来。失败模式三编输出了素材中不存在的内容。症状是Agent补全了没有提到的任务或负责人。这类问题靠提示几乎无解最稳定的是在脚本层把守住让脚本先跑一遍识别出素材中的实体清单LLM的抽取值必须在这个清单内不在清单内则丢弃。用确定性的代码给Agent的幻觉上锁。4.3 迭代节奏一次只改一个变量迭代技能最忌讳的是一次改五处效果好了也不知道是哪处的功劳效果差了也不知道哪处帮了倒忙。我自己执行的原则是一次只改一个变量小步快跑。比如这轮测试完WR-003去重效果不好那这轮只调整去重的相似度阈值从0.85调到0.8其他一律不动跑完回归集看结果。确定这次改动有效再进入下一轮的修改。另外要给技能文件标注正确的版本号并在SKILL.md里更新改动日志。这里不多说细节放到后面踩坑章节统一讲。5. 实战中踩过的坑五个反直觉的教训5.1 技能不是越多越好数量超过某个阈值后召回质量会崩早期我有一股万物皆可技能的热情把代码审查、文档润色、周报总结、会议纪要、邮件回复、SQL生成……一股脑全建了技能。两个多月攒了五十几个然后发现主Agent的选择开始飘了。原因在于技能选择本质上是在技能描述索引里做匹配。技能多了description之间会有概念重叠和语义竞争。比如会议纪要和周报整理在description里都提到了会议任务负责人这些词Agent面对一段会议记录时就可能在两个技能之间犹豫甚至把两个技能都加载进来互相干扰。踩过这个坑之后我给技能库立了两条规矩新技能入库前先检索现有技能库如果已有技能能从它的description覆盖场景就不新建而是扩展现有技能。每个技能description里必须写明不适用于哪些场景人为切分边界减少语义竞争。如果你发现技能数量已经超过四十个而且召回的准确率开始下降建议不要急着精简具体技能先检查是不是一批技能的description写得边界模糊——把边界写清楚通常就能解决大部分问题。5.2 技能里的默认值会悄悄污染上下文有段时间我的技能SKILL.md里写了不少默认设置比如输出格式使用默认模板超时时间默认5分钟。一点小改动但对Agent来说默认这个词是个大坑——Agent不知道你说的默认是指看assets里的模板文件还是它脑子里那个默认。实测中写着默认模板的技能Agent有较大概率直接按它对Markdown的通用理解输出完全不去读template.md文件。修复方式很简单删掉一切默认措辞改成具体的指向——输出格式必须使用 assets/template.md 中定义的模板不得使用其他格式。含糊的表述是Agent自由发挥的入口给它的输入越具体它的发散空间越小。5.3 模型升级后技能突然退化先查的不是逻辑而是措辞一次比较大的模型版本升级后我的好几个技能效果同时变差了。当时的第一个念头是技能逻辑过时了准备大改。后来冷静下来把回归测试集跑了一遍发现一个规律纯粹依赖语义判断的环节出错变多而依赖脚本和明确模板的环节一切正常。原因后来想明白了模型升级后对措辞的敏感度会变化。原来对判断是否为有效工作信息这个指令执行良好的表述新版模型的理解产生了偏移。**解决方法不是在逻辑层面推翻重写而是把原本纯语义判断的环节改成脚本预筛 LLM复核两步式。**先在脚本层用关键词规则缩小候选集再用LLM对缩小后的集合做语义判断。这样即使模型对措辞的理解有漂移由于候选集已经被卡得很小最终结果也不会跑偏太多。5.4 技能间的边界谁负责理解谁负责执行一个常见的错误是把技能做成大而全。比如我刚开始做的周报技能内部既做信息提取又做格式排版还想兼职判断风险等级。结果就是SPoE明显一个环节出错整个技能都不可用且很难定位哪里错了。后来我把周报场景拆成了一个技能组信息抽取技能只负责把素材变成结构化字段、风险判断技能接收结构化字段输出风险标注、周报渲染技能接收结构化数据渲染成Markdown。各干各的职责单一哪个环节出问题就修哪个技能。这样拆完一个看得见的好处是技能可以组合复用。信息抽取技能不光服务周报会议室纪要用它甚至项目复盘也能用它。这就是技能库从一堆一次性工具走向可组合模块的关键一步。5.5 版本管理与回滚技能也会被写坏你以为只有代码需要版本管理技能同样需要。有一次我在优化风险判断技能的描述措辞时顺手改了description里一个触发关键词结果直接导致该技能在几乎所有场景下都不再被召回。还好技能库整个放在Git仓库里一条git revert就把改动回滚了前后损失不过半小时。从那以后我养成几个习惯你可以直接拿去用每个技能独立目录、独立版本号SKILL.md里带version字段和changelog小节任何对SKILL.md的描述字段改动必须跑一遍完整回归集再提交技能目录整个纳入Git管理每次改动一个commitcommit message写明改了什么为什么改description字段的改动和正文字段的改动分开提交因为前者影响召回后者影响执行这套习惯看起来繁琐但在技能数量上来之后它帮你节省的排查时间远超维护成本。6. 从个人技能库到团队共享技能库再往前一步6.1 团队协作时的技能评审搞定了个人使用的技能库之后我自然想到让团队其他人也能用上这套东西。但共享之后发现每个人的使用反馈直接决定技能是否需要调整。同事在周报技能上反馈某个任务状态总变成阻塞但他觉得应该是进行中——这其实是风险判断规则在特定业务语境下产生了偏差。团队协作时我的做法是每个技能目录里加一个FEEDBACK.md使用方遇到问题直接把真实输入和期望输出贴进来。迭代者每个月集中处理一轮反馈把高频问题沉淀进新测试用例再针对性修改技能。技能不是写一次用三年的东西它更像是活文档需要持续喂养。6.2 技能的可测试性决定了这玩意儿能走多远技能库发展到后来最大的瓶颈一定不是模型的聪明程度而是你的回归测试集覆盖度。一个没有测试集的技能库改起来心都是虚的——你根本不知道一次改动是把准确率提高了3个点还是埋了一个大雷。我有一次调整周报技能的相似度去重阈值从0.85降到0.8初衷是希望更多重复任务被合并掉结果回归测试集里WR-003的精确率立刻掉了。要不是有这套测试集这个副作用放到真实使用中去可能很久都不会被发现等到发现时用户信任已经消耗得差不多了。所以如果你问我做技能库最值得投入的事情是什么我的回答是不是花时间雕琢SKILL.md的措辞而是花时间沉淀一套扎实的回归测试集。前者是术后者是道。6.3 个人体会技能库是Agent工程从个体户走向工业化的分水岭最后聊点实际的个人感受。我看过很多Agent项目从demo到落地之间隔着一道天堑。demo阶段靠提示词工程还能撑住一旦进入真实场景各种边界情况如潮水般涌来这时候还在靠堆提示词就像踢足球只靠一个前锋全场单干——前锋再强也要累死。技能库这套思路之所以值钱本质上是因为它把经验从对话上下文里搬到了可持久化、可版本化、可评测、可复用的独立模块。当前阶段我给这套体系定的目标是每个技能在放入库之前必须让它在回归测试集上的结果达到我能接受的基线——这条基线本身也在不断抬高从样例通过到回归集通过再到真实场景新用例连续两周稳定。整个过程像滚雪球测试集越厚技能越稳技能越稳就越敢接入更复杂的场景。如果你也准备开始搭自己的agent-skills我的建议是别一上来就规划一个大而全的技能库先挑一个你手头每天都碰、且结果可校验的任务按照这篇文章的流程把它做成第一个技能建好它的回归集然后跑两个月再说。等这个技能真的稳了你自然就知道下一步该往哪个方向扩了。