最近在补一门Agent开发方向的专题课第二讲终于进入了我期待最久的模块——Agent Skills。如果说上一讲的核心还在“工具调用”教你怎么给模型递扳手、告诉它扳手怎么握那这一讲完全换了个思路它教你把一整套“维修流程”直接打包好让模型自己决定什么时候用、按什么步骤执行、干完怎么汇报。我边写代码边记笔记这篇就是把第二讲里最值钱的东西拆开揉碎结合我自己的实测和踩坑整理成一份可以直接照着用的实战笔记。这篇内容适合几类人看已经会用基础工具调用、但觉得项目稍微一复杂提示词就失控的人刚接触Agent SDK、想搞清楚Skills和普通工具到底差在哪的人以及正在设计复杂Agent工作流、想找到一种更干净的组织方式的人。我会把Skills的运行机制、边界判断、编写规范、调试方法整个串一遍最后分享我在真实项目中从“一个200行工具函数”重构为“三个Skill”的具体体会。1. 从Tools到SkillsAgent开发里的一个关键转折1.1 单一工具函数膨胀的典型失控现场上一讲结尾我留过一个悬念工具函数一旦变多、变复杂真正难的不是写函数而是怎么让模型在合适的场景下选对合适的函数、填对几十个参数。这个痛点我在一个内部Demo里体会得很深。当时我做一个“图片处理”工具一个函数里塞了缩放、裁剪、滤镜、格式转换、水印等十几个操作。第一版只有5个参数跑起来很顺。需求一多参数涨到20多个系统提示词里光是解释这个工具的参数就写了将近800字。结果模型开始频繁犯错该用滤镜的时候传了裁剪参数想加水印却忘了传位置信息更离谱的一次模型把图片路径直接填到了布尔参数上。每调一次这样的工具我都要在解析层写一堆兼容逻辑最后还是乱。这不是我代码写得烂而是设计模型的思路出了问题——工具调用本质上是“让模型操作一个API”而API的粒度太粗、业务逻辑太重的时候模型一边要根据用户诉求做决策一边还要理解几十个参数的组合关系认知负担非常大。如果把这种复杂任务继续往工具函数里塞最后一定会走到提示词爆炸、参数互相打架的境地。1.2 Skill这层封装到底改了哪一环第二讲里提到的Agent Skills解决的就是上面这个失控问题。它最核心的思想是不要把一个复杂的操作过程塞进单一工具函数而是把一个完整的子任务封装成独立模块模块自带说明、执行脚本、依赖和资源模型只需要知道“这个技能是干什么的、什么时候用”不需要把过程细节全部背下来。打一个我常用的比方。以前我雇一个助理每次让他办事都要把流程从头讲一遍去哪里、带什么材料、见到人怎么说、办完回来怎么汇报。现在我不讲了我直接塞给他一本手册告诉他“遇到这类事翻第三抽屉里的手册照着做。”手册在我这里他要用时自己打开看用不着每次都在嘴上重复。System prompt就是“助理的岗位描述”Skill就是“抽屉里的手册”。这个设计最巧妙的地方在于手册不是一次性读进上下文的而是按需加载。模型判断当前任务需要某项技能时才去读取那个技能包里的说明执行完就不必一直占着上下文。我实测下来它比把所有逻辑写进主提示词要省很多token而且正确率还更高因为模型每次只需要专注理解一个边界清晰的小任务而不是同时在心里装着十几个流程。1.3 SDK对Skill的识别与加载机制具体落到SDK层面Agent Skills是以目录为单位组织的。一个典型的技能包长这样archive_project/ ├── SKILL.md # 技能说明书模型主要读这个 ├── scripts/ │ └── archive.py # 实际的执行脚本 └── requirements.txt # 脚本依赖模型侧的逻辑我之前专门做过一个最小实验结论是Agent启动时会先拿到所有可用技能的“索引”——也就是每个技能包里SKILL.md的头部摘要但这个索引很精简不会把整本说明书都加载进来。当用户的请求命中某个技能的场景时模型才会去完整读取那个SKILL.md然后决定要不要调用对应的执行脚本。所以关键来了SKILL.md写得好不好直接决定模型能不能在正确的时机做出正确的调用。它不是给人看的文档而是给模型看的“触发条件操作SOP”。我一开始按写传统文档的思路去写密密麻麻全是背景和原理结果模型读完根本不知道什么时候该用它。后面改成“什么时候用、什么时候别用、输入是什么、输出是什么、按什么步骤做”的结构命中率马上提上来了。2. 理解Skill的运行边界它和Tool、Subagent不是一回事2.1 三种组件放在一张表里看课程里有一个对比讲得很透彻就是把Tool、Skill、Subagent放在同一张表里看。这也是我学第二讲时收获最大的瞬间之一因为它帮我把之前脑子里模糊不清的边界给划清了。维度Tool工具Skill技能Subagent子代理粒度单次函数调用多步骤、自包含的子任务独立上下文的完整代理状态无状态调用即返回有内部脚本和执行流程有独立的对话上下文定义成本低一个函数就行中等需要编写说明书脚本高需要设计专属提示词和人设适合场景确定性操作、简单查询有固定SOP的复杂任务需要多轮拆解目标、自主规划的长流程模型需要掌握的信息函数入参SKILL.md里的触发条件和步骤系统提示词人设约束我自己的理解方式是Tool是“手”Skill是“一套操作流程”Subagent是“一个会自己接活、自己拆活、自己交活的小团队”。三者不是谁替代谁的关系而是适配不同复杂度、不同自主程度的任务。2.2 什么时候该用Skill而不是硬塞Tool判断标准其实就三个任务有没有明确的输入输出边界有没有相对固定的操作步骤是不是会被反复复用如果三个都是“是”那大概率应该做成Skill而不是继续往Tool列表里堆函数。举个例子。我做一个“生成周报”的功能。如果做成Tool我得定义Report数据模型、模板路径、数据源连接、异常处理……这些参数加起来又是二十多个模型每次生成周报都要在参数里挣扎。但如果做成Skill我只需要告诉模型有周报需求时调用这个技能输入是本周原始记录技能自己会读取模板、聚合数据、生成文档并放到指定目录。模型不需要知道模板长什么样也不需要知道数据是怎么查的它只负责“决定要不要做”和“把输入传进去”。这里还有一个很实际的token收益。Tool定义的参数越多每次对话都要连同完整函数定义一起发给模型。Skill的定义是“索引级的”完整操作说明只在需要时才加载做得越好的技能包日常占用的上下文越少。2.3 边界放错的典型症状如果硬把复杂任务塞成Tool前面说的“参数失控”和“调用错误”就是症状。反过来如果把本该做成Skill的任务做成了Subagent则会面临另一个问题Subagent每次启动都有独立上下文需要热身后才能干活而且状态不会自动同步回主对话你还要自己搭一套结果传递机制。对“流程固定”的任务来说这纯属杀鸡用牛刀token消耗会翻好几倍。我在群里见过一个同学的项目他把“发送邮件”这个按说是固定流程的任务做成了Subagent每次发邮件都要经历一轮“你好请帮我发一封邮件给A内容如下……”的多轮对话又慢又贵。其实这种任务做成Skill一个脚本加一份说明就能搞定。这里有个非常实用的判断口诀如果任务自己都会背流程用Skill如果任务连流程都要现场规划用Subagent如果任务只是一步操作用Tool。3. 手写一个可复用的文件归档Skill3.1 技能目录的结构设计纸上谈兵没用我把自己在课程作业里做的一个“项目文件归档”技能完整拆出来给大家看看一个Score级别的技能包到底长什么样。场景是这样的用户给一个项目目录路径Agent需要把该目录下的文件按扩展名分类、压缩成zip、生成一份归档清单CSV最后返回zip路径和统计表。这活儿有很多步骤但边界非常清晰适合做成Skill而不是一个大工具函数。目录结构如下skills/ └── archive_project/ ├── SKILL.md ├── scripts/ │ └── archive.py └── requirements.txt完整代码我不想贴太多重点说两个文件SKILL.md决定了模型“怎么理解这个技能”archive.py决定“技能实际能不能把活干漂亮”。前者比后者更容易被忽略但实际影响更大。3.2 SKILL.md的写法要点这是我踩坑最深的地方。第一版我写的SKILL.md开头是一段功能简介中间是设计理念结尾才提了一句“输入是路径输出是表格”模型看完全篇还是不太明白什么时候该用。后来我按课程里推荐的思路重写核心原则是SKILL.md是写给模型看的决策文档不是为了通过评审的PPT。每一句话都要服务于“模型能否正确判断时机、能否正确传参、能否按步骤执行”。我最终的SKILL.md大体是这个结构--- name: archive_project description: 将指定项目目录下的文件按扩展名分类归档生成zip压缩包和归档清单CSV。适用于用户要求“整理项目文件”“归档某个目录”“按类型归类文件”等场景。 --- # 使用条件 仅当用户提供明确的项目目录路径并要求对文件进行归档、整理、归类时使用。 如果用户只是查询文件列表不使用本技能。 # 输入 - project_path: 必填待归档的项目目录绝对路径。 # 执行步骤 1. 递归遍历 project_path 下的所有文件排除隐藏文件夹和临时文件。 2. 按扩展名建立分类目录例如 .txt 放入 text/.jpg 放入 images/。 3. 调用 scripts/archive.py 执行归档脚本会生成 zip 和 CSV 清单。 4. 返回 zip 文件路径和清单摘要摘要包括各类文件数量与总大小。 # 输出 - zip_path: 生成的压缩包路径。 - summary_table: 分类统计表Markdown 格式。 # 注意事项 - 不要修改原始文件只复制到归档目录。 - 归档目录统一放在项目目录下的 archive_output/。 - 如果目标目录无文件直接返回“目录为空”不生成空包。这里我想强调两个“模型的直觉”细节。一个是description不要写功能词汇堆砌而要写“当用户说什么话时你会想到这个技能”比如“整理项目文件”“归档某个目录”这种自然表达另一个是“使用条件”里的反例也很重要——明确告诉模型“什么时候不要用”比只说“什么时候用”更能减少误触发。3.3 注册与模型侧调用的行为观察把技能放进配置后我用一组测试跑了几轮专门观察模型什么时候读SKILL.md。参考实现里通常是通过配置把skills目录挂给Agent类似下面这种形式agent Agent( system_promptsystem_prompt, skills_pathskills/, )跑通之后我做了几个观察记录用户说“帮我整理一下项目文件夹”模型会立刻读取archive_project的完整SKILL.md并进入执行流程。用户说“列出项目文件夹里有哪些文件”模型不会动这个技能而是直接用基础工具查目录。用户说“整理一下但不要压缩只要分类”模型读了SKILL.md后发现“使用条件”和“注意事项”没有覆盖这种情况会停下来问用户而不是自己瞎改流程。第三个观察让我印象最深。说明SKILL.md写得越清楚模型越知道自己的边界在哪也越敢于在边界外主动向用户确认而不是硬着头皮瞎执行。这种“敢于不执行”的表现其实是提示词质量高的信号。4. 实战中的清单与调试方法4.1 开发一个Skill的完整验收清单看完上面的示例你可能已经想动手了。根据第二讲内容和我自己的实践我整理了一个开发技能包的验收清单每次做新技能都照着走一遍基本不会出大问题边界明确这个技能解决什么类型的任务输入输出是什么哪些情况它不负责复用价值这个任务是不是经常出现、流程相对固定如果不是建议还是用Tool。SKILL.md精简给模型的说明书控制在能一屏读完的篇幅用“触发条件→输入→步骤→输出→反例”的结构。脚本独立测试先不接Agent单独运行脚本验证流程正确保证依赖完整。错误处理脚本里对常见异常目录不存在、权限不足、无文件给出明确提示方便模型下次决策。Agent联调至少跑5个正例和3个反例确认模型不会误触发也不会漏触发。这套清单看似基础但每一个都是我付过学费换来的。比如“脚本独立测试”这条我第一次写归档技能直接接Agent跑结果脚本因为少装了一个依赖库报错模型在对话里把报错原样吐给用户体验非常差。后来我先在命令行里把脚本单独跑通再接Agent问题少了一半。4.2 我实测遇到的典型失败与修复第二个想展开说的是失败案例。我总共遇到过三种典型问题排查链路各不相同。第一种是误触发。用户问“帮我看看这个文件有多大”模型居然调用了归档技能。我查日志发现是我的description里写了“整理项目文件”和“查看文件信息”两个场景模型把后者也归进了归档范围。修复方式是把description改为“归档、整理、归类”这类带动作的词同时在“使用条件”里明确排除“查询类需求”。第二种是传参缺失。用户说“归档一下吧”没给路径模型就空着project_path调用脚本直接报错。原因是SKILL.md里写了这个参数必填却没有教模型“参数缺失时应该先反问用户”。我在输入部分加了一行“如果用户未提供完整路径应先向用户询问不要猜测默认值。”之后这类报错降到了零。第三种是输出格式不稳定。有时候脚本返回的统计表是Markdown表格有时候又变成纯文本列表。原因是我让脚本“打印统计结果”格式交给了模型现场发挥。后面我把输出规范直接写在SKILL.md里并且在脚本里生成结构化的JSON结果模型只需要把JSON翻译成人类可读的表格格式基本稳定了。4.3 多技能组合时的冲突处理思路项目一复杂技能不可能只有一个。当我同时挂上“文件归档”“图片压缩”“文本摘要”三个技能之后遇到了调度冲突用户说“把这个文件夹压缩一下”模型居然会犹豫是走“文件归档”还是“图片压缩”。解法不是说把description改得更花哨而是要让每个技能的表达里都带上“边界排斥”。我在“文件归档”的使用条件里明确写着“本技能负责分类与归档打包如果用户只是要压缩单个文件请勿使用本技能”在“图片压缩”里也写了“仅针对图片文件单独压缩如果用户要求归档整个目录请使用文件归档技能”。两个技能互相给对方指路模型就不容易抡错锤子了。这里的思路其实是不要指望模型是全知全能的调度器你可以在每个技能包里写好“我不是谁”把判断成本从模型身上转移到文档里。5. 第二讲学完后我对Agent开发方式的重新排序5.1 优先级翻转从“写函数的顺序”到“设计工作流的顺序”学第二讲之前我拿到一个Agent需求第一反应是我要写哪些函数然后写函数、在工具列表里注册、调prompt。现在我的顺序完全变了先梳理整个工作流按步骤拆分成边界清晰的子任务每个子任务独立决定用Tool还是Skill还是Subagent只有那些确实属于“一步完成”的原子操作才落到普通工具函数里。模型在整个架构里更像一个调度中枢而不是一个什么操作都要亲自记流程的执行者。这个顺序反转带来的直接好处是维护成本下降。以前改一个复杂工具的逻辑要小心不破坏模型对参数的既有理解现在改一个Skill脚本只要SKILL.md的对外接口不变模型侧完全无感回归测试也简单很多。5.2 架构上的肉眼可见改进我实际动手把之前那个“图片处理”老项目重构了。原来一个200行的工具函数现在拆成了三个Skill一个专门处理图片尺寸与格式一个专门处理滤镜与水印一个负责批量素材的命名整理。单片复杂度降了每个SKILL.md都在三五十行以内模型可以快速理解并精准触发。重构之后跑了两个星期的线上日志直观感受是参数错误类的bad_case下降了大概六成用户追问“你理解错了”的次数也少了很多。真要挑毛病的话缺点是技能目录的初期设计需要花时间思考不能像写函数那样随便开写但只要目录骨架立得住后面迭代非常舒服。5.3 留下待验证的问题第二讲笔记整理到这里我心里还有几个没完全吃透的问题放出来供大家讨论第一技能包怎么跟版本管理结合技能脚本更新后如何保证Agent所用版本与代码库一致第二技能依赖另一个技能的产出时是在SKILL.md里写交接规范还是让模型直接串联调用第三如何在技能内部做更精细的权限控制不让脚本拿到超出任务需要的文件访问范围。这些问题我打算在下一轮实战里逐个验证到时候再写第三篇笔记。最后说个实在的体会Agent Skills这套机制表面上是在教你一种新的代码组织方式实际上是在逼你重新思考一个问题——你究竟想让模型“学会操作”还是想让它“学会按手册办事”第二讲给出的答案是后者。当你把复杂的操作过程都收进抽屉里的手册时模型真正需要专注的就只剩下判断“什么时候该翻哪本手册”这一件事了。就冲这一点这篇笔记就值得记。