资讯动态

Agent工具太多反而挑花眼?从60个收敛到16个的实战优化

发布时间:2026/9/28 15:41:49 来源:尧图企业网站定制
Agent 工具给到六十个它开始挑花眼。这句话我在内部复盘时写了不下三遍。事情是这样的我把自己做的那个信息整理型 Agent 从只接一个日历 API一路扩到接搜索、读 PDF、写数据库、发通知、执行脚本……最终工具清单停在六十几项。我本以为功能越多越全能结果同一个任务连续跑五次五次选了五种工具组合甚至有一次直接报了 execution terminated due to error。那一刻我才意识到“挑花眼”不是人类才有的问题对依赖 function calling 的 Agent 来说当六十个工具的 schema 同时摆在模型面前它真的会陷入一种概率意义上的选择困难。这篇文章记录我从 60 个工具翻车、到逐步收敛到 16 个工具的完整过程包括背后的原理和一套可复用方法。如果你也在给 Agent 堆工具这篇应该能帮你少走不少弯路。1. 六十个工具堆上去之后Agent 真的开始“犯浑”1.1 我遇到的最典型一次一个整理任务把整个链路跑崩先说这次最让我崩溃的任务。用户把桌面文件夹里的三份 PDF 拖进对话要求是提取每份文档的核心观点按主题归类写入知识库并且每周汇总一次结果发到邮箱。这个任务在早期只有 8 个工具时跑起来基本是“一条直线”读 PDF → 解析文本 → 总结 → 写知识库。但在工具堆到 60 个之后同一任务的表现完全变样。我从日志里还原了 Agent 的实际路径它先调用了“网页搜索”工具去搜索“PDF 观点提取方法”而不是直接调用文档解析工具。随后又调用了 OCR 工具对 PDF 的第一页做了一次图像识别。中途还莫名其妙调用了“文件重命名”和“写入 CSV”两个与任务完全无关的工具。最后在写入知识库时选错了向量库写入接口传了一个不存在的集合名参数直接触发运行时异常整个执行链终止。任务目标本身被丢到一边Agent 在一个又一个工具之间东摸一下西碰一下。日志结尾那行 execution terminated due to error基本就是“挑花眼”最直接的证据。1.2 “挑花眼”的实质不是拟人化是概率分布变了很多人会把这种行为理解成“模型不够聪明”但真实原因更接近数学层面的问题。Function calling 的过程说白了就是让模型在候选函数集合里做一次分类它根据当前对话的上下文对每个可用的工具计算一个倾向性分数然后挑一个或多个作为本次调用结果。工具只有 5 个的时候正确答案就像五个选项里的明显高亮项模型选对很容易。但当候选变成 60 个而且里面有一批本质相似的工具时正确的那个工具获得的倾向性分数会被大量相似候选拉平。我后来翻具体输出概率时发现某些任务里正确工具的置信度只有 0.25 左右和另外两个错误工具的分数几乎一样。模型并没有“主观迷惘”它只是面对一个被拉平的决策边界自然容易滑向错误选项。所以“挑花眼”不是一句文学修辞它是工具集合变大之后函数选择概率分布发生恶化的真实结果。1.3 工具数量与成功率不是线性关系我用同一个测试任务做过一组非常粗糙的统计10 个工具时任务成功率达到 96%几乎不误选加到 20 个左右成功率掉到 87%开始零星出现“绕远路”的现象到 30 个成功率跌破 75%等到 60 个工具全部挂上去成功率只剩下三成出头。与此同时单个任务的平均工具调用次数却从 1.2 次涨到 4.6 次整体耗时翻了四倍多。这个曲线的形态让我印象很深工具带来的能力增量不是线性的超过某个阈值之后每加一个新工具不仅没有明显提升上限反而开始侵蚀稳定性。如果把每个工具视作一份“可被选择的动作”那么工具数量扩大时选择错误产生的连带成本是呈指数增长的。2. 为什么选项越多越容易选错工具调用的四个底层陷阱2.1 工具 Schema 正在悄悄挤占上下文窗口第一个陷阱是最容易忽略的工具描述会占用上下文。多数框架会把全部工具的 name、description、parameters 拼成一个 JSON Schema 列表传给模型。一个工具的平均描述若按 50 个中文字符算加上参数类型、必填标记、注释折算成 token 往往会到 200~300。六十个工具意味着光工具定义就是 12000 到 18000 个 token。这个数字放在 32k 上下文的模型里初看并不致命但账不能这么算。系统指令、历史对话、每一步工具返回结果这些全部要分享同一片上下文空间。工具定义吃掉的 token 越多留给主任务指令和中间推理的空间就越少。更麻烦的是注意力资源的分配模型不是一台扫描仪前面的工具列表太长后面真正重要的任务描述在注意力层面会被稀释最终表现为“该做的事情被忽略、不该管的工具反复出现”。2.2 命名和描述高度重叠时函数选择置信度被拉平第二个陷阱是候选工具之间的语义重叠。我早期给工具命名时很随意三个搜索类工具分别叫 web_search、search_engine、lookup_web每个工具的描述都写着“用于搜索”。模型面对这三个几乎同义的工具只能靠猜。这就像让你在六十款包装颜色都差不多的牙膏里挑指定的一支你盯着看半天反而选得比闭眼拿还随机。模型也一样工具的 name 和 description 在语义空间中距离太近函数选择的 logits 分布就会被“拉平”正确的工具难以脱颖而出。我在日志里见过不少次同一个搜索功能这次调用 A下次调用 B再下次甚至同时调 A 和 B。2.3 规划器“选择疲劳”来回切换、重复调用、恶性循环第三个陷阱是一种行为现象我叫它“选择疲劳”当模型不确定自己选没选对时会倾向于再做一次尝试来确认。于是简单的任务里经常出现奇怪的调用序列先调用“提取 PDF 文本”怀疑结果不对又调用“OCR 识别 PDF”再回到“提取 PDF 文本”。这种来回切换会显著拉长执行链。我见过一个原本只需要两步的任务最终被模型调用了 7 次工具其中有 4 次是重复调用。更离谱的一次Agent 在同一个任务里先删除了一个文件随后又调用工具新建了同名文件。单独看每一步都像在执行某个子目标实际上整个规划已经失去了稳定方向。2.4 一次错误选择污染整条执行链第四个陷阱是错误会在链路中持续放大。Function calling 是串行状态下的决策第二步基于第一步的结果第三步基于前两步的状态。当第一步工具就选错了后面所有步骤都建立在一个错误的地基上。比如 PDF 解析把“提取文本”错误地换成了“OCR 图片识别”那么后续用于总结的内容就是缺版式、缺层次、甚至带大量噪声的文本再往后写知识库时主题归类的依据就是这些残缺信息。最终产物的质量可想而知。与此同时错误调用产生的中间结果还会留在对话历史里让模型在下一次决策时更加混乱。所以工具选择的错误从来不是“本次调用错一下而已”而是会顺着执行链一路滚成雪球。3. 我在实测里的翻车全过程从 10 个工具加到 60 个的逐阶段记录3.1 实验设计为了把“挑花眼”这个问题讲清楚我搭了一个简单的测试台。被测对象是我那个信息整理型 Agent固定使用同一条系统提示只改变挂载的工具数量。测试任务分三类简单任务从一条 URL 抓取标题并保存、中等任务读取 PDF 并提取三个要点写入数据库、复杂任务综合搜索、多文档解析、归类、生成周报草稿。每一类任务在每种工具数量下各跑 10 次统计四个指标工具选择命中率、任务成功率、单任务平均调用次数、平均完成耗时。工具集合按照真实项目里的配置维护分搜索、文档解析、存储、通知、运维、文件操作等多个组。增加工具时我把同一类功能的变体也加进去比如三个搜索工具、四个文档解析工具、三个数据库写入接口模拟“看起来能力很全其实高度重复”的典型情况。3.2 10 到 15 个工具阶段稳定但出现第一次误选10 个工具时整体表现接近理想任务成功率高工具调用次数少基本不会出现无关调用。这个阶段我印象最深的反而是唯一一次误选发生在“PDF 文本提取”和“PDF 表格提取”两个工具之间因为它们的描述都写了“提取 PDF 内容”模型选错了。当时我没放在心上只是给两个工具的描述各加了一句边界说明。到 15 个工具时整体仍然可控但误选频率肉眼可见地上升了。三组任务各跑 10 次工具选择命中率从 100% 降到大约 90%。单次误选虽然不影响任务完成但已经提示我后续工具越多这类模糊区会越密集。3.3 30 个工具阶段上下文告急开始丢指令工具数量到 30 之后情况发生了质变。最明显的是模型开始“忘记”任务目标。我让 Agent 把 PDF 内容写入数据库结果它先去搜了一会儿“今年行业动态”又调用日历工具查看今天日期最后才回到 PDF 解析。任务没失败但路径已经完全走样。指标上工具选择命中率掉到 75% 出头平均调用次数从 1.5 次涨到 2.8 次耗时从 10 秒涨到 18 秒。我翻了一遍请求日志发现系统提示的整体 token 里工具定义已经占掉了一半以上。模型不是没有那个能力而是它的注意力被工具列表拖得七零八落。3.4 60 个工具阶段任务崩溃执行被终止60 个工具全部挂载之后测试结果比我预想的还要差。三种任务各 10 次只有简单任务保持稳定中等任务成功率约一半复杂任务基本全军覆没。最典型的失败就是文章开头那个场景Agent 绕了一大圈最后在知识库写入环节传错参数运行时直接抛出异常执行链终止。日志里还能看到一个特别有意思的规律模型在 60 个工具下更像一个“无头苍蝇”平均每个任务要调用 4.6 次工具其中有近一半是重复调用或无关调用。它并不是“不会做事”而是每一次都像站在一个堆满东西的货架前不知道该拿哪一件于是拿一个看看放下再拿另一个。3.5 数据汇总对比我把四组测试的结果汇总成一张表它后来成了我所有内部分享的固定开场工具数量工具选择命中率任务成功率平均调用次数平均耗时10 个98%96%1.2 次8 秒15 个90%88%1.5 次10 秒30 个74%68%2.8 次18 秒60 个52%34%4.6 次35 秒需要说明的是不同模型在绝对值上会有差异开源模型的下降幅度通常比闭源模型更大但趋势完全一致超过 20 个工具之后所有的稳定性指标开始加速恶化。4. 不要让 Agent 面对六十个工具六种经过验证的收敛策略4.1 分组与命名规范把六十个工具整理成六个目录第一个能立刻落地的改进是给工具分组并统一命名前缀。我把 60 个工具按职责域归成 6 组搜索类统一加 search_ 前缀文档类统一 doc_存储类统一 store_通知类统一 notify_运维类统一 ops_Agent 内部能力统一 agent_。这个改动看起来只是改名效果却很直接。模型在规划时会先从“语义域”层面做一次粗筛选如果任务是处理 PDF就优先扫码 doc_ 前缀的工具如果要写数据库就聚焦 store_。分组之后同样还是 60 个工具但模型面对的不再是 60 个平权选项而是“6 个目录 每个目录里 10 项左右”工具选择命中率能提升十几个百分点。4.2 动态工具发现按任务检索而不是全量叠加如果你确实需要保留大量工具的长尾能力就应该考虑动态装载只把当前任务最相关的若干个工具放进模型可见范围其余全部留在“仓库”里。实现思路其实和 RAG 很像。我把每个工具的 name、description、参数说明做成一条索引文档用 embedding 向量化后存进向量库。任务开头先根据用户输入和系统状态做一次检索取 Top 8 到 Top 15 个工具注入当前请求。这样实际传给模型的工具永远是少量精选而不是六十个全量。这里有个代价要提前说检索本身可能出错如果工具描述写得稀烂任何向量检索都救不回来。因此动态工具发现的前提仍然是先把每个工具的 name 和 description 写好。4.3 路由 Agent 与子 Agent让专家各管一摊动态工具发现适合能力集中在一个主 Agent 的场景。如果你的系统已经趋向多 Agent 架构那更合适的办法是做路由拆分把 60 个工具按职责域分给多个子 Agent文档 Agent 只管文档解析搜索 Agent 只管搜索存储 Agent 只管写入。主 Agent 只面对少量路由工具每次调用某个子 Agent由子 Agent 在自己的小工具集里继续选择。这种做法的收益很明显每个子 Agent 的工具数量控制在 10 个上下天然避开了“选项爆炸”。代价也实在一次原本只要一层工具调用的任务现在可能需要主 Agent 子 Agent 两轮甚至三轮大模型往返延迟会上升不少。所以我只在延迟不敏感但准确率要求高的任务里使用路由 Agent。4.4 描述工程在工具说明里写清触发条件和不适用场景工具描述本质上是一段提示词很多人都没意识到这点。我测试中发现给工具描述加上“触发条件”和“不适用场景”之后相似工具之间的误选率明显降低。一个写得比较合理的描述长这样实时搜索工具当用户需要新闻、最新数据、网页内容或任何“我不知道”的外部信息时使用。不要用于解释已有文档内容文档解释请用 doc_extract_text。示例搜索“2025 年 AI 行业报告”。这段描述给了模型清晰的判断依据和对比参照物。相比“一个功能强大的搜索工具”这种废话信息量完全不在一个量级。4.5 分层可见性不同阶段只看部分工具动态工具发现是“按内容检索”分层可见性则是“按规则手动控制”。我把工具分成基础层、扩展层和高级层对话一开始只暴露基础层 5 个工具对话总结、基础搜索、时间查询、简单存储、用户意图澄清当检测到用户上传文档或提到“PDF”等关键词时再把 doc_ 工具组挂载进来只有明确进入运维模式或调试模式时才把 ops_ 工具暴露出来。实现上并不复杂每次向模型发起请求之前根据当前状态动态组装 tools 参数就行。这样做的好处是 Agent 永远处于“视野刚好够用”的状态既不会因为工具太少而能力不足也不会因为工具太多而挑花眼。4.6 工具评估集用回归测试守住工具集的质量线最后一个策略很容易被忽略却是我认为最重要的建立一个工具层的回归测试集。我准备了 20 个典型任务每个任务都写清楚“预期工具调用路径”和“不允许出现的工具”。每次调整工具集、修改描述、新增工具都会先跑一遍这套评估。比如任务“提取 PDF 表格并写入数据库”预期路径是 doc_extract_table → store_write_to_db不允许出现 search_ 前缀工具。跑回归时若发现模型选了 OCR 工具就说明新增工具改变了决策边界需要回头调整命名或描述。这套评估集让我在“改坏”工具配置之后能快速发现而不是等线上用户被坑了才知道。5. 给工具集做“断舍离”从 60 个收敛到 16 个的实操流程5.1 审计日志先搞清楚哪些工具真正被用过收敛工具集的起点不是“我觉得哪个有用”而是“让日志说话”。我给 Agent 加了一层统一调用审计每次工具调用都记录时间、工具名、输入摘要、返回状态并在测试集上人工判断这次调用是否合理。跑了两周之后统计出来结果让我自己都愣了一下60 个工具里有 23 个从未被任何任务调用过另有 14 个虽然被调用过但次数不超过 5 次而且都有可替代方案。换句话说将近六成的工具是在“收藏夹里吃灰”。它们并没有让 Agent 更有能力只是在每次请求时占着上下文位置并把决策空间搅得更大。5.2 同类合并把多个相似工具收敛成统一网关砍掉完全没用的工具之后下一步是合并相似工具。我的做法是把三个搜索工具合并成一个 search用一个 scope 参数区分 web、docs、code 三种来源把四个文档解析工具合并成一个 parse_document用 input_format 参数指定 PDF、Word、Markdown 或纯文本。这个思路的关键在于对模型来说选择一个“抽象但带参数”的工具比从一堆相似工具里挑一个更简单。参数值的选择是自然而然的任务而工具名选择则容易被相似描述干扰。但也不要过度抽象如果某个工具的参数超过五六个、分支逻辑复杂模型反而会在参数选择上再次翻车这时候就应该拆回多个子工具。5.3 核心清单与外围删减原则经过审计和合并我最终保留了 16 个工具分成四类业务主线必备PDF 解析、知识库写入、任务规划、对话总结高频通用能力统一搜索、时间与日历、URL 抓取、向量检索基础文件操作读取文件、写入标记、文件重命名、批量整理安全兜底与协作只读审计、邮件发送、通知发送、用户意图澄清这条保留逻辑是先保证业务闭环的主链路再补上最高频的通用能力最后留少量兜底。所有“听起来有潜力但两周没人用”的工具一律移除。那些被删的工具并不是永远消失而是回到了“仓库”列表只有在动态工具发现的架构下才会被临时启用。5.4 重构后的效果对比收敛到 16 个工具之后我用同一套测试任务重新跑了一遍结果和 60 个工具阶段形成了非常鲜明的对比指标60 个工具16 个工具工具选择命中率52%91%任务成功率34%92%平均调用次数4.6 次1.4 次平均耗时35 秒9 秒最让我意外的是工具少了之后复杂任务的成功率反而大幅上升。因为模型不再需要花费大量精力去做“排除法”而可以集中注意力在真正的任务逻辑上。这个结果后来成了我逢人就讲的结论给 Agent 减工具不是拿走它的能力而是帮它找回判断力。6. 关于 Agent 工具数量的几个反直觉结论与我的底线6.1 “能力多”不等于“工具多”组合与编排才是上限经过了这一轮完整的踩坑、测试、重构我对“Agent 能力边界”的理解彻底变了。一开始我朴素地以为工具数量代表能力上限每多接一个 API 就多一份本事。后来发现真正决定上限的是工具的设计质量、描述清晰度、路由方式和编排策略。六十个粗放堆叠的工具实际可用能力可能不如十个精心编排的工具。十个工具里既有主干能力又有标准参数设计再加上清晰边界描述配合一层简单的路由已经能覆盖我之前六十个工具绝大部分的使用场景。这就好比给你六十块形状雷同的积木你未必能搭出复杂的结构反而是少数几种恰到好处的异形积木组合起来更容易搭出稳定的造型。6.2 我的默认建议8 到 12 个核心工具最多不超过 20 个现在我做 Agent 配置时心里有一条不太科学的经验线单 Agent 简单任务5 到 8 个工具尽量不做没有必要的扩展单 Agent 复杂任务10 到 20 个工具超过 15 个就必须做分组或描述强化多 Agent 架构每个子 Agent 控制在 8 到 15 个主 Agent 只留 5 到 8 个路由工具20 个工具某种意义上是一个“警戒水位”。如果业务确实要求更多我不会再试图让主 Agent 直接面对全量工具而是会优先选择动态工具发现或者子 Agent 拆分。自己踩过坑之后底线就变成了“宁可架构上多绕一层也不要让模型在六十个选项里做像素级辨别”。6.3 工具描述本身就是提示词要像写提示词一样写描述最后一条经验想分享给正准备接工具的人请把每个工具的 name 和 description当成提示词去打磨。函数名要语义唯一描述要写清触发条件、不适用范围最好附带一两个参考示例。同一个工具描述从“用于搜索”改成“当用户需要最新外部信息时使用不要用于解释已有文档遇到问题前先确认信息是否已存在于知识库”误选率可以下降三分之一以上。模型版本更新后它对描述的敏感度也会变化所以建议每隔一段时间重跑一次工具评估集顺手优化各工具的边界描述。我在项目里把这个动作固化为每月一次的例行检查虽然听起来不酷但它真的能拦住很多“线上突然变蠢”的诡异问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