☰
智能体技能(Agent Skills)实战:从提示词到可插拔工具调用
2026/10/14 8:21:14 网站建设 项目流程

1. 从"能聊"到"能干":Agent Skills 到底补上了哪块短板

去年底我在做一个内部效率工具时,遇到了一个特别典型的困境:大模型对话能力已经很强了,但把它接进真实业务流程里,总感觉差着一口气。模型能理解用户说"帮我查一下上季度所有未关闭的工单",可它不会自己调用工单系统的接口,也不知道该用什么参数去查询,更没法在拿到结果后自动做一轮筛选分析。说白了,模型有脑子,但没有手脚。

这个"手脚"的问题,就是 agent-skills 这类方案试图解决的。所谓 agent skills,行业内更常见的叫法是"智能体技能"或"可插拔能力模块",本质上就是把大模型在特定场景下需要执行的动作——查数据库、调接口、解析文件、生成图表、触发流程——封装成一个个可以被模型自主发现、选择、调用的功能单元。你可以把它们想象成给机器人装上的各种工具:锤子管敲、螺丝刀管拧,而大模型扮演的是那个看情况挑选工具并决定怎么用的工匠。

当时我把这个思路落成了一个项目,代号就叫 agent-skills。它不是一个多复杂的框架,核心就是一件事:定义一套技能注册、发现和调用的标准,让任意一个基于大模型的应用都能把"对话理解"和"动作执行"解耦开。项目跑通之后,我最大的感受是:以前写功能,是在提示词里堆规则,让模型"照着做";现在写功能,是搭一套技能库,让模型"自己选着做"。两者的可控性和复用性完全不在一个量级。

这篇文章不是理论宣讲,而是我这个项目从零到一的全过程复盘。内容包括:为什么需要技能化而不是继续堆提示词、技能系统的整体架构怎么设计、三个核心技能的实战实现、跑测试时踩过的典型坑,以及技能质量怎么评估。如果你正在做 AI Agent 相关的应用,或者正准备把一个"能对话"的原型改造成"能干活"的产品,这篇文章应该能给你不少可以直接抄作业的细节。

2. 为什么是"技能库"而不是"更长的提示词":一次选型复盘

2.1 堆提示词的问题,不在提示词本身

刚开始我也走过弯路。第一版系统里,为了让模型会查工单,我在 system prompt 里写了整整两页的调用说明,包括接口地址、参数格式、鉴权方式、返回样例。效果呢?单场景测试能跑通,一换数据就崩:接口返回结构稍有变化,模型的"理解"就跟着出偏;新增一个查询维度,又得回去改那段长文本提示词,而且改完还可能影响其他场景的表现。

问题的根源很好理解:提示词是"写在脑子里的说明书",而技能是"拿在手上的工具"。说明书背得再熟,遇到说明书里没写的场景就不会了;工具则是独立于说明书存在的,模型只需要知道"什么时候该用哪个工具",具体的执行细节由工具自己保证。这就像教一个新同事做事,你把所有流程写成文档让他背下来,不如给他一套标准化工具,再告诉他每个按钮是干嘛的——后者的容错和扩展空间大得多。

2.2 技能化的三个关键收益,我在实测里都验证了

第一是隔离性。每个 skill 只管一件事,接口变了只改对应技能,不影响其他部分。后来我把查询接口从旧系统迁到新系统,只动了工单查询技能的二十几行代码,对话层和管理层一行没改。

第二是可测试性。提示词方案里,你很难单独验证"模型对某段说明的理解是否准确";但技能化之后,每个技能都是一个可以被单独调用、单独测试的函数,输入输出都有明确约定。我后来专门写了一套技能冒烟测试脚本,每次改动跑一遍,比人工翻聊天记录排查问题高效太多。

第三是组合性。单个技能能力有限,但技能之间可以串联:先调用工单查询技能拿到数据,再调用数据筛选技能做过滤,最后调用报表生成技能输出图表。模型在运行时动态决定这条链路怎么走,而不是在代码里写死。这种组合能力,是提示词方案很难实现的——提示词里的"步骤说明"一旦复杂起来,模型的执行失败率会急剧上升。

2.3 选型时我对比过的其他方案

这里补充一下我当时考虑过的几条路线,方便你有个参照:

