你有没有过这样的体验:让 Agent 帮你整理邮件、列提纲、写文案,它表现得像个尽职的助手;但当你让它“把上个月的销售数据拉出来,按区域排个序,生成一页分析摘要,再按值班表分发给对应负责人”,它就开始一本正经地胡说八道了。不是模型变笨了,而是你缺了一层东西:技能系统,也就是业内常说的 Skill。
这一篇是这个系列里我最有话说的主题。因为“让 Agent 从聊天进化到干活”,差的从来不是模型参数,而是那套把能力显式化、工程化、可复用的中间层。Skill 技能系统,就是这套中间层的核心。你在热词里看到的 skill开发指南、skill和agent的区别、agent框架与编排、agent记忆、agent安全,几乎所有 Agent 实战关键词,最后都会汇到 Skill 这个点上来。这篇文章我会从原理讲到实战,从踩坑讲到治理,尽量把“让 Agent 真正干活”这件事讲透。无论你是在用 Claude、Cursor、Codex,还是自己搭 Agent 框架,这套方法论都适用。
1. 聊天容易干活难:Agent 能力跃迁的最后一公里
1.1 你遇到的“看起来会、实际不会”的 Agent
先说我自己的经历。早期我调试 Agent 时,问它“你知道什么是 Kubernetes 吗”,它能对答如流;但当我让它“把这台服务器上的 Nginx 日志按状态码归类,统计 Top 10 IP,输出到指定目录”,它先是说了一堆正确的方案,然后停在第一步——因为它根本没有执行入口。
这类场景你应该不陌生:Agent 擅长生成文本,却不擅长触发动作。原因在于大模型是语言模型,它的世界以 token 为单位,而不是以“文件系统”“API 接口”“数据库连接”为单位。你让它“读出这份 Excel”,它如果手上没有读取 Excel 的工具,就只能靠猜。于是它摆出一副“我会”的姿态,给你一段写好的 pandas 代码。代码是对的,但活没干。
这就是聊天和干活的分界线:聊天只需要输出,干活需要改变现实世界的某个状态。改变状态需要能力,而能力需要被显式地加载、调用、校验。Skill 技能系统,就是把这个过程从“模型自由发挥”变成“按图索骥”。
1.2 为什么单靠大模型上下文无法解决干活问题
有人会想:我多给 Agent 一点上下文提示词,让它知道自己是运维专家、数据分析师,不就能干活了吗?
还真不行。
你可以把大模型的上下文想象成一个博闻强识但手脚绑住的实习生。你把所有操作手册、API 文档都塞进上下文,他能看懂,但他的手还是没放开。真正放开手的是工具调用能力,而工具调用能力需要一个“明确的清单”——你的系统里到底有哪些可执行单元,每个单元的输入输出是什么,边界在哪里。Skill 就是这份清单的实体化。
还有一个现实问题:上下文是昂贵的。把所有可能用到的技能解释都塞进去,模型推理慢、成本高、还容易互相干扰。更好的做法是:平时只给 Agent 一个技能索引,按需加载某个 Skill 的完整描述。这就像你手机里的应用商店——你不会把几万个 App 的功能说明都背下来,你只需要在要用的时候搜索、安装、打开。
1.3 Skill 的本质:把能力从“隐含”变成“显式”
一句话总结:Skill 是把一组工具、指令、逻辑包装成一个可被 Agent 元认知识别、按需加载、可复用、可校验的能力单元。
注意这个词:元认知。Agent 不是普通程序,它需要“知道自己有什么手段可用”。如果你的能力分散在代码深处、函数名里、注释里,模型看不到,就形同虚设。Skill 系统做的事情,就是把能力从代码里“拉出来”,写成一个模型能读懂的说明书,注册进一个模型能查询的清单,再暴露给一个负责决策的调度器。
后面我会给一个完整的技能封装示例。在那之前,先理解 Skill 系统的四个核心模块:定义、注册、调度、执行。
2. Skill 技能系统的四大核心模块:定义、注册、调度、执行
2.1 Skill 描述文档:给 Agent 看的说明书
任何一个合格的 Skill,首先必须有一份“人类可读、模型可解析”的描述文档。目前我在实际项目中采用的规范,和主流 Agent 框架的做法基本一致:每个 Skill 独立目录,目录下必须有 SKILL.md,里面写清楚这个技能是干什么的、什么时候用、什么时候不可以用、输入参数有哪些、输出结果长什么样、依赖哪些外部系统。
描述文档不要写成论文,要写成电梯演讲。模型在决策时只会扫几眼,所以最关键的信息必须前置:技能的适用范围、触发条件、典型用例。比如“销售周报汇总技能:用于读取销售明细,按区域汇总,生成 Markdown 周报。不适合处理退款异常”。这就是一个合格的介绍段。
你以为这是写给人看的?不,这是写给模型看的。写得越清晰,模型在意图识别阶段就越少出现“该调用却不调用”或“不该调用却瞎调用”的误判。
2.2 注册中心与索引机制
有了 Skill 描述,下一步是注册。注册不是把文件放进某个文件夹那么简单,而是要把它登记在你的 Agent 框架的技能索引中——一个机器可读的清单。这个清单至少包含:技能 ID、技能名称、描述摘要、参数 Schema、入口文件、权限等级、依赖项。
为什么需要技能索引?因为 Agent 在每轮任务开始时,不太可能逐个读完全部技能文档。更高效的做法是:先扫描技能的索引列表(每个技能一句话摘要),让模型初筛出候选技能,再按需加载候选技能的完整 SKILL.md。
我们团队内部管这个过程叫“二级检索”:索引级筛选、描述级确认。没有这层设计,技能一多,Agent 的选择时间会指数增长,还会出现“明明有合适的技能却视而不见”的情况。
2.3 调度决策:Agent 如何知道该用哪个 Skill
调度是 Skill 系统里最“智能”也最容易被误解的环节。很多人以为调度需要写复杂规则引擎,实际上大部分 Agent 框架的调度就是一个“带工具选择的模型推理过程”。
具体说:系统把当前任务、可选 Skill 摘要注入给模型,模型基于任务推断输出一个结构化结果:选哪个 Skill、填什么参数。这一步天然是模糊的,所以最好给模型设置约束:参数必须符合 Schema、禁止选择权限之外的技能、不确定时询问用户。
我强烈建议在调度层加入一个“候选集收敛”的预处理:先用关键词匹配或小型分类器把几十上百个技能收敛到 3-5 个候选,再让模型做精排。这样既保留了大模型的语义理解能力,又把决策成本控制在一个合理范围内。实测下来,收敛后调度准确率能提升 20 到 30 个百分点。
2.4 执行沙箱与反馈闭环
最后一个模块是执行。执行不是简单地跑一段脚本,而是要解决两个问题:权限边界和反馈闭环。
执行沙箱决定了 Skill 能碰什么、不能碰什么。比如一个“发邮件技能”,它需要访问 SMTP 服务、通信录接口,但绝不应该有权限读取本地任意文件。所以每个 Skill 在注册时就要声明权限等级,底层运行时根据等级分配容器、目录、网络策略。这不是多余的安全洁癖,而是在真实业务环境中活下来的基本保障。
反馈闭环则是让 Agent 知道“活干得怎么样了”。Skill 执行结束后,需要返回结构化结果:退出码、执行日志、生成物路径、关键指标摘要。Agent 拿这些信息判断:任务是否完成?要不要根据结果进行下一轮操作?如果结果异常,是重试、换 Skill 还是求助?没有反馈闭环的 Skill 系统是断臂的,执行完就完,Agent 依然是个盲人。
3. 手写一个实战 Skill:从需求到封装的全过程
3.1 需求界定:一个销售周报汇总 Skill 的边界
光讲概念容易飘,下面我带大家手写一个真实的 Skill。假设场景是:每周五下午,运营负责人需要一份销售周报,包含各区域销售额、订单量、环比变化、TOP 3 客户,以及一句自动化结论。
第一件事不是写代码,而是界定边界。边界就是“什么归这个 Skill 管,什么不归它管”。我定的边界是:只负责读取固定目录下的销售明细文件,完成聚合统计,生成 Markdown 报告;不负责发送邮件、不负责处理退款、不负责预测下周销量。边界明确后,模型才不会越界发挥。
3.2 技能脚本与参数定义
接下来是技能主体。脚本我一般分成三层:入口层、业务逻辑层、异常处理层。入口层负责参数校验;业务逻辑层做数据读取和聚合;异常处理层负责文件缺失、格式错误、空数据集等场景。
参数 Schema 也在这里定义,用 JSON Schema 格式。以周报为例,参数包括:数据目录路径、起始日期、截止日期、区域列表、输出路径。Schema 要写上类型、必填、默认值和说明。这既是给模型看的,也是给运行时做校验用的。
下面给出一个极简版的脚本结构(Python 表示):
# skill_weekly_sales_report/main.py import argparse import json def generate_report(data_path, start_date, end_date, regions, output_path): # 核心逻辑:读取数据、按区域聚合、计算环比、生成 Markdown # 这里按项目实际数据格式扩展 return {"status": "success", "report_path": output_path, "summary": {...}} def main(): parser = argparse.ArgumentParser() parser.add_argument("--data-path", required=True) parser.add_argument("--start-date", required=True) parser.add_argument("--end-date", required=True) parser.add_argument("--regions", nargs="+", default=[]) parser.add_argument("--output-path", default="./report.md") args = parser.parse_args() try: result = generate_report(...) json.dump(result, sys.stdout) except Exception as e: # 返回可解析的错误信息,供 Agent 决策重试 sys.stderr.write(str(e)) sys.exit(1) if __name__ == "__main__": main()注意返回值不要用中文描述性的“成功”“失败”这种模糊字符串,而是用结构化 JSON:status、report_path、summary。Agent 拿这个结果才能做后续判断。
3.3 注册:接入主流 Agent 框架的技能清单
写完了脚本,接下来是注册。目前主流 Agent 框架的 Skill 注册方式大致相同:在技能目录下创建 SKILL.md,然后把目录挂载到框架的 skills 根目录。
下面是我项目中周报技能 SKILL.md 的缩略版:
--- name: weekly_sales_report description: 生成销售周报,用于按区域汇总销售额与订单量,并输出结论摘要 trigger: 用户提到周报、销售汇总、区域业绩分析 params: data_path: type: string required: true description: 销售明细 CSV 目录 start_date: type: string required: true description: 开始日期,YYYY-MM-DD ... permission: read_data, write_report output: Markdown 报告文件 + JSON 执行摘要 --- 基于指定日期范围和区域列表,读取 data_path 下的销售明细文件,按区域汇总销售额、订单量、环比变化,生成 Markdown 报告,输出 TOP3 客户名单和自动化结论摘要。若数据缺失,直接返回错误码。这里的前置元数据(YAML 格式)是关键。name、description、trigger、params、permission,每一项都会影响调度决策质量。尤其是 trigger,给模型一个“什么时候该想到我”的信号。
主流框架大多提供了自动扫描 skills 目录的加载器,按约定格式读取 SKILL.md,生成技能索引。你的责任是让每个 Skill 的元数据写得足够清晰。
3.4 联调验证:让 Agent 按预期调用
注册完成后,最后是联调验证。我有一个固定的验证清单:
- 直接命令行调用脚本,传合法参数,确认输出正常。
- 传非法的参数(日期格式错、目录不存在),确认错误能被结构化返回。
- 在 Agent 对话场景里给出触发语句,确认模型选择了这个 Skill。
- 给一个模糊请求(如“帮我看看这周卖得怎么样”),确认模型能正确推断参数,并回填默认值。
- 给一个越权请求(如“顺便把周报发给李总”),确认模型没有越权,而是明确指出“发送邮件不在本技能范围内”。
前四项验证的是能力,第五项验证的是边界感知。很多 Skill 翻车不是因为不会干活,而是因为边界模糊,才导致 Agent 干完活后随手瞎承诺。
这个联调过程看起来简单,实际上是最耗时间的环节。Agent 的调用行为有随机性,同一个请求多测几次,你会发现有时候它选错了技能,有时候参数填得不对,有时候忽略了返回结果。这些都要在联调阶段暴露并修正,而不是等上线后让用户替你发现。
4. 决定 Skill 成败的四个隐藏接口
4.1 工具调用协议:Skill 与 Agent 怎么对话
第一个隐藏接口是协议。你封装出来的 Skill,本质上是一个可被 Agent 触发的工具。但它和 Agent 之间怎么交互?
一套古老的思路是:把 Skill 当函数调用,Agent 生成参数,运行时执行,返回结果。这套思路能用,但在复杂任务里很局促。真正干活的时候,Agent 通常还需要中途确认、分批读取数据、多步迭代。我的建议是:Skill 的入口尽量简单,但内部可以拆成多个柔性步骤;对外暴露“调用-结果-下一步指引”这个铁三角。
也就是说,每个 Skill 执行完后,除了返回任务结果,还应该返回“下一步可能动作的提示”。比如周报汇总完成后,提示“可以对生成的 Markdown 做二次润色,或者直接输出给用户,但不包含邮件群发”。这就像给 Agent 递接力棒,它知道你这条胳膊到哪为止。
4.2 上下文记忆:Skill 之间怎么避免“失忆”
第二个接口是记忆节点。Agent 调用多个 Skill 完成一个复杂任务时,最头疼的问题就是“失忆”——上一个 Skill 的产出,到下一个 Skill 那里就没了。
比如周报生成之后,接着让另一个图表技能画折线图。画图技能不知道周报里算出的区域列表和销售额,于是又去重新读一遍数据。这种重复劳动还是小事,更大的问题是:如果前后数据源不一致,结果就对不上。
我的解法是:在 Agent 框架里维护一个共享的“任务工作单”,每个 Skill 执行完成后,把关键产出摘要写入该工作单。下一个 Skill 启动前,框架自动注入工作单中与它相关的字段。Skill 之间不需要知道彼此的存在,它们只需要知道“工作单里有我要的数据”。这比让 Skill 之间直接通信优雅得多。
4.3 权限边界:Skill 能碰什么,不能碰什么
第三个接口是权限边界,这也是和 agent安全 最直接相关的部分。Skill 一旦上线,就不能让它的能力毫无限制。我见过一个很典型的反面案例:同事把一个“PDF 转 Word”Skill 挂到了 Agent 上,配置时不小心给了它读取整个服务器数据目录的权限。结果 Agent 在处理用户请求时,转头就把一份无关的合同内容读进了上下文。虽然不是大规模泄漏,但这个行为本身已经触犯了数据合规底线。
权限治理不能指望 Agent 自觉,必须在运行时强制。具体方案:每个 Skill 声明需要的最小权限,框架在沙箱层做拦截,任何越权调用直接拒绝并记录日志。注意,权限审计日志一定要留存,一旦出问题,你能知道是哪一次任务、哪个 Skill、访问了什么。没有日志的权限系统,等于没有权限系统。
4.4 自我纠错:处理执行失败与重试机制
第四个接口是纠错。Agent 干活不可能一帆风顺:文件找不到,API 超时,参数理解错。关键是失败发生后怎么办。
有一个反人性的配置我特别提醒:不要给 Agent 无上限的重试权。一旦某个 Skill 执行失败超过两次,就该把控制权交还给用户,解释发生了什么,而不是永远循环“重试—失败—再重试”,既浪费 token 又制造幻觉。
重试策略也有讲究。不是简单的“再跑一遍”,而是要让 Agent 读上次的报错原因,调整参数后再跑。比如“文件不存在”和“文件格式错误”是两类完全不同的失败,前者需要检查路径,后者需要检查解析逻辑。所以 Skill 的异常信息一定要结构化、精确,至少要让模型看到错误后知道下一步该改什么。
5. 实测踩坑实录:我在集成 Skill 时遇到的五个典型问题
5.1 问题一:Agent 反复调用同一个 Skill,结果却不一样
这是我调试时最先遇到的问题。同一个周报任务,调了三次,三次的产出在细节上竟然有差异:第一次结论里写了“华东区增长”,第二次却写“华东区持平”。数据没变,为什么会变?
排查了半天,发现根因在调度层的 prompt:框架把整个对话历史都赋予了调度模型。前两轮产生的中间推理内容,污染了第三轮的判断,模型基于自己的上一条错误结论做了新结论,而不是基于真实数据。
解决方式是把“调度决策”和“任务执行”两种上下文隔离。调度模型只看到任务目标、技能索引、参数校验规则,看不到闲聊历史。这个改动立竿见影,结果稳定了很多。
5.2 问题二:多个 Skill 并行时互相污染
有一次我把“周报汇总”和“趋势预测”并行跑,结果两个报告里的数字对不上。细查之下发现:两个 Skill 各读各的 CSV 文件,但其中一个读到了带缓存标记的历史文件,另一个读的是最新导出的数据。数据源不同,结论自然打架。
这个问题的根子不在 Skill 本身,而在任务规划层。Agent 做并行调度时,没有检查多个 Skill 对同一数据源的一致性要求。
我的处理方式是:在 Skill 描述里增加一个“数据版本约定”字段。凡涉及数据读取的 Skill,都要声明它依赖的数据快照 ID;同一任务里并行调度的 Skill,必须保证快照 ID 一致。从根上堵住数据源漂移。
5.3 问题三:技能脚本卡死,任务没有任何产出
还有一次,Agent 调用一个外部系统接口的 Skill,等了整整六分钟,任务超时,什么日志都没留下。后来排查发现:外部接口因为鉴权过期,服务端一直返回 302 重定向,客户端循环重定向直到超时。
这个坑的关键在于:你的 Skill 脚本里没有超时控制和重定向兜底。现在我的所有 Skill 脚本都有一个硬性约定——所有外部 HTTP 调用必须设置显式超时,默认 15 秒;所有网络库必须关闭自动跳转,或者限制最大跳转次数。一次请求失败,快速失败,快速反馈,而不是傻等。
5.4 问题四:Skill 与模型内建能力重叠时,该信谁
很多 Agent 框架本身就有一些内建能力,比如生成文本、简单计算、查天气。当你把“天气查询 Skill”挂上去后,会发现模型有时候调用 Skill,有时候自己编一个天气出来。
模型更喜欢用内建能力回答,因为它“快、不依赖工具”,但正确性没有保障。这里必须配置优先级规则:凡是注册了对应 Skill 的领域,一律强制走 Skill,模型被禁止直接用“猜测”来回应事实型请求。
实现方式很简单:在系统级指令里加硬性约束,“当存在天气查询 Skill 且用户意图属于该领域时,必须调用该 Skill,不得自行编造天气信息”。同时,调度器在判定时,如果技能索引中存在高相关的候选,就把它作为第一选项推荐给模型。这算是一个轻量的策略控制手段。
5.5 问题五:恶意输入与参数注入
最后说说安全。Skill 接收的参数是用户自然语言里抽取的,它天然可能携带恶意内容。比如“指定输出路径”这个参数,用户可以说“./reports/周报.md”,也可以说“;rm -rf /”。如果脚本没有做安全过滤,这一句就能让整个技能脚本报废。
我的防御策略有两层:第一层是参数 Schema 规范,第二层是运行时命令黑名单。凡是路径参数,一律限制在预先声明的白名单目录内;凡是命令执行类 Skill,一律拒绝拼接 shell 字符串,改用 subprocess 的参数数组传参。你已经配置了沙箱,但这只是底线,脚本内部也要把自己管紧一点。Agent 生态的安全从来都不是单点防御,而是多层防线。
6. 从个人脚本到团队技能库:Skill 生态的进阶之路
6.1 盘点主流的选择:Claude Skill、Cursor Skill、Codex Skill 与自主框架
聊到这里,你一定好奇市面上的 Skill 实践具体长什么样。目前经常被提到的几个方向:Claude 的 Agent Skills 采用 SKILL.md 描述 + 资源文件加载;Cursor 的 skill 更侧重编辑器内操作自动化;Codex 技能偏向编码任务的分解执行;还有大量开源 Agent 框架自带的技能注册机制。
做一个中肯对比,方便你选型:
| 方向 | 核心思路 | 适合场景 | 注意点 |
|---|---|---|---|
| Claude Skills | 目录化、SKILL.md 描述、按需加载 | 通用知识型技能、文档生成、代码片段 | 描述质量决定调用准确率 |
| Cursor Skills | 与编辑器深度绑定 | 编码、重构、代码库问答 | 迁移性一般,依赖编辑器生态 |
| Codex Skills | 面向编码任务拆解 | 自动编程、代码库维护 | 更偏开发场景,非通用 |
| 自主框架 | 自己定义注册/调度/沙箱 | 生产系统定制化 | 初期开发成本较高,但可控性最强 |
我的建议是:如果你还在学习和验证阶段,优先用 Claude Skills 或类似通用方案,因为文档规范成熟、社区资料多。如果已经进入生产环境,且需要对接内部系统,一定要在自主框架上做二次封装,因为你需要权限审计、数据隔离和流程审批这些生产级能力。
6.2 把 Skill 变成可分享、可治理的资产
独立的 Skill 很容易写,难的是把它变成一份可持续治理的资产。这不只是技术问题,还是协作问题。
我见过不少团队的技能库整理得比烂代码库还可怕:几十个 Skill 目录堆在一起,描述写得不清楚,没有版本号,没有负责人,连接口变化了都找不到是谁改的。
建议团队内部推行三个约定:每个 Skill 必须有 owner、每个 Skill 必须标注版本号、每次改动必须写变更记录。把这些约定固化到 Skill 模板里,而不是依赖个人自觉。
至于对外分享,核心是把 SKILL.md 写得足够独立。技能不要依赖某个目录的绝对路径,所有依赖文件都放在 Skill 目录内,这样任何一个新环境只要导入目录就能用。这也是从个人脚本迈向成熟技能库的关键一步:技能自身要自洽、可移植。
6.3 学习路径建议:从 Prompt 到 Skill 再回到业务
如果你是新手,我的学习路径建议分三步走。第一步,别再只写 Prompt 了,刻意练习写 SKILL.md,逼自己把一个需求梳理成结构化的技能文档。第二步,拿一个真实的小任务(比如周报生成、PDF 批量改名),独立完成整个 Skill 的封装、注册和联调,跑通“定义—注册—调度—执行”闭环。第三步,对已有的技能做治理,加上版本、权限、日志,然后观察 Agent 在复杂任务里的表现,你会看到明显的稳定性提升。
这个路径的本质,是把注意力从“模型会不会”转移到“系统能不能”。你越早意识到 Agent 能力的上限很大程度上由它的工具箱决定,就越能理解 Skill 系统在整个智能体生态里的位置。
我也建议你持续关注 skill 开发指南类的内容和社区讨论。这个领域变化极快,每个主流框架的 Skill 规范都在快速演进,但核心思想是稳定的:显式化、模块化、可治理。抓住这三点,你就不会在未来半年的框架大战里迷失。
到了一篇文章写完的时候,我通常没有那种“终于讲完”的轻松感,反而觉得留下了很多没讲透的细节。最后一次给个小建议:当你自己的 Agent 开始稳定地完成一周的重复任务时,记得录一段视频留档。那是最好的复盘材料。
我个人是在调试了无数个翻车现场之后才真正理解 Skill 系统的价值。它不是什么高深技术,就是把“能力”这件事变得可描述、可注册、可调度、可治理。你的 Agent 能不能从聊天进化到干活,不取决于它多聪明,而取决于你给它配了多少能干事、守规矩、会汇报的 Skill。