工具调用策略
本节定位
上一节你已经知道怎样把工具安全地接到模型后面。
这一节要继续往前走一步:
工具不是接上就行,关键是怎么用。
真正拉开系统质量差距的,往往不是“有没有工具”,而是“什么时候调、先调哪个、失败后怎么办”。
学习目标
- 理解工具调用策略为什么是 Agent 成败关键之一
- 分清“ 不调用 / 单次调用 / 多步调用 / 回退策略”几种常见模式
- 学会设计基本的路由、重试和验证逻辑
- 看懂一个更完整的工具策略示例
一、为什么“有工具”不等于“会用工具”?
1.1 一个常见误解
很多人做 Agent 的第一步是:
- 接上搜索工具
- 接上计算器
- 接上数据库
然后就觉得系统会变强。
但现实里经常出现:
- 不该调工具时乱调
- 该调工具时反而不调
- 调错工具
- 一件事连着调 5 次还停不下来
所以真正的问题不是:
系统有没有工具
而是:
系统有没有“使用工具的策略”。
1.2 一个生活类比
你家厨房有刀、锅、烤箱、微波炉,不代表你就会做菜。
关键在于:
- 什么时候切
- 什么时候煮
- 什么时候烤
- 哪一步出错了怎么补救
Agent 的工具调用策略也是一样。
二、先把几种常见策略分清楚
2.1 不调用工具
适合:
- 常识性解释
- 简单改写
- 文风转换
例如:
“把这段话改得更正式一点”
这种任务通常不需要外部工具。
2.2 单次调用
适合:
- 查天气
- 算数学式
- 查一条知识库记录
这是最简单也最稳定的调用方式。
2.3 多步调用
适合:
- 先查订单,再查退款规则,再给结论
- 先搜资料,再总结,再生成输出
这时策略不再只是“调用哪个工具”,而是“下一步还要不要继续调”。
2.4 回退与兜底
如果:
- 主工具失败
- 结果不可信
- 参数校验不过
系统就要决定:
- 重试
- 换工具
- 让用户补充信息
- 直接承认无法完成
这也是工具策略的重要部分。
三、工具调用前要先判断什么?
3.1 这件事真的需要工具吗?
并不是所有问题都值得走工具链。
每次调用工具都会增加:
- 延迟
- 成本
- 失败路径
所以第一步常常是:
先判断需不需要调用工具。
3.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,而是“判断 + 分流 + 执行 + 兜底”的链路设计。