方案优点缺点我的结论
纯提示词驱动实现简单,零额外代码扩展性差,场景一多就乱只适合 demo,不适合产品化
硬编码工具函数执行稳定,完全可控模型无法动态选择,灵活度低适合固定流程,不适合开放场景
外部流程编排引擎可视化编排,状态管理强学习成本高,和模型能力割裂适合复杂业务系统,做 agent 有点重
轻量技能注册框架模型自主调用,扩展方便需要自己定规范和做好测试最终采用,性价比最高

做这个对比不是为了说明其他方案不好,而是想说:技能化是"提示词灵活"和"代码可控"之间的一个平衡点。它保留了模型的动态决策能力,同时把动作执行拉回到工程化的轨道上。

3. 技能系统的主干设计:注册、发现、调用三层拆解

3.1 技能注册:一份 Schema 解决"模型怎么知道有什么技能"的问题

技能系统要解决的第一件事,是让模型知道"你有哪些工具可以用"。我的做法是给每个技能定义一份标准 Schema,包含四个字段:技能名称、功能描述、参数定义、返回说明。

功能描述是给模型看的,要写得"像在跟人介绍这个工具":它解决什么问题、适合什么场景、有哪些注意事项。参数定义是给解析器用的,用 JSON Schema 格式,声明每个参数的名称、类型、是否必填、取值范围。模型会根据用户请求推断出该填什么参数,系统负责校验和转换。

这里有个特别容易忽略的细节:描述文本的质量直接决定模型调用技能的准确率。我第一版写的描述很简短,比如"查询工单信息",结果模型经常在需要查"未关闭工单"时错误调用其他技能。后来我学到一个技巧:描述里要写清楚边界,比如"查询工单列表。适用于按状态、负责人、时间范围筛选工单的场景。如果要统计某个维度的分布情况,请使用数据分析技能。"模型一看到边界说明,误调用的概率立刻降下来了。

技能注册的代码本身不复杂,核心就是维护一个注册表:

# skill_registry.py class SkillRegistry: def __init__(self): self._skills = {} def register(self, skill: BaseSkill): """注册一个技能到全局注册表""" schema = skill.get_schema() self._skills[schema["name"]] = { "instance": skill, "schema": schema } def list_schemas(self): """返回所有技能的 Schema,供模型调用时参考""" return [v["schema"] for v in self._skills.values()] def execute(self, skill_name: str, arguments: dict): """按名称执行技能""" entry = self._skills.get(skill_name) if not entry: raise SkillNotFoundError(f"技能不存在: {skill_name}") return entry["instance"].run(**arguments)

3.2 技能发现:零散技能如何被模型"看懂"

有了注册表,下一步是让模型在每一轮对话中决定"要不要用技能、用哪个技能、传什么参数"。这一步我试过两种路线。

第一种是"全量注入":把注册表里所有技能的 Schema 都塞进每次请求的上下文中。优点是实现简单,缺点是技能一多上下文就被撑爆了。我测过,技能超过 15 个之后,模型的选择准确率明显下降,响应速度也变慢。

第二种是"检索再注入":先把所有技能描述做向量化,用户请求进来时先做一次语义检索,只把最相关的 5-8 个技能 Schema 注入上下文。缺点是需要维护一套向量索引,但效果提升非常明显——选择准确率从 70% 左右提升到 90% 以上。

我最终用的是第二种。具体链路是:请求进来 → 对用户意图做向量检索召回候选技能 → 把候选技能 Schema 和对话历史一起拼进 prompt → 模型输出技能调用指令(JSON 格式) → 解析指令、校验参数、执行技能 → 把执行结果作为"工具返回"再次喂给模型,让它组织最终回复。

这套链路跑起来之后,整个系统才真正有了"智能体"的样子。用户不需要知道你在背后挂了哪些技能,他只要说需求,模型自己就知道该调谁、怎么调。

3.3 技能调用:从"模型输出"到"安全执行"之间的校验层

模型输出技能调用指令是一回事,真正安全地执行是另一回事。我在模型和执行器之间加了一层校验逻辑,专门做三件事。

第一是格式校验。模型偶尔会输出畸形的 JSON,比如多一个逗号、少一个引号,直接用 json.loads 解析会直接报错。我的做法是先用正则把模型输出里的 JSON 块提取出来,再用一个宽松的解析器(比如 demjson3)做容错解析,实在解析不了就返回一条"参数格式有误"的提示让模型自己修正。

