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

agent-skills 实战指南:从零搭建大模型技能库,让 Agent 真正“会干活”

最近半年我一直在折腾 AI Agent 相关的落地项目先后踩遍了工具调用、多轮对话、记忆管理这些坑之后发现一个很有意思的现象很多人把精力全扑在怎么让 Agent 更“聪明”上却忽略了一个最基础也最关键的问题——Agent 手里到底有哪些“本事”可以用。这个“本事”圈子里最近的叫法是 agent-skills。一说这个名字玩过 Anthropic Skills 或者关注 smolagents、OpenAI 最新 AgentKit 的朋友应该不陌生。它本质上是在给大模型准备一套可复用、可检索、可组合的技能库让 Agent 在接到任务后先“翻一翻”自己会什么再把合适的技能拿出来干活儿。这篇文章我就拿自己实际跑过的项目当例子把 agent-skills 的来龙去脉、底层机制、从零搭建的过程和掉过的坑一次说透。1. agent-skills 到底是什么和工具、插件、工作流有啥区别先说个容易混的点。我见过太多人把“技能”和“工具”混为一谈一上来就问“skills 是不是就是加了一堆 function calling”真不是一回事。agent-skills 的层次比工具高它更像是一个人脑里的“程序性记忆”。你想想一个人接到“帮我整理出差报销单”这个任务时不会先问“这个月打车花了多少钱”而是会先想起“报销这事儿有一套流程收集发票、填单子、领导审批、提交财务”。这套流程就是技能。技能是围绕一个完整任务组织的知识包里面可能包含多个工具调用也可能不直接调用任何工具纯粹是一套步骤和规则。工具则更像是“搬砖的手”。比如“查询天气”“发送邮件”“解析 PDF”每个工具只解决一个原子操作。插件是工具的成捆发布可以理解成把一个工具箱打包给你。工作流则更进一步它是“按固定顺序调用多个工具”的编排流程但问题在于编排是写死的任务一变流程就僵住了。agent-skills 最关键的区别在于它是“按需发现”的。Agent 接到任务后先根据任务描述在技能库里做一次语义匹配找到最相关的技能说明再把技能的具体步骤注入到上下文里执行。技能不是预先加载的全集而是像人一样“临场想起”。这个机制让 Agent 既能储备大量技能又不会把上下文撑爆是我目前试过的方案里扩展性最好的一种。我自己的项目里目前的技能库里存着三十多个技能覆盖文档处理、网页信息抽取、数据清洗、邮件周报生成、会议纪整理等等。真正跑起来之后每次任务平均只加载两到三个技能上下文开销很小响应速度和准确性都比之前把所有工具塞进 system prompt 的做法强不少。1.1 技能为什么适合做 Agent 能力库的基本单元我在实际对比中逐渐认识到技能做“能力的基本单元”有一个工具叫“人”很难替代的价值它可以携带大量高质量的过程性知识。工具只能告诉 Agent “我能干什么”技能却能告诉 Agent “这件事应该怎么干、分几步、中间要注意什么、输出格式长什么样、常见边界情况有哪些”。举个例子。我写了一个“会议纪要整理”的技能它的描述里包含了如何区分行动项和决策项、每个行动项要标注负责人和截止时间、决策项要记录提出人和背景、输出格式建议用 markdown 列表、如果原始内容没有明确责任人要标注“待确认”。这些知识如果全塞进工具描述里单个工具的 description 会冗长到影响匹配精度如果不塞进去Agent 就只会机械地转写会议内容而不是真正做整理。所以 agent-skills 的定位本质上是把“专家经验编码成可检索的文本知识”。它不需要多强的逻辑推理也不需要写代码才能建新技能你只需要把做某件事的步骤和要点写清楚Agent 就能照着执行。这一点对非程序员极其友好我团队里的运营同学在模板的引导下也能自己往技能库里添加新技能这不比每次改代码香多了2. 一个技能文件是怎么被“发现”和“调用”的这一节是核心中的核心。理解了技能被加载的机制你就理解了整个 agent-skills 的设计哲学。我把它拆成三个阶段来讲技能入库、技能匹配、技能执行。技能入库阶段每个技能通常是一个独立的目录里面包含一个SKILL.md描述文件和若干辅助资源。SKILL.md的开头有一段 YAML frontmatter里面写技能的名称和描述这段描述是后续匹配的关键。描述写得越准确Agent 越能在对的时候把技能想起来。辅助资源可以是示例数据、代码模板、参考文档甚至是一个独立的 Python 脚本。技能匹配阶段我实测对比了两种主流方案。第一种是关键词检索最简单把任务文本和技能描述的公共词做匹配适合技能数量少、描述高度规范的场景。第二种是向量语义检索先把技能描述向量化存进向量数据库任务到来时计算任务向量和技能向量的余弦相似度取 Top-K 候选。语义检索对措辞差异的容忍度高很多比如任务里写“整理会议结论”技能描述里写的是“会议纪要生成”关键词方案大概率漏掉语义方案能正确匹配上。我现在用的是轻量级方案先跑一遍关键词粗筛再用 embedding 模型对候选集合做精排效果和纯向量方案几乎持平但查询成本低不少。技能执行阶段匹配到的技能文件内容会被注入到 Agent 的上下文窗口连同用户任务一起交给大模型。模型读完技能里的步骤和规则后要么按步骤直接生成文本结果要么调用技能里引用的外部工具要么执行技能附带的脚本。这里有个重要细节技能内容不是每次都全部加载而是只加载命中的那几个所以技能库可以做到很大上下文却能保持精简。注意正因为技能只在匹配命中时才注入技能描述里提到的任何能力必须和实际可用资源对齐。我在早期犯过一个错技能描述里写了“调用内部工单系统 API”结果 Agent 看完描述跑去调 API技能附带脚本里根本没写对应的请求函数最后任务直接崩了。技能描述是给匹配用的不是给执行用的真正的执行能力必须落实在脚本或工具配置里。2.1 技能描述的好坏直接决定可用性上限技能描述在整个机制里是“命门”。它既要被检索系统匹配又要被大模型理解相当于一个文件的“电梯演讲”——几十个字里讲清楚这个技能解决什么问题、什么条件下用、大致怎么用。我在整理技能库时定了一条硬规则描述必须包含“触发场景 任务对象 结果形态”三要素。举两个我实际写的描述做对比bad处理 PDF 文件。 good当用户需要提取、解析或转换 PDF 文档内容时输出结构化的 markdown 或 JSON 数据。第一个描述的问题在于太宽泛“处理”是个动词黑洞什么都能往里装检索系统很容易把它召回到不相关的任务里。第二个描述明确写了任务对象是“PDF 文档内容”输出形态是“markdown 或 JSON”场景是“提取、解析或转换”匹配精度明显提升。描述长度也需要控制。我测过描述在 200 到 300 个汉字左右效果最佳太短信息量不够太长会让检索系统的向量更多偏向描述本身的用词而忽略任务语义。同时不要用“本技能可以用于……”这种废话开头直接说“当用户需要……时使用本技能……”反而更清晰大模型读起来也舒服。2.2 技能的内部结构和典型文件布局一个标准的技能目录长什么样我直接贴一个我在生产环境里使用的模板布局你照着建就行skills/ └── meeting-minutes-summarizer/ ├── SKILL.md ├── reference/ │ └── good_example.md ├── scripts/ │ └── split_transcript.py └── assets/ └── output_template.mdSKILL.md是入口文件必须存在里面写技能元信息和完整执行步骤。reference/目录放好的示例大模型从示例里学到的东西往往比从规则里学到的更具体。scripts/目录放可执行脚本比如文本切分、格式转换这类确定性工作交给代码更靠谱。assets/目录放模板或者其他静态资源。SKILL.md的内部结构我习惯遵循这么一套--- name: meeting-minutes-summarizer description: 当用户给出会议录音转写文本或会议原始记录需要生成结构化的会议纪要时使用。输出包含会议主题、讨论要点、决定事项、行动项清单。 ---正文部分我会分成几个固定的段落适用场景说明、执行流程步骤、注意事项、输出格式参考。执行流程要具体到步每一步说清楚输入是什么、如何处理、产出的中间结果去哪里。注意事项部分专门写边界情况比如“如果转写文本包含多人发言交叉先按 speaker 标签切分”“如果没提到责任人不要编造标待确认”。我的体会是正文里给“反面例子 纠偏方法”的段落特别管用。直接告诉模型什么不能做比只告诉它应该怎么做在实际执行中的准确率提升更明显。比如会议纪要技能里我写了一句“不要为每个发言人都添加观点评价只记录客观讨论结论”这句至少让输出质量提升了一个档次。3. 从零搭建自己的第一个技能库说完了机制直接上手。这一节我会带着你从零搭一个最小可用的技能库并且跑通一个端到端的调用链路。我会尽量用开源或者免费的组件避免一上来就绑定某个特定厂商的闭源生态。我的推荐技术栈是这样的技能文件统一存放在 GitHub 仓库里用标准目录结构管理本地运行时直接用git clone拉下来技能索引用 SQLite sqlite-vec扩展把技能描述的 Embedding 存进去检索时算余弦相似度Embedding 模型可以用bge-small-zh这类轻量模型下载到本地推理不走外部 API隐私和速度都有保障Agent 框架我这边用的是开源方案支持自定义工具注册和上下文注入。这里顺便解释一下为什么我选本地 SQLite 而不是直接上 Milvus 或者 Qdrant 这类独立向量数据库。技能库规模在几百个以内时SQLite 向量扩展的性能完全够用一次检索在几十毫秒量级而部署和维护成本几乎为零。如果之后技能库上了几千条再迁移到独立向量库也不迟不需要提前为了用不上规模复杂度买单。3.1 技能库目录设计和索引构建首先建仓库目录结构如下agent-skills/ ├── skills/ │ ├── _template/ # 技能模板新建技能时复制这个目录 │ ├── pdf-info-extractor/ │ │ └── SKILL.md │ ├── weekly-report-generator/ │ │ └── SKILL.md │ └── ... ├── indexer.py # 扫描技能库生成向量索引 ├── retriever.py # 给定任务描述返回匹配技能 └── requirements.txtindexer.py的核心逻辑不复杂我用伪代码展示一下要点import sqlite3 from pathlib import Path def build_index(skills_dir: Path, db_path: Path): # 遍历 skills 目录下所有 SKILL.md解析 frontmatter # 对 skill 的 description 文本做 embedding # 把 name, path, description, embedding 写入 sqlite conn sqlite3.connect(db_path) conn.enable_load_extension(True) conn.execute(SELECT load_extension(mod_sqlite_vec)) # 建表时给 vector 列声明维度比如 bge-small 是 512 维 conn.execute( CREATE VIRTUAL TABLE IF NOT EXISTS skill_index USING vec0(embedding float[512]); ) # 插入技能时逐条写入 # ...索引构建完成后retriever.py做的事情就更简单了把用户任务文本做同样的 embedding然后在skill_index里做 KNN 查询返回相似度最高的技能。def retrieve(query: str, top_k: int 3): query_vec embed(query) rows conn.execute( SELECT name, path, distance FROM skill_index WHERE embedding MATCH ? ORDER BY distance ASC LIMIT ? , (vec_to_blob(query_vec), top_k) ).fetchall() return rows这里有个实操建议WHERE embedding MATCH ?的查询对向量格式有要求不同的 sqlite-vec 版本对传入 blob 的字节序和 Float32 的排列方式要求不完全一致我第一次跑通花了不少时间排查。建议你构建完索引后先用一条已知样本做一次闭环查询确认召回结果合理再去调 Agent 集成不然问题和错误容易混在一起不好定位。3.2 让 Agent 真正“用”上技能技能库建好之后接下来把检索结果注入到 Agent 里。这一块的关键是不要让 Agent 直接拿到所有技能的内容而是只把检索到的技能摘要告诉它等它决定用某个技能时再由运行框架注入完整技能内容。我用的集成方式是这样的首先在 Agent 的工具列表里注册一个名为skill_lookup的检索工具这个工具接收自然语言任务描述返回匹配技能的编号和一句话摘要。其次给 Agent 的动态上下文检查逻辑加一个钩子当模型输出某个技能调用意图时运行框架自动去技能库读取对应技能的完整SKILL.md并注入到下一轮对话中。为什么这么设计因为 Agent 本身就是个对话循环模型每次回复都可能包含“我想调用技能 X”的信号。把检索做成工具让模型自己判断任务需要什么技能比预先用规则强行绑定任务和技能要灵活得多。我试过完全确定性的方案就是事前根据任务类型走流程模板遇到“任务类型模糊”的查询直接不会处理。改成模型主动检索后“帮我整理一下这个 PDF 里的客户联系方式”这类开放描述也能被正确路由到 pdf-info-extractor 技能上。def on_model_request(user_query: str): candidates retrieve(user_query, top_k3) # 把候选技能摘要拼接后作为工具的返回结果 skill_hints format_candidate_hints(candidates) # 构造 agent 消息 messages.append({ role: user, content: f用户请求{user_query}\n\n可参考技能\n{skill_hints}\n\n请判断是否需要调用某个技能。 })需要再次强调注入的内容一定要有节制。我之前贪心一次把 Top-3 技能全部展开完整内容注入结果系统提示词超过 20KBAgent 的响应速度和可维护性都明显变差。现在只给摘要等模型明确选中某个技能下一轮才补完整内容效果和效率都理想很多。3.3 技能执行中“确定性步骤”交给代码更省心在集成过程中我发现像 PDF 解析、文本切分、格式转换这些高度确定性的工作如果想让大模型按步骤写 Python 代码来做不仅耗时很长而且容易出错。更稳妥的做法是在技能目录的scripts/里直接写好可复用的函数技能执行时让 Agent 去调用这些现成脚本而不是从零写代码。比如我的 PDF 信息提取技能目录里的脚本做两件事用pdfplumber把 PDF 内容抽成纯文本然后用正则加规则模板把邮件地址、电话、联系人这类目标字段抽出来。Agent 的技能内容里明确写了“调用 scripts/extract_text_and_fields.py”运行框架会以子进程方式执行脚本并捕获标准输出。整个流程快且稳定大模型只负责判断结果是否符合用户需求不用纠结底层解析细节。这个思路背后的原则是大模型擅长的是理解意图、拆分任务、生成结构化结论计算、解析、遍历这类工作应该交给确定性的代码。agent-skills 的真正价值不只是“让 Agent 按步骤做”而是“让每一步都用最合适的工具来做”。技能本身是一个编排层它决定先后顺序和分支判断落地执行走引擎。4. 主流生态里的 agent-skills 实践盘点理论和自建方案都聊完了我顺手盘点一下目前几大流行的 agent-skills 生态方便你按自己的技术基础选路。Anthropic 官方开源的 skills 仓库是我最早的参考对象里面的每个技能都遵循类似的目录结构有清晰的SKILL.md描述还配有示例输入输出。我当时学习它的写作风格尤其注意到官方技能描述喜欢写“Use this skill when ...”这个句式几乎成了行业惯例匹配精度确实不错。OpenAI 最近布局的 AgentKit 则把技能体系玩得更系统它把 skill、记忆、工具统一纳入了 Agent 的配置化管理有可视化界面可以拖拽调整 Agent 的能力配置。对团队协作来说这个设计很加分因为非技术人员也能通过界面了解 Agent 被赋予了什么能力而不是只看到一堆代码和配置。开源社区这边Hugging Face 的 smolagents 一直坚持“代码即行动”的理念技能和工具基本都是 Python 函数的形式灵活度极高。如果你本来就熟悉 Python这个框架可以让你很快跑通自己的技能库如果你的团队以业务人员居多那建议还是走纯文本SKILL.md的思路让运营和产品也能直接参与技能写作。4.1 值得收藏的常用技能类型清单根据我在真实项目里的使用频率我把目前积累的技能库按热度分了几类你可以直接参考这个清单来起步文档处理类 - PDF 信息抽取文本、字段、表格 - Word 报告转 Markdown - 长文档自动摘要 数据处理类 - CSV 数据清洗与字段校验 - 从非结构化文本中抽取结构化字段 - 数据表之间的关联合并 写作生成类 - 周报/月报自动生成 - 会议纪要整理 - 邮件草稿撰写与润色 信息采集类 - 网页正文提取 - 商品信息批量获取 - RSS 源定时汇总 个人助理类 - 日程安排与任务拆解 - 待办清单优先级整理 - 学习笔记卡片化整理我的建议是前期不要贪多先挑你日常工作里频次最高、重复性最强的三到五件事做成技能。比如我做咨询出身最常用的三个技能是“会议纪要整理”“调研材料摘要”“周报生成”。这三个技能上线后每周至少能省出四五个小时这种正反馈会让你更有动力去扩展技能库。技能库贵精不贵多一百个常年不用的技能只是给检索增加噪音。5. 实操中踩过的坑与排查技巧实录最后这部分我专门用来记录我在落地 agent-skills 过程中的常见问题。这些问题不亲自跑一遍很难发现写出来给你扫个雷。第一个问题是技能匹配不准明明库里有对应技能Agent 却绕路干蠢事。后来排查发现是描述里的术语和用户任务用词相差太远。解决办法是给描述里加别名比如“会议纪要”后面加上“会议总结、讨论记录、minutes of meeting”然后重新建立索引。这个操作虽然土但效果立竿见影。第二个问题是技能技巧之间出现“抢活”多个技能的相似度都很高Agent 选错。比如“周报生成”和“项目进度汇报”在语义上确实接近。我的解决办法是提高描述的场景差异性一个强调“以时间维度汇总已完成与计划内的任务”另一个强调“以项目维度分析当前进展、阻塞和下一步行动”。差异化之后匹配准确率肉眼可见提升。第三个问题是技能里要求 Agent 调用脚本但脚本名或路径写错Agent 在执行阶段报错。这个问题最隐蔽因为我最初把脚本说明写在SKILL.md的注意事项里Agent 没细读。后来我把“执行步骤”写成绝对清晰的命令形式比如“执行python3 scripts/extract_text_and_fields.py input.pdf output.json注意当前工作目录是技能根目录”并去掉所有可能的歧义表达。5.1 常见问题速查表问题现象可能原因排查与解决检索到的技能和任务无关技能描述宽泛、术语不一致重写描述增加触发场景、任务对象、结果形态和别名多个技能相似度太高选错技能功能重叠或粒度不清合并技能或差异化描述明确每个技能专属场景Agent 读了规则但执行走偏SKILL.md 步骤不具体步骤拆到可执行粒度补充输入输出示例和反面案例技能涉及脚本报错路径不对、参数不符在技能正文里写明完整命令和当前工作目录上下文被技能内容撑爆一次注入技能过多过全改为先注入摘要确认命中技能后再注入完整内容老技能更新后行为没变化检索命中旧缓存检查 Agent 运行时的缓存策略必要时强制刷新5.2 技能库的版本管理小技巧技能库本身是个文本仓库天然适合 Git 管理。但真正用起来会发现一个问题大模型对新技能的“记忆”来自索引索引不更新技能就永远不生效。我建议建立一条自动化流程git push主分支时触发一次索引重建任务把全量技能重新向量化并更新进 SQLite。发现技能改动后召回变差也可以临时回滚索引不过大部分情况是技能描述质量问题不是索引问题。另外强烈建议每个技能里都加一个测试集尤其是“黑话测试”。我每写一个新的技能都准备三条该技能应该接得住的代表性用户请求然后跑一遍检索看看排名结果。只要任何一条没有排在前三我就回去改描述。这个习惯用肉眼就能极大提升技能库的稳定性比上线后被用户发现再修要省心太多。写在最后的实际感受断断续续跑了几个月的 agent-skills 之后我最大的感受是这事儿难的不是技术而是“知识拆解”的耐心。把一个熟悉的工作流拆成可执行步骤、写成模型能看懂的说明、配好示例和边界提醒远比调一个 API 参数更费心思但回报也最大——因为技能库一旦建起来你等于在给 Agent 打地基地基稳了上面盖什么楼都安心。你不需要一开始就追求技能数量先把两三个最顺手的工作流做好跑顺了再慢慢扩这条路我验证过值得走。
分享:

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

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