☰
Agent Skills与Tools的本质区别及开发实战全解析
2026/10/28 16:29:35 网站建设 项目流程

1. 听到Agent Skills这个词,我一开始想到的是插件系统

做Agent开发做了两年多,我承认自己有个毛病:每次看到新名词,第一反应就是"这不就是把插件换个说法吗"。Agent Skills刚出来的时候,我也是这个态度——直到有一天,我在Claude的官方市场里随便翻了翻,看到一个技能描述文件,才意识到这东西跟传统的插件系统根本不是一回事。

先说结论:Agent Skills本质上是一套"如何教会模型完成特定任务"的标准化交付物,它打包的不是一堆可执行代码,而是上下文、步骤、约束和经验。

它解决的核心问题很实在:大语言模型虽然能力很强,但它不知道你的具体工作流是什么。比如模型知道怎样用Python处理图片,但它不知道你公司内部的命名规范是项目名_日期_版本,也不知道你处理表格之前必须先去重、校验编码、备份原文件。这些东西没法靠"模型知识"解决,必须靠一套显式的、有结构的指引注入到上下文里。

那它跟我们说的"Fine-tuning"有什么区别?微调是把知识固化进权重,代价是训练成本高、迭代周期长,而且每次业务调整都要重训。Agent Skills走的是另一条路:把方法论写在明面上,让模型每次调用时现读现用。模型读完说明就能干活,干完之后这套技能还能被别的Agent复用,跟在GitHub上开源一个项目差不多。

在动手之前,你需要知道几个关键事实:

  • Agent Skills不是一个人写的,它是一套约定,是"模型+脚本+文档"三位一体的组合。
  • 它不依赖特定框架,Claude能用,Codex能用,某些多Agent编排框架也能兼容。
  • 学习成本不高,但设计成本很高。写一个能跑的技能很简单,写一个在任何场景下都稳定的技能很难。

这篇文章我会从底层拆解Agent Skills,讲清楚它内部的结构、运行机制、开发流程,以及我在实际项目里踩过的坑。如果你正在做Agent开发,或者想把前端的自动化经验迁移到Agent技能设计里,这篇文章应该对你有帮助。

2. Agent Skills与普通Tools的本质区别:为什么它不是一个"新瓶装旧酒"

2.1 鸭子测试:一个技能描述文件引发的思考

先说个我自己的经历。有一回我在测试一个Agent Skills,它的功能很简单——从Instagram链接批量下载图片。我本来以为它就是个网页抓取工具集,结果打开SKILL.md一看,里面写得密密麻麻:包括如何处理短链接、如何解析页面里的JSON数据、用户可能输入的链接格式有哪些、下载失败时该重试几次、重试间隔多久……那一刻我才真正反应过来:

普通工具(Tools)是一把螺丝刀,它等着人去操作、去判断用在哪;Agent Skills是一个完整的"作业指导书",它把"什么人、在什么情况下、用什么方式、按什么顺序、达到什么标准"全部写清楚了。

这个区别,我用一个鸭子测试来总结——普通Tools是"看外形像鸭子就算鸭子",Agent Skills是"不仅长得像鸭子,还得会游泳、会叫、会吃小鱼、能跟其他水鸟相处"。

2.2 普通工具是"即用即走",技能是"带教程上岗"

一个标准的Agent Tool,本质上是给模型暴露了一个函数接口。模型知道有这么个函数,知道参数长什么样,然后它自己判断什么时候调用、怎么调用。这是"即用即走"的模型——模型是用工具的人,而不是被工具训练的人。

Agent Skills拆掉了这个假设。它假设的是:模型面对的是一个之前没见过的任务,所以必须把任务背景、操作步骤、注意事项、验收标准全部塞给模型。技能文件就是模型在这个任务里的"入职培训手册"。

