ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从技能库到能力地图:AI Agent 技能化设计与编排实战指南

从技能库到能力地图:AI Agent 技能化设计与编排实战指南

玩AI Agent的朋友,最近应该都绕不开一个词:agent-skills。说白了,就是给智能体装上一套可复用的“技能库”,让它不再靠一次次临时拼 prompt 和 function calling 来干活。我在多个项目里试过这套思路之后,最直观的感受是:没有技能体系的 Agent 就像手里没有工具箱的维修师傅,什么都得现找现做;有了技能库之后,它才算真正“会干活”。

这篇内容适合谁看?你已经把单个 Agent 跑通,但发现它的能力边界很模糊、调用逻辑越写越乱、换个场景就得重写一套的开发者。我会从为什么需要技能化、怎么设计一套可落地的技能框架、到怎么编排和排查,完整拆一遍我的实操记录和踩坑经验。

1. 先聊清楚:agent-skills 到底解决什么问题

1.1 单体 Agent 开发的“水管式”困境

大部分团队刚开始做 Agent 时,走的都是“水管式”开发:用户问一句,Agent 调一个函数,返回一段文本。流程短、结构直,感觉一切都在掌控中。但项目一复杂,问题立刻冒出来——比如 Agent 自称“能做数据分析”,但拿到 CSV 之后不知道先清洗还是先建模;又比如同一个工具函数,在A场景要处理JSON,在B场景要查询数据库,结果函数里堆满了if else;更麻烦的是,当你要把同一个能力从“单聊机器人”迁移到“自动工单系统”时,几乎是把过去写的代码全部复制一遍,然后改掉一半。

这不是代码质量问题,而是结构问题。单体 Agent 把“意图识别”“工具执行”“结果生成”全部绑死在一起,边界不清,自然无法复用。

1.2 技能化带来的三个关键转变

agent-skills 的思路是把“能力”从“流程”中拆出来,变成独立定义、独立注册、可插拔的模块。我实践下来,它带来三个明显变化:

第一个转变,从“写函数”变成“定义技能”。普通函数只关心输入和输出,技能还要关心触发条件、适用场景、依赖资源、失败策略。第二个转变,从“代码调用”变成“声明式路由”。Agent 不再硬编码地调某个函数,而是根据用户意图去匹配技能列表。第三个转变,从“单机脚本”变成“组织资产”。技能可以被多个 Agent 共享,更新一次,处处生效。

比如我之前做的一个内部问答 Agent,早期它的“查天气”能力是写在主流程里的,后来另一个团队做会议助手也要查天气,没办法,只能把那段逻辑复制过去。改成技能库之后,查天气就是一个独立技能,两个 Agent 各自声明“我拥有 weather_skill”,底层只维护一份代码。这就是技能化的核心价值——能力跟场景解耦。

1.3 技能、工具、插件,这几个概念别搞混

我在跟团队讨论时发现,很多人容易把“技能(skills)”“工具(tools)”“插件(plugins)”混为一谈。实际操作中这三者的定位差异很关键。

工具(tools)是最底层的能力单元,比如“发送HTTP请求”“读取本地文件”;技能(skills)则是工具的组合加上使用策略,比如“获取股票行情”技能由“调用行情API”“解析返回数据”“判断涨跌幅”三个工具步骤构成;插件(plugins)是技能的打包分发形式,可以包含多个技能、配置文件和说明文档。

理解了这个层级,再看 agent-skills 就顺了——它关注的是“技能”这一层,而不是更底层的工具。设计一个技能时,你其实是在写一份“能力使用说明书”,告诉 Agent 这个能力是干什么的、什么时候用、怎么用、用完怎么收尾。

2. 如何设计一套可复用的技能框架

2.1 技能描述、参数定义、运行逻辑、依赖隔离

技能框架的核心组件我总结为四块:描述(description)、参数(parameters)、运行逻辑(execution)、依赖隔离(isolation)。

描述是给 Agent 看的,不是给你自己看的。它要能准确告诉大模型“这个技能做什么、适合什么场景、不适合什么场景”。参数定义决定技能能被怎么调用,清晰、严格的参数声明比啥都强。运行逻辑是技能内部的执行步骤,可以是代码函数、API调用,也可以是混合流程。依赖隔离则是说技能之间的依赖要显式声明,不能互相踩脚。

我自己设计技能时有一个“三可”检查标准:可描述、可调用、可回退。一个技能如果连自己的使用条件都说不清楚,那 Agent 就一定会误用。

2.2 用一份标准化的技能清单开始设计

{ "skill_name": "stock_quote_query", "description": "查询指定股票的最新行情,包括价格、涨跌幅、成交量等。适合用户在询问股价、行情变动时使用。不适合历史数据回测或投资建议。", "parameters": { "symbol": {"type": "string", "description": "股票代码", "required": true}, "exchange": {"type": "string", "description": "交易所代码", "required": false, "default": "JPX"} }, "execution": { "type": "python_function", "entry": "get_quote", "timeout": 10 }, "dependencies": ["market_data_connector"], "fallback_strategy": "如果行情接口无响应,返回上一次缓存的收盘数据并提示数据延迟" }

