news 2026/10/7 13:10:30

Agent技能库:告别工具失控,构建可复用的技能层

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent技能库:告别工具失控,构建可复用的技能层

今年做Agent相关的项目时,我遇到一个特别尴尬的阶段:工具函数写了一堆,Agent反而开始“挑三拣四”,不是调用错工具,就是在无关场景里硬套某个函数。后来我把重心从“堆工具”转到一个我自己命名为 agent-skills 的技能库方案上,情况才慢慢好转。这个方案的核心思路很简单——把Agent能用到的能力封装成目录化、文档化、可测试的技能包,而不是继续往系统提示词里塞操作说明。这篇文章就聊聊这个方案到底解决什么问题、技能包怎么写、调度机制怎么设计,以及我在实测中踩过的坑,适合正在做Agent应用、工具链设计、或者被“工具一多就失控”困扰的朋友参考。

1. 为什么要单独建一个“技能层”:工具调用的三个典型失效场景

先说我遇到的问题。最初做Agent功能时,我按教科书的方式把所有能力都做成函数调用(Function Calling),每个函数配一段简短描述,让模型自己选择。开始时确实好用,但随着业务需求扩展,函数数量从5个涨到20多个,问题开始集中爆发。

1.1 Function Calling沦为“函数农场”的三个信号

第一个信号是误调用。有一次我写了一个“获取天气”的函数,又写了一个“查询节假日”的函数,这两者的描述里都含有“日期”这个词。结果用户问“明天适合开会吗”,Agent居然同时调用了天气和节假日接口,返回的信息七零八落。这不是模型笨,而是函数描述太薄,模型根本没有足够信息判断哪个才是真正相关的。

第二个信号是上下文污染。为了让模型知道每个函数怎么用、什么时候不要用,我不得不把更长的说明写进系统提示词。结果每轮对话都要携带一大段工具说明,Token消耗肉眼可见地上涨,而真正留给业务数据的空间却越来越少。

第三个信号是经验无法沉淀。函数是一段代码,它只能“执行”,不能“思考”,更无法承载一整套方法论。比如“做一轮竞品调研”,这不是单个API调用能搞定的,它涉及信息源选择、筛选标准、报告结构、异常处理等多个步骤。这些步骤用函数表达很别扭,用Prompt表达又容易超出窗口。

1.2 技能与工具的边界:菜谱与锅碗的关系

我后来想明白一个类比:函数是锅碗瓢盆,技能才是菜谱。

锅碗瓢盆是单次动作,切菜、翻炒、装盘,你让Agent调用它们没问题,但Agent不知道“今天要做一盘鱼香肉丝”意味着什么。菜谱则不同,它包含目标、步骤、关键火候、常见翻车点、以及最后怎么判断菜品成功。技能就是给Agent的一份菜谱。

所以在 agent-skills 体系里,我对“技能”的定义是:一段面向特定任务的方法论文本,加上配套的资源文件和可执行脚本,它们共同构成一个可复用的能力单元。技能可以调用函数,但函数不是技能。

1.3 技能层能否成立的验证标准

我在建技能库之前,先定了三条验证标准,免得自己把技能库做成另一个“函数农场”:

  • 可解释性:一个技能是否能让模型明白“什么时候该用、什么时候坚决不用”。
  • 可复用性:同一个技能能否在不同项目、不同Agent之间迁移,而不是绑死在某段代码里。
  • 可演进性:技能的改进是否可以脱离代码发版独立进行,比如修改方法论文档后立刻生效。

如果这三条不满足,那就说明还是在用旧思路做新容器,不如回去继续堆函数。

2. agent-skills 的技能文件标准:目录、SKILL.md 与资源拆分

确定要建技能层之后,第一个要解决的就是技能包的文件结构。没有一个统一结构,技能之间就会长得各不一样,Agent无法从异构格式里稳定提取信息。

2.1 技能目录的最小可用结构

我的 agent-skills 仓库里,每个技能都遵循同一个最小目录结构:

skill-name/ ├── SKILL.md # 技能主描述,包含元信息与核心方法论 ├── scripts/ # 可执行脚本,用于稳定输出格式 │ └── main.py ├── references/ # 长文档、参考资料,按需加载 │ └── api_notes.md ├── templates/ # 输出模板,保证生成内容结构统一 │ └── report_template.md └── examples/ # 输入输出样例,作为few-shot参考 └── expected_output.json