举个例子。你给Agent加一个"获取天气"的工具,模型调用一次就结束了,它不需要知道气象数据后续该怎样应用。但如果你给Agent加一个"处理销售报表"的技能,技能文档里会写:数据源是哪个、CSV的编码格式、空值怎么处理、金额单位是多少、汇总口径按什么维度、输出表格的格式……这些信息能帮助模型在后续多个步骤里做出正确判断。这是深度和广度的双重扩展,完全不是"多一个函数"能做到的。

2.3 运行时上下文的复用价值

我再说个实际感受。普通Tools每次调用都是独立的,模型用完一个函数,上下文里留不下什么"操作经验"。但Agent Skills设计上就鼓励把经验固化下来——技能文档里可以写"上次处理此类数据时,发现某些行有重复,建议先按订单号去重",这就是经验的下沉。

而且,一个技能可以被多个任务复用。我在项目里设计过一个"数据清洗"技能,写清楚了一套清洗规则和脚本。后来做报表可以用,做推荐系统特征工程可以用,做日志分析也能用。每一次复用,模型的表现都更稳定,因为它每次进上下文时都"复习"了一遍正确的处理流程。

所以,如果你只看表象,Agent Skills确实像"带参数的工具包";但如果你看运行机制,它是一个完整的、可迁移的、能够持续积累经验的认知单元。这也是为什么越来越多做Agent开发的人开始把Skills当作一等公民来设计。

3. Skills的内部结构:三个核心文件各管什么

3.1 SKILL.md:写给模型看的手册

一个Agent Skills最核心的文件是SKILL.md,名字固定,大小写敏感。这个文件就是整个技能的灵魂。

它的职责非常明确:在Agent执行任务之前,把模型需要知道的所有信息告诉模型。内容一般分成几块:

  • YAML格式的元信息头,包括技能的name、description、version等。
  • 该技能的适用场景和边界:什么情况下该用、什么情况下不该用。
  • 输入输出的格式说明:接受什么样的指令、返回什么样的结果。
  • 操作步骤的详细说明:从头到尾,每一步应该做什么、为什么这么做。
  • 常见的错误模式:模型容易在哪里犯傻、怎样的输出会被当作异常。

写SKILL.md最大的难点是分词粒度。写太细,上下文里塞了一大堆废话,模型反而抓不住重点;写太粗,模型遇到边缘情况没法自己兜底。我自己的经验是:默认情况下只写关键路径和最常见3-5种变形情况,其他情况让模型根据脚本反馈再判断。

3.2 脚本目录:给技能兜底的执行层

SKILL.md是给模型看的,但模型毕竟不是人,它理解指令之后还得靠实际代码去执行。一个完整的Agent Skills通常会包含一个scripts/目录,里面放着这个技能实际要用的脚本。

脚本不要求用同一种语言,Python、JavaScript、Shell都行,甚至可以是编译好的二进制。它只需要满足一个条件:能够在无交互环境下被模型调用,并且输出结果要能被Agent进程捕获和分析。

我在设计脚本时的习惯是:

  1. 每个脚本功能单一,避免"大而全"的胶水脚本。
  2. 输出尽量结构化,用JSON比用纯文本强,方便Agent解析。
  3. 脚本内部要做异常捕获,不要让堆栈信息直接暴露给模型。
  4. 脚本参数尽量少,复杂的默认值直接写在脚本里。

因为模型在"阅读"脚本输出的时候,它其实是在做推理判断。如果输出太乱,模型很容易误判结果,甚至自己编一个结果出来"圆谎"。这个坑我在后面章节会专门展开。

3.3 元信息声明:模型如何判断"该不该用这个技能"

除了SKILL.md和脚本,Agent Skills还需要一个能让框架识别的最小描述信息,通常是name和description。这部分决定了模型何时激活这个技能的关键决策节点。

模型每走一步都会做意图判断:"当前任务是什么?有没有哪个技能可以帮上忙?"如果技能description写得太泛,模型会在无关任务里反复尝试调用它,拖慢执行效率;写得太窄,模型又不知道该技能其实也适用于边缘场景。