这段配置我每次都会作为模板来用。看起来简单,但它把技能的生命周期管理得很清楚:入口函数是哪一个、超时多久、依赖什么连接器、失败时怎么办。特别注意一下“fallback_strategy”,多数初版技能框架都会漏掉这个字段,导致 Agent 一遇到接口报错就直接崩掉或者胡说八道。

2.3 技能注册机制:让 Agent 知道“我有什么”

有了技能定义还不够,还要有注册机制,让 Agent 在每次对话前知道当前它有哪些可用技能。我的做法很简单:维护一个技能注册表(skill registry),里面存放所有技能的最简信息列表,然后在每次请求时把注册表注入到系统提示词中。

技能注册表(精简版): 1. stock_quote_query - 查询股票最新行情 2. news_search - 基于关键词搜索新闻摘要 3. meeting_scheduler - 创建日程、邀请参会人,需要日历权限 4. sentiment_analysis - 对文本进行情感倾向判断

注册表不能太长,我一般控制在几十个到一两百个技能描述之内,不然大模型的上下文窗口和注意力都会被拖垮。注册表里的描述要做到:一看就懂,一调就对。

3. 核心细节解析:技能编排与路由选择

3.1 技能路由策略:让 Agent 学会选技能,而不是硬编码

技能定义好之后,最大的挑战是“怎么选”。早期的做法是在代码里写if else,后来变成让大模型自己选。我测试下来,让大模型自由选择技能很灵活,但容易选错;纯规则的硬编码可靠但没法覆盖复杂场景。最稳的方案是“意图分类 + 规则兜底”的混合路由。

1. 先对用户输入做意图分类(可用分类小模型,也可用LLM) 2. 根据意图过滤出候选技能列表 3. 再让 LLM 从候选技能里选择具体哪一个,并填充参数 4. 如果候选技能为空,走默认的闲聊或转人工流程

拿一个实际例子来说:用户说“帮我看下今天的天气,顺便问下明天开会的时间”。如果直接让 Agent 在所有技能里自由选,它很可能只选到“查询天气”而漏掉“日程查询”。但加了一步意图分类,拆成“天气查询”和“日程查询”两个意图,再分别匹配技能,准确率会提高很多。

3.2 上下文上下文压缩:技能调用的隐形瓶颈

你可能会说,技能不就是在函数里调用一下吗?真正跑了大规模场景之后,我发现最大的瓶颈是上下文。一个技能执行完之后,它会返回一段结果,这段结果要放进上下文让大模型继续生成回复。但如果技能返回的数据很长(比如分析报告、搜索结果),上下文就会迅速被填满,导致多轮对话时“记忆”被挤掉。

我习惯在每个技能执行完推荐加上“结果摘要”机制。比如“search_news”技能执行完,不要返回全部新闻列表,只返回标题和关键的摘要。必要的话,再提供一个“获取详情”的二级技能,让 Agent 只在用户真正需要时深入。

3.3 技能冲突与优先级:两个技能都能用怎么办

实际跑起来之后,一定会遇到技能冲突:用户说“帮我查一下某某公司”,这时候“company_profile”和“news_search”两个技能都能用。怎么选?我的规则很简单——优先选择意图匹配度高的,其次选择粒度更细的。还是那个例子,“查一下某某公司”明显更符合“company_profile”这类定向查询技能的定位,而不是泛泛的“news_search”。

如果两个技能匹配度接近,就看技能描述里的“适用场景”部分是否出现关键词。遇到这种情况最忌讳的是让 Agent 自己“自由发挥”编一个答案。我遇到过 Agent 把“查公司简介”回答成了“查最新新闻”,就是因为技能描述写得太模糊,没做优先级控制。

4. 实操过程:从零搭一个技能库的完整路线

4.1 第一步:盘点现有能力,拆出技能清单

不要一上来就写代码,我先做了一次“能力盘点”。把自己现有 Agent 的所有功能列出来,然后按照“查询类”“计算类”“操作类”“生成类”四个大类归类。归类之后,再去拆技能。

盘点阶段的关键是识别“伪技能”——有些功能看似独立,其实只是另一个技能的子步骤。比如“获取用户信息”和“获取用户订单”是两个技能,但“获取用户基本信息并计算其消费总额”就是一个组合技能,不应该单独拆出来。拆技能的原则是:粒度要细到可以单测,但不能细到没有独立意义。

4.2 第二步:从单体 Agent 中逐步剥离技能

我在某个模拟项目X里做了一个客户支持 Agent,刚开始所有逻辑都写在主流程里。改造时我没有一次性重写,而是用了“边拆边留”的策略:

