
看到“agent-skills”这个项目标题我的第一反应是这名字取得挺克制没有加什么“超级”“智能”“大脑”之类的花哨前缀但它其实碰的是AI Agent开发里最要命的那一环怎么让大模型不只是会聊而是能干实事。这段时间我一直在折腾Agent相关的工程化落地试过把各种功能堆进系统提示词里也试过给模型挂一堆乱七八糟的工具函数最后都卡在同一个问题上——模型要么不知道在什么场景该调用什么能力要么调用的时候参数传得七零八落。后来转到“技能”这个思路上把能力封装成结构化的技能单元整个系统才慢慢顺起来。这篇不聊华丽的架构也不画高大上的框图就单纯把这套基于技能的Agent构建思路掰开揉碎讲讲为什么要用技能抽象技能怎么定义才能让模型准确理解以及调度和编排环节有哪些坑是只有实际操作过才能发现的。1. 内容整体设计与思路拆解1.1 Agent开发的第一性问题模型不是不会做是不知道有什么可做很多刚接触Agent的人会有一个误区觉得给大模型挂上工具调用能力它就像加了buff一样什么都能干。但实际上大模型本身不具备“发现工具”的能力它只能根据你提供给它的描述和参数规范来决定要不要调用某个函数。这里有个特别容易被忽视的细节系统的提示词空间是有限的。你不可能把一百个工具的说明全部塞进上下文就算塞得进去模型在长长的清单里选择正确工具的概率也会急剧下降。这就是为什么“技能”这个概念会变得至关重要——它本质上是在模型和外部能力之间建立了一层结构化的中间表示。举个例子你做一个电商客服Agent。如果直接把查订单、开发票、修改地址、申请退款这四个能力悬空交给模型它可能会在处理退款请求时错误地先调用开发票因为两者描述里都有“订单”这个关键词。但如果把这四个能力封装成四个技能每个技能有明确的触发条件、输入参数和输出格式模型在决策时的误判率就会明显降低。技能抽象带来另一个隐藏的好处它把“做什么”和“怎么做”彻底分开了。复杂业务逻辑里的状态管理、多轮信息确认、异常重试这些都可以下沉到技能内部去处理模型只负责基于用户意图选对技能然后把参数填对。这样一来Agent更像是一个调度中枢真正的领域能力全部内聚在技能单元里后续迭代升级也有了清晰的边界。1.2 方案选型为什么把能力收敛为技能而不是靠模型自由发挥我早期做过一个实验让模型直接操作数据库查询工具希望通过自然语言自由发挥达到目的。结果发现当查询需求稍微复杂一点比如“查一下上个月销量最高的三个SKU在华东区的退货率”模型生成的SQL不是语法错误就是逻辑漏掉了“上个月”这个时间窗口。问题不在于模型的生成能力而在于自由发挥的代价太高。数据库字段、业务口径、权限边界这些信息模型根本不知道它只能靠猜。与其让模型猜不如把这类高频操作固化成技能比如说“销售退货统计”技能把时间范围、区域、商品维度都定义成可传参数任何上层需求先经过意图识别命中“销售统计”这个意图后就交给技能去执行。这个选择背后的核心逻辑是在Agent架构里模型负责“决策”技能负责“执行”决策要快要准要轻量执行要稳要可控要可审计。如果让模型既做决策又做执行等于是一个人既要当裁判又要下场踢球出错的概率自然就上来了。还有一个从工程角度考虑的选型原因——可观测性。当所有能力都收敛成技能Agent的每一次调用就变成了输入了哪个技能、传了什么参数、返回了什么结果、耗了多少时间。这些数据可以用来做系统的持续优化比如哪些技能经常被误触发哪些技能的描述需要改写哪些场景缺失了技能覆盖。没有技能的Agent黑盒调用很难沉淀这样的优化数据。2. 核心细节解析与实操要点2.1 技能设计的三个核心要素命名、描述与参数Schema技能的命名和描述直接决定了模型能不能在关键时刻认得出它。我见过不少翻车案例都是因为命名太随意比如有个项目把一个功能命名为fetch_info内部人知道这是获取用户信息但模型看到的是一堆字母根本猜不出用途。命名的黄金法则是让技能名称本身就像一句清楚的意图声明。比如get_order_status就比fetch_info好得多哪怕不去读描述光看名字就能判断它和订单状态相关。描述字段要写清楚“这个技能在什么情况下被调用”写成“当用户查询订单配送进度时使用”比干巴巴写“获取订单状态”更容易被模型理解。参数Schema是更考验功力的部分也是最容易在实操中出问题的地方。每个参数都要考虑三个问题类型是什么必传还是选传枚举值范围是多少。我建议对参数的描述也写得细一点比如时间是number类型必须注明是时间戳还是格式化字符串地址是string类型最好注明支持的省市区格式。之前遇到一个很典型的坑技能接收一个date参数调用方传的是“2024-01-15”但技能内部是用时间戳解析的结果解析出来的时间差了整整一个时区。这种问题靠模型自己纠正是做不到的只能在定义参数时就把格式约定写清楚。技能定义还有一个容易被忽略的点该不该为每个技能单独配置返回值的Schema。如果返回值的结构是固定的、可枚举的尽量定义清楚因为有些模型会在技能返回脏数据时尝试“脑补”结果导致错误信息被当成真实业务数据传给用户。给返回值加上Schema约束等于给模型立了规矩——解析不了就如实返回错误不要自作聪明。2.2 技能描述与系统提示词的关系别在提示词里重复技能内容很多人在写系统提示词时会在里面详细描述一个技能怎么用、什么时候用然后再把技能的完整描述放到工具列表里。这种做法会带来两个问题一是系统提示词会被迅速撑大浪费上下文窗口二是模型在收到重复信息时会搞混优先级反而更容易选错技能。我的经验是系统提示词里只写技能调用的“元规则”比如“处理订单相关问题时优先调用技能不能编造订单状态”具体每个技能是什么、什么时候用全部只放在技能注册表里。让模型自己去查询技能定义而不是把定义背进提示词。这么做还能带来一个额外收益技能可以按需注入。当Agent处理一个售后请求时只需要把售后相关的技能加载进来完全不需要把二十个技能全部挂载上既省token又减少干扰。这个动态加载的思路在技能数量一多之后会非常实用。2.3 从技能到技能的编排多个技能如何组合成完整流程单个技能解决的是单步动作真实业务几乎都是由多个技能按照一定顺序组合完成的。像退货退款流程先要用validate_order验证订单是否满足退货条件再调用calculate_refund_amount计算退款金额最后通过submit_refund_request提交申请。这三个步骤串起来就是一个有状态的流程。实现编排的方式有几种。第一种是纯代码编排在代码里写死调用顺序Agent只负责在每一步选择合适的技能参数。第二种是让模型自己编排把流程的所有技能一次性给到模型让它根据用户对话动态决定调用顺序。第三种是基于意图模板的编排也就是把常用流程做成预设模板模板里定义了技能链路和每个节点的跳转条件。从稳定性的角度我推荐优先用第三种。因为纯代码编排灵活度太低改一个流程要发一次版让模型自由编排中间一旦出现跳步或者错序排查起来又很费劲。模板化编排等于是在灵活和稳定之间取了折中态模板覆盖的常见路径走固定流程模板覆盖不到的边界情况再允许模型动态编排兜底。编排还有一个容易踩的坑技能执行失败之后的恢复策略。假设退货流程已经走到计算退款金额这一步这时候订单服务挂了整个流程是回滚到起点重来还是保留已验证的订单信息、只重试金额计算显然应该是后者但这需要设计编排框架时就得支持节点级的状态缓存。这些细节如果不在初始设计时想清楚碰到线上故障时再改就真被动了牵一发动全身。3. 实操过程与核心环节实现3.1 构建技能注册中心技能清单、版本管理与灰度发布知道技能怎么定义之后接下来要考虑的是技能在哪里“住”。如果只写在代码里那么每次新增技能其实就是一次代码变更测试、上线、回滚都是紧耦合的。我建议搞一个轻量的技能注册中心把技能的元信息、实现接口、所属领域、依赖关系集中管理起来。注册中心里每条技能记录的核心字段包括技能ID、名称、描述、版本号、参数Schema、实现方式、所在服务、超时时间、幂等性标识。版本号特别关键因为技能描述改了之后模型的调用行为会变化如果线上效果开了倒车要能快速切回上一版本。灰度发布也是实际工作中绕不开的环节。大模型的调度结果有一定随机性同一个技能改完描述可能对某些意图的识别更准对另一些反而误召回了。稳妥的做法是新版本技能先在模拟环境里跑一批历史对话数据对比新旧版本的选择准确率准确率没有下降再全量上线。3.2 技能执行器编排、状态管理和异常处理技能注册中心是大脑里的记忆执行器就是手脚。执行器负责解析模型输出里的技能调用指令校验参数分发到对应实现最后把返回值按Schema规范化后回传给模型。执行器里最重要的一块是参数校验。模型传参数时经常会出现类型不对、缺字段、格式串了这类问题千万不能直接把这些脏参数透传到后端服务。正确做法是先按Schema做一次严格校验校验不过就生成一个明确的错误信息返回给模型让它基于错误信息修正参数后重新调用。有序执行多步技能时要用会话ID串起上下文状态。比如用户问完订单状态又追问“那退款大概什么时候到账”模型需要理解“退款”这个话题对应之前订单查询的结果这就要靠会话存储把技能执行的历史结果留存下来给模型做上下文推理用。异常处理方面执行器至少要做两层。第一层是技能内部的重试比如网络抖动、超时这类瞬时故障重试两次基本能恢复正常。第二层是业务层兜底比如技能执行失败且重试无效要返回一个友好错误给用户同时记录日志绝不能让Agent反复拿同一个错误去尝试那样既消耗token又给下游制造垃圾流量。3.3 快问快答式的技能演练实际场景下的流程梳理拿一个最常见的场景来说“用户下单后发现地址错了要修改”。这个场景看似简单实际要串起三个技能。第一步是调用订单识别技能把用户说的“下午刚下的那单”翻译成真实的订单ID。这里有个细节客服场景里用户通常不会准确说出订单号所以得先通过时间、商品、收件人等模糊信息去捞订单捞出来再和用户确认确认通过后才进入下一步。第二步是物流拦截技能修改地址前必须先确认包裹是否已经出库。如果包裹在途直接改地址是改不了的要么拦截转寄要么等签收后再处理这里需要根据物流状态决定走哪条分支。第三步才是地址更新技能在修改地址的同时把变更结果通知到物流侧。整个过程有判断、有分支、有依赖靠单个技能完成不了必须靠编排把三段串起来。而模型在其中的作用是理解用户诉求、提取订单上下文、在关键决策点向用户确认真正的业务控制是技能编排在兜底。这个例子能直观看出“技能”和“自由发挥”的区别自由发挥是让模型自己编一个改地址的全流程技能方案则是把不可控的部分全部收敛到固定逻辑里模型只做意图理解和决策稳定可靠自然就上来了。3.4 链路追踪与效果评估技能化Agent的观测怎么落地技能化Agent比自由发挥的Agent好观测得多因为每一次模型行为都被结构化为“调用了哪个技能传了什么参数返回了什么结果”。基于这个结构可以搭一个简化版的链路追踪体系。每轮请求进来先记录意图识别的结果模型选择技能时把候选技能列表和最终选中结果都记下来如果选错了或者选了之后又改选这些过程信号对优化技能描述特别有价值。技能执行阶段要记执行耗时、返回码、重试次数数据沉淀到一定量级之后就可以分析出哪些技能经常出慢查询、哪些技能偶发失败提前做容量评估。评估体系这边我一般用的是两个核心指标。一个是技能选择准确率目标是模型选中的技能要符合真实意图拿标注好的数据集来跑回归测试准率低的时候优先怀疑技能描述有歧义。另一个是任务完成率衡量的是从技能入口到最终正确返回结果的比例这个指标更能反映用户的真实体感。做完一轮技能调整后把两个指标都跑一遍对比基线数据再决定灰度放量。4. 常见问题与排查技巧实录4.1 现象复现模型总是选错技能的几种典型场景选错技能是技能化Agent上线后最常遇到的问题而且出错方式多种多样。一种典型场景是用户一句话里包含多个意图比如“这个订单不要了顺便把之前的发票开了吧”模型可能只会选一个技能另一个意图直接被无视了。这个问题的解法是在技能选择阶段支持多技能并发触发允许模型返回多个技能调用意图执行器再按依赖关系串行处理。另一种出错是相似技能之间互相抢占。比如“查一下上个月工资”和“查一下上个月考勤”如果两个技能描述都写得比较泛模型很容易把考勤需求选成工资技能。排查时去翻链路日志能看到两个技能的评分非常接近这时候应该把技能描述重新打磨一下写清楚各自的边界和关键词信号。还有一种场景是模型在参数不足时不主动追问直接选了一个需要完整参数的技能去调用执行器报参数缺失后又被模型修改来来回回好几轮用户等着急。这种问题要靠两招解决一是技能描述里写清楚前置条件二是把常用参数做成可选默认值宁可技能内部做二次确认也不要让模型在参数不齐时反复卡壳。4.2 实战排查token消耗为什么居高不下技能化Agent上线一段时间后我开始盯成本发现token消耗比预估的高了一大截。排查思路是一条条捋对话链路最后定位到两个元凶。第一个是技能返回结果太长后端服务很实诚把数据库里能查到的字段全量返回结果光是一次库存查询就塞了几千个token进上下文模型下一次回复又把所有字段都读一遍白烧了。解法是技能返回Schema不仅要定义结构还要做字段层面的裁剪返回最必要的字段。第二个是失败重试链太深技能A失败后模型尝试换技能BB还是失败又绕回A来回切换四五轮才放弃每一轮都是整段上下文重新计费。解法是给技能编排加上熔断机制同一会话内同一个技能连续失败两次就禁止再次调度并触发兜底话术转人工。4.3 数据安全与权限边界技能滥用的风险怎么守技能化Agent天然会把很多真实系统的操作能力暴露给大模型权限边界如果做得不严风险极大。每个技能在注册时我都会要求标注所需的权限等级、适用范围和数据敏感度执行器在调度前先做一次权限校验模型想调用高敏技能但会话上下文没有获得授权直接拒绝并返回“无权访问”的提示。技能内部的数据审计也不能省。谁在什么时间通过哪个技能访问了哪些数据日志得留够保存周期。尤其是涉及到个人信息、资金相关操作的技能该走的审批流一步都不能省。我见过一些团队图省事把所有技能都授权给所有内部账号结果模型在测试环境拿到了生产环境的操作权限这种事出了事故再补救就晚了。4.4 常见问题速查表症状可能原因排查方法解决思路模型经常选错技能技能描述模糊或重叠度过高查看链路日志中候选技能的评分分布重写技能描述明确触发边界技能调用成功但返回结果不对参数格式理解偏差比如日期/单位不统一检查执行器收到的原始参数Schema细化参数描述增加预校验和归一化token消耗异常偏高技能返回字段过多或重试轮次过多分析单链路Token消耗明细裁剪返回字段加入熔断机制技能执行偶发超时下游服务抖动或执行器并发不足看技能执行耗时P95和P99增加本地重试必要时做限流模型在技能失败后反复重试缺少主动放弃机制观察会话内技能调度次数在编排层设定技能失败熔断阈值线上新技能表现不如测试线上真实用户口语差异大对比线上样本和测试集之间的描述分布持续补充线上语料并微调技能描述4.5 独家避坑指南来自真实上线的经验描述里的那些“差不多得了”其实才是进阶的坑位。就拿技能名称来说中英文混写会降低模型对技能的分类准确度我尝试过全中文、全英文、英文单词翻译式三种命名风格最后全英文命名效果最优但条件是描述也全面英文化。经验值又有讲究的地方是技能数量与模型选择准确率的负相关关系。技能数量从5个涨到20个之后如果描述没有同步重构选择准确率会明显下滑。破解的办法是给技能增加分类域比如“订单域”“物流域”“售后域”让模型先选域再选具体技能相当于建立二级索引比一次性从二十个技能里挑一个靠谱得多。踩过最惨的坑是技能内部实现升级时没同步更新参数格式。有个技能原本接收省份名称的字符串后来后端切到了省份编码但技能描述还写着让模型传省份名结果模型每次调用都踩参数解析错误。所以技能内部逻辑改了一定要回头审核一遍技能的对外Schema和描述是否需要同步变更不然再好的内部实现也白搭。5. 这个方向后续还可以怎么演进如果项目继续做下去我觉着有几个方向很值得琢磨。第一个是技能的自动生成把后端已有的API接口通过规范文档自动转成技能定义省去大量手写描述的时间但前提是接口文档的质量得过关GiA定义里那些字段说明含糊的接口自动生成出来的技能八成也选不准。第二个方向是技能调度的个性化不同用户群体对同一个技能的上下文要求不一样。比如企业用户查订单时关心采购批次和合同编号个人用户关心的是物流轨迹和预计送达时间如果能基于用户画像微调技能输出的字段权重体感会好不少。第三个是技能效果的自动化评估我现在的评估主要还是靠人工标注意图然后跑回归周期长成本高。后续想把线上日志的高质量对话自动沉淀成测试集结合大模型当裁判来评测技能选择的效果把人工从重复劳动里解放出来。做Agent落到工程上经常会被各种概念绕得找不着北但技能这个抽象只要做对了后面整个链路就稳了。别急着给Agent堆能力先把每个能力的边界、描述、参数、版本这些都理清楚模型再聪明也架不住底下是一团乱麻。我实际操作下来的体会是一套结构清晰的技能体系配上一个能把调度链路管好的执行器比什么都管用的多。