这里有个实操技巧:description里建议写清楚典型触发句和反例。比如"当用户需要批量下载社交媒体图片时可用"是一句好的描述,而"一个图片下载工具"就是一句差的描述。

3.4 设计一个Instagram风格图片下载技能

我拿一个实际技能示例来说明整体结构。假设要做一个"社交平台图片批量下载"的技能instagram-photo-downloader:

instagram-photo-downloader/ ├── SKILL.md ├── scripts/ │ ├── fetch_post.py # 解析单条帖子的图片地址 │ ├── download_assets.py # 批量下载图片资源 │ └── helpers.py # 公共函数:格式化、去重、重试 └── assets/ └── sample_outputs/ # 给模型参考的输出样例

SKILL.md里会写明:什么链接格式可以处理、短链接是否支持、图片命名规则是什么、下载到哪个目录、失败后的重试策略。模型读完这个文件,遇到用户发来一条Instagram链接,它就知道了全流程——先解析、再下载、最后按规则命名整理。

这个结构的好处是:模型负责决策和编排,脚本负责确定性的操作。各司其职,Agent的每一步行为都既有"智能"又有"确定性"。

4. 手动开发一个Agent Skills的完整过程——从0到能跑起来

4.1 场景选择:为什么选"批量重命名截图"做练手

讲完理论,我带你完整走一遍开发流程。我挑一个对大多数人有实际意义的例子:批量重命名截图文件。

选这个场景有几个理由:

  • 需求明确,几乎人人都遇到过:Windows或macOS里截图默认命名一堆杂乱字符串,想改成2024-05-12_项目截图_001.png这种格式。
  • 不需要外部API,不依赖网络,方便本地测试。
  • 既能体现SKILL.md里"知识性指引"的价值(比如命名规范、分类规则),又用得上脚本执行能力(遍历文件、判断类型、改文件名)。

4.2 从SKILL.md开始:一份好的说明文档长什么样

先写SKILL.md。我要考虑的是:模型读了这个文件,面对"帮我把今天的截图整理一下"这种模糊指令时,能不能自动完成这些事:

  1. 找到目标目录下的截图文件(PNG/JPG/WebP)。
  2. 根据EXIF信息或修改时间,把文件按日期分组。
  3. 按YYYY-MM-DD_描述_序号.ext的格式重命名。
  4. 遇到文件名冲突时自动加序号。
  5. 处理完成后给用户输出一份汇总表。

我把这些要求转化成SKILL.md内容(简化版):

--- name: screenshot_organizer description: "当用户需要整理/重命名/归档截图文件时使用该技能。典型触发语:'整理我的截图'、'把截图按日期重命名'、'帮我归拢桌面上的图片'。不适合处理非图片文件或需要AI生成图片的任务。" version: 1.1.0 --- # Screenshot Organizer ## 适用场景 - 用户指定的目录下存在截图文件(.png, .jpg, .jpeg, .webp) - 目标是将杂乱命名改为"日期_描述_序号"格式 ## 执行步骤 1. 使用 `list_files.sh` 扫描指定目录,收集所有图片文件 2. 读取每个文件的修改时间,格式化为 YYYY-MM-DD 3. 根据文件名或内容上下文推断描述字段,如果无法推断,使用"未命名" 4. 检查目标文件名是否冲突,冲突时自动追加 _1, _2... 5. 使用 `rename_files.sh` 执行实际重命名 6. 输出 Markdown 表格,列出原文件名 -> 新文件名 ## 关键规则 - 不要修改文件修改时间 - 不要移动文件到其他目录,除非用户明确要求 - 如果目录里有非图片文件,跳过并在最终汇总中提示

注意两个细节:

  • 我在description里写了"反例"——"不适合处理非图片文件或需要AI生成图片的任务"。这个小动作能显著降低模型误调用该技能的概率。
  • 我在SKILL.md里只写了"关键路径",没把所有边角情况都列出来。模型在执行时若遇到SKILL.md没覆盖的情况,它会自动用常识兜底,或者向用户提问要信息。

