Agent Skills 最近在智能体开发圈子里讨论度非常高。你要是做过一段时间的 Agent 应用应该已经察觉到单纯靠一堆工具函数去扩展模型能力越来越不够用了。函数定义写得再细模型也未必会在正确的时机调用正确的函数功能逻辑散落在各处换个项目就要重写一遍。技能Skills这套方案就是奔着这些问题去的核心思路是把“完成某类任务的完整能力”打包成一个标准目录让模型在需要时自己发现、自己读取、自己执行。这篇文章不聊空泛的概念直接拆到底技能包的标准结构是什么SKILL.md 该怎么写模型是靠什么机制发现技能的以及我从零做一个可用技能包的完整过程和踩坑记录。无论你是刚接触智能体开发还是已经在用工具调用做应用这篇文章都能给你一套可以直接上手的技能封装方法论。1. 技能体系解决的核心问题从零散工具到“完整手艺包”1.1 传统工具调用的三个痛点先说清楚我们原本是怎么做的。早期给大模型扩展能力最通用的方案是函数调用function calling把外部操作封装成一个个带参数定义的函数模型根据用户请求决定要不要调用、传什么参数。这套机制本身没问题但用久了会撞上三堵墙。第一堵墙是“定义越写越长模型越看越懵”。一个真实业务系统里工具函数动辄几十上百个。每个函数都要写清楚名称、参数、类型、含义模型每次都要在巨大的函数列表里做匹配不仅消耗上下文还经常选错。尤其当两个工具的功能边界模糊时模型一走神就调用了驴唇不对马嘴的那个。第二堵墙是“函数只解决单点不解决流程”。工具的本质是一个动作但真实任务往往是多步骤的。比如“整理一份会议纪要”这个任务包含提取议题、归纳观点、拆分行动项、确定负责人、套用输出模板好几个环节。你用函数调用去做需要把每一步都拆成独立的函数再指望模型自己按正确的顺序串起来。模型一旦漏一步整个输出质量就塌了。第三堵墙是“复用成本太高”。一个业务场景里调通的函数组合搬到另一个项目基本要重写。因为函数与具体系统的数据结构、调用上下文耦合得很深很难做到任务级复用。1.2 技能包的运作模式一个目录就是一套能力技能Skill换了一条思路不跟模型强调“你会哪些原子操作”而是直接告诉模型“你具备哪些完整手艺”。每个技能是一整个目录里面装着说明书SKILL.md、可选的辅助脚本和参考资源。目录放在技能仓库中模型在使用时按需发现并读取其中的内容。举个例子。传统做法里“生成周报”可能需要五个函数读 Git 日志、统计变更文件、汇总 PR、读取待办、拼报告。技能方案里你只需要一个 weekly-report 目录里面放一个 collect_commits.py 脚本会在本地帮你拉取一周的提交记录再放一份 SKILL.md告诉模型这些数据怎么整理、周报按什么结构输出。模型看到用户说“把本周的周报发我”就会去找到这个技能包读取说明按里面写的步骤执行。这个模式的关键在于模型读取的是一份有结构、有示例、有步骤的“操作手册”而不是一串干巴巴的函数签名。任务上下文被完整地写在了技能文件里模型不需要凭空猜测流程。1.3 技能与工具、工作流怎么分工很多朋友会问技能和工作流Workflow又有什么区别我个人的理解是工作流是“预先编排好的固定流程”每个节点做什么都是设定好的适合重复性极高、容不得模型自由发挥的场景技能则是“能力单元”它把专业方法和约束条件交给模型让模型结合当前上下文灵活执行。技能之间可以互相组合输出可以彼此接力扩展上更开放。技能和函数调用也不是替代关系而是互补。函数调用适合作为技能内部的执行手段技能则负责更上层的任务组织。你可以在一份 SKILL.md 里写“调用 xxx 函数获取数据再调用 yyy 函数执行写入”这个技能就成了业务能力的封装边界。2. 技能包的核心文件SKILL.md 到底怎么写2.1 基本信息段让模型认得并记住这个技能SKILL.md 是每个技能包里真正起决定性作用的文件。它的编写质量直接决定了模型能不能在正确时机发现技能、能不能准确执行技能。这个文件通常以一段 YAML frontmatter 开头里面至少包含 name 和 description 两个字段。name 是这个技能的唯一标识相当于人的姓名。它需要短、准确、可记忆。比如 meeting-minutes、weekly-report、code-review这类命名比“文档处理助手”要好得多因为模型在做概念匹配时会更自然地命中。description 是整个技能包的“广告牌”。模型决定是否调用技能主要就是看这段描述与当前用户请求的语义匹配程度。很多人在这里犯的最大错误是“宽泛无边界”比如写成“用于处理文档”结果用户每次提到“文档”它都想往上凑频繁误调用。我建议 description 里至少说清楚四件事技能完成什么任务、适用于什么输入、输出什么产物、不适用于什么情况。这就像给技能划了一块清晰的责任田模型只有在用户需求落在责任田内时才会接管。2.2 正文说明书步骤、模板与边界条件frontmatter 之下就是正文。正文是写给模型看的操作手册目标是从自然语言层面描述具体怎么做。结构上建议分成几个固定段落目标、适用场景、操作步骤、输出模板、注意事项。目标段用一两句话说明这个技能要达成的最终产物。适用场景段列举哪些输入适合使用这个技能哪些情况应该明确拒绝。操作步骤段是整个文档的灵魂要按顺序列出所有执行环节同时把“如何判断”“遇到异常怎么办”这类决策规则写进去。输出模板段给模型一个明确的最终格式样本让模型知道产出的样子。注意事项段用来写负面清单和边界条件比如“不要编造信息”“不要修改原始文件”“材料缺失时标注待确认”。还记得前面提到的会议纪要例子吗实际操作步骤可以这样组织先通读用户提供的会议材料识别会议主题、时间、参会人和缺席人然后提取核心议题按主题分组归纳主要观点接着区分“已决定事项”和“待讨论事项”最后从待办描述中提取行动项明确负责人与截止时间材料里没写明的标注“待确认”。每一步都指向明确的产出模型执行起来不会迷路。在正文末尾强烈建议加一段“输入示例”。给1到2个真实触发样例比如“帮我整理今天的会议纪要”“把这段聊天记录转成行动项”这样模型会更清楚什么场景下该把这段说明书翻出来。实测下来带样例的技能比不带样例的技能触发准确率高不少。2.3 技能粒度多大才算“一个技能”技能粒度是新手最容易失控的地方。技能切太粗比如搞一个巨大的“全能办公助手”模型读取时会花费大量上下文而且内部步骤互相纠缠执行质量很不稳定技能切太细比如“提取标题”“提取正文”“格式化输出”各做一个技能模型要来回切换好几个包才能完成一个任务效率和准确率反而更低。我的经验是一个技能应该对应“一个完整、可独立交付的任务”任务内部可以有步骤但步骤不应该散到外部。比如“整理会议纪要并产出行动项”是一个技能而“从文字里提取时间”就不值得做成一个技能。粒度判断还有一个简单标准如果这个能力你换了项目还要反复用到且每次执行方式基本一致就值得封装成技能如果只是某个业务流程里的一次性小动作留在提示词里就行。2.4 给技能加工具辅助脚本与资源文件SKILL.md 负责“讲方法”但有些任务光靠讲方法不够还需要真实的外部数据。比如统计 Git 提交、抓取网页、读取本地文件这些操作是模型本身做不了或做不好的这时候就要在技能目录里附上辅助脚本。辅助脚本的使用约定要写得非常明确。我习惯在 SKILL.md 的步骤里写明“先运行目录下的 collect_commits.py把运行结果作为输入数据再进行整理”同时注明脚本的运行方式“python collect_commits.py /path/to/repo”。这样模型就知道什么时候该调脚本、脚本该怎么跑。技能目录里还可以放模板文件、参考文档、示例输出这些静态资源。它们的作用是给模型提供稳定的输出参照。脚本生成的数据、模板定义的格式、模型负责的归纳整理三者各司其职一个技能包就成了一个微型自动化流水线。3. 从零做一个会议纪要技能完整实操记录3.1 先想清楚技能的输入输出边界做技能的第一步不是写文件而是先想清楚输入和输出的边界。我以“会议纪要整理”为例把这个思考过程完整过一遍。输入侧这个技能要能处理三类材料会议录音的转录稿、线上聊天中的会议讨论记录、用户手写的碎片笔记。输出侧它要产出一份结构化的会议纪要包含会议信息、会议目标、讨论要点、决定事项、行动项五个部分。同时行动项必须明确负责人和截止时间没有负责人信息的宁可标“待确认”也不能编造。想清楚边界之后还要确定“什么情况不归它管”。我的做法是在 description 里明确写上“本技能仅用于会议相关材料的整理不适用于日常任务记录、个人备忘录或项目管理排期”。这个负向约束非常有用能挡掉大量误触发。3.2 搭建目录与编写 SKILL.md接下来是搭目录。我的技能仓库路径很简单每个子目录一个技能包目录名就是技能名。会议纪要技能的目录结构长这样skills/ ├─ meeting-minutes/ └─ SKILL.md这个技能不需要外部脚本因为核心工作是信息提取和结构化整理直接用 SKILL.md 把方法论写清楚就够了。下面是完整的 SKILL.md 内容你可以直接照抄改成自己的版本--- name: meeting-minutes description: 将会议材料整理成结构化纪要与行动项。适用于会议录音转录稿、聊天讨论记录、手写会议笔记等输入。当用户要求生成会议纪要、总结会议内容或提取会议行动项时使用。不适用于日常任务清单整理、个人备忘录或项目管理排期。 ---# 会议纪要整理 ## 目标 从原始会议材料中提取关键信息输出一份干净、结构化、可直接分发的会议纪要。 ## 适用场景 - 会议录音转录稿的整理 - 群聊中会议讨论记录的归档 - 用户零散笔记补充成正式纪要 ## 操作步骤 1. 通读用户提供的材料识别会议主题、会议时间、参会人与缺席人。 2. 提取讨论过的核心议题按主题分组归纳主要观点。 3. 区分“已决定事项”和“待讨论事项”。 4. 从“待办”描述中提取行动项明确负责人与截止时间材料中未提及的统一标注“待确认”。 5. 按下方模板输出最终纪要。 ## 输出模板 ### 会议信息 ### 会议目标 ### 讨论要点 ### 决定事项 ### 行动项负责人 / 截止时间 / 状态 ## 注意事项 - 不编造参会人、时间或结论材料缺失时明确标注“待确认”。 - 保持原始表述中性不添加主观评价。 - 行动项必须包含负责人没有负责人的行动项一律列为“待确认”。这里面有几个细节值得说一下。操作步骤里的第4步专门强调“负责人缺失时标注待确认”是为了防止模型强行编造人名输出模板固定了五个区块是为了让模型每次产出的结构都一致注意事项里的负面清单是为了压制模型“自由发挥”的冲动。这些细节决定了技能的实际可用度而不是停留在“看起来不错”的层面。3.3 挂载到客户端并验证触发效果写好 SKILL.md 之后需要把它挂载到智能体客户端里做验证。目前主流的智能体客户端基本都支持自定义技能目录把 skills 目录路径加入配置客户端启动时会自动扫描每个技能子目录并建立技能索引。我建议用一个对照实验来验证技能是否生效。准备一段模拟的会议讨论记录分别用两种方式向客户端提问。方式A不包含“会议纪要”四个字只说“这段内容帮我理一下看看有哪些事要做”方式B明确指出“帮我生成一份会议纪要并列出行动项”。对比两种情况下的响应重点观察模型是否主动读取了技能。如果模型在方式B下正确调用了技能说明 description 的触发匹配是有效的如果方式A也能触发反而说明描述写得过于宽泛会带来误触发风险需要收紧边界。我第一次测试时方式A频繁触发后来我把 description 里加上了“仅限会议记录场景”的限定词误触发率立刻降了下来。3.4 用脚本技能做进阶自动汇总周报纯文本指令型技能只能做到“整理”还做不到“获取”。如果想做一个能自动汇总项目进展的周报技能就需要在技能目录里加入辅助脚本让技能同时具备“读取数据”和“组织内容”两段能力。目录结构可以这样设计skills/ ├─ weekly-report/ ├─ SKILL.md ├─ collect_commits.py └─ weekly_report_template.mdcollect_commits.py 的作用是从指定仓库读取最近一周的提交记录并输出成 JSON 格式方便模型后续处理。脚本核心逻辑很简单用 Git 命令读取提交日志解析出哈希、作者、日期和提交说明再输出标准 JSON。#!/usr/bin/env python3 import subprocess, json, datetime, sys def get_commits(repo_path, days7): since (datetime.date.today() - datetime.timedelta(daysdays)).isoformat() log subprocess.run( [git, -C, repo_path, log, --prettyformat:%h|%an|%ad|%s, --dateshort, f--since{since}], capture_outputTrue, textTrue, checkTrue ).stdout commits [] for line in log.strip().splitlines(): hash_id, author, date, subject line.split(|, 3) commits.append({hash: hash_id, author: author, date: date, subject: subject}) return commits if __name__ __main__: repo sys.argv[1] if len(sys.argv) 1 else . print(json.dumps(get_commits(repo), ensure_asciiFalse, indent2))SKILL.md 里的步骤就要写清楚两段式执行先运行脚本拿到一周提交记录再结合用户口头的重点进展组装成一份带本周概述、提交明细、风险提示三部分的周报。这里面有个容易被忽略的点就是脚本输出的格式越规整模型后续的整理成本越低。数据清洗的动作尽量在脚本里做完不要指望模型替你做。4. 实战中高频踩坑现象、原因与排查方法4.1 模型迟迟不调用技能问题多半出在描述上技能包做好了挂上了配置也对了但模型就是不调用。这是所有人都会遇到的第一道坎。我排查这类问题的顺序是固定的第一步确认技能目录有没有被客户端正确扫描到第二步检查 name 和 description 是否与用户请求里的关键词匹配第三步看 description 是不是写得太抽象。最常见的坑就是用了内部术语当技能名比如把“会议纪要”技能命名为 doc-processor。用户嘴里说的是“把会议记录理一下”模型脑子里想的是“会议记录”再看技能列表里只有 doc-processor它根本对不上号。所以技能命名原则是用目标用户最常说的自然词汇命名而不是用内部代号。如果你的描述里连“会议纪要”“行动项”“会议记录”这类同义词都没覆盖到模型识别不到也正常。4.2 技能给了但模型“读不进去”另一个让人头疼的情况是模型明明触发了技能但产出结果完全没按 SKILL.md 里的要求来好像那份说明书根本不存在。这个问题的根源通常是文档太长、结构太散。模型读取技能说明书时也有注意力瓶颈一份几千字、把背景故事写了好几段的说明书模型很可能看完前面忘了后面。应对方法是改用“金字塔结构”最重要的步骤和输出模板前置背景和解释靠后。操作步骤控制在5步以内每步用一个动词开头简明扼要。输出模板必须挨着操作步骤放让模型在决定输出结构时能直接看到。我还有一个习惯就是在注意事项里挑一条最关键的放在最前面比如“严禁编造缺失信息”这比写在最后有效得多。4.3 技能里的脚本执行失败脚本型技能出问题的点比较集中常见的有四类路径写错、依赖没装、权限不够、输出格式不符合预期。路径问题最普遍。脚本里用了相对路径但模型执行时的工作目录未必在技能包目录下。我的做法是在 SKILL.md 里明确要求使用脚本时带上完整路径且脚本内部统一用绝对路径拼接不依赖当前工作目录。依赖问题更简单凡是技能包需要的外部库要么在 SKILL.md 里写清楚安装命令要么就用 Python 标准库实现避免运行时还要装包。权限问题主要体现在执行位没设置好解决方法是建技能时就 run chmod x 设置可执行权限并在文档里写清楚。如果脚本输出了空结果或者异常数据别急着改脚本先手动在终端跑一遍确认脚本本身没问题再回头看是模型调用方式的问题还是数据源本身的问题。脚本负责的边界要收敛到“稳定输出结构化数据”其余所有判断和归纳都交给模型处理。4.4 多个技能相互打架时怎么办技能库一多就会出现边界重叠。比如你同时有“会议纪要”和“每日总结”两个技能用户发来一段会议转录稿说“帮我总结一下今天讨论了什么”两个技能都被激活了模型就得猜该用谁。解决思路是在 description 里把“触发条件”写得再窄一点。可以用“当用户明确提到会议、纪要、行动项时使用”和“当输入是个人当天完成事项时使用”这类句式把两个技能的适用场景彻底隔开。如果两个技能确实经常同时匹配那就要认真考虑是不是技能划分本身有问题把粒度重新调一下而不是靠 description 硬撑。4.5 技能调试速查表我把这几个月的调试经验整理成一张表遇到问题先对着表排查能省不少时间。现象可能原因快速验证方法处理建议技能从不触发描述与用户措辞不匹配用描述中的原词改写提示词再测补充同义词与触发样例技能频繁误触发描述过于宽泛查看所有误触发上下文限定场景边界加排除条件技能内容被忽略SKILL.md 过长、重点靠后让模型复述技能步骤金字塔结构步骤前置脚本执行失败路径或依赖问题手动运行脚本用绝对路径、预装依赖输出结构不统一缺少模板或模板不清晰对比多次输出差异提供固定输出模板和示例多技能混淆边界重叠查看激活日志收紧描述调整粒度5. 个人体会技能不是堆出来的是打磨出来的动手做了一段时间技能库之后我最大的感受是技能数量的多少不重要技能说明书的清晰度才决定一切。一个描述精准、步骤清晰、边界明确的技能包能顶得上十个写得模棱两可的“全功能包”。每次遇到执行结果不稳定我做的第一件事永远是回头修改 SKILL.md把模糊的表述改精确把缺失的约束补上而不是急着增加新技能。另一个体会是技能体系的真正价值在于积累。你每做完一个项目都会沉淀下来一批可复用的技能目录下一次做类似项目时直接挂载就能用这比每次从零开始在提示词里写方法论高效得多。我现在的新项目启动流程就是先盘一遍技能库里有哪些能直接用再针对增量需求新增技能包。最后分享一个我踩过几次坑之后养成的习惯在技能包目录里额外放一个 notes.md记录这个技能的调整历史和调试中发现的关键信息。看起来多此一举但技能越积越多之后这个文件的价值会被无限放大——它能帮你回忆起当时写这个技能时到底堵了什么坑、规避了什么风险。关于 Agent Skills我目前觉得最值得投入精力的方向就是不断打磨每个技能说明书的质量。毕竟对模型来说一份清晰的操作手册比任何花哨的技术方案都更管用。