Agent 多技能调用的精准选择机制(详解工具目录与路由分层落地)

当一个 Agent 同时挂载数十个 Skill,主流做法是把 Skill 描述成可调用的工具目录,再以分级路由 + 检索召回 + 工具选择三段式策略让模型先缩范围、再做最终挑选;只要 Skill 描述按契约写清「做什么、不做什么、参数边界」,即便超过 50 个工具,准确率也能稳住在生产可用区间。

一、Skill 数量超过 20 个就开始掉准度

把 Skill 直接全量塞进模型上下文,命中率会随数量级递减。多个一线团队在生产中观察到,单步工具目录超过 20–30 后,模型选择错误率明显抬头;越过 50 个量级,工具选错的比例会迅速放大,原因是大模型对长 prompt 中的工具描述记忆与对比能力有限,远短于它对短而聚焦的列表的判别能力。

实际落地时,会把 Skill 池切成两层:先用一个轻量召回层把候选压到 5–10 个,再让模型在压缩后的目录里做最终决定。召回层的输入一般是「当前目标 + 当前状态 + Skill 元数据」三元组,输出是 Top-K 个候选 Skill 列表,模型只看压缩后的目录,等同于把”目录噪音”前置过滤掉。

二、Skill 描述必须写成”契约”而不是注释

工具描述是模型选择 Skill 的唯一依据。描述含糊(”做邮件相关的事”)会让模型把不同意图都映射到同一 Skill,描述过度(”在 A 且 B 且 C 时用”)又会让模型对边缘 case 失忆。业内共识是把描述写成”何时用 + 何时不用 + 参数边界”三段式。

描述要素 作用 写法要点
何时用 给出正面触发条件 用一句话点出典型场景和输入形态
何时不用 划清与邻近 Skill 的边界 明确”不适用于 XX”以减少误选
参数说明 让模型填对入参 每个字段标注类型、必填、单位、示例
错误码与返回 便于模型回读 列出主要返回结构与失败模式

对比一个”含糊”与”清晰”描述的效果:把 search 写成「搜索互联网内容」会让模型把任何信息查询都路由过去;改成「search(query: string, recencydays?: number): 在公网抓取网页与摘要,recencydays 未指定则取近 30 天结果,不适用于已知 ID 查单条记录」后,与 get_record_by_id 的误判明显下降。

三、分层路由:三段式召回 + 二次选择

把整套路由拆成三段,可在不增加模型成本的前提下把准确率拉回生产区间。

  1. 意图分类(轻量模型或规则):先用一个小分类器或规则判定当前请求属于”读 / 写 / 搜索 / 通讯 / 编码”哪个大区,缩到对应分组;
  2. 向量召回(Top-K):在分组内对 Skill 描述做 embedding 相似度检索,取 Top-K(一般 5–10),把候选目录推给主模型;
  3. 最终选择(主模型 Function Calling):主模型在压缩后的目录里按描述做最终决定,并按 schema 填参。
# 三段式路由:意图分组 + 向量召回 + 模型选择
from typing import List, Dict

def route_skill(user_goal: str, skills: List[Dict], embedder, k: int = 8) -> List[Dict]:
    # 1) 意图分组(用关键词或小模型把 skill 池切成 5–8 组)
    groups = group_by_intent(skills)  # {"search": [...], "db": [...], ...}
    intent = classify_intent(user_goal, groups.keys())

    # 2) 组内向量召回,取 Top-K
    goal_vec = embedder.encode(user_goal)
    cands = sorted(groups[intent], key=lambda s: cosine(goal_vec, s["vec"]), reverse=True)[:k]

    # 3) 仅把候选目录交给主模型做最终选择
    return cands

召回层用便宜的 embedding 模型即可,候选压到 8 个后,主模型一次推理就能稳定选对。Anthropic 工程团队在公开经验里也强调,目录规模是 Agent 可靠性研究中权重排在前面的单一变量,超过阈值就要前置过滤,不能”硬塞”。

四、用工具描述的四个必填字段

工程上要把每个 Skill 注册成可被 Function Calling 消费的 schema,必备四件套:

字段 含义 选型要点
name 工具唯一名 命名贴近用途,避免 tool1、tool2 这类无意义名
description 工具的契约说明 三段式:何时用、何时不用、参数边界
parameters 入参 schema JSON Schema 描述,每个字段带类型、必填、说明
returns 返回结构 列出主要字段、可能为空、错误码语义

name 是模型推断用途的第一信号,起名时尽量带意图词(如 get_weather 而非 tool_1);description 是消耗最多工程精力的字段,对选择准确率影响最大;parameters 用 JSON Schema 描述能让模型按结构填参,避免手误;returns 提前声明返回结构,方便模型下一步解析与串联。

五、并行调用与错误回退

当一个任务需要多个独立信息(比如同时查天气与股价),模型可一次推理发出多路调用,并发执行后按调用 id 归并结果,能把端到端延迟压到一轮。但并发不是越多越好,常见的反模式是”为并行而并行”,把本来有依赖的两次调用并发出去,导致第二次拿不到第一次的结果。

错误处理采用三层策略:临时错误(5xx、超时、限流)走指数退避重试;schema 不匹配或工具选错走”重规划”——把失败原因作为观察塞回上下文,让模型另选;多次重试仍无进展则升级人工或停止循环。三层策略之间的阈值要根据业务敏感度调整:写操作的重试上限要严于读操作。

六、易踩的两个坑

第一是描述”伪精确”。写「send_email 用于发送邮件」几乎等价于没写,模型无法靠它区分”发送通知邮件”与”发送营销邮件”两个相邻 Skill。补救方式是把场景词写进描述(「send_email 用于向单收件人发送事务性通知,支持主题与纯文本正文,不用于群发或带附件」)。

第二是目录合并后丢失分组信息。召回层把候选压到 8 个,但若 8 个全部来自同一组,模型反而缺了”应该选另一组”的能力。召回阶段要保留分组多样性约束(每组至少 1 个候选),让最终选择阶段还能在组间对比,而不是只在同组内二选一。

到这里,”在 Skill 数量大时让模型选得准”的链路就完整了:把 Skill 当成可调用工具、把描述写成契约、用召回 + 二次选择替代全量塞入、最后用并行与重规划托底稳定性。目录规模与描述质量决定了天花板,分层路由决定了能否稳定达到这个天花板。

常见问题(FAQ)

Q1:Skill 数量到 30 个就必须分层吗?

不一定。若每个 Skill 描述粒度细、相互之间无重叠,30 个以内仍可全量塞入;超过 50 个建议强制分层。

Q2:向量召回的 K 怎么定?

通常 5–10。K 越大选择越准但 token 开销上升,K 越小省 token 但误选率升,需结合业务测一组 A/B。

Q3:Function Calling 与 Tools 协议是否通用?

主流平台(OpenAI、Anthropic、Google、主流开源推理框架)都遵循同一类 schema 协议,但字段命名与并行语义略有差异,跨平台切换时要重写适配层。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部