4.3 编写辅助脚本:把不可靠的判断交给代码

我写了两个脚本,都很简单。

第一个用于扫描图片:

#!/usr/bin/env python3 # scripts/list_files.py import os import sys import json from datetime import datetime IMG_EXT = {".png", ".jpg", ".jpeg", ".webp"} def scan_files(directory): result = [] for fname in os.listdir(directory): ext = os.path.splitext(fname)[1].lower() if ext not in IMG_EXT: continue path = os.path.join(directory, fname) mtime = os.path.getmtime(path) result.append({ "filename": fname, "modified": datetime.fromtimestamp(mtime).strftime("%Y-%m-%d"), "ext": ext }) result.sort(key=lambda x: x["modified"]) return result if __name__ == "__main__": directory = sys.argv[1] if len(sys.argv) > 1 else os.getcwd() print(json.dumps(scan_files(directory), ensure_ascii=False, indent=2))

第二个用于重命名:

#!/usr/bin/env python3 # scripts/rename_files.py import os import sys import json def unique_name(path, base, ext, counter=1): new_name = f"{base}_{counter:03d}{ext}" new_path = os.path.join(os.path.dirname(path), new_name) if not os.path.exists(new_path): return new_path return unique_name(path, base, ext, counter + 1) def rename_files(mappings): changed = [] for item in mappings: old_path = item["old_path"] new_path = item["new_path"] if os.path.exists(new_path): new_path = unique_name(old_path, item["new_base"], item["ext"]) os.rename(old_path, new_path) changed.append({"old": os.path.basename(old_path), "new": os.path.basename(new_path)}) return changed if __name__ == "__main__": mappings = json.loads(sys.stdin.read()) print(json.dumps(rename_files(mappings), ensure_ascii=False, indent=2))

这里我故意把"描述字段"的推断留给了模型,脚本只负责确定性操作。原因是:模型在理解上下文后,能把Screenshot 2024-05-12 at 14.32.45.png推断成2024-05-12_界面截图_001,这个能力靠脚本写正则很痛苦;但"实际改文件名"这件事必须由脚本做,因为模型直接去调用文件系统API容易出错,而且没有事务性和回滚机制。

4.4 本地安装与验证:从"能用"到"好用"的迭代

装技能的方式各家略有差异,但思路一致:把技能目录放到指定路径,然后给模型提供技能访问权限。我用的是Claude的本地技能目录方式,验证时先跑一个最简单的场景——只有一张.png和一个.json文件:

测试输入:整理我今天桌面的截图 预期输出:列出原始文件名和目标文件名,执行重命名

第一次测试就翻车了:模型把.json文件当作"其他图片相关文件"处理了,给我的汇报里写"需要额外处理",但它并没有实际把JSON移动或改名——它只是在自己的理解里把这个文件纳入了流程。

这个行为的本质是:模型把SKILL.md里的"规则"当成了逻辑规则,而不是执行边界。事件之后我在SKILL.md里加了一行"如果文件扩展名不在列表内,不要做任何操作,忽略它,不要汇报它,除非用户明确要求"。第二次测试就正常了。

然后我再验证复合场景:10张混在一起的.png和.jpg,文件名乱得像被炸弹炸过,外加2个txt文件干扰。这次我的目标是确认模型会:

  • 跳过txt
  • 按时间排序
  • 输出Markdown汇总表格

跑完效果不错,脚本端没报错,模型端的判断也基本贴合预期。但这里有个观察我想提醒你:模型在处理复杂任务时,会和脚本来回交互很多次。如果脚本输出不符合模型预期,模型会想办法"自己改一下再跑一次"。所以要确保脚本的可重复执行性——幂等性。如果一个脚本被跑两次会产生副作用(比如重复添加序号),那一定要在SKILL.md里明确说明"本脚本只能被执行一次"。

4.5 测试中的失败记录:模型不会自己踩刹车

