跳到主要内容

工具调用策略

本节定位

上一节你已经知道怎样把工具安全地接到模型后面。
这一节要继续往前走一步:

工具不是接上就行,关键是怎么用。

真正拉开系统质量差距的,往往不是“有没有工具”,而是“什么时候调、先调哪个、失败后怎么办”。

学习目标

  • 理解工具调用策略为什么是 Agent 成败关键之一
  • 分清“不调用 / 单次调用 / 多步调用 / 回退策略”几种常见模式
  • 学会设计基本的路由、重试和验证逻辑
  • 看懂一个更完整的工具策略示例

一、为什么“有工具”不等于“会用工具”?

1.1 一个常见误解

很多人做 Agent 的第一步是:

  • 接上搜索工具
  • 接上计算器
  • 接上数据库

然后就觉得系统会变强。

但现实里经常出现:

  • 不该调工具时乱调
  • 该调工具时反而不调
  • 调错工具
  • 一件事连着调 5 次还停不下来

所以真正的问题不是:

系统有没有工具

而是:

系统有没有“使用工具的策略”。

1.2 一个生活类比

你家厨房有刀、锅、烤箱、微波炉,不代表你就会做菜。
关键在于:

  • 什么时候切
  • 什么时候煮
  • 什么时候烤
  • 哪一步出错了怎么补救

Agent 的工具调用策略也是一样。


二、先把几种常见策略分清楚

2.1 不调用工具

适合:

  • 常识性解释
  • 简单改写
  • 文风转换

例如:

“把这段话改得更正式一点”

这种任务通常不需要外部工具。

2.2 单次调用

适合:

  • 查天气
  • 算数学式
  • 查一条知识库记录

这是最简单也最稳定的调用方式。

2.3 多步调用

适合:

  • 先查订单,再查退款规则,再给结论
  • 先搜资料,再总结,再生成输出

这时策略不再只是“调用哪个工具”,而是“下一步还要不要继续调”。

2.4 回退与兜底

如果:

  • 主工具失败
  • 结果不可信
  • 参数校验不过

系统就要决定:

  • 重试
  • 换工具
  • 让用户补充信息
  • 直接承认无法完成

这也是工具策略的重要部分。


三、工具调用前要先判断什么?

3.1 这件事真的需要工具吗?

并不是所有问题都值得走工具链。
每次调用工具都会增加:

  • 延迟
  • 成本
  • 失败路径

所以第一步常常是:

先判断需不需要调用工具。

3.2 如果需要工具,该选哪个?

例如用户问:

“我这个订单还能退款吗?”

可能需要:

  1. 查订单状态
  2. 查退款政策

所以工具选择不总是“单选题”,有时是“有顺序的组合题”。

3.3 参数是否足够?

有些问题即使知道该调哪个工具,也可能参数还不够。

例如:

“帮我查天气”

缺城市名。
这时最合理的策略不是乱猜,而是:

先向用户追问。


四、工具调用后还要判断什么?

4.1 结果是否可信?

工具返回了,不代表就可以直接用。

比如:

  • 接口超时后返回空值
  • 搜索结果相关性不高
  • 数据库查不到记录

4.2 是否需要继续下一步?

有些任务一次调用拿不到最终答案。

例如:

  • 先查知识库
  • 再做计算
  • 再汇总成用户能读懂的话

所以工具策略本质上经常是:

调用 -> 观察 -> 再决定下一步


五、一个最小但有教学意义的策略示例

下面这个例子会区分三种情况:

  • 不调工具
  • 调单个工具
  • 参数不足时先追问
def route_query(query):
if "总结" in query or "改写" in query:
return {"action": "no_tool", "reason": "纯文本任务"}

if "天气" in query:
if "北京" in query:
return {"action": "tool", "tool": "weather", "arguments": {"city": "北京"}}
return {"action": "ask_user", "question": "你想查哪个城市的天气?"}

