
最近半个月陆陆续续有朋友在群里聊 Agent Skills我发现不少人第一反应是“给智能体加几个工具”然后就开始堆 function calling结果玩了两天就放弃了。这个理解不能说错但确实把维度想低了。今天这篇我不聊概念 PPT也不做框架横评就从一个正在做 agent 项目的实践者角度把 Agent Skills 是什么、为什么要把它当成独立层来设计、怎么落地、踩过哪些坑尽量用大白话讲清楚。这篇文章适合两类人。一类是已经在用 Claude 或 OpenAI API 做 agent 应用但觉得项目代码越来越乱、技能越叠加越难维护的人另一类是刚接触智能体开发想快速搞懂“技能”这个抽象层到底在解决什么问题、跟工具调用的本质区别在哪的初学者。不管你是哪一类读完第三部分你至少能照着思路把一个最小可用的技能从零搭起来并且理解它背后的设计取舍。1. 先说清楚“Agent Skills”到底在解决什么问题1.1 从“会调用工具的模型”到“拥有技能库的智能体”在早期的函数调用时代我们习惯把每个能力封装成一个 function比如search_news(keyword)、send_email(to, subject, body)。模型收到用户请求后根据函数描述决定调用哪个函数然后我们的代码去执行再把结果回传给模型。这套模式解决的是“模型能触达外部系统”的问题但它的短板也很明显——每个函数都是一次性的、上下文无关的调用函数既不知道自己的最佳使用场景也没有“经验”可以沉淀。Agent Skills 的思路不一样它把一组指令、脚本、示例、校验规则和资源文件打包成一个独立技能模块让智能体像人一样“学会”一项完整工作而不只是“执行一次操作”。简单说function 是“拨一下转一下”skill 是“给了一份操作手册加全套工具”。这个区别看起来不大实际用下来差距非常大。我举一个例子。你要让 agent 每周帮团队所有人写周报。如果走 function calling 路线你得写好几个函数get_week_events、get_tasks、format_report还得在主程序里维护一个“什么时候该调用哪个函数”的状态机逻辑。换成 skill 路线你会创建一个weekly-report技能里面包含取数据的脚本、周报模板、写作规范、几篇优秀样例以及一段告诉模型“必须先看本周数据再动笔、结构必须符合模板、语气要偏业务口语”的说明。agent 拿到任务后自己会按手册走完整套流程而不是你替它编排每一步。1.2 技能、工具、插件这三者到底有啥区别很多文章把这三个词混着用导致不少人学完更糊涂。这里我用一张表把区别拉清楚维度工具 Tool技能 Skill插件 Plugin粒度单次原子操作一整套流程/方法论技能工具的聚合包是否包含知识通常不包含包含指令、示例、模板、规范可包含配置与多技能是否带执行逻辑有后端代码实现可内嵌脚本也可靠模型执行通常依赖外部实现复用方式代码级别复用语义层面复用产品级分发典型例子get_weather(city)weekly-report、pdf-analyzerVS Code 插件、Chrome 扩展一句话总结tool 是技能里可调用的“肌肉”plugin 是技能的“分发容器”skill 则更像一份完整的“能力定义文档执行资产包”。我们聊 Agent Skills 时重点在中间这层。1.3 技能层的核心价值让经验沉淀下来我见过不少团队agent 跑得挺好但整个系统完全依赖那个巨大的 system prompt。今天加一个规则明天加一个格式说明过两周 system prompt 变成 8000 token 的庞然大物模型表现反而越来越随机。技能层解决的就是这个“经验沉淀”问题——每项工作技能独立成目录有版本、有更新记录、有单独的功能边界系统提示词只保留最基础的沟通规范其他全部外包给技能。这个思路跟程序员写函数其实一脉相承你不会把所有业务逻辑全塞进一个几万行的 main 函数里你会拆模块、做封装、搞复用。Agent Skills 就是在智能体世界里的“模块化”。它让每个能力可以单独测试、单独迭代、单独下发到不同 agent而不是每次改动都牵一发动全身。这个价值做过大型 agent 项目的同学应该感触特别深。2. 拆解一个技能的内部结构SKILL.md 才是关键2.1 技能目录的通用布局我自己的技能仓库一般长这样skills/ ├── weekly-report/ │ ├── SKILL.md │ ├── scripts/ │ │ ├── fetch_events.py │ │ └── format_markdown.py │ ├── assets/ │ │ ├── weekly_report_template.md │ │ └── examples/ │ │ ├── good_report_1.md │ │ └── good_report_2.md │ └── requirements.txt ├── pdf-summarizer/ │ ├── SKILL.md │ ├── scripts/ │ │ └── extract_pdf_text.py │ └── assets/ │ └── summary_template.md └── README.md每个技能目录的核心就是那个SKILL.md其他脚本和资源都是它的“配套”。目录名就是技能名必须短、清晰、一眼能看出用途别搞skill_utils_v3_final这种自己都看不懂的命名。README 我建议写上每个技能的适用边界和依赖版本不然过三个月你自己都不记得当初为什么写这个脚本。2.2 YAML 元信息决定智能体能不“发现”你SKILL.md 最开始的部分一般是 YAML frontmatter相当于技能的“身份证”。这部分决定 agent 在执行任务时能不能想到调用这个技能写不好等于白做。--- name: weekly-report description: 根据本周任务与会议生成结构化周报。当用户提到“周报”、“本周总结”、“weekly report”时使用。 categories: - productivity - reporting metadata: version: 1.2.0 author: your-name tags: [weekly, report, meeting-notes] ---name要跟目录名一致。description是重中之重务必写清楚“什么时候该用”而不是“它做了什么”。举个例子与其写“一个生成周报的工具”不如写“当用户需要汇总一周工作、会议纪要与任务进展并输出 Markdown 周报时使用”。前者描述的是功能后者描述的是触发场景模型在规划阶段匹配触发场景的能力远比匹配功能描述要靠谱。categories 和 tags 在高技能库数量较多时特别好用有些框架会按分类裁剪搜索范围能把匹配准确率拉高一个台阶。metadata 里的 version 我强烈建议维护因为在技能迭代过程中你难免要回滚没有版本号只能靠 git 历史硬翻。2.3 指令正文的写作套路测试驱动你写说明正文部分反而是最容易被低估的。很多人写完 description 就开始堆脚本正文里只丢一句“使用 scripts/fetch_events.py 获取数据”结果模型根本不知道该怎么编排这些步骤。我的建议是把正文当成一本给新员工看的 SOP而不是技术注释。至少包含四块内容任务目标这个技能在什么场景下用、输出什么形式的结果。执行步骤从收集输入到加工到输出的完整流程越具体越好。规则与限制哪些是绝对不能做的比如“不要编造会议内容”哪些是必须遵守的格式。示例至少给 2-3 个输入输出对让模型照葫芦画瓢。一个反例“获取任务列表并按模板生成周报”。这句话对模型没有任何执行力它不知道数据从哪获取、模板长什么样、格式要求是什么。正例则是类似下面这样# 周报生成技能 ## 目标 根据用户提供的时间范围自动获取该周内的任务与会议记录生成结构化 Markdown 周报。 ## 执行步骤 1. 运行 python scripts/fetch_events.py --start YYYY-MM-DD --end YYYY-MM-DD获取原始事件列表。 2. 使用 assets/ 中的模板文件 weekly_report_template.md 确定报告结构。 3. 将事件按“项目推进”、“会议纪要”、“风险与问题”三类归组。 4. 运行 python scripts/format_markdown.py 将结果格式化为最终 Markdown。 ## 规则 - 严禁编造事件条目。原始数据不完整时明确写出“数据缺失”。 - 每个项目必须写“进展”和“下一步”不得省略。 - 输出语言默认跟随用户输入语言模板中英双语。 ## 示例 ### 输入... ### 输出...写完之后你自己就是第一测试者把这段说明给一个没有见过代码的 agent看它能不能按步骤跑通。跑不通就回去改说明而不是改代码。这是“测试驱动写文档”的思路实测比反复调整描述词有效得多。2.4 辅助脚本与资源文件技能真正的执行引擎skills 定义了“怎么做”但真正干重活的还是背后的脚本。脚本的重点不在于实现多复杂的逻辑而在于两点输入输出都结构化错误信息足够友好。我自己的习惯是每个脚本都做成命令行可单独运行、参数可传、异常时打出人能看懂的提示这样既方便调试也方便模型在被中断时把错误信息正确反馈给你。拿前面那个fetch_events.py举例它至少应该做到python scripts/fetch_events.py --start 2025-02-10 --end 2025-02-16 # 输出 JSON 到 stdout错误时返回非零退出码并打印 stderr 说明这样模型只需要记得“运行命令 读输出”不需要理解脚本内部怎么调 API、怎么解析数据。脚本越无脑模型跑得越稳。资源文件模板、示例则建议用 Markdown因为模型对这种格式理解最自然。PDF、Word 这类二进制格式不是不能放但模型没法直接读每次都要靠脚本先转成文本链路越长越容易出错。3. 手把手从零实现一个可复用的技能3.1 场景选择与技能边界纸上谈兵没意思这里我拿一个可复现的小项目来讲透做一个“会议纪要转行动计划”技能——输入一堆会议文字记录输出一份带负责人、截止日期、优先级和风险标记的行动计划表。选这个场景有三个原因第一它依赖的“工具”极简不需要设计复杂的 API 对接适合第一遍演示第二它是绝大多数团队每天都有的真实需求你学完可以直接拿去用第三它的边界足够清晰——“把会议记录变成行动计划”不涉及权限、不做知识库搜索、不碰多轮对话状态模型不容易跑偏。3.2 搭建目录与初始文件按上面的通用布局先创建目录mkdir -p meeting-actions/scripts meeting-actions/assets然后写一个最简版SKILL.md。新手最容易犯的错是一上来就想把文件写完美我建议先写一个 60 分的版本跑通流程后再迭代。首次我一般只写目标、执行步骤和一条规则。3.3 编写 SKILL.md从草稿到完整版第一版大概长这样--- name: meeting-actions description: 将会议记录转化为带负责人、截止日期的行动计划表。当用户提供会议记录并要求“生成待办”、“下一步行动”、“行动计划”时使用。 categories: [productivity, project-management] metadata: version: 0.1.0 --- # 会议纪要转行动计划 ## 目标 把原始会议记录转换成 Markdown 格式的行动计划表。 ## 执行步骤 1. 阅读用户提供的会议记录全文。 2. 提取所有行动项每条行动项必须包含 - 行动描述 - 负责人若原文未指明则写 TODO - 截止日期若原文未指明则写 TBD - 优先级高/中/低根据上下文判断 3. 按优先级从高到低排序输出。 4. 输出格式参照 assets/action_template.md。 ## 规则 - 不得新增原始记录中不存在的行动项。 - 不得臆断负责人或日期必须明确标注 TODO/TBD。 - 输出表格中必须包含“风险提示”列若存在风险则简述否则写“无”。模板文件assets/action_template.md我写了一个极简版| 行动描述 | 负责人 | 截止日期 | 优先级 | 风险提示 | | --- | --- | --- | --- | --- | | ... | ... | ... | ... | ... |这一版已经能跑了但还缺少示例。示例在这类技能里特别关键因为“提取行动项”有多种风格有的会议记录是一段话有的是一长串 bullet points模型需要从示例里学“如何处理不同格式”。于是我在 SKILL.md 里加了两组示例## 示例 ### 输入 “关于 Q1 发布王丽负责完成新用户引导文档3 月 15 日前。李强在 3 月底前完成灰度环境搭建。另外法务反馈隐私协议需要修订暂时没明确负责人。” ### 输出 | 行动描述 | 负责人 | 截止日期 | 优先级 | 风险提示 | | --- | --- | --- | --- | --- | | 完成新用户引导文档 | 王丽 | 03-15 | 高 | 无 | | 完成灰度环境搭建 | 李强 | 03-31 | 高 | 依赖法务协议修订 | | 修订隐私协议 | TODO | TBD | 中 | 无负责人需尽快指派 |加不加这一步模型输出质量差距非常明显。没有示例的时候模型经常把“法务反馈隐私协议需要修订”漏掉因为它是一句“背景描述”而不是典型的“行动指令”有了示例之后模型至少知道这类句子也应该尝试提取成行动项。3.4 注入本地环境跑通第一个完整流程不同框架注入技能的方式略有差异但底层逻辑差不多都是把技能目录映射到一个可访问路径然后让模型在规划时读取 SKILL.md。我用的是本地环境模拟的方式相当于手动模拟 agent 的“技能加载”环节方便调试。export SKILL_PATH/path/to/meeting-actions cat $SKILL_PATH/SKILL.md # 这句话模拟 agent 在执行任务前先“阅读技能手册”的动作然后我把 SKILL.md 的内容和用户输入的会议记录拼在一起作为一次对话发给模型。这一步相当于一个最小可用的 agent 流程跑通后再接入具体框架或运行时。实测下来这一步能帮我隔离绝大多数问题——如果直接拼在 prompt 里都跑不通那就别指望放到框架里能自动跑通。3.5 复盘升级让技能越用越准第一次跑通之后技能还远没到“完成”的状态。我每次跑完都会问自己三个问题哪些输出不对说明里漏了什么示例是不是还不够有代表性举个例子我第一版跑下来发现当会议记录里全是“同步一下进度”“更新一下文档”这种模糊表达时模型会乱猜负责人。我就在规则里加了一条“若行动描述本身不明确或过于口语化负责人在原文无法对应时输出 TODO 并在风险提示列标注‘需澄清’”。同时新增一组“模糊表达”的示例。技能就是从这些真实反馈里一点点磨出来的一开始写得多完美不如后边迭代得多勤快。4. 常见问题与排查技巧实录4.1 症状速查表技能“失灵”的四种典型表现实操中遇到问题第一反应不是改代码而是先定位问题属于哪一层。下面这个表是我自己总结的定位清单症状常见原因优先排查方向模型完全没调用技能description 描述场景不对或触发词不匹配改 description加入用户真实会说的短语调了技能但输出格式不对SKILL.md 正文规则不够具体缺示例补充格式示例明确“必须”与“禁止”调用后报错且反复重试失败脚本输入输出不规范边界处理弱命令行手动执行脚本查看错误信息输出内容“好像对但信息残缺”规则里没定义缺失信息处理方式增加 TODO/TBD/数据缺失等兜底规则4.2 描述质量不够技能成了摆设这是最常见的问题没有之一。很多人把 description 写成“A tool that converts meeting minutes into action items”模型看完根本不知道什么时候该用它。你说“帮我整理一下今天的会议内容”它不会联想到这个技能因为“整理会议内容”和“converts meeting minutes”之间是语义跳跃的。解决办法是回到用户视角搜集真实需求表达把用户可能说的 10 种说法都映射到描述里。比如“生成下一步计划”“把会上的决定列出来”“谁负责什么整理一份表”都可能是用户原话。description 里不需要把所有说法堆进去但至少要涵盖最典型的几种表达。我的习惯是描述里用户口语在前、功能描述在后description: 根据会议记录整理行动项。当用户说“整理会议待办”、“下一步谁负责什么”、“把会议决定列成表”时使用把原始记录转为带负责人、截止日期、优先级的行动清单。4.3 Token 预算失控指令越长越不可控很多技能文档越写越长最后 SKILL.md 快 2000 token每个技能点都展开写结果模型执行时被大量信息淹没。技能文档需要精简但精简不是删内容而是把“必须做什么”和“背景参考”分开。我的做法是核心执行步骤、规则和示例控制在 800 token 内更详细的背景说明、设计取舍、常见错误案例放到assets/best_practices.md并在 SKILL.md 里注明“只有在遇到异常情况时才阅读该文件”。这样大多数执行过程模型只看精简版遇到边界情况才去深入阅读Token 消耗和稳定性都能保住。4.4 环境与权限本地技能的安全底线技能里带了脚本就带来两个问题环境依赖和权限隔离。先讲依赖技能用到的 Python 包必须在requirements.txt里显式声明并且脚本启动时最好做一次依赖检查缺包就报“missing dependency: pandas”别让模型去猜“cannot import pandas”到底什么意思。权限方面我的底线是技能脚本默认不读取工作目录之外的文件不写全局配置不在未经用户确认的前提下发送网络请求。尤其是“发送邮件”“更新数据库”这类有副作用的操作必须在 SKILL.md 里写明“执行前必须向用户确认”的硬规则。这些规则不是防模型而是防误操作带来的连锁反应。你永远不想遇到一个“帮我整理会议记录”直接给你把任务管理工具里的数据全部重排的场面。5. 关于 Skill 开发的几点经验心得最后分享几个个人体会不算总结就是纯粹的使用感触。第一技能之间要保持低耦合。每个技能只负责一个清晰的任务域别做一个“什么都能干”的超级技能。我的项目里曾经有人写了个general-utils里面既有写周报的脚本又有解析 PDF 的逻辑最后模型经常选错入口debug 到怀疑人生。拆开之后一切恢复正常。技能和函数一样做薄做专才能稳定复用。第二把技能当成产品来迭代而不是写一次就完事的脚本集合。技能本身有“用户”大模型、“输入”任务和“输出”结果你认真对待它它就认真回报你。我维护一套技能库半年下来最明显的变化是新 agent 接入时不用再从零训练和调 prompt直接把技能挂上去就能干活效率提升是全队的。第三多花时间在 example 上而不是规则堆砌上。模型从两三个好例子中学到的东西经常比二十条文字规则都管用。规则太多反而互相打架例子多了模型自然能总结出模式。这一点我在多个技能上反复验证过值得一试。如果你也正在做 agent 项目我建议从今天起就把技能单独建库先拿一个真实场景练手不要贪多。第一个技能上手了第二个、第三个就是流水线的事。