还有一个典型失败场景值得记录。有一次我给模型加了另一个技能,两个技能都声称"能处理文件重命名"。结果模型在处理截图时,调用错了技能,用另一个技能的工具脚本去处理,浪费了好几轮token,最终成功倒是成功了,但是效率很低。

这个问题不是脚本的问题,是技能边界的描述问题。后来我在两个技能的description里加了"唯一适用场景"的说明,模型调用准确率才恢复正常。

所以开发Skills时,回归测试一定要覆盖"任务与技能匹配"这一层,不光是测脚本本身。

5. Agent Skills运行机制与边界:模型在哪个环节最容易出错

5.1 意图识别:模型怎么决定"该调用技能了"

技能调用的第一步是意图识别。模型要区分用户意图属于:

  • 常规对话,不需要技能。
  • 已经激活的技能能覆盖的任务。
  • 现有技能不能覆盖,需要组合多个技能的任务。

这个环节模型出错通常有两种:

  • 误调用:用户只是问了一句"你懂怎么整理截图吗",模型以为用户要执行任务,直接把技能拉进来跑了一遍。
  • 漏调用:用户给出明确指令"帮我处理一下昨天做界面测试的截图",模型没反应过来技能能处理这种"隐含语境"的任务。

减少误调用和漏调用的手段只有一个:把description写得像"搜索索引",让模型在判断时能快速命中。

5.2 参数提取:从用户的模糊表达中还原结构化参数

意图判断完了,模型要提取参数。比如用户说"把桌面上今天的截图整理一下",里面隐含了:

  • 目标目录:桌面(其实是~/Desktop)
  • 时间范围:今天
  • 文件类型:截图(.png/.jpg可能都有)

模型需要把这些模糊表达转成脚本需要的精确参数。出错场景一般是:

  • 用户说"最近的截图",模型不知道"最近"是24小时还是7天,这时候应该问用户,而不是自己拍板。
  • 用户说"放桌面上",但模型把桌面路径解析成了家目录。

解决办法是:在SKILL.md里显式声明"如果参数信息不全,必须问用户,不要猜"。这看起来有点傻,但能省掉大量返工成本。

5.3 执行与验证:脚本跑完不等于任务完成

脚本执行完之后,Agent还不能急着交差。这一步要做的是人(用户)可感知的验证。

我在技能设计里加了"验证"约束:模型执行完重命名脚本后,必须重新扫描目录,确认新文件名存在、旧文件名消失,然后把结果整理成表格呈现给用户。如果不加这步,模型可能只看到脚本输出的JSON就以为任务完成,但脚本半路崩了的情况它发现不了。

另外还有个边界问题:技能里最好别出现"用户确认"这种多轮交互请求,除非任务是破坏性的(比如删除文件、覆盖文件)。因为Agent在设计理念上是尽量自动化,多一轮交互就多一次失败风险。能靠日志和回滚机制解决的,就不要把决策压力抛给用户。

6. 生态选型建议:不同平台的Skills入口怎么选

6.1 Claude的Agent Skills:文档质量高,起步平滑

Claude的Agent Skills目前算是体验最完整的。官方市场里有不少现成的技能可以下载试用,更重要的是它的文档把SKILL.md的编写规范讲得很清楚,适合新手照着写。

只要注意一个点:官方的Skills版本迭代较快,旧版的目录结构可能不兼容。我维护的本地方案对版本号敏感,升级时建议先跑一遍回归测试。

6.2 Codex的Skills:偏工程师场景,脚本能力是亮点

Codex(OpenAI的命令行Agent)对Skills的支持也在演进中,它在文件名和结构上兼容类似的SKILL.md路线,更适合工程师场景——因为它更贴命令行工作流,脚本的执行和错误堆栈回传做得好,对前端开发、DevOps自动化来说非常顺手。

但Codex的生态还相对散,自定义Skills的数量和成熟度比不上Claude官方市场。如果你已经在用Codex处理代码工程类任务,可以试试把常用的代码重构、规范检查流程固化成Skills。