这个结构不复杂,但每层都有它的用处。SKILL.md 是入口,scripts 负责模型无法稳定复现的确定性计算,references 存放不该灌进上下文的冗长材料,templates 让输出保持一致,examples 给模型一个“标准答案”做参照。

2.2 SKILL.md 怎么写才真正被模型读懂

SKILL.md 是整个技能包的心脏。目前各家主流做法大同小异,核心是YAML格式的元信息块加上Markdown正文。我常用的模板长这样:

--- name: meeting_notes_skill description: 用于将会议原始记录整理成结构化纪要。 when_to_use: 输入包含会议转写文本、聊天记录,或需要输出结论、待办与负责人时。 when_not_to_use: 输入不包含任何会议信息,或只是一个简单问答时。 version: 1.2.0 --- # 任务目标 将原始语音转写或文本记录,转换为带结论、待办、风险与负责人的结构化纪要。 # 执行步骤 1. 提取参会人与讨论主题。 2. 按话题聚类原始内容,保留关键决策。 3. 为每个决策标记负责人与截止时间。 4. 无法确认的信息标记为“待确认”,不要自行补全。 # 注意事项 - 原始文本中经常有语气词,直接忽略。 - 如果同一个结论出现两次,合并表达,不重复记录。 - 截止时间没有明确日期时,写成“未明确”,不要用“尽快”这类模糊词。 # 输出格式 详见 templates/report_template.md,并严格按模板字段输出。

这里有两个容易被忽略的细节。第一,when_not_to_use 一定要写。很多技能描述只写“能做什么”,不写“不该做什么”,Agent就会在模棱两可时倾向于误调用。第二,关于“不要自行补全”这类约束,我建议用肯定句加否定句双保险,单纯说“不要补全”效果有限,最好同时写明“标记为待确认”,模型才有替代动作。

2.3 资源文件是拉开体验差距的地方

我在接手项目时,别人给的技能只有一页说明,没有任何资源文件。看起来简洁,结果Agent每次输出格式都不一样,今天用表格,明天用列表,后天直接给我一段散文。

后来我补了几个资源文件,效果立刻不同。references 目录放的是详细的领域背景,比如复杂规则说明,这些内容只有在Agent认为必要时才被纳入上下文,平时不占窗口。templates 目录更关键,它让模型有锚点可依,输出结构至少能保持在同一个坐标系内。examples 目录则承担few-shot职责,给一个输入输出的成对样例,比在描述里写十句“要工整”都管用。

资源文件要不要拆分,取决于一个原则:高频信息留在 SKILL.md 里,低频信息移到 references 里,稳定格式交给 templates,正确示范放进 examples。这四类信息的加载成本不同,拆开之后,Agent才能按需取用。

3. 从零实现一个“调研纪要技能”:完整实操记录

空谈结构没有说服力,我拿一个实际技能举例:调研纪要整理技能。这个技能在我内部叫 research_notes_summary_skill,它的任务是把散落的访谈、网页摘录、数据片段整合成一份轻量调研报告。

3.1 先写描述再写步骤,描述决定一切

第一次写这个技能时,我直接开始写执行步骤。结果用起来很别扭,Agent经常在用户问“帮我查一下竞品定价”时,把整个调研纪要技能搬出来跑一遍,输出一堆不相关的框架。

后来我调整了写技能的顺序:先写 description,再写步骤。描述部分我拟了三个维度:

  • 做什么:把多个来源的信息片段综合成一份调研纪要。
  • 什么时候用:用户提供多条来源信息,或要求“汇总”“对比”“整理调研结果”。
  • 什么时候不用:用户只是提出一个问题,不附带任何信息源;或者信息量极小,单独一句就能回答。

写完描述再回头看步骤,整个技能就清晰了。

3.2 方法论文本与可执行脚本的配合

调研纪要里有一项工作让我很头疼:为每条观点标注信息源的可信度。模型本身做不到精确计算,它不知道一个网站是官方渠道还是个人博客。这块我选择用脚本辅助,写一个 SourceRanker 的小工具,接收来源URL和域名,返回一个1到5的可信度评分,判断规则写死在脚本里。

