Agent技能体系设计:从技能注册、路由到容错与评测的工程实践
1. 从技能这个词说起为什么Agent需要一套技能体系第一次看到agent-skills这个组合词很多人会下意识地把它理解成给智能体加几个工具函数。我一开始也是这么想的直到真正动手把一个只会聊天的智能体改造成能干活的东西才发现事情远没有这么简单。工具函数只是最表层的一层皮真正决定一个智能体能不能稳定完成任务的是它背后那套技能的组织方式——也就是技能怎么定义、怎么被选中、怎么被调用、调用失败之后怎么办。打个比方一个刚入职的实习生你给他一把螺丝刀、一把扳手他未必能修好一台机器。他缺的不是工具而是什么情况下用哪个工具、先拧哪个后拧哪个、拧不动了怎么办这套判断力。智能体也是一样。你给它挂上十个API它可能第一个问题就选错了工具或者在两个相似工具之间反复横跳最后把上下文烧光还没解决问题。所以agent-skills这个标题背后真正要讨论的不是怎么给智能体加工具而是怎么设计一套让智能体可靠干活的技能体系。这篇文章适合三类人看一是正在做智能体应用、被工具调用不稳定折磨的开发者二是想理解智能体能力边界、准备做技术选型的产品或架构同学三是对这个方向好奇、想自己搭一个能跑起来的小系统的爱好者。我会从技能的本质讲起一路讲到技能注册、路由、执行、容错、评测这些实操环节中间穿插我自己踩过的坑和总结出来的经验。全文不依赖任何特定平台讲的是通用的设计思路你用什么框架都能套进去。需要先明确一个概念边界这里说的技能skill指的是智能体可以调用的一个有明确输入输出、有明确适用场景、有明确失败模式的能力单元。它可能是一次API调用、一段本地计算、一次文件读写、一次检索也可能是一串更小的技能编排出来的复合能力。把技能当成函数是最低限度的理解把它当成带契约的能力才是能落地的理解。2. 技能的本质不是函数而是一份带约束的契约2.1 一个技能至少要说清四件事很多人写技能的时候只写了一个函数体和一句描述然后就指望模型能正确调用。实测下来这种技能在简单场景能跑稍微复杂一点就开始出问题。一个能被智能体可靠使用的技能至少要包含四部分信息缺一不可。第一部分是能力描述也就是这个技能能做什么。注意不是这个函数叫什么名字而是用自然语言说清楚它在什么场景下有用。比如查询某只股票当前价格就比get_stock_price这种命名对模型友好得多因为模型是靠语义匹配来选技能的不是靠背函数名。第二部分是输入契约包括每个参数的名字、类型、是否必填、取值范围、以及最重要的——参数之间的约束关系。比如开始日期不能晚于结束日期这种约束如果不写清楚模型很可能给你传一个反过来的区间然后你的技能内部报错模型又不知道错在哪就开始瞎猜。第三部分是输出契约包括返回值的结构、字段含义、以及可能的错误码。这一点最容易被忽略。很多技能返回一个裸字符串模型拿到之后不知道该怎么用。如果返回的是结构化数据并且每个字段都有清晰语义模型后续的推理质量会高一大截。第四部分是失败模式也就是这个技能在什么情况下会失败、失败时返回什么。这一条是区分业余和专业的核心。一个成熟的技能失败时应该返回明确的错误类型和可读的错误信息而不是抛一个异常让整个流程崩掉。2.2 为什么描述比实现更重要我做过一个对比实验同一个功能写两版技能实现代码完全一样只有描述不同。第一版描述是处理用户数据第二版描述是根据用户ID查询该用户的订单列表返回最近30天的订单按时间倒序。结果在同一个测试集上第二版的调用准确率比第一版高出接近一倍。原因很简单智能体选技能的过程本质上是一次语义检索。它把你的问题转成向量然后和所有技能的描述做匹配。描述越具体、越贴近真实使用场景匹配就越准。所以写技能描述的时候要站在用户会怎么问的角度去写而不是站在我实现了什么的角度去写。把用户可能用的同义词、近义表达都考虑进去甚至可以在描述里直接列出几个典型问法。提示技能描述里不要出现高级智能强大这类形容词它们不携带任何可用于匹配的信息反而会稀释真正有用的关键词。2.3 技能粒度的取舍太粗和太细都是坑技能拆得太细会导致模型在几十个技能里挑花眼调用链变长出错概率上升。技能拆得太粗会导致一个技能内部逻辑复杂、参数众多模型很难正确填参而且复用性差。我的经验是遵循单一意图原则一个技能对应一类明确的用户意图。比如查天气和查空气质量是两个意图就拆成两个技能但查今天天气和查明天天气是同一个意图的不同参数就合成一个技能用日期参数区分。判断标准很简单如果两个技能的描述在语义上高度重叠模型经常分不清该用哪个那就该合并如果一个技能的参数里出现了模式这种需要模型自己判断填什么的字段那大概率该拆。3. 技能注册与路由让智能体在正确的时候想起正确的技能3.1 注册表不是简单的列表技能注册表registry是整套体系的入口。最朴素的做法是维护一个数组每个元素是一个技能对象。但真正上线之后你会发现技能数量一多全量塞进提示词里既浪费上下文又干扰模型判断。这时候就需要给注册表加上分层和索引的能力。我通常会把技能按领域分组比如数据查询类文件操作类计算类外部服务类。每一组有一个组描述模型先选组再选组内的具体技能。这样即使有上百个技能模型每次面对的候选也就十来个准确率明显提升。更进一步可以给每个技能打上标签用标签做粗筛再用语义相似度做精排。3.2 路由的三种策略与适用场景路由就是给定一个用户请求决定调用哪个技能。常见的有三种策略各有各的适用面。第一种是纯语义匹配把请求和所有技能描述做向量相似度计算取最高的。优点是实现简单、无需训练缺点是当技能描述写得不好或者请求本身模糊时容易选错。适合技能数量少、描述质量高的场景。第二种是模型直接选择把所有技能描述塞进提示词让模型输出要调用的技能名和参数。优点是模型能理解复杂意图、能做多步推理缺点是技能一多就吃上下文而且模型可能幻觉出不存在的技能。适合技能数量中等、需要多步推理的场景。第三种是混合路由先用规则或标签做粗筛缩小候选范围再交给模型做精排和参数填充。这是我在生产环境里用得最多的方案兼顾了准确率和上下文成本。粗筛阶段可以用关键词匹配、意图分类模型甚至简单的正则把候选从上百个降到十几个剩下的交给模型。路由策略实现成本准确率上下文开销适用场景纯语义匹配低中低技能少、描述规范模型直接选择中高高需多步推理、技能中等混合路由高高中生产环境、技能多3.3 参数填充比选技能更容易翻车的地方选对技能只是第一步把参数填对才是真正的难点。我见过太多案例技能选得没错但参数填错导致结果完全不对而模型还一脸无辜地拿着错误结果继续往下推理。参数填充的核心是给模型足够的约束和示例。每个参数除了类型和描述最好再给一两个示例值。对于枚举型参数把所有合法取值列出来。对于有格式要求的参数比如日期、金额在描述里明确格式并给出示例。对于有依赖关系的参数在描述里写清楚当A为某值时B必填这类规则。还有一个实用技巧在技能内部做参数校验和归一化。不要指望模型每次都填对技能入口处做一层校验把常见的格式问题比如日期写成明天、金额带单位自动转换或纠正能大幅降低失败率。校验失败时返回的错误信息要具体到哪个参数、期望什么格式、实际收到什么这样模型下一轮才有机会自我修正。4. 技能执行与容错真正拉开差距的地方4.1 执行不是调用一下就完事技能执行看起来就是拿到参数、调用函数、返回结果但实际工程里要考虑的东西很多。首先是超时控制外部服务可能卡住必须有超时否则整个智能体流程会被拖死。其次是重试策略对于网络抖动这类瞬时故障重试一两次往往能成功但要注意幂等性——查询类技能可以随便重试写入类技能重试前必须确认是否已经生效。然后是结果截断。很多技能返回的数据量很大直接塞回上下文会撑爆窗口。我通常会在技能层做一次摘要或截断只返回和当前任务最相关的部分。比如查询返回一百条记录技能可以只返回前十条加一个总数并告诉模型还有九十条如需更多请指定筛选条件。这样既控制了上下文又给了模型继续探索的入口。4.2 失败分类可恢复与不可恢复容错的前提是能区分失败的类型。我把技能失败分成三类处理方式完全不同。第一类是参数错误比如类型不对、必填缺失、取值越界。这类失败是可恢复的因为模型有机会通过修改参数重试。处理方式是返回结构化的错误信息明确指出问题所在让模型下一轮修正。第二类是环境错误比如网络超时、服务不可用、权限不足。这类失败对模型来说是不可控的重试同样的调用大概率还是失败。处理方式是返回一个简短的错误说明并建议模型换一条路径或告知用户稍后再试而不是让它无脑重试。第三类是业务错误比如查询的订单不存在、用户没有权限。这类失败其实是有效结果只是结果是否定的。处理方式是把错误信息当成正常结果返回让模型基于这个信息继续推理而不是当成异常中断流程。注意千万不要把所有失败都统一成一个调用失败的字符串返回。模型拿到这种模糊信息要么反复重试同一个错误调用要么直接放弃。失败信息的颗粒度直接决定了智能体的自愈能力。4.3 一个真实的排查链路说个我踩过的坑。有段时间一个查询类技能在测试环境一直很稳上线后却频繁失败。日志里只看到调用超时但测试环境明明很快。我按下面的顺序排查了一遍。第一步确认是不是偶发。统计了一小时的失败率发现是稳定在百分之十几不是偶发说明有系统性问题。第二步对比测试和生产的差异发现生产环境的输入数据量是测试的几十倍怀疑是数据量导致的慢查询。第三步在技能内部加计时日志发现耗时确实集中在数据检索环节。第四步检查检索逻辑发现没有对高频查询字段建索引数据量一大就全表扫描。第五步加上索引并做了一次查询缓存失败率直接降到接近零。这个链路的价值不在于最后那个索引而在于排查的顺序先确认是否偶发再对比环境差异再定位耗时环节最后才改代码。很多人一上来就改代码改了半天发现方向都错了。5. 技能编排当单个技能不够用时5.1 什么时候需要编排单个技能能解决的问题是有限的。真实任务往往是多步的先查数据再根据数据做判断再根据判断调用另一个技能最后汇总。这时候就需要技能编排也就是让智能体按一定逻辑把多个技能串起来。编排有两种做法。一种是让模型自由发挥给它一堆技能让它自己决定调用顺序。这种方式灵活但不可控容易绕圈子或者漏步骤。另一种是预定义工作流把常见的多步任务固化成一条流程模型只负责在流程的某些节点做判断。这种方式可控但灵活性差遇到流程外的任务就抓瞎。我的做法是两者结合对高频、稳定的任务用预定义工作流对长尾、多变的任务让模型自由编排但给自由编排加上步数上限和循环检测防止它陷入死循环。5.2 编排中的状态传递多步编排最容易出问题的地方是状态传递。第一步的输出怎么传给第二步如果直接塞进上下文数据量大了会爆如果只传一个引用模型又可能拿不到实际内容。我的经验是只传必要字段并且用结构化格式。第一步返回一个对象第二步需要的只是其中某几个字段那就只把这几个字段提取出来传给第二步而不是把整个对象塞过去。同时每一步的输出都保留一份完整版在外部存储里上下文里只放摘要和引用ID需要细节时再按ID取。这样既控制了上下文又保证了信息不丢失。5.3 循环与死锁的预防模型自由编排时最常见的失控模式是循环调用A技能的结果让它想调BB的结果又让它想调A来回几次上下文就烧光了。预防手段有三个一是设置最大步数超过就强制终止并返回当前进展二是记录已调用过的技能和参数组合如果出现重复组合就警告模型三是在提示词里明确告诉模型如果连续两次调用没有获得新信息就停下来汇报。6. 技能评测怎么知道你的技能体系好不好用6.1 评测集怎么建技能体系好不好不能靠感觉得靠数据。评测集的建设是第一步。我的做法是从真实日志里采样覆盖三类样本正常样本技能应该被正确调用并返回正确结果、边界样本参数处于临界值、输入格式不规范、失败样本技能应该失败并给出正确错误信息。每类样本都要有明确的期望输出包括应该调用哪个技能、参数应该是什么、最终结果应该是什么。评测时不仅看最终结果对不对还要看中间过程对不对——技能选错了但碰巧结果对了这种蒙对的情况必须能被识别出来。6.2 关键指标我关注的指标主要有四个。技能选择准确率即选对技能的比例参数填充准确率即参数完全正确的比例端到端成功率即整个任务成功完成的比例平均调用步数反映效率步数越多通常意味着绕路越多。这四个指标要一起看。选择准确率高但端到端成功率低说明问题出在参数或执行环节端到端成功率高但步数多说明路由不够精准模型在试错。单独看任何一个指标都可能被误导。6.3 持续迭代的机制技能体系不是一次建好就完事的。我的做法是建立一个失败案例回流机制每次线上失败都把当时的输入、调用链、错误信息记录下来人工分析后归入评测集。每周跑一次全量评测看指标有没有退化。同时技能描述和参数约束的修改也要走评测改完必须证明指标没降才能上线。这套机制听起来重但它是技能体系能长期稳定的唯一办法。没有评测你永远不知道一次小改动是不是悄悄拉低了整体成功率。7. 一些不那么显然的经验最后分享几条我在实际做技能体系时总结出来的、文档里通常不会写的经验。第一条技能描述要定期重写。业务在变用户的问法在变半年前写得恰到好处的描述半年后可能就匹配不上了。我一般每季度会把调用量低但预期应该高的技能挑出来重新看它的描述是不是和当前用户表达脱节了。第二条给技能加使用示例比加详细说明更有效。模型对示例的敏感度远高于对抽象说明的敏感度。一个技能配两三个输入-输出示例调用准确率的提升往往比把描述写长一倍还明显。第三条不要追求一次做完美。技能体系是长出来的不是设计出来的。先做最小可用的一批技能跑起来看真实调用数据再根据数据决定加什么、改什么、删什么。我见过太多团队花几个月设计了一套完美的技能体系上线后发现真实场景和设想差很远推倒重来。第四条留一个兜底技能。当模型不知道该调什么、或者所有技能都失败时有一个兜底技能负责把问题转给人工或返回一个友好的提示。这个技能平时调用量很低但它是整个体系的安全网没有它一次意外就可能让用户体验彻底崩掉。这套东西说到底核心就一句话把智能体当成一个需要清晰职责边界和可靠协作机制的同事来对待而不是当成一个许愿池。技能定义得越清楚它干活就越靠谱。