第二是参数校验。模型推断的参数经常有离谱值,比如查询时间范围传了"很久以前"。我把 JSON Schema 的校验器接进来,必填字段缺失、类型不匹配、超出枚举范围的都会在这里被拦住。校验失败时,系统会把失败原因返回给模型,让它重新生成调用指令——而不是直接让程序崩溃。

第三是权限校验。不是所有技能都面向所有用户开放的,比如删除类操作、修改类操作就要走鉴权。我的方案是在技能定义里加一个 required_role 字段,执行前检查当前会话的用户角色。这一步看着简单,但在生产环境里是救命的,后来有一次模型在对话中错误地触发了数据删除技能,就是因为角色校验拦截住了,只差一步就酿成事故。

4. 三个典型技能的实现笔记:检索、工具调用、长文本处理

4.1 检索技能:让 Agent 长出"记忆"和"外脑"

第一个我实现的核心技能是语义检索。场景是这样的:用户在对话中问"我们之前讨论过的那份关于接口改造的文档在哪",这属于典型的"模型不知道,但系统里有答案"的问题。没有检索技能,模型只能瞎猜或者直接说不知道;有检索技能,它就能去知识库里把相关文档捞出来,基于真实内容作答。

这个技能的构成分三层:文档入库、向量化、相似度检索。文档入库阶段需要做格式清洗,把 PDF、Word、Markdown 里的内容统一转成纯文本,按固定块大小(我用的 512 个字符)切分,保留段落间的上下文关联。向量化用的是 embedding 模型,切出来的每个文本块转成一个向量存进向量数据库。检索时把用户问题的向量和库里的向量做相似度计算,取 Top-K 结果返回。

这里我想单独说一个我踩过的坑:纯向量检索的召回质量不稳。用户问"上个月的数据"这类问题,语义相近但表达方式多变,向量相似度往往不是最优信号。我的解决办法是做了个混合检索:向量召回的同时,再用关键词做一次倒排索引匹配,两路结果按权重融合排序。改完之后检索准确率明显上了个台阶,尤其是在长尾问题的处理上。

4.2 工具调用技能:把"能用嘴说"变成"能动手做"

检索技能解决的是"找信息",工具调用技能解决的是"做动作"。比如用户说"帮我给张三发一封提醒邮件""把这周的报表导出成 Excel",这些都是要触发真实系统动作的场景。

我的实现方式是把外部系统的接口封装成技能。比如邮件技能,内部就是调邮件的发送接口,参数包括收件人、主题、正文、附件。但封装不是简单的接口转发,中间要做很多工程化处理:敏感操作要二次确认、接口鉴权要注入 token、调用失败要分类处理并返回用户可读的提示。

工具调用技能里最重要的一件事,是错误处理策略。我在测试时发现,模型调工具失败后容易进入两种极端:一种是失败之后直接放弃,跟用户说"操作没成功"就完了;另一种是执拗地重试同一个错误调用好几遍。我的方案是在技能执行结果里加一个结构化字段,包含成功/失败状态、失败原因、可操作建议。模型看到这些信息后,如果原因是参数问题就自己修正重试,如果是权限问题就如实告知用户,如果是临时故障则提示稍后再试。这样处理下来,用户体验好了非常多,不再对着一个"操作失败"的干巴巴提示发呆。

4.3 长文本处理技能:超长内容如何拆、怎么喂、如何答

第三个让我头疼的技能是长文本处理。用户的输入经常超过模型的上下文窗口,比如直接甩上来一个 50 页的 PDF,问"总结一下这份合同里的风险条款"。直接把原文塞进上下文肯定是不行的,溢出不说,模型对超长输入的注意力也会分散。

我的做法是做一个组件化的处理方案。第一层是内容压缩:先用一个模型把长文本按章节做粗粒度的摘要,把几百页的内容压缩成几个关键段落。第二层是分段问答:基于压缩后的内容先做一轮粗答,定位到具体章节,再回到原文取相关段落做细答。第三层是答案拼装:把细答的结果整合成最终回复。

