Tool Call 工具调用原理
工具调用阶段
在对话过程中,Qwen-Chat模型会根据用户请求的需求,判断是否需要调用外部工具函数。如果模型认为需要(例如用户问的是实时信息、计算、数据库查询等超出模型训练知识范围的问题),它会在生成回答时触发一个特殊的工具调用标记<tool_call> 来标识「调用工具」的意图。
模型经过专门微调,学会了在适当情况下产生这个标记。例如,当用户在旅行助手场景中提出“请帮我查找7月20日从北京飞上海的航班,并推荐上海市中心的酒店”这样的请求时,模型判断需要查询航班和酒店信息,就会进入工具调用流程,首先在输出中生成 <tool_call> 开头的片段。
触发机制:Qwen-Chat 在训练和对齐阶段接触了大量带工具使用的示例,对何时应调用工具有一定的内在判断。官方评测显示,Qwen-Chat 模型在需要用工具时能够较高概率地正确调用,而在不需要时很少误调。例如,Qwen-7B-Chat 在中文工具使用测试中,工具选择准确率达 95.5%,误调用率仅11.6%,性能远超一般模型。
这说明模型已掌握了何时触发 <tool_call> 的策略,尽量只在必要时才调用函数。
JSON 参数格式化
一旦模型决定调用工具,在<tool_call>标记后面需要跟随规范的函数调用参数格式。Qwen 模型采用JSON结构来表示函数名和参数,以便结构化地传递给外部工具。模型会产生形如:
<tool_call>
{
"name": "<函数名>",
"arguments": { ... 参数 ... }
}
</tool_call>
工具执行阶段
当模型输出了 <tool_call>...JSON...</tool_call> 内容后,轮到外部的调度器(orchestrator)或宿主程序处理了。这个组件通常由我们编写,用于解析模型的工具调用请求并实际执行对应的函数。具体流程如下:
解析输出:首先,提取出<tool_call> 标签中的 JSON 文本。例如可以用正则表达式 r"<tool_call>\n(.+?)\n</tool_call>" 来查找所有工具调用片段。
对每个匹配到的 JSON 子串,用 json.loads 反序列化为 Python 对象。这一步将模型生成的文本转换为结构化的数据结构(如字典),方便后续处理。
映射函数:解析得到一个或多个调用请求后,调度器需要根据 "name" 找到对应的实际函数实现。通常我们事先会有一个工具函数映射表或直接用 Python 的同名函数。
参数传递与执行:取出 JSON 中的 "arguments" 字段作为参数调用对应的 Python 函数。
工具响应整合阶段
工具函数执行完毕后,我们得到了结果数据。接下来,需要将这些结果提供给模型,让模型据此生成回答。在Qwen的框架下,这通过一个特殊标记 <tool_response> 来实现。也就是,我们把工具的输出结果再封装成JSON字符串,放入 <tool_response> ... </tool_response> 标签内,作为新的对话消息追加到消息历史中。
模型识别到 <tool_response> 信息通常对应它之前的提问,因此会将其中的数据整合进自然语言答案
优化策略⭐
通过“场景 → 找badcase → 定位问题 → 优化 → 示例”的,首先把模型的能力榨干,结合提示词、函数名、上下文路由、CoT与结果校验来进行优化。
动态函数路由 (Dynamic Function Routing)
场景: 用户输入 "帮我查一下明天北京的天气怎么样?"
问题 (无动态路由): 如果我们将所有6个工具 都提供给LLM,LLM需要从更多选项中选择,增加了出错概率和token消耗。对于这个简单查询,航班和酒店工具完全不相关。
优化 (有动态路由)
-
设置一个简单的意图分类器,基于关键词进行匹配。输入:"帮我查一下明天北京的天气怎么样? "关键词检测:"天气" -> 意图识别为 "查询天气"。
-
根据意图 " 查询天气 ",动态路由模块选择相关的工具子集。
-
LLM 接收到的可用工具只有 [get_weather] 。 LLM 输出
(Function Call): get_weather(city="北京", date="明天")
缓解token压力: 传递给LLM的工具描述大大减少。显著减少歧义: LLM不需要在不相关的航班/酒店工具中做选择,降低了选择错误工具的概率。
CoT (Chain-of-Thought) + Plan-Execute
场景: 用户输入 "帮我订一张明天从上海到北京的机票,然后订一个机场附近的酒店住一晚。
"问题 (无CoT): LLM可能尝试一次性生成所有参数,或者错误地调用工具顺序,或者遗漏步骤。例如,可能先尝试订酒店,但不知道具体日期(因为机票还没订)。
优化 (CoT + Plan-Execute):
-
步骤1: LLM 生成思考过程和计划 (Thought & Plan)
-
User Query: "帮我订一张明天从上海到北京的机票,然后订一个机场附近的酒店住一晚。
-
"LLM Output (Thought & Plan):
Thought: 用户需要分两步完成任务:先订机票,再订酒店。
1. 订机票:需要确认出发地、目的地、日期。这些信息在用户提问中已经明确。
2. 订酒店:需要确认地点(机场附近)、入住日期、退房日期。入住日期是明天,退房日期是后天。地点是北京机场附近。
Plan:
Step 1: 查询从上海到北京的明天日期的航班。
Action: call search_flights(origin="上海", destination="北京", date="明天") Output: {{flight_options}}
Step 2: (假设用户已选择航班,获得 flight_id = "CA123") 预订该航班。
Action: call book_flight(flight_id="CA123", passenger_name={{user_name_from_profile_or_ask}}) Output: {{flight_booking_confirmation}}
Step 3: 查询北京机场附近,入住日期为明天,退房日期为后天的酒店。
Action: call search_hotels(location="北京机场附近", check_in_date="明天",check_out_date="后天") Output: {{hotel_options}}
Step 4: (假设用户已选择酒店,获得 hotel_id = "HOTEL789") 预订该酒店。
Action: call book_hotel(hotel_id="HOTEL789", guest_name={{user_name_from_profile_or_ask}}, num_guests=1) Output:{{hotel_booking_confirmation}}
-
步骤2: 审核与单步执行 (Execute)系统(或人工)可以审核这个计划。
-
步骤3: 执行后续步骤,处理失败与自我纠错 (ReAct)
结果校验层
场景: LLM调用 search_flights 工具,但API返回的数据格式有时不规范,或者LLM生成的参数不符合API要求。
结果校验层 (参数校验):
-
如果不可自动修复,可以记录错误,反馈给LLM
-
或者如果定义了重试逻辑(例如,可能是临时API故障),则进行重试。设定最大重试次数: 比如最多重试3次。
更多推荐



所有评论(0)