相关新闻

litellm实战:搭建大模型统一网关,实现多模型接入与成本控制

litellm实战:搭建大模型统一网关,实现多模型接入与成本控制

litellm 这个项目,我第一次注意到它是因为实在被“多模型调用”这件事烦到了。手头同时维护着几个大模型平台的接入:各自的路由地址不一样,鉴权头不一样,错误码五花八门,连流式返回的字段都对不齐。每次产品想换个模型…

2026/10/13 4:55:17 阅读更多 →
时序差分控制算法详解:从Sarsa到双Q学习的原理与实战

时序差分控制算法详解:从Sarsa到双Q学习的原理与实战

1. 从动态规划到无模型控制:为什么需要时序差分如果你已经啃过强化学习的基础部分,大概率会有一种割裂感:动态规划那一章讲得头头是道,策略迭代、值迭代推导得严丝合缝,但一合上书就发现一个致命问题——它要求你完全知…

2026/10/13 4:55:17 阅读更多 →
litellm统一大模型调用接口:架构解析与部署实践

litellm统一大模型调用接口:架构解析与部署实践

1. 项目概述与核心定位1.1 这个项目到底解决什么问题第一次接触 litellm 是在一个多模型混用的项目里。当时团队同时接入了好几个不同厂商的大模型服务,每个平台的接口规范、鉴权方式、返回结构都不一样,代码里到处是 if-else 分支,维护起来非…