这个技能做完之后,系统能处理的输入长度从几万字符直接扩展到几百万字符。虽然不能保证每个细节都完美覆盖,但至少用户问的绝大多数问题都能从原文里找到依据,而不是得到一句"超出处理范围"。我后来在复盘笔记里写了一句:长文本处理的核心不是"记住所有内容",而是"知道去哪找答案"。这个思路适用于几乎所有大模型应用。

5. 实测中最容易翻车的三个环节:并发、超时、上下文

5.1 并发:技能调用不是串行表演,要防"雪崩"

技能系统上线后第一次遇到真实的并发压力,是在一个团队内部试用时——二十几个人同时用,每个人可能同时触发两三个技能调用。结果系统响应时间从 300 毫秒飙升到 8 秒,部分请求直接超时。

排查下来问题出在几个地方。一是技能实例没有做并发控制,多个请求同时调用同一个技能实例时,内部状态互相污染;二是外部接口没有统一限流,瞬时打出去的请求直接把下游系统压垮;三是模型层的调用和技能执行是串行的,一次对话里如果模型决定调用多个技能,得一个接一个等,用户体验很差。

解决办法分三层:技能实例改成无状态设计,每次调用新建会话上下文,避免共享状态;给每个外部接口配置独立的限流器和熔断器,下游一旦异常就快速失败并返回提示;对需要多技能组合的场景,把能并行执行的调用放到线程池里并发跑。改造完成后,同样的二十人并发场景,响应时间回到了 1 秒以内。

5.2 超时:大模型思考慢,技能执行更要留出"提前量"

超时问题是我在产品化阶段才真正重视起来的。对话场景里,用户发出请求后,模型要先理解意图、再决定调用哪个技能、然后生成调用指令、等待技能执行、最后组织回复。整个过程链路很长,任何一个环节慢了都会拖垮整体体验。

我最初设置的技能执行超时时间是 10 秒,后来发现模型在一个请求里有可能连续调用两个技能,每个技能拿结果后还要再跟模型交互一轮,总耗时经常超过 30 秒。前端等待超过 20 秒用户就开始流失了。我的调整是把长任务改成异步模式:技能执行放到后台队列里,前端先给用户一个"任务处理中"的反馈,执行完成后通过消息推送通知结果。虽然实现复杂了一些,但体验提升是质的飞跃。

这里再分享一个细节:技能调用的超时时间,不要和模型响应时间混在一起设置。模型生成一篇长回复可能要 10 秒,但技能执行(比如查接口)通常 1-2 秒就应该返回。如果你把两者合并设一个总超时,技能执行出问题时会浪费掉宝贵的超时预算。分开设置,每个环节都在自己的预算内完成,排查问题时也能更快定位到是哪一环慢了。

5.3 上下文:技能调用结果不是"一次性消耗品"

最后一个坑是上下文管理。刚开始我做的实现很简单:技能执行完,把结果拼进对话历史,模型基于它组织回复,回复完了结果就不要了。但实际使用中我发现了问题:用户会在下一轮对话里继续追问上一轮的结果,比如"刚才那个报表里华南区的数据是多少"。如果上一轮技能返回的数据已经被丢掉了,模型就只能瞎编或者再次调用技能(浪费算力)。

我的解决方案是给技能调用结果加上"有效期"和"摘要缓存"。技能返回的完整结果存在一个短期缓存里,同时把结果的摘要(比如"查询了 2024 年第一季度华南区销售数据,共 128 条记录")注入到对话历史中。模型回答后续问题时,如果发现用户问的内容命中摘要里的关键词,就去缓存里取完整结果;如果没命中,就重新触发技能查询。

这个机制上线后效果显著,用户不会再说"我刚才问过的你怎么不记得了"。但注意,缓存要设置合理的过期时间,比如我设置的 30 分钟——时间长了数据可能已经不新鲜了,再返回旧结果反而误导用户。

6. 技能质量怎么评:我给 agent-skills 建的测评标准和迭代闭环

6.1 指标设计:不能用"感觉变聪明了"来评判

技能多了以后,很快面临一个问题:怎么判断这个技能改得好不好?光靠人工试用聊天记录,效率太低,而且主观性太强。我做了一套面向技能的自动化测评框架,核心指标有四个。