6.3 多Agent框架中的Skills编排

走到多Agent层面,Skills的价值被进一步放大。在一个编排框架里,每个子Agent可以加载不同的Skills,然后通过调度器把任务拆解到合适的Agent上。

我试过的做法是:给"前端开发"子Agent装一套"最佳实践检查"技能,给"数据分析"子Agent装一套"SQL优化"技能,多个Agent并行工作,每个技能在自己的上下文里生效。这种情况下,Skills就像模块化的能力积木,互不干扰,但又能在编排层被统一管理。

这里面容易踩的坑是技能冲突:两个子Agent的技能文档都比较大,编排框架在分发上下文时可能超载。我建议在生产线多Agent应用时,给每个技能的SKILL.md设定字数和复杂度上限,确保分发时上下文预算可控。

7. 踩坑记录与工程化建议:从示例走向生产环境

7.1 版本管理:技能也会漂移

Skills不是写一次就完事的。业务规则变了,SKILL.md里的步骤就要跟着改;依赖脚本的API变了,脚本就要更新。如果不对技能做版本管理,你可能会遇到"上个月还好好的,这个月突然不工作了"的诡异问题。

建议的工程化做法:

  • 每个技能目录对应一个Git仓库,SKILL.md里的version字段和Git tag对齐。
  • 在Agent的配置里记录"当前使用版本号",升级时手动确认。
  • 有条件的跑一套"技能回归测试套件",把该技能的所有历史用例放进去自动跑。

7.2 安全边界:技能不等于免死金牌

我把"批量删除文件"这种危险操作做成过技能的一部分。实测下来,模型会把SKILL.md里的规则当作用户意图,直接执行删除操作。后来我加了两层拦护:

  • SKILL.md里明确"删除操作前必须输出将删除的文件列表,等待用户输入CONFIRM后才能继续"。
  • 脚本内部做回收站保护,被删除文件先移到~/.trash,而不是直接rm。

没有这层,一个依赖项解析失误可能让用户的文档目录瞬间清空。Agent Skills在生产环境里,安全设计一定要前置。

7.3 权限最小化:技能是用户的权力放大器

很多人忽略的一点:Agent Skills的脚本拥有的是当前Agent进程的权限。也就是说,如果Agent以root身份运行,技能里的rm -rf是可以毁掉整台服务器的。生产中一定要用专门的低权限账号运行Agent,技能目录使用只读权限,脚本只被允许访问它声明的目录。

7.4 依赖幻觉:模型把不存在的库描述得头头是道

我最后要提醒一个很隐蔽的问题:模型在写脚本时,有时候会使用它"听说过的库"但不检查这个库是否真的存在——比如虚构一个os.shutil_pretty_rename()函数,然后信心十足地调用它。脚本一执行报错,模型又开始"自我解释",把自己编的API说得像真的。

应对方案是:加一层"脚本执行前检查"。具体做法是让模型的常用脚本先跑一次--version或import检测,或者预先在SKILL.md里列出所有可用的依赖和函数名,严格限定脚本能用的库。把"发挥空间"收窄,模型的幻觉率会大幅下降。

写在最后

Agent Skills这套机制,说新也不新,本质上是将工程经验标准化、显式化交给模型调用;说旧也不旧,因为它第一次把"方法论"当作一等公民打包进了Agent的开发流程里。

我在实际开发中的体会是:技能设计得好不好,关键不在脚本写得多漂亮,而在于你相不相信模型能把SKILL.md里的规则执行到位。你要做的,就是把每一步规则打磨到"即使是最笨的模型也能顺着走完"的程度,同时把脚本设计成"即使是最激进的模型也玩不坏"的样子。

如果你之前一直在写Tools,不妨抽半天时间把其中一个工具改造成Skills试试。我敢打赌,跑完一次之后你就回不去了——因为当一个Agent能带着"经验"和"规范"上岗的时候,它就不再是一个只会调函数的工具,而是一个真正能独当一面的数字员工。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询