#!/usr/bin/env python3 import sys import re def rank_source(url: str) -> int: domain = re.sub(r"^https?://", "", url).split("/")[0] official_domains = {"stats.gov.example", "who.int", "openai.com"} if domain in official_domains: return 5 if "edu" in domain or "ac." in domain: return 4 if "github" in domain or "arxiv.org" in domain: return 3 return 2 if __name__ == "__main__": url = sys.argv[1] if len(sys.argv) > 1 else "" print(rank_source(url))

方法论文本负责告诉模型“判断维度”和“什么时候调用脚本”,脚本负责给出确定性的分数。一条信息既给了编号,又给了分数,模型再综合排序就稳定很多。

3.3 第一次实测暴露的问题:技能被调错与输出漂移

实测过程中翻车经历很有价值。第一次跑通后,我用一个包含访谈记录和网页摘要的测试集去验证,出现了两个问题。

第一个问题是技能被调错。输入里包含“请你比较一下A和B两个产品”——我的本意是用普通问答处理,但Agent把调研技能拉了出来。看日志发现,我的 description 里写了“比较”“对比”作为触发词,导致模型认为任何比较类问题都属于调研。

修正方案是给触发词加上边界条件:只有当“提供了多个信息源”时才适合本技能,并以最核心的使用条件开头。我把 description 改成“用于将多条已采集信息综合成结构化的对比纪要。适用于用户已经在输入中提供原始素材的场景”,触发词从句子开头移到了句子中段。改完之后,误调用明显减少。

第二个问题是输出漂移。同一个测试输入,第一次输出的是表格,第二次输出的是编号列表。我检查 Skill 的正文,发现里面有一句“尽量采用结构化形式输出”,这个“尽量”给了模型太多自由。我直接删掉这句,换成明确指令“输出必须使用 templates/report_template.md 规定的表格字段”。

# 输出格式 严格遵循 templates/report_template.md 中的字段顺序: 简介、主要发现、证据来源、待确认问题、下一步动作。

换成“必须”之后,输出稳定性肉眼可见地提升。

4. 技能调度与多技能协作:我在组合调用中踩过的坑

技能文件写好了,技能数量一旦上去,调度问题就会浮出水面。Agent怎么从几十个技能里选中正确的那个?多个技能一起用时怎么防止上下文互相污染?这些坑,我一个个说。

4.1 技能选择的底层逻辑:不是精确匹配,而是语义相近度

先明确一件事:Agent选择技能本质上不是“查字典”式的精确匹配,而是一次语义相似度计算。模型把用户请求向量化,与所有技能的 name 和 description 做对比,然后挑相似度最高的候选。这意味着 description 里的措辞质量,直接影响技能是否被命中。

我的实测经验是,描述里动词的粒度很关键。比如“清洗数据”和“修正数据格式”,语义距离看着近,但适用场景差很多。前者更适合用统计方法处理缺失值,后者更适合统一字段格式。我会尽量把描述里的动词写具体,避免用“处理”“分析”这类万能动词。

还有一个容易被忽视的信号是技能自身的前置条件。比如我有个代码审查技能,要求用户提供代码上下文。如果描述里写明“需要项目路径或代码片段作为输入”,模型在用户没给具体代码时就会拒绝执行并追问补充信息,而不是硬着头皮把无关代码翻出来。

4.2 上下文污染:长技能文本在轮次对话里的隐形消耗

技能调度一旦启动,SKILL.md 就会被注入上下文。如果一个技能文件超过2000字,还在对话里被反复用到,那每轮对话都要携带这2000字的“固定成本”。

我自己定的规则是这样的:SKILL.md 正文控制在800字以内,凡是超过的内容都放进 references。比如技能涉及一套完整的企业内部规范,正文里只写“按 references/company_rules.md 执行”,把完整规范放到外部文件里,由脚本或者二次检索按需塞入上下文。这样既保留了必要的信息约束,又没把整个规范文本常驻在上下文里。

另外,我会把“输出格式模板”的维护频率降低,尽量不每轮都重新解释。模板在状态机里属于稳定部分,频繁变动的模板会让模型无所适从,反而增加输出随机性。

4.3 技能间依赖与串联:不要指望Agent自由发挥