第一个是调用准确率,指模型在应该调用某个技能时是否正确地调用了它,以及调用时的参数推断是否和标注的一致。第二个是执行成功率,指技能真正执行时的完成情况,包括接口返回是否正常、数据处理是否完整。第三个是结果有用率,由人工或者评测模型判断技能返回的内容对用户的问题是否有帮助。第四个是端到端响应时间,衡量整个调用链路的延迟。

每一项指标都在评测集上跑。评测集是我陆陆续续攒的,包含两百多条真实用户问题和对应的期望技能调用路径,分成多个场景组。每次修改技能或者调整调用的提示策略,就全量跑一遍回归测试,对比各项指标的变化趋势。

6.2 评测集的建设:从"拍脑袋问题"到"分层样本"

评测集的质量直接决定指标的可信度。我的经验是别只用自己拍脑袋想的问题,要分层覆盖:一层是正常场景,即高频出现、意图明确的请求;一层是边界场景,比如参数缺失、范围过大、输入特殊格式;还有一层是干扰场景,即用户说的话听着像要触发某个技能,但实际意图不是。这三层样本比例大概控制在 6:3:1。

积累评测样本的途径,我用了两个:一是从真实使用日志里随机抽样并手工标注,这个比较费人力但最真实;二是用"干扰式生成"——让模型针对每个技能反向生成"听起来要调用但你实际不该调用"的问题,这类样本对提升模型的选择准确率帮助非常大。

6.3 迭代闭环:一个实例看技能怎么"变好用"

以语义检索技能为例,第一版上线时调用准确率只有 72%。评测集里的典型错误是:用户问"哪份文档提到了部署步骤",模型经常不调用检索技能,而是直接用自己训练知识里的通用答案作答。

我做的第一个改动是强化技能描述,在描述里明确加了一句"如果你的知识库中没有明确依据,请调用检索技能查询后再作答"。这一个改动把调准率提到了 81%。第二个改动是调整召回路,把检索候选数从 5 增加到 8,并且把召回结果按相关度分数做了过滤,低分文档直接不注入上下文。这次改动把准确率提到了 88%。第三个改动是把对话历史纳入检索条件,让模型可以根据前文提到的话题做进一步的精准检索,最终稳定在 93% 左右。

整个迭代过程只靠"感觉"是完全走不下去的,因为每个改动对指标的影响不是一眼能看出来的。有了评测集和量化指标,才能科学地决定改还是不改、怎么改。这是我做 agent-skills 项目最大的收获之一:AI 应用的质量提升,必须建立在可量化的工程方法之上。

7. 坦白说:这些坑我到现在也没完全填平

项目做了这么久,有些问题的解法我已经有了比较清晰的答案,但有些坑仍然客观存在,写出来是希望后来者有所预期。

技能数量的天花板。当技能数量超过三四十个之后,即使有检索召回,"该不该用、该用哪个"的选择还是会出问题。我试过给技能加分类层级,也试过让模型先做子任务规划再逐个选技能,效果有好转但没根治。我目前的思路是,与其优化模型选择能力,不如主动控制技能的粒度——把相关的小技能合并成功能更完整的中型技能,减少模型做选择的次数。

技能之间协作时的冲突。多个技能同时被调用时会产生一些不可预料的相互作用。比如检索技能返回了知识库的旧文档,而数据技能返回了系统里的新数据,两者口径不一致时模型怎么取舍?我的临时做法是在技能返回结果里标记数据的时间戳和来源等级,让模型优先采信更权威的来源。但这个方案还比较粗糙,从产品层面看,更合理的做法是让技能之间可以显式声明依赖关系和优先级。

评估集本身会过时。用户的使用模式和真实场景会不断变化,评测集也需要持续更新。我给自己定的节奏是,每两周复盘一次近期的失败案例,把新出现的错误类型补充进评测集。这个过程没有终点,因为 AI 应用和传统软件最大的不同就是:它面对的是开放世界,永远不会有一套"做完就万事大吉"的测试覆盖。

最后说一点个人体会。做 agent-skills 这段时间,最让我感慨的是,很多人对 AI Agent 的期待是"有了它什么都能干",但真正落地的时候你会发现,工程上的功夫一点都省不了:接口要封装、异常要处理、上下文要管、质量要测。技能化这件事,本质上是把"智能"这件事重新拉回到工程可控的轨道上——它不炫酷,但它是把大模型从玩具变成工具的关键一步。希望这篇复盘能让你少走几步弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询