我一向不迷信把更多工具塞给模型这件事直到有一次在项目里被迫把所有能力重新组织了一遍才真正理解了 agent-skills 这个抽象的价值。它不是一个库也不是一个框架而是一套让智能体能力可描述、可组合、可复用的组织方式。今天这篇东西不是泛泛讲概念我会结合实际项目的拆解过程把技能从定义到落地整条链路掰开揉碎讲清楚。如果你正在做一个稍微复杂点的 Agent 应用或者觉得现在的 Prompt 越写越长、任务却越做越乱那这篇文章应该能给你一个明确的方向。1. 为什么 agent-skills 会成为现在大家都绕不开的概念1.1 大模型从会聊天到会干活的质变先回顾一个基本事实大模型本质上是一个语言引擎它的强项是生成文本、分析语义、归纳逻辑但它的弱项也非常明确——不会可靠地执行重复操作不会访问外部实时数据也没有内置的长期记忆。过去我们把模型当成更聪明一点的聊天机器人只需要它输出文字问题不大。可一旦想让模型代替人去查订单、改配置、跑脚本、发消息事情就成了调用工具的参数格式不对、中间某一步漏了、同一个操作每次执行的表现都不一样。我在早期做过一个内部助手核心功能是让员工用自然语言查预算、提工单、更新进度。当时方案很原始——把几十个 API 的描述全部塞进系统提示词让模型自己从里面挑一个来调用。最开始只有三五个接口的时候挺好使慢慢增加到十几个之后模型开始频繁走神有时候它把两个相似接口参数弄混有时候明明应该先查权限再操作它直接就调了核心接口。这种体验放在内部工具里还能忍但要对外提供服务根本不可能。这就是智能体能力需要被技能化的第一个现实原因接口和工具多了之后让模型直接面对一个扁平清单既不安全也不稳定。你需要有一种中间层把能干什么以及怎么干封装成一个边界清晰的技能单元让模型拿到的不是一张大杂烩菜单而是一系列带有明确触发条件和内部约定的服务。1.2 技能体系和传统 Prompt 工程的本质区别不少人会把 agent-skills 理解成更高级的 prompt 编排我觉得这个理解有偏差。Prompt 工程解决的是怎么把问题描述清楚、把输出格式约束好而技能体系解决的是怎么把一项能力固化成可复用的执行单元并且让模型学会按需选取它。打个比方就清楚了。Prompt 像你告诉一个实习生工作需要做市场调研先收集数据、再分析竞品、最后写报告。你可以在邮件里把流程写得再细但实习生每次执行都可能因为理解差异而跑偏。而技能体系像给这位实习生一套标准作业程序卡片每张卡片只讲一件事比如如何调取竞品数据卡片上有明确的输入字段、调用步骤、输出格式和常见异常处理。你不需要在项目说明里重复写这些细节团队协作效率和执行一致性都会好很多。从实现层看这两者的区别更加明显。纯 Prompt 方案中模型知道某个功能的存在但没有内建保障它会正确使用技能体系则会为模型提供一个面向功能的接口描述集配合校验模块、执行引擎和回退策略形成一层可控的边界。也就是说技能不仅是一段说明文字它还配套了参数校验、执行时限、重试逻辑、错误映射这些工程化设施。这部分能力改变了靠模型自觉的不可靠性让智能体第一次可以像模块化软件一样被组织。1.3 为什么偏偏现在集中式技能库开始火还有一个很有意思的现象各大 Agent 平台和开源框架不约而同地在做类似 agent-skills 的事情——把技能做成一个独立于模型之外的资产。比如 LangChain 里的 Tool 抽象、OpenAI 后来的 Function Calling 演进、Claude 生态里的 Tools 用法本质都在解决同一个问题让模型能在运行时动态发现并调用外部能力而不是把全部能力写死在提示词里。这个趋势背后的驱动力我总结为三个第一是模型上下文窗口永远不够用。你不可能把所有 API 文档、参数说明、业务规则都塞进上下文塞进去之后模型的有效注意力会被稀释反而容易出错。把能力折叠成一段精炼的技能描述可以极大节省上下文空间。第二是安全边界越来越重要。直接给模型一个大而全的工具清单意味着它理论上可以调用任何接口权限控制很难做细。把能力封装成技能后可以按技能粒度做授权、限流和审计任何一次调用都能追溯到具体技能。第三是可复用性。同样一个搜索能力可能在智能客服、知识助手、数据分析助手三个应用里都要用。做成统一技能之后三个应用共享同一个实现和同一套测试用例谁出了问题都能一起修维护成本明显下降。这些因素叠加在一起让 agent-skills 不再是学术论文里的概念而成为每个做 Agent 应用的人迟早要面对的设计问题。2. 技能的最小可用单元一个优秀的 Skill 到底该包含什么2.1 技能清单元数据、触发条件、执行体在动手做人设技能之前先得把技能的原子结构定下来。我的经验是一个技能至少分成三层。第一层是技能的说明书也就是元数据。它告诉大模型这个技能是干什么的、适合什么场景、需要哪些输入参数、输出长什么样。这层信息写得越精确模型就越不容易误用。我一般会包含这几个字段skill name唯一标识、description一句话说明用于给模型做语义匹配、input schema声明输入字段和类型、output format明确输出结构、keywords可选辅助模型检索。第二层是触发约定告诉模型什么情况下应该优先使用这个技能而不是其他能力以及什么情况下绝对不要使用。这一步容易被忽略其实是降低误调率的关键。比如一个查询天气技能触发条件写当用户提到某地当前或未来天气、气温、降水等情况时排除条件写当用户询问历史气候趋势而非实时天气时不要调用本技能。触发条件写得越具体模型在技能之间选错的概率就越小。第三层是执行体也就是真正干活的代码或调用链。高水平的执行体不仅仅把业务接口包一层更要把输入规范化、做参数校验、把外部接口的各种异常吸收掉再映射成模型能理解的标准返回消息。这部分最关键至少对应一半的稳定性问题。2.2 一个具体例子从天气接口到完整技能拿一个最普通的功能来举例——查天气预报。没有技能化之前的做法是在提示词里告诉模型你现在有一个工具可以调用 /api/weather?cityxxx 这个接口返回 JSON 数据。但这样做的隐患是什么模型不知道城市名该用全称还是缩写如果接口返回 404它不知道该不该告诉用户查不到如果用户说的是北京而接口要求 city_code模型很可能忘记转换。技能化之后这个功能被组织成这样{ name: weather_query, description: 根据城市名称查询当前天气和未来三天预报输入城市中文名即可。, input_schema: { type: object, properties: { city: { type: string, description: 城市中文名如北京、上海 } }, required: [city] }, triggering: { when: 用户想了解某地的实时天气、气温、降水概率、风力或未来几天预报时, not_when: 用户询问气候平均数据、历史天气统计或穿衣建议时 }, executor: { prepare: 将城市名映射为 city_code对非常见城市返回友好错误, call: GET /api/weather?city_code{code}days3, handle: openapi 返回码非 200 时转换为 标准消息超时重试一次最终失败时返回 抱歉天气服务暂时不可用, format: 将原始 JSON 精简为 city、date、temperature_range、weather、wind_level 五项 } }这个结构看起来不复杂但每一个字段背后都有实际教训。比如输入 schema 里特意标注城市中文名是因为模型有时会把北京自动翻译成 Beijing而接口只接受中文维映射导致查不到触发条件里排除穿衣建议是因为若不写清楚模型有可能拿天气结果硬接一句建议穿羽绒服——这不是天气技能的职责会导致技能边界无限膨胀。2.3 技能之间如何协作而不互相打架单个技能定义清楚还不够技能体系复杂之后真正考验人的是技能间的关系管理。最常见的两类问题是重叠覆盖和串联顺序。重叠覆盖指的是两个技能的描述相似导致模型不知道选哪个。比如一个创建待办技能和一个创建日程安排技能语义上很接近模型很容易混淆。我的处理原则是如果能力边界真的很难区分就合并成一个技能在内部做参数路由否则必须把两个技能的触发条件写得完全互斥。另一种方案是给技能加上白名单关键词例如待办和日程分别只接受自己领域内的说法。串联顺序则更难处理。比如用户说帮我把这个文件转成 PDF 然后发到某个群里这里至少涉及文档格式转换和消息发送两个技能。对这类问题一种可靠做法是把编排逻辑交由主 Agent 完成但每个技能的结果要足够结构化方便下一步技能接住。转换技能输出的不要是一段成功啦的文案而应该是一个 file_path 值发送技能只需要输入这个 file_path。只要接口契约清楚模型自然能完成串联如果技能输出含糊那么整个链路都会断在半路。串并联问题上我一直坚持一个原则先解决每个技能自身稳定再谈编排。技能自己都不稳定任何协作都是空谈。3. 从零搭建你自己的 agent-skills 技能库3.1 选型与目录结构设计市面上已经有一些开源框架支持技能管理但如果你希望深度掌控我建议直接基于一份简单目录和注册机制自研。我的选型思路是轻量、可审计、不绑定模型厂商所以采用了目录即技能库的设计每个技能一个文件夹。因为技能描述和代码分离甚至可以让非技术人员通过编辑 JSON 描述文件来提交新技能。一个比较顺手的目录结构是skills/ ├── common/ │ ├── weather_query/ │ │ ├── skill.json │ │ ├── executor.py │ │ └── test_cases.json │ ├── search_web/ │ │ └── ... ├── domain/ │ ├── customer_service/ │ │ ├── track_order/ │ │ ├── refund_status/ │ │ └── ... ├── registry.json └── loader.pycommon 放通用能力domain 按业务域分组区分度能让权限管理和复用策略清晰一些。registry.json 维护每个技能的启用状态、版本号、是否对外暴露等元信息loader.py 负责扫描目录把技能描述批量载入一个统一的索引。3.2 技能注册机制与动态调用路由加载之后核心问题变成给定一次用户请求如何让模型选中正确的技能我接触过三种路由方式各自适用场景不同。第一种是纯语义路由。把所有技能的 description 拼给模型或嵌入模型让它根据用户意图选择一个。这个方案实现最简单也是多数框架默认的做法缺点是大规模技能库下容易出现选择不稳定。第二种是关键词预筛先通过倒排索引或者正则逻辑粗筛出候选技能缩小范围。第三种是基于 embedding 相似度计算对用户请求向量化和每个技能描述向量化求最近邻再用模型做最终裁决。我在实际项目中用的是第三种和第一种的结合先 embedding 召回 Top-5 候选然后由大模型从候选里选最终调用同时夹带触发条件的约束。这样既保留了模型对语义细微变化的判断力又通过召回机制把无关技能完全排除掉误调率下降明显。有一种情况需要注意如果技能库出现大量语义接近的技能embedding 召回可能召回一串重复候选这时候靠模型硬选也容易出错。我的建议是控制每层技能数量同一功能有多个变体时优先合并而不是让模型去挑选几乎一样的选项。3.3 权限、速率和回退策略的设计技能到了一定规模后你不得不考虑工程设施层面的问题。很多 Agent 原型Demo跑得挺好一上线就故障频发往往不是因为模型变笨了而是技能调用的保障机制没跟上。权限要按技能粒度走。一个技能可以声明需要审批仅限内部用户只读复用等级别。我的做法是在 loader 里对每个技能打标签internal / external / admin。用户请求先经过会话鉴权再禁止模型调用超出当前会话权限的技能。模型自然语言发送指令时执行体里必须再校验一次技能所需的权限不能只依赖模型自觉。限流同样关键尤其是技能可能对第三方 API 做了聚合调用。我在每个技能执行体外面包了一层统一的执行器包装提供固定速率控制同一个用户的技能调用频率被限制在 N 次/分钟同一技能所有用户总频率被限制在 M 次/分钟。超限时不直接报错而是告诉用户请求过于频繁请稍后再试同时给模型一个技能暂时不可用的信号让它可以转用替代方案。回退策略是我特别想强调的一点。不要假设外部接口永远在线。每个技能执行体都应该设计至少一层降级路径比如天气接口挂了可以从备用的另一个数据源读订单系统超时就回退到读缓存快照。如果没有降级能力技能再丰富也只是纸面上的功能。3.4 错误处理和重试逻辑这里具体展开一下我在执行体里的错误处理模板。一个执行体的骨架通常是参数标准化 → 语义校验 → 调用前准备 → 外部调用带重试 → 结果标准化 → 错误映射。参数校验必须做在前因为模型生成的参数偶尔会是幻觉。比如用户说北京明天天气怎么样模型传给执行体的可能是一个日期字段但日期语义错乱比如传了后天。校验阶段就需要对参数做合理性检查像日期至少在合理范围、城市名必须命中城市库否则直接拒绝调用并告诉模型参数不合法请向用户澄清或给出正确参数。外部调用重试不是简单的失败了再来一次。重试要有次数上限和退避策略。我常用的模式是总共最多重试 2 次第一次等待 500ms第二次等待 1s并且重试前先重新读取外部服务的健康状态。如果连续失败就立即走降级路径不再浪费请求。需要把一个容易被忽视的误区写出来不要在重试逻辑里无限循环哪怕是循环两三次也要设定超时网络抖动时重试有意义但接口本身返回业务错误时重试通常毫无价值只会放大下游压力。4. 真实案例用技能库让客服机器人故障率下降 70% 的经历4.1 原始方案的痛点什么都要 LLM 自己折腾讲一个我自己去年做过的客服机器人改造项目。当时项目已经上线了第一版用户能通过自然语言查询订单、申请退款、修改收货地址框架用的是 Prompt 加十多个 API 工具描述的方案。刚上线两周数据还行但越用越不对劲。最典型的问题是用户明明说我要退掉昨天那个红色毛衣的订单机器人却调用了修改地址技能用户说帮我看看快递到哪了机器人调用订单详情时参数总是把订单号弄错成手机号。客服团队一个星期接到几十次误操作投诉差评率直接飙升。把所有责任归给大模型并不公平——问题出在整体架构上任务描述、输入输出定义、异常处理全部塞在提示词里模型成了一个独木桥上的杂技演员什么活都让它干出错概率自然指数上升。4.2 技能拆分和复用的过程第二版改造的思路非常明确把所有客服业务能力拆成独立技能包括 order_query、refund_request、address_update、track_logistics、human_handover 五个核心技能外加 check_customer_auth 这类支撑技能。拆技能的时候我做了两件很有价值的事。第一件是把每个技能的触发条件写成正例 反例双份。比如 refund_request 的触发条件里明确写了仅当用户明确要求退款或退货时使用。用户仅询问退款政策时不得调用本技能应直接基于知识库回答。第二件是把输入 schema 全部改成了业务友好的定义比如 order_query 要求传入 order_id 或订单号字符串执行体内部再根据业务规则判断该字符串是否合法而不是让模型自己决定传什么。改造过程中我还做了一次技能复用的实践。客服场景里有大量实体识别需求比如识别用户提供的订单号、手机号、地址库。最初每个技能各自写了正则但我后来抽了一个 common/entity_parse 技能专门做实体识别和归一化其他技能执行体只需要调用它。这直接让代码量减少了大约三分之一也让后续新增技能时不用重写实体逻辑。4.3 上线后的意外收获和踩坑技能化改造上线后客服机器人主要指标确实明显改善。以一个月为口径对比技能误调率从之前的较难直视降到了一个可控范围无效请求率下降约 70%同时平均问题解决时长缩短了约 30%。这里我的收获不只是一串数字而是定位问题的效率变得非常高。以前模型出了错你得翻整个 Prompt 猜它是哪里理解偏了现在一个请求出了事日志里会明确记录它选了哪个技能、执行体返回了什么、哪一步走了回退问题链路清清楚楚。但也不是没有坑。我踩过最典型的坑是技能过粗和技能过细的平衡。改造刚开始我把所有订单相关功能全部塞到一个大技能里心想反正内部可以做路由省得让模型纠结。结果模型经常直接从大技能里选错子功能因为它只看到了一个笼统的描述。后来我把订单详情、退款、物流查询拆成了三个独立技能明确各自触发边界问题才缓解。这让我明白了一个道理技能边界应该对齐用户意图的自然分类而不是对齐后端的接口归类。后端的接口可以复用前端的技能分类要服务模型的理解。还有一个值得分享的坑是测试用例不可能覆盖所有自然语言表达。我最初给技能配的测试用例全是标准句式比如我要退款查一下订单根本没覆盖口语化变体比如我那个东西不想买了能退不。后来我专门花了几天时间把客服对话历史里的真实语句抓出来做成测试集每条语句标出应该命中哪个技能再拿这套测试集去回归每一个技能。这一步让技能描述的迭代有了数据支撑不再靠感觉修改。4.4 我总结的注意事项如果你也要往这个方向做我基于这个项目的教训提几个具体的注意事项。第一技能的 description 最好先写反例再写正例。模型对不该做什么的敏感度其实比该做什么更高反例能有效减少误调用。第二技能执行的返回消息必须面向模型设计而不是面向用户。比如执行体返回refund: created, idREF20240101让它能被模型直接转述或指引下一步而不是返回退款申请已创建业务编号是 REF20240101请保存。前者可以继续触发下一个技能动作后者只能让模型读给人听。第三技能日志和链路追踪要提前设计好。技能化之后一次用户请求往往横跨多个技能调用如果日志不带上 request_id 和技能调用序列排查问题会极其痛苦。5. 技能化之后的下一步从技能到生态5.1 技能的版本管理和质量评测当技能数量超过一百个就不能再把技能当静态配置文件对待了版本管理和质量评测必须提上日程。版本管理方面我目前采用的方式是每个技能目录里放一个 CHANGELOG.md记录每次变更和原因registry.json 里记录当前版本号loader 加载时校验版本索引。一旦某个技能被多个 Agent 使用新版本必须先灰度发布到测试环境由自动化测试集跑完回归才能上线。这个流程听起来像传统软件工程但干过的人都知道没有这套流程技能改崩了一个线上 Agent 的排查成本会让人崩溃。质量评测方面我建议建立两个级别的指标。一级是技能级正确率给定 N 条测试语料模型能否选对技能、执行体能否成功完成任务、返回消息格式是否规范。二级是端到端任务成功率模拟完整对话流程看用户从一个具体场景出发到目标达成中间是否顺畅、是否需要大量澄清。这两个指标分开统计非常有价值因为前者能定位到具体技能的问题后者能反映技能之间协作质量。5.2 跨 Agent 共享技能技能化一个很大的红利是可以跨 Agent 复用。同一个企业内部通常有客服 Agent、数据分析 Agent、办公助手 Agent、工单处理 Agent如果每个 Agent 各自实现一套技能量和维护成本都惊人。更合理的做法是建立一个公共技能仓库Agent 按需注册自己需要的技能子集。在这样架构下一个技能的所有权归属和使用方必须分离。技能可以有 owner负责维护执行体和接口质量其他 Agent 通过只读方式引用不能私自修改。接口变更时所有注册了该技能的 Agent 都要做回归测试。我当时用了一个简单的 skill dependency graph每次技能版本更新自动生成一份引用清单发给受影响项目的负责人。这种工程上的严谨程度决定了一个技能生态能不能长久运转。5.3 我个人的一点实操体会最后说说我自己的感受。很多人看到 agent-skills 会先考虑用什么框架、什么模型但我认为顺序应该反过来先想清楚你的业务中哪些能力是稳定的、可以固化的再把这些能力封装成技能。模型的迭代速度很快但技能资产是可以沉淀的。业务规则、接口契约、异常处理、权限管控这些内容都藏在技能层即使底层模型换了一家整个系统依然能稳住。技能也不是一次就能做完善的。我过后回看最初版本的技能描述会发现很多描述写得太晦涩、太追求完整反而让模型抓不住重点。后来我遵循了一条简单原则把一个技能描述想象成你发给同事的一条微信消息你需要他在三秒钟内知道你想让他做什么、什么情况不要做。这种直觉比任何格式规范都更可靠。希望这篇内容能帮你少走一些弯路。如果你也正在搭建自己的技能体系欢迎把你在技能边界划分或路由选择上的心得发出来交流有时候同样的坑第二个人踩的时间可以缩短很多。
阅读完成 · 觉得有帮助?