工具使用策略,Agent什么时候该用工具、怎么选工具
工具多了以后,新的问题来了。Agent能不能选对工具、能不能用好工具。
工具少的时候还好,三五个工具,Agent基本能分清楚。工具一多,十几个几十个,它就开始混乱了。有时候该用的不用,有时候不该用的乱用,有时候参数还填错。
这一篇我们聊一聊,怎么让Agent更聪明地使用工具。有哪些实用的技巧,常见的问题怎么解决,以及工具设计的一些原则。
工具是不是越多越好
很多人刚开始做Agent的时候,有一个朴素的想法。工具越多,Agent能力越强。
于是使劲加工具。搜索、计算、数据库、文件、邮件、日历、天气、地图,能加的都加上。结果加完以后发现,Agent反而变笨了。经常选错工具,或者简单问题也要调半天工具。
工具不是越多越好。工具越多,Agent的选择成本越高,选错的概率越大。就像人一样,选项太多了反而不知道选什么。
我的建议是,起步阶段工具控制在五个以内。最核心、最常用的几个装上就够了。等用起来了,确实需要再加,再慢慢加。
而且工具之间的功能边界要清晰。两个工具做的事不要太像。功能重叠了,Agent就容易选错。比如已经有了通用搜索引擎,就不要再加一个类似的网页搜索工具。真的需要,就合并成一个,通过参数区分。
少而精,比多而杂效果好。
怎么让Agent选对工具
让Agent选对工具,主要靠工具描述。描述写得好,选得就准。
描述怎么写,之前讲自定义工具的时候说过一些。这里再补充几个技巧。
第一个,描述里明确说清楚适用场景和不适用场景。
比如搜索工具的描述,可以写"适用于需要实时信息、最新知识、或者你不确定答案的问题。不适用于你已经知道答案的常识性问题"。把边界说清楚,Agent就知道什么时候该调用、什么时候不该调用。
第二个,加正反例子。
光说什么时候用还不够,再说几个不该用的情况。比如"不要用这个工具来做数学计算,数学计算请用计算器工具"。这样能减少误用。
第三个,工具名要直观。
名字本身就能传达很多信息。叫search比叫tool1好懂多了。叫calculate_math比叫compute强。名字越直白,Agent越容易理解。
第四个,用结构化的描述。
用Pydantic定义输入,每个字段都有description。参数说明越清楚,Agent填错的概率越低。
这些看起来都是细节,加起来影响很大。我自己的经验是,同样的工具,描述写得好不好,准确率能差百分之二三十。
工具调用的常见问题
该调用的时候不调用
最常见的问题之一。明显需要查外部信息的问题,Agent就是不调用工具,自己瞎编答案。
原因通常有两个。要么是工具描述写得不够清楚,Agent没意识到该用。要么是模型能力不够,它判断不出来。
解决办法。
在系统提示里强调。告诉Agent,不知道的、不确定的,一定要用工具查,不要编造。强调事实准确性的重要性。
优化工具描述。把使用场景写得更明确,多加几个例子。
用更好的模型。能力强的模型,工具调用的判断力也更好。GPT-4就比GPT-3.5准不少。
加一层校验。Agent给出答案之前,先让它自己检查一下,这个答案是不是需要外部信息验证。如果是,就去查。
不该调用的时候瞎调用
另一个极端。简单的问题它也要调用工具,浪费时间浪费钱。
比如问一个"1加1等于几",它也要调计算器。这种问题大模型自己就能回答,完全没必要调工具。
解决办法。
在工具描述里说明,简单的、你确信能答对的问题,直接回答就行,不用调用工具。
在系统提示里说清楚。能直接回答的就直接回答,别什么都找工具。
工具选择的时候加阈值。如果Agent对直接回答的置信度很高,就跳过工具调用。这个需要自己实现。
其实这个问题的影响通常没有前一个大。多用几次工具,多花点钱,至少答案是对的。总比瞎编答案强。对准确性要求高的场景,宁可多调用几次,也别让它自己瞎猜。
参数填错
参数名写错,参数格式不对,该传数字传了字符串。都是常见问题。
解决办法。
用Pydantic定义参数,每个字段写清楚description和类型。
参数加例子。在描述里说明参数的格式,比如"日期格式为YYYY-MM-DD,例如2026-08-06"。
枚举值列出来。如果参数有固定的可选值,全部列出来。Agent从里面选,就不会填错了。
加参数校验。工具内部拿到参数先校验,不对就返回明确的错误信息,告诉Agent应该怎么改。它可以调整参数重新调用。
调用顺序不对
多步骤任务,Agent可能会把顺序搞反。比如应该先查A再算B,它先算了B再去查A。
这个问题比较深层,涉及到规划能力。简单的ReAct Agent规划能力有限,复杂任务经常顺序不对。
解决办法。
用LangGraph定义流程。把步骤和顺序固定下来,Agent不用自己想顺序,按流程走就行。
用更强的Agent框架。比如Plan-and-Execute,先做计划再执行。规划能力比ReAct好一些。
任务拆细一点。太复杂的任务Agent规划不好,拆成几个小任务,一个一个做。
工具设计的原则
自己设计工具的时候,有几个原则可以参考。
单一职责。一个工具只做一件事。不要做一个万能工具,什么功能都塞进去。Agent理解不了那么多。
原子操作。工具尽量是原子的。做一个独立的动作,返回明确的结果。太复杂的工具,Agent不容易用好。
幂等安全。尽量设计成幂等的。调用一次和调用多次,结果一样。Agent可能会重复调用,幂等的工具不容易出问题。
只读优先。先做只读工具,再做写操作。只读的出不了大事,写操作风险高很多。
返回自然语言。工具的返回结果,尽量整理成自然语言。别把原始JSON直接扔回去。Agent理解自然语言的能力比理解JSON强。
错误有意义。出错了返回有意义的错误信息。告诉Agent哪里错了、为什么错、建议怎么改。它才能自我修正。
这几条都是经验之谈。照着做,工具会好用很多。
工具成本控制
工具调用都是要钱的。搜索API按次收费,大模型按Token收费。调用多了,成本也是一笔不小的开销。
控制成本有几个办法。
第一个,限制最大迭代次数。AgentExecutor有max_iterations参数,设一个上限。防止Agent死循环,一直调用工具。
第二个,缓存。同样的问题,同样的工具调用,结果缓存起来。下次再碰到,直接用缓存的结果,不用再调用一次。搜索工具特别适合加缓存。
第三个,简单任务用便宜的模型。工具选择和简单推理用便宜的模型做,复杂生成用好的模型。这样能省不少钱。
第四个,监控用量。记录每次工具调用的时间、成本、结果。定期看一下,哪些工具用得多、哪些用得少、哪些是浪费。心里有数,才能优化。
第五个,设置预算上限。给Agent设一个每次对话的最大成本。超了就停下来,请示用户。防止意外情况把额度花光。
做小Demo的时候不用太在意成本。真上线了,这些都得考虑。
工具篇到这里就结束了。我们从Function Calling的原理讲起,讲了内置工具、自定义工具、搜索、数据库、文件、API,最后聊了工具使用策略。
工具是Agent的手脚。工具越多、越好用,Agent能做的事就越多。但也不是越多越好,适合的才是最好的。
从下一篇开始,我们进入RAG篇。给Agent装上知识库大脑,这是目前Agent落地最成熟、最广泛的应用场景。