先挑出最独立的功能(比如订单查询),把它改造成独立的技能模块,注册到技能库;然后把主流程里的对应代码删除,改为动态调用技能;测试通过后,再拆下一个功能。这个过程很慢,但非常稳,每次改动都可以回退,不会出现“拆了一半,Agent 全瘫了”的情况。

4.3 第三步:给每个技能配测试用例和失败场景

注意,技能测试和普通函数测试不一样。普通函数测试看输入输出对不对,技能测试还要看:描述是否被大模型理解、参数是否能被正确抽取、失败时大模型的回复是否合理。

我推荐给每个技能配置“三件套”测试:正向测试(用户正常请求是否命中)、边界测试(参数缺失、参数超长是否处理得当)、误导测试(用户用相近但不同的说法请求,是否会被误路由)。这三个测试做完,技能才算达到“可用”状态。我曾经漏掉误导测试,导致用户说“帮我看看我买的那只基金”时,Agent 调用了“股票行情查询”而不是“基金详情查询”,那一次就给我长了个记性。

4.4 技能复用与跨 Agent 迁移的工程细节

同一个技能被多个 Agent 使用时,最怕的就是“改一个,坏一串”。我采用的方案是给技能加“版本号”,并且在做不兼容变更时保留旧版本一段时间。另外还要做好“技能归属”管理——每一个技能都指定一个负责人,不能出现一个技能谁都能改、改完没人负责的局面。

技能跨 Agent 迁移时,除了拷贝技能代码,还要把技能依赖的 API Key、数据源地址、权限配置一起打包。我见过太多次“代码复制过去了,但忘记配环境变量”导致的线上故障。所以我现在会为每条技能维护一张“环境依赖表”,迁移时逐项核对。

5. 常见问题与排查技巧实录

5.1 高频问题速查表

症状可能原因排查思路
Agent 总是选错技能技能描述不清晰检查描述是否包含明确的触发条件和排除条件
技能被执行了但参数不对参数抽取不准检查参数描述是否给出具体示例格式
技能执行超时依赖服务响应慢为技能设置合理的超时时间,增加重试机制
Agent 编造技能执行结果缺少结果校验在技能返回前增加字段完整性校验
多个技能互相冲突缺乏优先级配置在技能配置中增加“优先级”和“互斥技能”字段
技能库越来越乱缺乏定期评审每两周做一次技能清单review,下线低质量技能

5.2 经验一:技能描述里藏着大坑

我踩过最大的坑就在技能描述上。一开始我写的描述非常简短,比如“搜索新闻”,结果 Agent 动不动就调它,哪怕用户只是问了句“今天有什么消息”。后来我把描述改成“基于关键词搜索指定主题的新闻摘要,返回标题列表;适合用户明确询问新闻、资讯、公告时使用;当用户只问‘最近怎么样’这类寒暄时不该使用”,误调率瞬间下来了。

技能描述就是给大模型看的“使用手册”,要多写限制条件,少写空泛的能力介绍。写得越具体,Agent 选得越准。

5.3 经验二:技能编排要留“人工确认”余地

对于会产生实际影响的操作型技能(发邮件、下订单、删数据),我的习惯是启用“确认机制”。技能在执行前先返回一个“待确认”状态,由 Agent 跟用户复述一遍即将执行的操作,用户确认之后才真正执行。

这个设计初看会拖慢交互效率,但真实场景里真的能救命。我有一次测试时让 Agent 自动发会议邀请,结果它误解读了用户的意图,把邀请发给了全部同事。从那以后,所有“高影响动作”类技能全部强制走确认环节。具体实现就是在技能配置里加一个“requires_confirmation: true”字段。

5.4 经验三:别忽略技能的“冷启动”问题

技能库建好之后,新加入的技能往往没有足够多的调用历史,路由模型很难判断它的好用程度。我有个办法是给新技能设置“试用期”——先用规则强制在部分请求中调用它,收集反馈数据。运行一段时间后,如果技能的调用准确率和用户满意度达标,再放开给所有 Agent 使用。

6. 进阶方向:从技能库走向能力地图

技能积累到一定数量后,光靠“列表式”的注册表就不够了。我现在的做法是为技能库建立一张“能力地图”,把技能按功能域分组、标注依赖关系、显示覆盖率。能力地图让我一眼看出哪些能力过剩、哪些能力缺失。

比如某次我分析内部技能库时发现,“内容生成类”技能占了四成,但“内容审核类”技能几乎为零。如果没有能力地图,这种结构性的缺口很难被察觉。有了地图之后,技能库就不只是一堆工具的集合,而是真正变成了一套帮助 Agent 持续进化的基础设施。

最后再分享一个我的个人习惯:技能库是活的东西,不是写完就固定的。每跑一个新场景、每遇到一次错误路由、每收到一个效果反馈,都可以回到技能定义里去修正描述、调整参数、优化回退策略。这也是 agent-skills 这套思路在我看来最有魅力的地方——它不是一套一次性开发完就没动静的代码,而是一个越用越顺手、越沉淀越值钱的系统。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进