技能数量多了以后,组合调用的需求自然出现。比如“周报生成”这个技能,基础信息来自“会议纪要技能”的输出,还可能需要“工时统计技能”的数据。

一开始我允许Agent自行串联,结果出现了几类问题:会议纪要技能输出的标题,周报技能无法解析;工时统计技能的日期口径两边不一致;两个技能同时工作时,上下文里的角色设定互相干扰。

解决方式是为技能声明依赖关系。在 SKILL.md 元信息里增加 requires 字段:

--- name: weekly_report_skill description: 根据会议纪要、工时数据生成周报草稿。 requires: - meeting_notes_skill - timesheet_stats_skill ---

然后在主技能的方法论文本里写明“先获取 meeting_notes_skill 的结构化输出,再汇总 timesheet_stats_skill 的数据,最后套周报模板”。依赖关系显式化之后,Agent 的行为预期变得可控,不会再出现“先把会议纪要整理了一遍,又基于整理结果再整理一遍”这样的无效循环。

5. 技能仓库的治理:版本、冲突与跨项目复用

技能数量到二三十个之后,光靠脑子记已经不现实了。这里我讲一下在 agent-skills 仓库里怎么治理这些技能资产。

5.1 用Git管理技能资产:版本号与变更日志

我把每个技能当作一个可独立发版的小型组件。技能目录下的 SKILL.md 头部带 version 字段,只有当描述、步骤、模板发生实质变化时,我才会递增版本号。用语义化版本规范:主版本号在方法论彻底改变时递增,次版本号在新增场景时递增,修订号用于修正错别字或补充案例。

配套维护一个 CHANGELOG.md,每次改技能都记录“改了什么、为什么改、影响了哪些场景”。看历史记录时,价值非常大。有次我发现某技能一周前还是好用的,两个小时后失效了,翻 CHANGELOG 才发现中途改过描述里的触发词,把一个敏感条件删掉了。

5.2 技能命名冲突与仓库分层

多个技能之间最容易出现的冲突是描述重叠。比如“文档总结”和“会议总结”,看起来能共存,但模型经常搞混。我实践下来的做法是给技能名称加领域前缀,让命名空间结构化:meeting_xxx_skill、doc_xxx_skill、news_xxx_skill。这样一来,即使描述里出现重叠词,名称本身也能提供额外的区分信号。

仓库内部我还分了三个层级:

  • core:经过多轮测试、稳定通用的技能,比如基础格式转换、日志解析。
  • community:单项目里验证过、但还没经过跨场景测试的技能。
  • personal:个人偏好或一次性场景专用的技能,不在跨项目场景里共享。

这种分层有点类似代码仓库里的主分支和功能分支,个人技能可以先在 personal 里快速试错,稳定后合入 core。

5.3 跨Agent跨项目复用的关键细节

我遇到过最典型的失败是把技能放在某个项目专用目录里,收到“代码路径写死”的错误。技能的复用性其实取决于它对项目细节的抽象程度。

跨项目复用的硬性要求有三条:

  • 技能内部不得出现具体项目的绝对路径。
  • 技能引用的资源文件必须都在技能目录内部,不能散落在项目根目录。
  • 技能的输出模板必须自包含,不依赖项目特定的表结构。

如果某个技能在项目A里依赖了A系统的接口,我会在 references/adapters 目录下写适配器说明,把A系统的差异隔离到单独文件里,而不是直接改 SKILL.md。

实际效果是,我把“日志异常检测技能”从A项目迁到B项目时,只改了一个 adapter 文件,其余部分原样沿用。这种“一次迁移只动一个地方”的体验,让技能库真正变成了跨项目资产。

6. 给新手的入坑路线与我的长期体会

如果你现在正准备用 agent-skills 的思路搭建自己的技能库,我给几条实操建议,都是我实际走过来觉得最划算的方向。

6.1 从“先有5个技能而不是50个”开始

刚开始最忌讳求多。技能库的维护成本体现在:每一个技能都要写描述、测触发、看输出,数量上去了,维护负担是线性增长的,但调度复杂度会指数上升。我的建议是先从日常最高频的5个任务入手,比如会议纪要、信息提取、周报生成、代码审阅、日志分析。把这些做到“不需要思考就能稳定命中”的程度,再拓展数量。

6.2 我的技能迭代循环:写-测-记-删

