
干Agent开发这一年多我有一个越来越强烈的感受很多项目卡住不是模型不够聪明而是“技能”这两个字没想清楚。你让大模型直接去完成一个复杂任务它大概率会一本正经地胡编但你给它一组结构清晰、描述精准、边界明确的技能它就能像熟练工一样按步骤把事情办妥。这就是我今天想聊的agent-skills——把Agent从“能聊天”推到“能干活”的那一层工程化能力体系。这篇文章适合正在做Agent应用、写工具调用、搭自动化流程的开发者也适合刚入门想搞明白“为什么我的Agent总掉链子”的朋友。我会把技能拆解、描述编写、调用编排、质量测试、常见坑一次性讲透。1. 为什么我说“技能”才是Agent真正能落地的关键1.1 没有技能体系的Agent像什么先说个反例。早期我做客服机器人直接把知识库文档灌给模型然后让它“根据文档回答用户问题”。表面看没问题但实际效果惨不忍睹用户问退款流程模型把物流政策背了一遍用户问发票抬头怎么改模型开始科普订单状态。不是模型笨是它面对一个模糊指令时只能凭训练数据里的“大概印象”发挥根本没有一个可以精确执行的动作入口。后来我把每个业务动作做成独立技能——查订单、查物流、发起退款、修改发票——每个技能有名字、有参数、有触发条件。模型再去回复用户时就不是“凭空组织语言”而是“先选技能再根据技能返回的结构化结果组织语言”。这个转变带来的效果是质变级的回答准确率从七成提到九成五以上而且每个动作可追溯、可测试、可回滚。这就是技能体系的第一个价值把不可控的“自由发挥”变成可控的“按单执行”。1.2 技能化的三个核心收益第一个收益是可复用。同一个“查库存”技能电商场景能用仓储场景能用售后场景也能用。技能一旦沉淀就变成团队的公共资产新项目直接复用不用每次从头写Prompt、写工具。第二个收益是可评估。你没法给一次自由对话打分但你可以给“查订单技能在500条测试数据上的准确率”打分。技能是独立的、有输入输出边界的模块这意味着每个技能都能单独测试、单独优化、单独发版。这是Agent工程质量控制的基本单元。第三个收益是可组合。单个技能能力有限但技能之间的排列组合能覆盖复杂场景。比如“退货”这个上层任务可以拆成“校验订单状态→生成退货单→推送仓库→通知用户”四个技能串联。大模型不需要重新发明流程它只需要做“路由”根据当前状态决定下一个调用哪个技能。我个人体会是凡是Agent项目做到后期开始失控的几乎都是因为技能边界模糊、调用关系混乱。技能体系不是锦上添花是Agent从demo走向生产的必经之路。2. 技能拆解怎么把业务任务切成可复用的技能模块2.1 拆到多细才算合适这是所有人第一个卡住的问题技能粒度到底怎么定拆太粗技能内部还是要塞一堆逻辑大模型照样蒙圈拆太细技能数量爆炸模型在几百个技能里选一个命中率也会下降。我现在的原则是两条。第一一个技能只干一件完整的事。所谓“完整的事”是指这件事有明确的输入、明确的输出、明确的成功/失败标准。比如“查订单”输出订单状态和商品列表输入只有订单号这就是完整的一件小事。第二上面永远有一层组合层。技能只管原子操作复杂流程交给上层编排。比如“退货退款”不是技能是流程“创建退货单”才是技能。流程可以被多个场景复用但技能只做最底层的确定性操作。粒度判断有个实用方法如果你发现自己给技能描述写了三大段才说清楚它干什么那它大概率太粗了如果技能参数超过六个那它大概率太细了。中间那个“三句话能说清、参数三到五个”的粒度基本合适。2.2 技能描述怎么写模型才愿意选技能描述是很多人忽略的细节但它直接决定模型会不会选对技能。描述不是给人看的是给模型看的所以要按模型的理解方式写。我自己总结下来好的技能描述必须具备四要素技能职责、适用场景、边界条件、返回内容。看两个例子对比差描述“处理订单。”——太模糊模型不知道什么时候该用它。好描述“根据订单号查询订单的当前状态、商品明细、金额及物流信息。适用于用户询问订单进度、催发货、核对商品时。仅支持查询不支持修改订单。返回结构化订单信息。”好描述的核心逻辑是告诉模型这个技能的“触发时机”和“不触发时机”。模型做技能选择时本质是在做文本匹配你的描述里如果有和用户意图高重叠的词“查询”“物流”“订单”它命中率就会高。2.3 一份可以直接套用的技能定义模板下面是我们项目里实际在用的技能定义结构用YAML写方便存入技能库统一管理name: query_order description: 根据订单号查询订单状态、商品明细、金额及物流信息。 当用户询问订单进度、催发货、核对商品内容时使用。 仅支持查询不支持修改订单数据和状态。 version: 1.2.0 input_schema: type: object properties: order_id: type: string description: 用户提供的订单号格式如DD20250101。 required: - order_id output_schema: type: object properties: order_status: type: string description: 订单当前状态枚举pending/shipped/completed/refunded items: type: array description: 商品明细列表 total_amount: type: number description: 订单总金额元 logistics: type: object description: 物流信息包含承运商和单号 error_handling: order_not_found: 返回错误码404提示“订单不存在请核对订单号” timeout: 请求超时则返回错误码504提示“系统繁忙请稍后重试”这个模板里有两个容易被忽视的细节。一个是description里写了“仅支持查询不支持修改”这叫负向声明能有效防止模型在用户说“帮我改订单”时错误调用查询技能。另一个是error_handling把每个技能可能出现的异常和对应话术提前定义好这样模型在技能失败时不会自己瞎编。3. 技能调用与编排让大模型选得对、串得顺3.1 意图路由从“大海捞针”到“命中目标”技能库建好之后下一个问题就是模型到了现场怎么知道该调用哪个技能大型语言模型的本质是文本生成模型让它直接输出一个技能名本质上是在做“给定用户问题和技能描述评估相似度”的事。技能描述写得清楚这事就成功八成了。但如果技能库有几十上百个技能光靠描述匹配会开始不稳定。这时候我建议在技能选择环节加一道“预筛”用传统的文本检索或者轻量向量检索先把候选技能从100个缩到5个再让大模型在这5个里面做精细选择。这一步能大幅降低干扰。这个设计背后的逻辑是大模型擅长比较不擅长检索。让它从100个选项里硬选它的注意力会被无关技能的描述干扰但你给它两三个高度相关的选项它能判断得很准。这其实是把“模型擅长的事”和“传统程序擅长的事”做了分工。3.2 技能之间的数据契约技能编排最容易被忽视的问题是数据传递。技能A的输出要作为技能B的输入如果两边的数据格式对不上整个流程就会断掉。代码里这叫“接口”在Agent里我习惯叫它“数据契约”。举个例子“生成退货单”技能输出的是return_id而“推送仓库”技能要求输入refund_id同一个东西两个名字模型在串联时就得自己猜一猜就容易错。我的经验是全局统一名词和格式形成一份数据字典。订单字段就叫order_id退货字段就叫return_id所有技能共用这个字典不允许各自发明别名。另外技能之间的数据传递建议采用“管道式”上一个技能输出的JSON直接作为下一个技能的输入上下文不做中间自然语言转换。很多人图省事让模型把结果“用一句话告诉下一个技能”这就是在给错误埋雷——自然语言一转结构化信息就丢了模型再理解一次误差就出现了。3.3 兜底与降级模型乱调技能的时候怎么办技能编排上线后一定会遇到一个问题模型在多个技能之间跳来跳去甚至调用了明显不合理的技能。比如订单已发货它还去调“创建退货单”。这不算模型“傻”而是它缺少状态感知。我的解决思路是三层兜底第一层在技能描述里写明前置条件比如“仅当订单状态为已完成时允许创建退货单”第二层在编排层加状态机校验技能A返回的状态是 “shipped”系统直接拦截“创建退货单”的调用并返回提示第三层全局兜底话术——当模型连续两次调用被拦截或选择了技能但执行失败就切换到处理不了的人工转接话术。这套三级兜底框架我用了很久非常稳。核心思想是不要把决策权全部交给模型确定性强的规则放在代码层卡死模型只负责做模糊判断不负责做规则判断。4. 技术选型自研技能协议还是抱现成框架4.1 主流实现路线对比现在市面上的Agent工具越来越多了有偏框架的有偏平台的。我做技能体系时把主流路线都试了一圈简单说一下对比和选择逻辑。路线代表形态优点缺点模型原生Function CallingOpenAI/Claude等接口自带的工具调用接入快模型对格式理解好技能管理弱多技能时逻辑容易乱专用Agent框架各类开源Agent开发框架配置化程度高自带编排和记忆学习和改造成本高项目大了受框架约束自研技能协议自定义YAML/JSON 调用的中间层完全可控贴合业务初期的设计成本高需要自己踩坑我不反对直接用现成框架但如果你遇到下面的情况我建议直接自研第一你的技能数量会超过20个第二你有复杂的编排逻辑和多层校验第三你需要对每一个技能做精细的版本管理。框架能给的是通用能力你要的是业务控制。4.2 自研协议时的关键字段设计自研技能协议我建议在之前那份YAML模板的基础上再补几个关键字段routing_keywords路由关键词一组和用户意图高度相关的词比如“催发货”“快递到哪了”。这个字段在预筛阶段用能大幅提升匹配速度。required_context前置上下文技能执行前必须存在的上下文变量比如“user_id”“order_id”缺失时先触发上下文收集技能。can_fallback_to可降级技能当本技能失败时可以尝试调用的备选技能比如“查订单失败→查本地缓存订单快照”。timeout_ms超时时间每个技能的期望时长。这个字段表面上没用实际很重要——技能卡住时系统能不能快速做出超时处理就看这个参数。这些字段设计不是凭空想的都是我在实际项目里遇到问题后才补上的。比如can_fallback_to就是因为在一次促销活动中用户量暴增导致订单系统查询超时模型只能干等后来加了降级路径才解决问题。4.3 技能多了以后库存怎么管技能数量多了管理本身就是技术活。三个建议一是目录化组织。技能按功能域分目录比如order/、logistics/、payment/发热加载时只加载当前场景命中的目录不用全量塞给模型。这能显著减少模型的选择干扰也能降低token消耗。二是统一注册中心。每个技能在注册时登记名字、版本、描述、依赖关系系统维护一张技能清单。用的时候不管底层实现是Python函数、HTTP接口还是写死的规则上层暴露的都是同一套技能协议。三是技能健康度监控。每个技能记录调用次数、成功率、平均耗时。一个月跑下来成功率低于九成的技能要单独拿出来复盘。这一步看着繁琐但它是保证技能体系长期稳定性的关键。5. 技能质量评测集、回归测试与灰度发布5.1 技能评测集怎么搭才不流于形式很多人测试技能就是拿几条数据跑一下看看返回对不对这就够了。但真正上线后你会发现技能回归是常态不是例外。每次改技能不管改的是描述还是底层逻辑都可能影响其他技能的调用效果。所以我强烈建议搭一套技能评测集结构是“意图→技能→参数→期望结果”。比如{ case_id: case_001, user_query: 我的订单DD20250101到哪里了, expected_skill: query_order, expected_params: {order_id: DD20250101}, expected_output: {order_status: shipped, tracking_number: SF123456} }每个技能至少保证50条测试样本覆盖正常请求、边界参数、异常输入三类。正常请求看命中率和参数提取准确率边界参数看模型会不会把缺参数当成乱码异常输入看技能会不会被并不匹配的话触发。这其实是把软件工程里的测试方法论搬到Agent场景来用。我一直在用的做法是把评测集和代码仓库放在一起每次技能更新跑一遍全量回归成功率下降超过2个百分点就不允许合并。听上去严格但救过我很多次。5.2 灰度发布与版本回滚技能发版是最容易出事故的环节。一个技能改了描述可能让原本选对技能的请求选错了一个技能底层接口换了可能让几十个依赖它的流程全部报错。我的做法是技能格式兼容优先新旧版本并存。灰度发布时把新版本技能标记为“候选”系统只让5%的流量走新版本观察一天如果没有异常再逐步放量到50%、100%。全程不用重新部署系统只改技能库的版本标记就行。如果灰度中发现异常直接一键把版本标记回滚到上一个稳定版本。因为技能协议层做了兼容回滚不会引发系统级问题。6. 踩坑实录我遇到的几个典型问题6.1 问题速查表问题现象根因解决办法模型反复选错技能用户问物流模型调用退款技能技能描述缺少负向声明且路由关键词不全在描述中补充“不适用场景”扩充路由关键词参数总提取不全用户说“帮我查一下那个黑色的订单”参数缺失模型在用自己的想象补全增加参数缺失追问技能而不是放大模型生成技能串联时字段对不上A输出order_idB要求输入order_no数据字典不统一全局统一字段命名建立数据契约修改一个技能导致其他技能失准改了支付技能退款技能开始乱选技能之间存在隐式关系但未做关联校验建立技能依赖图改任何一个技能跑全量回归多人协作时技能重复两个组各建了一个“查库存”没有统一的技能注册中心技能注册时先查重统一目录管理模型在几个技能间跳来跳去用户问一句话模型连续调了三个技能才回答技能粒度太细缺少上层流程编排增加流程层把组合操作封装成组合技能6.2 两个亲测有效的调试技巧第一个技巧是“写日志比通灵有效”。技能被调用时把“用户原文、技能命中结果、参数提取结果、执行结果”全部结构化记录下来。出问题时翻日志一分钟就能定位是哪一步出了问题。不要靠肉眼去看模型在对话窗口里输出了什么那个是表象。第二个技巧是“用系统prompt约束行为边界”。我会在系统提示词的末尾固定加一段你是任务执行器不是对话机器人所有回答必须以技能调用结果为依据禁止编造未返回的信息。这一句话能解决大量“一本正经胡说八道”的问题成本几乎为零但很多人从来没用过。我做agent-skills这几个月最深的体会是让大模型稳定干活从来不是靠“骂它”或者“换一个大模型”就能解决的而是在模型外面搭一套高度确定性的工程框架。你给的确定性越多模型发挥的失误就越少。技能库、评测集、路由规则、降级策略每加一层系统的稳定性和可控性就上一个台阶。这套方法论放到任何一个Agent项目里都通用我现在接手新项目的第一件事永远是先盘一遍技能清单而不是先改模型参数。