
大语言模型火了这么久真正让我觉得“这东西能干活了”的转折点其实是 Agent 和 Skill 这套玩法出现之后。之前我们调模型基本就是“你问我答”再聪明也只是一个大脑但有了 Agent 和 Skill模型终于从“只会想”进化到了“还能做”。这篇文章想用最通俗的话把 Agent Skill 是什么、怎么设计、怎么写、怎么踩坑一次讲清楚。不管你是刚入门的新手还是已经接过不少项目的开发者应该都能从中找到点有用的东西。我会尽量避免甩一堆术语糊脸而是用“拆开揉碎”的方式结合我实际做过的模拟项目经验把 Skill 的每个环节都掰开来看。你能看到它为什么是 Agent 能力的核心载体也能看到一份最小可用的 Skill 到底长什么样还会看到我在真实项目里踩过的一些比较典型的坑。1. 从大模型到 Agent为什么需要 Skill1.1 大模型只会“想”不会“做”先说一个很基础的认知大模型本质是一个“概率预测器”。你给它一段文字它预测下一个词是什么你再给它一段它再预测下一个。它的强项是理解、归纳、生成但它的天然短板是——它不会主动调用外部工具不会自己去查数据库不会定时触发某个任务也不会在一个复杂流程里把每一步都做得稳稳当当。你可以把大模型想象成一个极其聪明的军师。军师可以分析敌情、制定策略、给出各种建议但真要让他上场布阵、搬运粮草、点燃烽火他必须借助士兵和器械。Agent 扮演的就是“指挥官”而 Skill 就是那一件件具体的“器械”。没有 Skill 的 Agent等于一个只会空谈的指挥官嘴上头头是道手上一点力气都没有。1.2 Skill 的本质把“想”变成“做”那 Skill 到底是什么用一句话说Skill 是让大模型能够完成一个具体任务的、可复用的能力单元。它通常包含几个要素什么时候被触发、需要哪些输入、执行什么逻辑、返回什么结果。你可以把 Skill 理解为给大模型装了一个“插件”。它既可以是纯代码逻辑比如计算、爬取、处理数据也可以是一套提示词流程比如让模型先拆解问题、再分步回答还可以是“代码加提示词”的混合体。在 Agent 的系统里模型是大脑负责“理解任务、制定计划、选择 Skill”Skill 是肌肉和工具负责“真正把活儿干了”。比如用户说“帮我把这个文件夹里的图片都压缩一下”模型自己不会压缩图片但它可以识别出“这是一个图片压缩任务”然后调用对应的“图片压缩 Skill”由 Skill 里的 Python 代码去完成压缩最后把结果反馈给模型再由模型组织语言回复用户。1.3 一个生活化的例子我经常用一个“厨房”的比方来解释这件事。大模型就像一个看过无数菜谱、理论知识极其丰富的厨师你说“鱼香肉丝”他能把菜谱背得滚瓜烂熟。但他没有手没法切肉、没法调味、没法颠勺。Agent 就是那个给他打下手的人而 Skill 则是“切菜技能”“调汁技能”“颠勺技能”。每一个技能都是独立封装好的切菜技能只管切菜调汁技能只管调汁。厨师说“先切菜”助手就调用切菜技能说“调个汁”助手就调用调汁技能。这样一来再复杂的菜也能通过拆解成一个个 Skill 来完成。这个类比里有个关键点Skill 一定是“独立、可复用、边界清晰”的。如果切菜技能里混杂了调汁的逻辑那系统一复杂起来就很容易乱套。后面我会详细讲怎么设计这种边界。2. Agent Skill 的组成与设计思路2.1 一个 Skill 的四大件触发条件、输入参数、执行逻辑、输出规范虽然不同框架对 Skill 的叫法不一样有的叫 Tool有的叫 Action有的叫 Plugin但核心组成基本逃不开四件事。触发条件解决的是“什么时候用这个 Skill”。有的框架靠模型自己根据描述判断有的框架用正则匹配还有的框架用分类器。不管哪种方式核心是让 Agent 在遇到某类任务时能精准地选中这个 Skill。输入参数解决的是“要调用 Skill需要告诉它什么”。比如一个“查询天气”的 Skill需要城市名和日期一个“生成周报”的 Skill需要用户提供一堆零散工作记录。输入参数设计得越清晰模型就越容易从对话里抽取出正确的信息。执行逻辑是 Skill 的核心我们实际要执行的代码或流程。它可以是请求一个接口、查一次数据库、跑一段算法、处理一份文档也可以是让模型自己按特定格式输出。执行逻辑要保证“确定环境下有确定结果”不能模棱两可。输出规范解决的是“Skill 干完活后怎么把结果交还给模型”。这里最常见的问题是——Skill 自己觉得干得很好但输出给模型时格式凌乱模型根本看不懂。我一般会要求 Skill 返回结构化结果比如 JSON 格式并附上一段“给模型的摘要”。2.2 从需求到 Skill 的拆解方法我在正式动手写 Skill 之前会先做一个叫“任务拆解树”的动作。把用户的一个需求拆成几个子需求再拆到“每个子需求能不能用一段明确、可测试的逻辑完成”。如果一段逻辑就是“调用某个接口”或者“执行某个函数”那就可以把这段逻辑包成一个 Skill 了。举个例子我做过一个“会议纪要整理”的模拟项目。从用户需求看它要录音转文字、要提炼待办、要识别责任人、要生成邮件草稿。如果不拆解直接让模型“帮我整理会议纪要”模型很容易泛泛而谈。但拆成“录音转写 Skill”“关键信息抽取 Skill”“待办生成 Skill”“邮件草稿生成 Skill”之后每个 Skill 都很轻量、边界清楚组合起来质量会稳定得多。拆解时有个原则我一直很信奉一个 Skill 只做好一件事。判断标准很简单——如果这个 Skill 的描述里出现了“并且”或者“同时”说明它已经被塞了太多职责是时候拆开了。2.3 为什么不是把所有能力塞进一个 Skill可能有人会说拆成这么多 Skill调用链路不就变长了吗模型多绕几步不是更容易出错吗这个担心有一定道理但实际测试下来问题更多出自“大而全的 Skill”。当一个 Skill 的职责很多它的触发描述就必须写得很长模型反而容易判断失误。而且内部的执行逻辑一旦出错排查范围会扩散到整个 Skill 里定位问题的时间会成倍增加。更麻烦的是当两个需求都想复用其中一部分能力时大 Skill 没法单独抽出那一块只能复制粘贴长此以往代码冗余会非常严重。所以我自己更偏好“小而专”的 Skill。虽然单次任务可能需要模型做多步编排但每步都更可控。用工程上的话说这是用一点点运行时开销换来了更好的可维护性和可测试性。3. 快速上手手写一个最小可用的 Skill3.1 先定义场景与输入输出聊完理论我们直接上手做一个最小的 Skill。假设我们的场景是用户给 Agent 发来一篇文章Agent 能提取出文章里的“关键词列表”和“一句话摘要”。这是一个非常典型、也非常适合入门的 Skill。第一步问自己三个问题这个 Skill 什么时候触发——用户要求“提取关键词”“总结文章”“生成摘要”时。输入是什么——文章的原始文本。输出是什么——一个 JSON包含 keywords 数组和 summary 字符串。这三句话看起来简单却是整个设计里最重要的部分。输入输出不清晰后面写代码、接模型都会非常难受。3.2 写一份简单的配置与 Python 代码实现在一个常见的 Agent 框架里Skill 通常由一个描述文件和一个实现文件组成。描述文件用来说明“这个 Skill 是干嘛的、需要什么参数”实现文件是真正的代码。描述文件大致长这样name: article_summarizer description: 提取文章的关键词和一句话摘要。当用户要求总结文章、提及关键词提取或内容摘要时使用。 parameters: type: object properties: article_text: type: string description: 用户提供的文章全文 required: - article_text接着是 Python 实现。def article_summarizer(article_text: str) - dict: # 实际项目中我会在这里调用大模型做抽取。 # 为演示这里用一个简单的方法按句子切分后返回首句作为摘要 # 关键词则抽取出现频率最高的几个词。 sentences article_text.split(。) summary sentences[0] 。 if sentences else words [w for w in article_text.replace(。, ).split() if len(w) 1] freq {} for w in words: freq[w] freq.get(w, 0) 1 keywords [w for w, _ in sorted(freq.items(), keylambda x: -x[1])[:5]] return { keywords: keywords, summary: summary, status: success }这个实现很简单但具备了一个 Skill 应该有的形态清晰的入参、明确的返回、结构化输出。3.3 把 Skill 接入 Agent 的两种常见方式Skill 写好了怎么让 Agent 用起来我在实践中主要用过两种接入方式。第一种是函数调用方式。模型根据用户意图生成一个结构化的函数调用请求里面包含函数名和参数。框架拿到这个请求后执行对应的 Python 方法再把返回值送回给模型。这种方式最稳定因为函数名和参数是模型明确输出的不容易产生歧义。第二种是自由文本工具方式。Agent 把 Skill 的描述、参数列表塞进提示词里让模型在回复中按约定格式输出“我要调用某某工具参数是什么”。框架再用正则或代码解析这句话提取出工具名和参数。这种方式更灵活但对格式要求非常严格模型一旦输出不规范解析就直接失败。我个人的建议是如果框架支持函数调用优先用函数调用。它是一个被约束过的输出空间比自由文本可靠得多。自由文本方式适合做原型验证时快速试错但不适合上生产环境。3.4 测试与验收标准Skill 接入后不能“感觉没问题就算过了”。我会用一套简单的验收标准来检查给 10 段不同类型的输入Skill 是否正确触发对每段输入返回的 JSON 是否严格符合预定义的结构把 Skill 的输出喂给模型后模型能否用这个输出组织出符合用户预期的回答。具体操作上我会用几个典型的标注用例既有明确的“请总结文章”也有含糊的“帮我看看这段话说了啥”假想式的“这篇东西主要讲什么”。如果这些用例都能跑通我才会认为这个 Skill 基本合格。4. 真实项目中的 Skill 设计经验4.1 三个典型场景信息整理、定时提醒、工具调用Skill 的应用范围很广我挑三个自己实际落地过的场景讲一下设计上的差异。第一个是信息整理类。比如把一堆零散的对话消息整理成结构化表格。这类 Skill 的难点在于“提取字段的准确率”。我一般不会让模型一次性生成最终表格而是先让模型抽取出诸多个中间结构再通过代码做合并和排序。这样即使模型在某个字段上猜错了我们也能定位到具体位置而不是拿到一张看着不错、实际全是错的表。第二个是定时提醒类。有人可能觉得定时提醒不就是“到点了发消息”吗有什么技术含量但你设置过就会知道定时任务最麻烦的是“解析用户的模糊时间表达”。用户说“明天上午提醒我带身份证”模型需要结合当前时间计算出具体的毫秒级时间戳同时还要处理时区问题。这类 Skill 我会把职责分成两块一块用模型解析自然语言时间一块用代码做时区转换和任务调度。模型负责“理解”代码负责“算准”。第三个是外部工具调用类。比如查天气、查股价、发邮件。这类 Skill 的本质是“把模型的意图翻译成一次 API 请求”。我踩过很多坑之后总结出一个经验永远不要信任外部接口返回的格式。在接口返回后先用代码做一层抽取和校验再转成模型认识的结构化数据。否则接口返回一堆乱七八糟的字段模型会直接懵掉。4.2 设计粒度、命名与错误处理的细节Skills 设计里的“细节魔鬼”往往不在代码而在工程规范。粒度我前面提过一个 Skill 尽量只做一件事。但“一件事”怎么定义其实是高深的学问。我的判断基准是“能不能用一个动词加一个对象来描述”。比如“提取关键词”“发送邮件”“生成图表”都是动词加对象粒度就比较合适。如果变成了“处理文档并发送通知并记录日志”那就太粗了。命名上我要求 Skill 的名字必须让人一眼看懂用途。不要用“helper”“utils”“process”这类毫无区分度的名字。好的名字是extract_keywords、send_email、calculate_bmi。名字直接影响模型的选择准确率这点很多新手会忽略。错误处理是容易被低估的环节。Skill 在执行时可能会遇到接口超时、参数缺失、数据为空、权限不足等情况。如果没有统一的错误处理机制模型就会“一本正经地胡说八道”。我会在每个 Skill 里强制返回一个类似status: error的字段同时附上给模型的可读错误说明让模型知道“这个任务没完成原因是什么能怎么补救”。这样即使用户看到失败信息也不是冷冰冰的技术堆栈而是有上下文的一句解释。4.3 安全性、权限与稳定性考量Skill 赋予了模型“动手能力”也意味着它有了“闯祸”的能力。所以实际操作里安全性和权限设计一定不能省。先说权限。一个能操作文件的 Skill应该只能访问白名单目录不能让它拿到全盘路径。一个能发邮件的 Skill应该限制收件人范围不能允许用户随意指定任意地址。你可以把这些设计看成“给模型上的保险拴”。宁可多校验一步也不要让它自由发挥。再说稳定性。外部 API 会有抖动模型本身有随机性。为了降低这种不确定性我在 Skill 内部会做三层防线第一层永远有默认值兜底第二层对关键操作做重试第三层把每次调用的输入输出记录下来方便事后回溯。最后说审计。我会给每个 Skill 加一个“记录调用日志”的钩子。哪个用户、什么时间、触发了哪个 Skill、传了什么参数、返回了什么结果都留下痕迹。这既是排查问题的依据也是后续评估 Skill 质量的重要数据。5. 常见问题与排查实录5.1 问题一模型不调用 Skill 或调用很随机这是几乎所有初搭 Agent 的人都会遇到的情况。明明已经写了很清楚的描述模型就是不用偶尔用了选中的还不对。我排查这类问题的顺序是固定的。先查描述文件看描述里是不是包含足够的触发关键词。如果你只写了“该工具用于文件操作”模型很难判断“帮我整理桌面文件”该不该调用它。描述里最好这样写什么场景、什么句式、什么意图会触发它。描述不一定是英语短句也可以是中文长句重点是“覆盖用户真实说法”而不是“覆盖功能名称”。然后查参数。如果参数定义不清晰模型可能连这个 Skill 是否被“需要”都说不好。比如参数要求是“用户提供的截图路径”模型可能根本搞不清楚从哪拿这个路径。尽量把参数设计成能从用户原话中直接抽取的内容。之后如果还是不行我会加一个“明确的小实验”用不同的提示词模板让模型面对同一道用户指令打印出它自己认为最匹配的 Skill。这样可以直接看到模型对 Skill 描述的解读逻辑有针对性地优化描述。5.2 问题二Skill 执行成功但结果让模型“看不懂”Skill 返回了一堆正确数据结果模型回复用户时完全没利用上。这种情况非常气人但原因通常很统一返回结果的格式对模型不友好。我自己的经验是不要让 Skill 返回一个巨大的嵌套 JSON 然后指望模型自己理顺。更好的做法是除了结构化数据额外附一段“自然语言摘要”专门给模型看。比如查询天气的 Skill 返回{temperature: 24, condition: 多云}之外也可以提供一个summary: 当前温度24摄氏度多云体感舒适。这样模型理解起来零成本回复质量也会明显提升。5.3 问题三多个 Skill 之间互相干扰Agent 里如果挂了十几个 Skill模型的选择难度会直线上升。这个并非危言耸听。当两个 Skill 功能有点类似时模型很可能选错。比如“生成文章大纲”和“生成 PPT 大纲”听起来差不多但实现逻辑完全不同。解决办法有两个。第一精简数量。能合并的先合并能删掉的就删掉宁可少而精不要多而乱。第二把描述之间的差异写得更明显。比如明确写“如果用户需要分页展示请使用 A如果只需要文本大纲请使用 B”。本质上是替模型做判断把模型从多选题变成了单选题。5.4 问题四长任务执行不稳定有些任务需要 Agent 调用多个 Skill 串联完成比如“读取文件—提取数据—生成图表—发送报告”。在这种长链路里某一步出错后面全乱。我后来总结出两个经验。第一每个 Skill 都必须是“幂等性尽量好”的也就是说同一输入执行两次结果应该一致。这样在任一步重试时不会产生重复副作用。第二把长任务拆成多个“子 Agent”或“阶段”每个阶段结束都把中间结果落盘。这样出问题时可以直接从断点恢复不用从头再来。你可能觉得这是工程上很重的方案但如果做的是正式项目这套机制早晚能帮你省下大量排查时间。5.5 问题速查表我把上面遇到的常见问题整理成一张速查表方便实际排查时直接对照。问题现象可能原因优先排查点模型不调用 Skill描述不够明确、参数难抽取优化描述中的触发场景与参数定义调用随机、不稳定Skill 数量过多、职责重叠精简 Skill 数量区分描述边界执行成功但回答错返回结果对模型不友好添加自然语言摘要简化返回结构多 Skill 串联出错状态未保存、无重试机制阶段化落盘、保证幂等性安全风险权限过大、未做白名单校验加权限校验、限制访问范围、记录日志这张表不能覆盖所有问题但百分之八十的新手调试需求都在里面了。你对照着自己项目里的现象去查大概率能省很多时间。最后再分享一个小技巧。我在设计 Skill 时会专门给每个 Skill 写一个“失败示例”它什么时候不该被调用或者某类输入它应该拒绝。这个反例往往比整段正面描述更管用。因为模型的语义判断是靠正反两个方向的比对建立边界的。你在描述里主动说清楚“这个 Skill 不适合处理哪些情况”比你反复强调“它是做什么的”更有效。这一点我在好几个项目里实测效果都很明显。毕竟让模型少犯错比让模型多做对更值钱。