工具调用阶段

在对话过程中,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消耗。对于这个简单查询,航班和酒店工具完全不相关。

优化 (有动态路由)

  1. 设置一个简单的意图分类器,基于关键词进行匹配。输入:"帮我查一下明天北京的天气怎么样? "关键词检测:"天气" -> 意图识别为 "查询天气"。

  2. 根据意图 " 查询天气 ",动态路由模块选择相关的工具子集。

  3. 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次。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