每个技能都要经历四步循环:

  • 写:先写 SKILL.md 的 description 与执行步骤。
  • 测:准备2到3个正例和2个负例,验证误调用和输出稳定性。
  • 记:把失败现象记进 REmark 文件,或者在 CHANGELOG 里记录调整点。
  • 删:如果一个技能连续两周使用频率极低,或者总产生无关输出,就考虑删除或合并。技能不在多,在精。

这套循环看起来麻烦,但长期看特别有效。我删掉过两个触发频繁但输出无用的技能,去掉之后主Agent的响应准确率反而上升了。

6.3 三个小技巧

最后分享三个平时不太会写进文档、但实测特别有用的小技巧。

第一个,description 的开头第一句决定命中概率。模型在做语义匹配时,句子开头的权重往往更大。所以把最核心的使用场景写进第一句,不要在开头写“这是一个用于……的工具”这类废话。

第二个,给技能加“验收样例”。在 examples 目录里放一份标准的“输入输出对”,当技能行为出现漂移时,拿样例做回归测试,马上能看出是哪一步变了。我通常把这份样例命名为 gold_test_case.json,每个技能必须保留。

第三个,把失败案例写进 SKILL.md 的注意事项。Agent运行中出现的典型错误,比如“日期缺失时不要默认填今天”,直接写进正文。这样系统提示词没覆盖到的边界情况,会在技能层补齐。文本只会在该技能被调用时进入上下文,也不会挤占主线对话窗口。

我自己的体会是,模型能力越来越强的今天,很多人把Agent项目的成败押在提示词工程上,却忽略了更底层的“能力资产化”问题。你对付出的每一次技能整理,本质上都是在给Agent沉淀一套可迁移、可测试、可演进的操作手册。我踩过工具一多就失控的坑,也体会过技能库稳定命中带来的踏实感。如果你也正被“工具函数一堆但效果稀碎”困扰,不妨从三五个技能包开始,给自己建一个 agent-skills 体系,这条路值得走。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 13:10:30

Tinkercad虚拟电路:零代码玩转Micro:bit传感器教学

1. 为什么“不写代码也能玩转Micro:bit”这件事,值得你花15分钟认真读完 Micro:bit 这块巴掌大的开发板,从英国BBC推广起家,到今天已成全球中小学信息课、创客教育和电子入门的标配。但现实很骨感:很多老师想带学生做传感器实验&a…

作者头像 李华
网站建设 2026/10/7 13:09:10

评论大数据+CNN情感分析:从清洗到可视化落地链路

简介:这份资源面向自然语言处理初学者与大数据分析实践者,提供一套基于卷积神经网络对评论大数据进行情感分析并完成可视化展示的完整项目。内容围绕文本预处理、词向量构建、CNN模型搭建、训练调优、指标评估与结果可视化等环节展开,帮助读者…

作者头像 李华
网站建设 2026/10/7 13:09:06

GPU利用率低的六大根因:从PCIe降速到DataLoader瓶颈

1. 为什么GPU利用率常年卡在30%不是硬件问题,而是训练流程的“慢性窒息” 你盯着 nvidia-smi 里那根永远爬不上去的GPU Util曲线,心里发毛:明明是RTX 4090,显存用掉85%,但GPU计算单元却像被捆住手脚——利用率死死钉…

作者头像 李华
网站建设 2026/10/7 13:08:51

四线法测毫欧电阻:从原理到实操的完整指南

1. 从一次“翻车”的电流采样说起 几年前调一块电机驱动板,电流采样电阻用的是2512封装的1毫欧合金电阻,标称精度1%。板子焊好之后上电,电流环的反馈值跟钳形表读数差了将近8%,怎么调PID都不对。一开始怀疑是运放失调、ADC基准不准…

作者头像 李华
网站建设 2026/10/7 13:07:49

Triplet Loss实战指南:从三元组构造到训练避坑全流程

简介:Triplet Loss(三元组损失)是度量学习中的重要损失函数,广泛应用于人脸识别、图像检索等相似性任务。这份实战资源以MNIST手写数字数据集为场景,完整给出基于Triplet Loss的模型训练与推理代码,涵盖模型…

作者头像 李华
网站建设 2026/10/7 13:07:40

BUCK电源PCB设计核心要点:SW节点、地分割与BOOT电路实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华