if "计算" in query:
expression = query.replace("计算", "").strip()
return {"action": "tool", "tool": "calculator", "arguments": {"expression": expression}}

return {"action": "fallback", "reason": "当前没有合适策略"}

queries = [
"把这段话总结一下",
"北京天气怎么样",
"帮我查天气",
"计算 12 * 7"
]

for q in queries:
print(q, "->", route_query(q))

这个例子虽然简单,但已经体现出“策略”这个层次了:

  • 不是所有输入都交给工具
  • 不是一缺参数就硬猜
  • 不知道怎么办时有 fallback

六、一个更完整的策略闭环

6.1 定义几个工具

def get_weather(city):
return {"city": city, "temperature": 22, "condition": "sunny"}

def calculate(expression):
return {"result": eval(expression, {"__builtins__": {}})}

6.2 调度 + 校验 + 执行

def execute_strategy(query):
decision = route_query(query)

if decision["action"] == "no_tool":
return {"type": "answer", "content": "这类任务更适合直接由模型生成文本结果。"}

if decision["action"] == "ask_user":
return {"type": "question", "content": decision["question"]}

if decision["action"] == "tool":
if decision["tool"] == "weather":
result = get_weather(**decision["arguments"])
return {"type": "tool_result", "content": result}
if decision["tool"] == "calculator":
result = calculate(**decision["arguments"])
return {"type": "tool_result", "content": result}

return {"type": "fallback", "content": "当前无法稳定处理这个请求。"}

for q in ["北京天气怎么样", "帮我查天气", "计算 9 + 8"]:
print(q, "->", execute_strategy(q))

这段代码真正教的是:

工具调用策略不是一行 if,而是“判断 + 分流 + 执行 + 兜底”的链路设计。


七、真实系统里最常见的几种策略模式

7.1 Router 模式

先判断问题属于哪个工具或哪个子系统。

适合:

  • 工具很多
  • 任务边界明确

7.2 Verify 模式

工具调用后,不马上信结果,而是再做检查。

适合:

  • 外部数据不稳定
  • 工具失败率较高

7.3 Retry / Fallback 模式

先重试,再降级,再兜底。

适合:

  • 外部 API 波动
  • 线上服务不稳定

7.4 Plan-then-tool 模式

先规划,再决定工具顺序。

适合:

  • 多步任务
  • 多工具依赖

八、什么时候该“少调工具”?

这其实也是很重要的策略能力。

8.1 少调工具的典型场景

  • 纯总结
  • 纯改写
  • 风格转换
  • 已有上下文足够

8.2 为什么少调有时更好?

因为每增加一次工具调用,就增加一次:

  • 时延
  • 失败可能
  • 状态管理成本

所以一个成熟系统不是“能调就调”,而是:

该省的时候就省。


九、初学者最常踩的坑

9.1 把工具调用策略理解成“路由规则”

路由只是其中一部分。
真正的策略还包括:

  • 是否调用
  • 是否追问
  • 是否继续下一步
  • 是否回退

9.2 调用失败后没有下一步

没有重试、没有 fallback、没有补问,这种系统线上会很脆。

9.3 每次都默认模型自己决定一切

实际工程里,很多策略应该由程序框架明确约束,而不是完全放给模型自由发挥。


小结

这一节最重要的不是知道“可以调哪些工具”,而是理解:

工具调用策略决定了 Agent 会不会在正确的时机、以正确的顺序、用正确的方式调用工具。

这往往比“多接几个工具”更影响系统质量。


练习

  1. 给本节示例再加一个 search_docs(keyword) 工具,并扩展路由逻辑。
  2. 增加一个“如果工具执行报错,则 fallback 到人工确认”的分支。
  3. 想一想:如果用户问“帮我查天气并计算穿衣指数”,策略层应该怎样拆分这件事?
  4. 用自己的话解释:为什么说工具调用策略是 Agent 质量的分水岭之一?