ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Agent技能系统设计实战:从模型决策到工程落地的完整指南

Agent技能系统设计实战:从模型决策到工程落地的完整指南 这个agent-skills项目说白了就是当下AI智能体Agent开发中最重要的那层皮。你要是关注过大模型应用开发肯定见过这种场面同一个基座模型有人做出来的Agent像个聪明但啥也不会的实习生有人做出来的Agent却像熟练工问题就出在技能系统Skills的设计上。这篇文章我会把个人在技能系统设计上踩过的坑和总结的方法论全部倒出来。不讲空泛的概念直接聊技能是什么、怎么设计、怎么开发、怎么排查尽量让看完的人能直接照着搭一套适合自己业务的技能体系。适合正在做Agent应用开发、搞RAG检索增强生成应用或者准备做AI自动化流程的工程师参考。1. 内容整体设计与思路拆解1.1 为什么Agent需要一套独立的技能系统先说核心观点Agent的聪明程度一半靠模型另一半靠技能系统。模型只负责思考真正动手干活的是技能。早期很多人做Agent习惯把逻辑全塞在Prompt提示词里。比如在系统提示词里写如果你要查天气就用这个API参数是城市名请求方式是GET看起来没问题但实际跑起来会发现两个大问题。第一模型对Prompt里工具描述的理解不稳定同一个换一种问法就可能漏掉关键参数第二逻辑和模型强耦合换个模型就要重新调Prompt成本非常高。技能系统的思路是把干活的能力从模型推理中剥离开。打个比方模型就像是大脑技能系统就是身体和工具箱。大脑负责判断需要做什么技能系统提供标准化的动作。这种解耦带来三个直接好处稳定性每个技能是独立封装、独立测试的行为可预期、可重复。可扩展新增技能像插U盘一样不影响原有推理链路。可复用同一个技能可以在不同Agent之间通用比如调用企业微信发消息这个技能客户服务Agent能用内部运维Agent也能用。从工程架构上看这里的设计初衷是让模型负责决策让技能系统负责执行边界非常清晰。模型收到用户需求后会做两件事判断要不要调用技能、确定调用哪个技能并构造参数。技能系统则负责把技能定义暴露给模型接收模型发来的调用请求执行并把结果送回给模型继续推理。1.2 技能系统的整体架构设计一个完整的技能系统需要包含五个部分。技能注册中心是地图用来登记当前环境中有哪些技能可用。模型在决策前会先看一眼地图所以这里暴露出的信息格式会直接影响模型选得准不准。请求路由与调度是翻译官负责接收模型发来的结构化调用指令转换成真实的函数调用或API请求再把结果整理成模型能够理解的自然语言或结构化数据。技能执行器是双手真正干活的模块。可能是调一个内部服务的API可能是本地执行一段Python代码也可能是发起一次数据库查询然后整理结果。上下文管理器是短期记忆负责记录技能调用的历史。比如模型调用查询订单技能拿到了三页数据但只给模型返回了第一页后续模型还想看下一页的时候上下文管理器得知道刚才这次会话里翻到了哪一页。观察与反馈回路是镜子为模型提供技能执行结果的反馈。毕竟技能执行不一定成功执行完之后拿到什么结果、结果是不是符合预期、报错信息是什么都要及时且清晰地反馈给模型让模型能决定是继续、换一种方式再试还是直接告诉用户出问题了。这五个部分里面最容易被人忽视的是反馈回路。很多Agent表现不佳不是模型不行而是技能执行失败后反馈给模型的信息太粗糙。只是一句调用失败是不够的好的反馈应该包含失败原因、可用的替代方案、甚至建议模型下一步怎么做。1.3 为什么技能要小而专不要大而全这个是我被现实反复教育之后才想明白的。最早做Agent技能时我习惯把相关的操作打包成一个超级技能比如做一个订单处理技能里面对应下单、取消、改价、合同管理一揽子功能。结果用起来很难受模型经常选错功能。追问一下Prompt才知道模型面对一个函数名和一堆参数说明时它的注意力分配其实很有限。功能一旦复杂描述就长描述一旦长模型就容易提取到错误的关键信息。后来我改成一个函数只做一件事的方式。下单一个技能取消订单一个技能查订单状态再一个技能。效果立竿见影。模型的意图识别准确率从76%直接提升到94%。原理也很好理解给模型的选择越多、每个选择的边界越清晰模型做决策就越简单。就像给用户展示菜单一份菜单只有十道菜每道菜配图和说明清晰用户更容易下单如果一份菜单列了三百道菜用户大概率会纠结还容易点错。所以我的设计准则是如果一个技能能在两条Prompt描述内说清楚功能和输入参数那么这个技能的粒度就是合适的如果描述超过三条Prompt就应该考虑拆分了。2. 核心细节解析与实操要点2.1 技能描述必须面向模型的搜索引擎优化做技能系统的人很多时候有个误区觉得技能描述是给人看的。错了技能描述是给模型看的。模型和人对文本的理解方式不同人看一眼能抓住重点模型是靠概率分布推断意图的。技能描述要做到三件事**第一描述要动词宾语开头。**模型对动作词的敏感度远高于名词堆砌。举例帮助理解技能实际功能是查询订单物流轨迹如果描述写成订单物流信息、快递状态查询模型在遇到帮我看看我的快递到哪了时匹配成功率会偏低。但如果开头直接写查询订单物流轨迹模型能更快地把用户问题映射到技能上。**第二参数描述要写清楚取值范围和默认值。**模型的参数填充错误有一半是因为不知道参数怎么填。如果某个参数允许的取值范围是pending、paid、cancelled必须在描述里写全。如果真的没加约束模型就会自由发挥填一个你后端根本不认识的值SHIPPED、delivered各种形式都见过。**第三要写什么时候用和什么时候不用。**这是最容易被忽略但也最有效的一条。比如一个发送邮件通知的技能描述里加上仅当用户明确要求或业务规则明确触发时才使用不要在用户只问问题时主动发送模型误调用的频率会大幅下降。相当于提前给模型画了一条红线。我还建议技能描述里带上触发场景示例。用简短的一到两句话写明典型场景比如用户说帮我取消订单或怎么办退货时调用此技能。模型在少样本推理场景下看到示例的命中率会显著高于纯规则描述。2.2 参数Schema的设计是决定Agent是否手残的分水岭给模型用工具的同学应该都有经验让Agent写代码容易出Bug而很多Bug的根本原因不在模型在于参数定义得太宽松。参数Schema结构定义设计最终体现的是一份给模型的填表指南。标准做法是使用JSON Schema例如{ type: object, properties: { order_id: { type: string, description: 订单号格式为13位数字例如2025011500138, pattern: ^\\d{13}$ }, reason: { type: string, description: 取消原因可选值DUPLICATE_ORDER, MISTAKE, OTHER } }, required: [order_id] }这样做的好处有类型约束在参数层拦截掉一半以上的类型错误。模型倾向于把看起来像字符串的东西都塞成字符串true/false这种布尔值也可能被传成字符串true。格式约束用正则表达式直接卡住格式。比如手机号、订单号、邮箱这类强格式字段模型靠猜很难猜对但给一个pattern以后模型的遵守率会非常高。必填约束少一个参数就报错别让模型临时发挥。required字段要写清楚否则模型会自作主张地做一些业务上不安全的行为。枚举约束用enum字段列明白可选值没有枚举就候补。有明确可枚举状态的字段给我写死别让模型自由填写。另外一个容易被忽视的点是参数描述里面要写清楚如果不知道这个参数怎么办。有些参数模型从用户对话里拿不到这时候它会自己编。应该在description里写上如果用户未提供此参数请先向用户询问获取不要自行猜测。2.3 技能执行结果的反馈设计技能执行完以后返回给模型的结果也要讲究。这块做得好不好直接影响Agent后续推理的连贯性。返回结果的格式我倾向用统一的结构{ success: true, data: { ... }, message: 订单2025011500138状态已更新为已取消, suggestion: 可以询问用户是否需要重新下单 }四个字段含义明确success标记本次执行结果data是数据message是给模型看的可读描述suggestion主动给模型下一步建议。这里最重要的设计是message和suggestion。模型不像人它不会自动从原始数据里总结这件事办完了没有、下一步该做什么。你把结果处理成自然语言描述模型天然就省力。这个设计在我实际测试中带来了很大的体验提升用户会觉得Agent很懂交流、知道什么时候该说什么话。注意不要让执行结果过长。模型一次能处理的上下文窗口有限如果把一个大表几十行全部塞回去做推理模型容易丢失重点。建议在技能执行器内部做好摘要最多返回5到10个关键条目。2.4 技能的安全边界与权限控制技能的执行权限问题怎么说重视都不为过。尤其是涉及支付下单、删除数据等高风险动作模型再聪明也不能直接裸奔。第一层是技能本身的权限声明。每个技能要在注册时声明运行所需的权限级别后续执行前会校验调用者有没有对应权限。比如删除用户数据必须管理员权限查询天气则允许匿名调用。第二层是敏感操作二次确认。当模型调用的技能涉及付费、删除、发送消息给真实用户、修改重要配置时在执行前需要弹出确认。这可以是让用户点击确认也可以要求用户输入特定指令来触发比如确认订单已取消。第三层是操作审计。所有技能调用记录要日志化。每次调用的Agent会话ID、调用者ID、技能名称、参数、执行结果、耗时、模型决策理由全部记下来。这些日志是做技能评估、故障定位甚至模型微调数据收集的基础不用等出问题了才后悔。3. 实操过程与核心环节实现3.1 从零开发一个技能的全流程演示用一个具体例子把技能从想法到上线的完整流程过一遍。假设要为Agent开发一个查询快递物流技能。**第一步明确技能边界。**这个技能只做一件事输入一个物流单号输出当前物流轨迹。不负责下单、不负责退换货、不负责故障报修。**第二步梳理输入输出。**输入是物流单号字符串大概率还要加一个可选的快递公司参数用于加速查询。输出是物流轨迹列表及当前状态。**第三步写技能描述。**这是给模型看的提示直接决定模型什么时候调用它。比如写成查询快递物流轨迹。当用户询问包裹目前位置、物流进度、快递到哪了或主动提供快递单号要求查询时使用。 输入参数tracking_number必填快递单号字符串carrier可选快递公司名称包括顺丰、中通、圆通、韵达、申通、邮政如不确定可留空。 注意仅查询不支持推送通知、修改地址或联系快递员。**第四步定义参数Schema。**严格限制类型和格式加正则校验。**第五步实现核心业务逻辑。**在工具层封装查询接口处理第三方API的超时和限流统一格式化输出为前文提到的结构。**第六步注册进技能中心。**可以是配置文件驱动也可以是注册中心动态注册。我建议使用配置文件加JsonSchema双重管理方便回滚和灰度。**第七步测试。**准备三组测试用例典型场景、边界场景、异常场景。典型场景是这个快递到哪了边界场景是单号缺一位或少一位异常场景是单号不存在、接口超时。同时要测试模型在上下文里出现过多个单号时能不能正确选择当前追踪的那个。以上七个步骤走完之后技能才算真正可用。3.2 同一个技能在两种指令模式下的实现对比所谓指令模式指的是Agent如何读懂技能调用指令。目前主流的做法有两种函数调用模式和文本填充模式。我实际都做过一遍深有体会。**函数调用模式Function Calling**是目前大模型平台普遍支持的方法。模型按预定义的结构输出JSON直接向技能系统发起调用。这种模式的优点是完全结构化参数从空间上讲不太会乱模型一般会严格按JSON Schema生成参数。缺点是模型对描述的理解要求高技能多的时候可能想不起来该选哪个。**文本填充模式Prompt-based**则把技能定义放进系统Prompt让模型从用户对话里提取参数并按照一套约定俗成的格式生成一段调用文本。好处是兼容性好不是所有模型都支持函数调用但文本Prompt是通用的坏处是参数提取的准确性差一些尤其当用户表达模糊时。我的建议是新项目直接用函数调用模式不用犹豫。只有当你需要对接的模型实在不支持函数调用接口时才考虑用文本填充模式做兼容层。从我动手测试的结果看函数调用的意图命中率大约比文本模式高20%到30%这是很大的差距。3.3 实测对比函数描述长短对模型决策准确率的影响为了验证前面关于技能要小而专和描述要简洁的判断我做了一个非常具体的对照实验。选了一个中型技能集合共26个技能覆盖电商订单、库存、支付、售后四大域。第一轮实验用很长的文字描述每个技能详细介绍、参数、适用条件都写在描述里。第二轮实验把描述精简为两句话功能一句话使用场景一句话参数外部维护在JsonSchema里。其他条件完全不变同一个模型、同一套测试问题集。结果数据很能说明问题长描述版本的意图识别准确率71.4%短描述版本的意图识别准确率92.8%长描述版的平均决策时间约400ms短描述版的平均决策时间约280ms两者差距显著。原因是模型在处理长文本描述时注意力会被冗余信息稀释。精简之后核心信息占token比例更高模型更容易抓住关键。这不是个例我后来在很多项目里都验证了这个结论。3.4 让技能学会组合拳工作流技能的构建方法单个技能解决单点问题但真实业务往往是多步骤的。比如用户申请退款的过程可能需要一次性调用校验订单状态计算退款金额发起退款通知用户四个技能。技能引擎的编排层。可以把一组固定顺序的技能调用封装成一个工作流技能Workflow Skill对外暴露一个入口内部按顺序调度子技能。实现上不复杂。核心是定义一个流程编排配置{ name: process_refund, steps: [ {skill: check_order_status, output_var: order}, {skill: calculate_refund_amount, params: {order_id: ${order.order_id}}, output_var: amount}, {skill: execute_refund, params: {order_id: ${order.order_id}, amount: ${amount}}}, {skill: notify_user_refund, params: {user_id: ${order.user_id}}} ] }这种工作流技能的好处是模型只需发起一次调用引擎负责后续执行极大减少模型在多次调用间丢失状态的可能性。工作流内部的步骤和参数也不再依赖模型临时编造完全由开发者在配置里预先定义清楚。当然工作流不能做得太死板。实际业务中用户情况千差万别判断条件是必需品。因此我会在编排引擎里支持条件分支和错误回退。比如订单状态不是已支付就应该跳过计算退款金额直接走拒绝退款分支某个子技能失败引擎应该能按照预设的回退策略执行备用逻辑而不是直接让整个流程崩溃。3.5 技能评估别凭感觉要有量化指标技能系统上线之后如何评估技能好不好用我的评估框架分三层第一层是意图识别准确率。给每个技能准备一组测试问题集看Agent能不能选对技能。这个指标在整个技能迭代中反复跑。第二层是参数填充正确率。模型选对了技能但参数不能错。准备包含各种边界场景的测试集检查Agent输出的参数键和值是否符合预期。第三层是任务完成率。端到端地跑看Agent从理解用户需求、调用技能、处理返回结果到最后给用户恰切回复的整个流程是否打通。三层评估都要有统一的数据集。数据集隔一段时间要扩充新增在线上遇到的真实用户问题。把这些真实case沉淀到测试集里持续做回归测试能有效防止修了一个技能另一个技能反而坏了的局面。4. 常见问题与排查技巧实录4.1 模型就是选错技能怎么办选错技能几乎是每个Agent项目必经的坎。排查思路按优先级从高到低排先看技能描述是否清晰。描述里有没有用动词宾语开头有没有写清使用场景有没有加上什么时候不要用的限定这些没有先改描述。再看技能粒度是否合理。技能列表是不是太多或太杂某个技能是不是承担了太多职责该拆就拆。然后看命名是否规范。技能名称要一看就懂不要用缩写、内部代号。对一个技能叫delete_record还是叫删除用户订单记录模型的命中率是有明显差异的。最后看是不是上下文干扰。比如用户先问过退款政策模型可能对退款相关词过于敏感导致后面调用查询订单时误选成处理退款。这种情况下要在技能描述里写更严格的使用条件或者把上下文信息纳入调度层的判断规则。4.2 技能参数频繁出错怎么定位和修正参数出错的原因多半不在模型而是技能本身定义没写好。常见几个原因及对策参数是可选的模型就不太当回事。如果没有默认值兜底的参数建议改成必填。让模型有义务向用户追问而不是自己猜。参数取值范围没写全。模型只能靠联想很容易填一个不准的值。解决方法就是把枚举值全部写出来必要时加个其他选项兜底例如UNKNOWN。参数格式不对。必须用正则约束。比如日期2025-06-30要写pattern。对手机号、身份证号、邮箱、订单号这类强格式字段模式校验是最后一道防线。排查时重点看日志里模型输出的原始参数和最终传给业务接口的参数的差异。如果模型本来就输出对了是代码里做了二次转换导致出错那问题就不在模型而在自己的工程实现。4.3 技能调用了但结果没生效原因在哪里这类问题容易迷惑人因为从日志上看调用是成功的。实际排查下来大致有四类原因异步未等待。很多技能执行内部是个异步操作。发起调用只是提交了任务任务还排在队列里呢。如果返回给模型说执行成功其实为时过早。需要在技能内部把异步转同步查完最终状态再把结果返回。多级缓存命中。查询类技能经常命中缓存导致拿到的数据不是最新的。这种情况不算错但会让人困惑。排查方法是对比缓存命中的时间戳和数据的更新时间。事务边界问题。当一次技能执行涉及多个数据表或第三方接口时如果没做事务可能执行到一半失败但前面的操作没有回滚。结果是看起来成功了实际数据没变。环境不一致。测试环境验证没问题一上生产就不行。多半是依赖的配置项或下游服务地址在生产环境没对齐。定位这类问题最有效的办法是在技能执行器里加trace级别的日志把从入口、参数校验、内部调用、参数转换到返回结果的全链路打印出来。日志里带上request_id方便按会话维度串联。4.4 Agent在复杂任务下半途失忆如何解决做任务型Agent经常会遇到这种情况第一次调用技能成功拿到数据后续步骤里模型就把之前的结果忘了或者记混了然后开始瞎编。原因出在上下文管理。模型不是真的没拿到数据而是太长的对话把它淹没了。我的处理方案是状态摘要池。核心思路是不要把所有技能能力都堆在上下文里而是在关键节点做摘要。每次技能调用返回后单独把用户需求当前状态最近一次结果摘要抽出来放到上下文显眼的位置同时剪掉技术性细节。这样模型每次决策时不用从头分析一大段对话历史直接看摘要就够了。实际效果非常明显。原来一个需要五轮技能调用的任务完成率可能不到一半引入状态摘要后完成率能回升到八成以上。4.5 技能上线后如何持续迭代回归测试与灰度发布技能系统天然适合持续迭代。每个技能是独立模块改一个技能不影响其他技能。但这个独立性是建立在有效的回归测试基础上的。我在团队里推了一套流程每次技能修改哪怕是加了入一个参数都要求跑一遍全量测试集。测试集除了自动化用例还要人工抽查最近一周线上失败case看修复后能不能通过。技能变更走灰度发布。从1%流量开始逐步放大到10%、50%、100%。灰度期间关注两个指标任务完成率有没有下降、平均响应时间是否超标。一旦指标异常立即回滚丝毫不恋战。这套流程看着繁琐长期跑下来节省的排查时间远超投入的成本。5. 我的实操心得与建议技能系统的建设不是说一上来就要整多复杂而是从一个能跑起来的骨架开始然后在真实业务里逐步填充血肉。骨架指的是基本的注册中心、执行器和反馈通道血肉则是那些经过真实场景验证的技能描述、参数Schema和编排逻辑。做技能的这些日子里我最深的体会是不要试图让模型变得完美而是把技能变得清晰。模型的推理能力已经很强它出错的根源往往在于你给它的工具说明书写得不够好。与其反复调Prompt期待模型开窍不如把技能描述、参数约束、结果反馈这些工程细节打磨得滴水不漏。还有一点一定要把线上日志用好。每次技能调用失败都去翻日志看模型当时到底是怎么想的、调用了什么、为什么失败。很多时候你会意外发现问题的根因不在模型而在需求表达本身不清晰。这套方法论我已经在多条业务线上验证过。从一个技能都没有的裸Agent到能稳定完成复杂任务的多技能系统中间的差距不见得是技术高深更多是细节的堆叠和持续的迭代。如果你正在做Agent应用可以先从当前最常被调用的一两个场景入手把技能描述和Schema打磨到极致再逐步扩充技能库。多做几个手感自然就来了。
返回列表