
标题“agent-skills”给的信息量很少但恰恰是当下AI Agent落地时最绕不开的一个话题。我在实际做Agent应用时最大的感受是模型能力已经不再是瓶颈真正卡住项目进度的往往是“怎么把能力稳定、可复用、可维护地交到Agent手里”。技能系统skills就是为解决这个问题而生的。这篇就围绕agent-skills聊清楚它到底是什么、怎么设计、怎么避免踩坑。1. 为什么Agent需要一套独立于提示词之外的技能体系先从一个很常见的现象说起。很多人第一次做Agent应用是在系统提示词里把功能说明写清楚比如“你可以调用天气查询接口参数是city和date返回JSON格式”。模型大部分情况下确实能听懂但效果很不稳定——同样的描述换个模型版本、换种问法结果就可能走样。我自己接过一个项目客户要求Agent在对话中实时查订单、改订单、催发货最初版本就是靠提示词堆功能结果上线没多久就频繁出现“工具参数传错”“明明该调改单接口却去查单”之类的问题。这个阶段最缺的其实不是更强的Prompt技巧而是一套把能力封装成“结构化技能”的机制。所谓agent-skills本质上是把“模型需要调用的外部能力”从自然语言描述里抽离出来变成一组有固定Schema、有明确触发条件、有可观测执行过程的能力单元。Agent不再“猜”怎么用能力而是“查”技能库、“选”最匹配的技能、“按”既定协议执行。另一个推动技能体系出现的现实原因是复用。同一个业务场景里查库存、算运费、下单这类操作往往会在多个Agent里反复出现。把它们写死在各自提示词里等于每次都在复制粘贴改一个逻辑就得全量同步。技能化之后这些能力是独立注册、独立升级的A应用和B应用共用同一套技能改动一次全部生效——这是技能体系最朴素也是最刚性的收益。还要提一点容易被忽略的可观测性。提示词里的能力调用过程基本是个黑盒出了问题只能靠日志猜。而技能系统在运行时可以做统一拦截——记录触发了哪个技能、传了什么参数、返回了什么结果、耗时多少。这些数据一旦汇集成面板Agent的每次行为都有据可查。我在后面会展开讲这块的设计这里想先强调一件事技能系统不是给Agent“加功能”是给Agent“建规则”。2. 技能系统的核心架构从注册到执行的完整链路2.1 技能注册与元数据设计任何技能要想被Agent稳定使用第一步是“注册”。注册的本质是把技能的外壳信息告诉Agent这个技能叫什么、是干什么的、什么时候该用、需要哪些参数、执行完返回什么。这些信息合在一起就是技能的元数据Metadata。以一个“查订单状态”技能为例元数据大致长这样技能名称nameorder.query_status描述description根据订单ID查询订单的当前状态支持状态包括待支付、已支付、配送中、已完成、已取消触发条件triggers当用户询问订单进度、物流状态、是否发货时优先匹配该技能参数Schemaorder_idstring必填订单编号、include_historyboolean选填是否返回状态变更记录输出Schemastatus字段、recent_event字段、last_update_time字段这套元数据里描述description的质量直接决定技能被正确触发的概率。我给团队的内部要求是描述里必须写明“这个技能解决什么问题”“哪些情况不该用它”“参数的单位和格式”。比如“查订单状态”的描述里如果只写“查询订单”模型很可能把“查物流轨迹”也归类进来导致返回数据对不上。更稳的写法是同时写正面和反面的触发条件——这算是技能描述设计里的一个实战要点。2.2 技能注册中心与动态路由技能多了以后光有注册还不够得有一个地方统一管理所有技能这就是技能注册中心。注册中心做的事情类似“能力目录”记录当前Agent可用的全部技能清单、各技能的启用状态、版本号、所属模块、依赖关系。路由层则是另一件事。Agent接收到用户意图后会先做一次“意图到技能的匹配”。两种主流做法一种是让模型自己根据技能描述做选择语义路由另一种是按规则做硬路由比如用户消息里出现“订单号”就强制走订单类技能。实际项目中我推荐混合路由——先用规则过滤明显不该用的技能缩小候选集再让模型做最终决策。这样既减少模型“眼花”选错技能的概率也能降低传入模型的技能Schema数量省Token。路由还有一个容易忽略的细节技能优先级。有些技能天生应该先执行比如“用户身份校验”必须在查单、改单之前跑。注册中心里可以做依赖声明声明“order.query_status依赖user.verify_identity”路由层在调度时会自动把依赖技能排队在前面。2.3 执行引擎与上下文注入技能注册与路由之后真正干活的是执行引擎。执行引擎负责把Agent侧传来的参数做校验类型对不对、必填项齐不齐、调用对应的业务接口、把返回结果按输出Schema整理、然后注入回当前对话上下文。上下文注入这块是我在实践中花最多时间调优的地方。返回结果给多了模型容易被无关字段干扰给少了模型又没法回答用户追问。一个可行的做法是分层输出技能返回结果分成“核心字段”和“扩展字段”默认只把核心字段注入上下文只有模型判定用户需要深挖时才触发扩展查询。和“先给结论、再给明细”的信息呈现逻辑一致Agent对话也会干净很多。执行引擎同时要管好异常。接口超时、返回空数据、参数非法这些情况不能粗暴地当成“查询失败”丢给模型而是应该在返回结构里带上错误码和可读的错误消息让模型能够向用户解释清楚发生了什么、以及下一步可以做什么。等级化的错误反馈直接决定Agent在异常场景下是否像个“正常人”。3. 技能和工具Tools到底有什么区别边界划分与协作方式很多人会问agent-skills和OpenAI Function Calling那一套工具Tools有什么区别这个问题的答案本质上关系到技能系统的设计边界。工具Tools是函数级的抽象很贴近OpenAI的工具调用范式模型根据函数声明生成结构化参数应用层执行函数并返回结果。它是“一个动作”——比如“调用get_weather(city)”。而技能Skills是任务级的抽象它可以包含多个动作、多步决策、甚至嵌套其他技能。举个例子“查订单一键催发货”这个技能内部可能是校验用户身份技能A- 查询订单状态技能B- 若状态为配送中则调用物流接口工具C- 组合消息回复。对Agent来说它只需要说“我要用催发货技能”至于里面调了哪些工具由技能编排层去处理。这里就引出一个边界划分的实用原则单一动作、无内部状态的东西做成工具涉及多步逻辑、会组合判断的东西做成技能。我维护过一个电商售后Agent最初把所有接口都平铺成工具模型一次要“看”二十多个函数声明决策准确率能到八成但反复调试成本很高。后来把“退款申请”“换货登记”“催发货”这类组合逻辑封成技能单个技能内部再挂多个工具模型面对的选择面瞬间变小准确率和响应速度同步改善。技能和工具的协作方式也直接影响系统的扩展性。技能内部可以自由调用工具还可以代理给另一个技能这种“技能嵌套”让复用真正发生。比如“订单查询技能”和“库存查询技能”都是基础能力“推荐补货技能”则可以同时依赖这两者——先查销量再查库存最后给出补货建议。技能的编写从“指令编码”变成了“能力组装”这是量变到质变的区别。在设计边界时还有一条经验不要把业务规则写进工具层。比如“超过7天不可无理由退货”这条规则放在工具逻辑里每改一次都要发布一次代码放在技能编排层通过配置规则引擎来控制就能做到不发布代码、只改配置。把规则上移让技能系统更灵活、更贴近业务变化。4. 从零实现一个可扩展的技能库Schema、路由与运行时的工程细节讲完架构概念落到工程实现。这里给一套我实践下来比较稳定、可扩展的实现路径适用于绝大多数对话类Agent应用。4.1 定义技能Schema一份技能一份契约首先为每个技能定义一份JSON Schema既用来校验参数也作为注册中心的登记内容。建议使用类似OpenAPI风格的Schema便于后续扩展成HTTP接口文档。下面是一个简化的“查订单状态”技能Schema例子{ name: order.query_status, description: 查询订单当前状态。仅用于查询不执行任何修改操作。当用户询问发货、物流、签收进度时也可使用。若用户要求修改订单请勿使用本技能。, input_schema: { type: object, properties: { order_id: { type: string, description: 订单编号格式如ORD20250101XXX }, include_history: { type: boolean, description: 是否返回状态变更记录默认false } }, required: [order_id] }, output_schema: { type: object, properties: { status: { type: string }, recent_event: { type: string }, last_update_time: { type: string } } } }每个技能一个文件放在统一目录注册中心启动时扫描该目录完成加载。以后新增技能就是新增一个文件不需要改主程序代码。4.2 技能匹配路由的实现策略路由层是Agent“选择障碍”的关键。实际工程中我推荐三步走候选过滤基于用户消息中的实体词、触发词用规则先剔除完全无关的技能。比如消息里没有订单号相关主题就不进入订单类技能候选。语义打分把候选技能的描述和用户意图做向量匹配或交由模型打分选出Top N。最终决策把Top N技能的Schema拼进最终提示词让模型选出最合适的那个并生成参数。这个三步策略的好处是既能利用规则的高确定性又能保留模型语义理解的灵活性。对于技能数量超过50个的Agent这一步几乎是必须的——否则光是把所有技能Schema塞进模型上下文中已被占掉不少且选择准确率也会下降。4.3 执行与观测做好日志、追踪与护栏技能执行时至少做四件事参数校验拦截在调用业务接口之前先按input_schema校验失败直接返回错误码不触碰底层接口保证安全。统一拦截器记录每次技能执行的入参、出参、耗时、模型决策轨迹方便回放调试。护栏策略在执行层设置“危险操作二次确认”机制。凡是涉及修改、删除、支付的技能执行前必须经过用户明确确认或预先配置的审批流。熔断与降级某个技能连续失败时自动熔断路由层暂时将其移出候选集避免Agent反复调用出错技能造成体验恶化。这些工程细节看似琐碎但恰恰是技能系统从“demo可用”走向“生产可用”的分水岭。5. 实战验证用技能系统改造一个售后客服Agent的全过程空谈架构不好消化我拿一个实际案例过一遍。当时我们要把一个售后客服Agent从“提示词堆功能”升级到“技能系统驱动”目标是让“查单、催发货、申请退款”三个高频场景稳定可用。5.1 问题复盘与改造目标旧版Agent的问题很典型用户问“我的快递到哪了”模型有时调用“查订单”有时调用“查物流”返回信息对不上用户说“我不想要了”模型会直接触达“申请退款”接口但缺少风险判断退错单的事发生过新增业务规则时需要改提示词再评测一个改动要花两天。改造目标很明确把三个高频场景封装成“order.query_status”“order.expedite_delivery”“after_sale.apply_refund”三个技能并纳入路由与护栏体系。5.2 技能拆分与编排设计改造中重点设计了技能之间的关系。以“催发货”为例它在内部编排了三个子步骤user.verify_identity校验用户身份防止越权操作他人订单order.query_status先查订单是否处于“已支付待发货”状态如果不是直接返回原因终止技能避免无效催单order.expedite_delivery校验通过后才真正发起催发货动作。这种编排把“应当满足的条件”前置到流程里而不是依赖模型自觉。模型在整个过程中只负责“判断用户意图并选择一个入口技能”细节执行完全由技能内部完成。这样做的另外一个附带好处是同一套编排可以被“查订单”技能的会话复用不用为每个意图重写一遍业务逻辑。5.3 评测数据集与回归保护技能系统改造完成后必须建立回归评测机制。我们为每个技能准备了一个评测集每个技能至少20条典型用户问法外加10条边界问法。比如对“申请退款”技能用例覆盖正常申请用户明确说“我要退款”多轮隐含意图用户先说“这个商品不合适”再问“能不能退”条件不满足订单已超过七天、订单已签收危险前置用户身份校验不通过。每次修改技能描述或编排逻辑就跑一遍全量评测集检查技能触发准确率、参数生成正确率、安全拦截成功率三项指标。回归测试从制度上保证了技能系统可以持续迭代而不担心改一处坏一片。6. 技能系统迭代中的常见坑上下文污染、技能冲突与冷启动问题技能系统跑起来之后新的问题也会随之出现。这里列几个实践中非常容易踩的坑以及对应的处理思路。6.1 上下文污染技能返回结果模板化技能执行后返回的信息会注入上下文但如果返回格式不稳定模型会“学坏”。比如查询接口返回的recent_event里包含了内部错误日志的片段模型可能引用这些日志当作“订单动态”反馈给用户非常尴尬。应对办法是技能输出层做强制模板化所有注入上下文的字段都是面向用户的可读文本内部日志绝不进入上下文。另外一个上下文污染场景是技能编排过程中的中间变量。编排层在执行“催发货”时内部查询接口会暴露库存字段、内部供应商ID等这些字段一旦被注入模型上下文模型反而可能生成让用户困惑的说法。中间变量和最终话术必须分两个通道中间变量只用于程序逻辑不进模型上下文。6.2 技能冲突候选技能描述相似导致误触发技能多了以后描述很容易写得“看起来差不多”比如“查订单状态”和“查物流轨迹”。模型在语义路由时很可能选错。最直接的解决办法有两种一是描述差异化在描述里明确写出“本技能不处理什么”。比如“查订单状态”里写“不返回物流轨迹物流轨迹请用logistics.track”“查物流轨迹”里写“不处理订单金额、退款等订单维度信息”。这种“互斥描述”能让模型更容易做排除。二是路由层加硬规则。比如用户消息里出现“快递”“包裹”“运单号”字样时强制优先匹配物流类技能出现“订单号”“退款”时优先匹配订单类技能。规则优先模型兜底两者结合效果远好于单一策略。6.3 冷启动问题新技能没有“案例数据”新注册的技能即使描述写得再好模型也可能因为没见过实际调用案例而不敢使用。这也是技能系统冷启动阶段最常见的问题。缓解办法有两个。第一在技能描述里附加一个“example_query”字段给模型一两个真实的用户问法示例让模型更快建立“什么情况该用我”的认知。第二初期人工强制路由一段时间。也就是新技能上线的头两周运营或开发人员手动把相关用户问题分配到新技能上积累一批真实调用数据再用这些数据优化描述。这种做法虽然“土”但比任何提示词技巧都有效。6.4 技能膨胀数量失控后维护成本飙升一个Agent的技能数量超过一百个维护难度会指数级上升。技能之间互相依赖、描述交叉、触发条件重叠都会变成日常负担。我见过一个项目半年时间技能堆到两百多个最后连负责人自己都说不清某个技能会不会被另一个技能覆盖。技能不是越多越好。实际管理时可以引入层级分类把同类技能收到一个“技能域”下并在路由层做域级过滤。例如“物流域”下面再挂多个物流子技能。还可以定期做技能健康度复盘统计哪些技能从未被触发、哪些技能高频出错考虑下架或合并。技能库的可持续性靠的是持续治理而不是一次性设计。7. 技能评测与安全护栏如何保证Agent能力“敢上线”最后聊一个在所有工程细节之上更重要的层面——评测与安全。没有这两层前面做的都只是“看起来能用”而已。技能评测不能只看“功能正常”我建议至少从四个维度打分触发准确率应当触发某技能时系统是否选对了技能不应当触发时是否没有被误选。漏触发和误触发都要统计。参数正确率模型生成的关键参数是否正确、完整比如订单号、金额、数量。编排成功率多步技能内部是否按预期顺序执行中途是否有步骤失败。安全拦截率涉及修改、删除、支付等高危技能时拦截机制是否在必须有用户确认的位置生效。这四个指标应该在每次技能变更后都跑一遍。可以做成一个简单的评测脚本自动跑评测集、自动汇总指标变更合入前必须达到阈值低于阈值就阻止发布。这比靠人肉回归可靠得多。安全护栏这块在前面也提过总结成三条硬性要求高危技能必须二次确认身份校验类技能必须是前置依赖执行引擎端必须有独立于模型的参数校验不能盲目信任模型生成的参数。安全不能只靠模型“懂规矩”必须由工程机制兜底。我把这三条写进团队的技术规范里每条都是踩过坑之后沉淀下来的。另外每次上线新技能都建议先灰度只放开给一小部分用户。技能冷启动阶段的表现和稳定期差异很大灰度期间密切看触发准确率和用户反馈有问题能快速回滚到上一个大版本。灰度体系对于“技能系统敢不敢上线”这个问题给出了最稳妥的答案。我在实际项目中越来越意识到一件事agent-skills的成败归根结底不在模型的聪明程度而在于我们把多少“确定性”注入到系统里。技能描述、路由规则、Schema校验、执行日志、评测护栏——每一层都在帮模型降低决策难度也在帮系统降低失控风险。如果你也在做Agent应用建议从最简单的两个技能开始先把注册、路由、执行、观测这条链路跑通再逐步扩容。跑通一次之后你对技能系统的理解会完全不同。