2026/10/13 4:55:17 阅读更多 →

最新新闻

手写Tool Use面试题:从函数到生产级工具调度系统

手写Tool Use面试题:从函数到生产级工具调度系统

1. 面试现场的真实压力:当“手写 Tool Use”成为临场能力试金石“请手写一个 Tool Use 实现。”这句话从面试官嘴里说出来的时候,我正端着一次性纸杯喝第三口温水——不是因为紧张,而是前两轮算法题刚结束,嗓子发干。但这句话一落…

2026/10/13 5:34:33 阅读更多 →
Carla 0.9.15 zlib-1.2.13 编译避坑指南:ABI兼容与符号导出实战

Carla 0.9.15 zlib-1.2.13 编译避坑指南:ABI兼容与符号导出实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:34:33 阅读更多 →
Kudu线上集群性能优化实战:内存、IO与RPC调优指南

Kudu线上集群性能优化实战:内存、IO与RPC调优指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:34:33 阅读更多 →
电动牙刷BLE上传刷牙时长至家长App的芯片方案与低功耗设计

电动牙刷BLE上传刷牙时长至家长App的芯片方案与低功耗设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:34:33 阅读更多 →
开源BOM管理系统:从Excel到可追溯数据库的实战落地

开源BOM管理系统:从Excel到可追溯数据库的实战落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:34:33 阅读更多 →
IIS管理器打开全攻略:本机启动、远程连接与排错实战

IIS管理器打开全攻略:本机启动、远程连接与排错实战

搞Windows服务器的同学都清楚,IIS管理器这个窗口,看着不起眼,却是撑起大量Web业务的关键工具。很多人以为它就是个“打开就能用”的图形界面,但在实际运维里,光是怎么把它顺利打开、正常连上远程站点,就能筛…

2026/10/13 5:33:32 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →