当前位置: 首页 > news >正文

一个例子看LLM的工具调用流程

前面在我们使用langchain等框架做多工具调用的时候,我们不清楚具体的交互流程。LLM的推理过程是怎么样的,是一次做完规划还是逐个调用工具。

我们今天直接使用openai的接口,用原始的写法来看它具体执行的过程是怎样的。

代码如下:

import os
import json
from openai import OpenAI
from dotenv import load_dotenv# 加载 .env 文件中的环境变量 (如果存在)
# 建议将 API Key 存储在 .env 文件中,例如 OPENAI_API_KEY=your_key_here
load_dotenv() # --- 配置 ---
# 确保设置了 OPENAI_API_KEY 环境变量
# 或者取消下面的注释并直接设置密钥(安全性较低)
# os.environ["OPENAI_API_KEY"] = "sk-..." api_key = os.getenv("OPENAI_API_KEY")
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1/"
model_name = "qwen-plus"
print(f"api_key: {api_key}")
print(f"base_url: {base_url}")
print(f"model_name: {model_name}")# --- 工具定义 (本地函数) ---
def get_current_weather(location, unit="celsius"):"""获取给定地点的当前天气"""print(f"--- 正在调用工具: get_current_weather(location='{location}', unit='{unit}') ---")# 在实际应用中,这里会调用真实的天气 API# 为了演示,我们返回模拟数据if "beijing" in location.lower() or "北京" in location:weather_info = {"location": location,"temperature": "15","unit": unit,"forecast": "晴朗",}elif "nanjing" in location.lower() or "南京" in location:weather_info = {"location": location,"temperature": "18","unit": unit,"forecast": "多云",}else:weather_info = {"location": location,"temperature": "未知","unit": unit,"forecast": "未知",}return json.dumps(weather_info, ensure_ascii=False) # ensure_ascii=False 以正确处理中文def get_stock_price(symbol):"""获取给定股票代码的当前价格"""print(f"--- 正在调用工具: get_stock_price(symbol='{symbol}') ---")# 在实际应用中,这里会调用真实的股票 API# 为了演示,我们返回模拟数据if symbol.upper() == "AAPL":stock_info = {"symbol": symbol, "price": "170.50", "currency": "USD"}elif symbol.upper() == "MSFT":stock_info = {"symbol": symbol, "price": "420.72", "currency": "USD"}else:stock_info = {"symbol": symbol, "price": "未知", "currency": "未知"}return json.dumps(stock_info)# --- 主逻辑 ---
def run_conversation(user_query: str, model: str):"""运行包含工具调用的对话流程 (顺序执行)"""try:client = OpenAI(api_key=api_key, base_url=base_url)# 确保 API Key 已设置if not client.api_key:print("错误:OPENAI_API_KEY 环境变量未设置。")returnexcept Exception as e:print(f"初始化 OpenAI 客户端时出错: {e}")print("请确保已安装 'openai' 库并且 OPENAI_API_KEY 已正确设置。")returnmessages = [{"role": "user", "content": user_query}]# 定义 OpenAI API 需要的工具格式 (只需定义一次)tools = [{"type": "function","function": {"name": "get_current_weather","description": "获取给定位置的当前天气信息","parameters": {"type": "object","properties": {"location": {"type": "string","description": "城市和省/州,例如 San Francisco, CA 或 Beijing",},"unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位"},},"required": ["location"],},},},{"type": "function","function": {"name": "get_stock_price","description": "获取指定股票代码的当前价格","parameters": {"type": "object","properties": {"symbol": {"type": "string","description": "股票代码,例如 AAPL, MSFT",}},"required": ["symbol"],},},}]# 将本地函数映射到其名称,方便查找available_functions = {"get_current_weather": get_current_weather,"get_stock_price": get_stock_price,}print(f"\n{'='*10} 对话开始 (顺序工具调用) {'='*10}")print(f"初始用户请求: {user_query}")iteration_count = 0 # 防止无限循环max_iterations = 5  # 设置最大循环次数while iteration_count < max_iterations:iteration_count += 1print(f"\n--- 第 {iteration_count} 轮 API 调用 ---")print(f">>> 步骤 {iteration_count}.1: 向 OpenAI 模型发送当前对话历史和工具")print(f"    原始发送消息: messages={messages}, tools={tools}")try:response = client.chat.completions.create(model=model,messages=messages,tools=tools,tool_choice="auto", )response_message = response.choices[0].messagetool_calls = response_message.tool_callsfinish_reason = response.choices[0].finish_reasonprint(f"\n<<< 步骤 {iteration_count}.1 响应: 收到模型的决策")print(f"    原始响应: {response}") # 打印完整响应对象print(f"    响应消息: {response_message}")print(f"    结束原因: {finish_reason}")except Exception as e:print(f"\n!!! 调用 OpenAI API 时出错: {e}")break # 出错时退出循环# 将模型的回复添加到消息历史中 (无论是否包含 tool_calls)messages.append(response_message)# --- 步骤 {iteration_count}.2: 检查模型是否请求调用工具 ---if tool_calls:print(f"\n>>> 步骤 {iteration_count}.2: 模型请求调用 {len(tool_calls)} 个工具。将处理第一个。")# --- 步骤 {iteration_count}.3: 顺序执行第一个工具调用 ---tool_call = tool_calls[0] # 只处理第一个工具调用function_name = tool_call.function.namefunction_to_call = available_functions.get(function_name)tool_output_content = "" # 初始化工具输出内容print(f"\n--- 开始执行工具: {function_name} (ID: {tool_call.id}) ---")if not function_to_call:print(f"!!! 错误: 模型请求了未知的函数 '{function_name}'")tool_output_content = json.dumps({"error": f"函数 {function_name} 未找到"})else:try:function_args = json.loads(tool_call.function.arguments)print(f"--- 准备调用函数: {function_name} 参数: {function_args}")tool_output_content = function_to_call(**function_args)print(f"--- 函数 {function_name} 执行完毕。结果: {tool_output_content}")except json.JSONDecodeError:error_msg = f"无法解析函数 {function_name} 的参数。原始参数: '{tool_call.function.arguments}'"print(f"!!! 错误: {error_msg}")tool_output_content = json.dumps({"error": error_msg})except Exception as e:error_msg = f"执行函数 {function_name} 时出错: {e}"print(f"!!! {error_msg}")tool_output_content = json.dumps({"error": str(e)})print("--- 工具执行结束 ---")# 将工具执行结果添加到消息历史中,准备下一次调用messages.append({"tool_call_id": tool_call.id,"role": "tool","name": function_name,"content": tool_output_content,})print(f">>> 步骤 {iteration_count}.4: 已将工具 '{function_name}' 的结果添加到消息历史中,准备下一轮。")# 继续循环,将带有工具结果的消息发送给模型else:# --- 如果模型没有请求调用工具,说明得到了最终回复 ---print(f"\n>>> 步骤 {iteration_count}.2: 模型没有请求调用工具 (结束原因: {finish_reason})。流程结束。")print("\n=== 模型最终回复 ===")if response_message.content:print(response_message.content)else:print("(模型没有返回文本内容,可能是因为 finish_reason 不是 'stop')")break # 退出循环if iteration_count >= max_iterations:print(f"\n!!! 警告: 已达到最大循环次数 ({max_iterations}),强制结束对话。")print(f"\n{'='*10} 对话结束 {'='*10}")# --- 示例用法 ---
if __name__ == "__main__":# 示例 1: 需要调用多个工具query1 = "请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?"run_conversation(query1, model_name)

测试场景一:

问题:请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?
模型:qwen-plus

========== 对话开始 (顺序工具调用) ==========
初始用户请求: 请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?--- 第 1 轮 API 调用 ---
>>> 步骤 1.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取 指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 1.1 响应: 收到模型的决策原始响应: ChatCompletion(id='chatcmpl-1d154842-4f25-9ae6-8521-d8bb0faa4e50', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_8c892135f8ff4b9a97faf2', function=Function(arguments='{"location": "北京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]))], created=1746515789, model='qwen-plus', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=25, prompt_tokens=300, total_tokens=325, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0)))响应消息: ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_8c892135f8ff4b9a97faf2', function=Function(arguments='{"location": "北京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)])结束原因: tool_calls>>> 步骤 1.2: 模型请求调用 1 个工具。将处理第一个。--- 开始执行工具: get_current_weather (ID: call_8c892135f8ff4b9a97faf2) ---
--- 准备调用函数: get_current_weather 参数: {'location': '北京', 'unit': 'celsius'}
--- 正在调用工具: get_current_weather(location='北京', unit='celsius') ---
--- 函数 get_current_weather 执行完毕。结果: {"location": "北京", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}
--- 工具执行结束 ---
>>> 步骤 1.4: 已将工具 'get_current_weather' 的结果添加到消息历史中,准备下一轮。--- 第 2 轮 API 调用 ---
>>> 步骤 2.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_8c892135f8ff4b9a97faf2', function=Function(arguments='{"location": "北京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]), {'tool_call_id': 'call_8c892135f8ff4b9a97faf2', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "北京", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 2.1 响应: 收到模型的决策原始响应: ChatCompletion(id='chatcmpl-61e19306-02aa-9a7f-a60a-00d54f149002', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_f928cc129fbe41068e83f9', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=0)]))], created=1746515790, model='qwen-plus', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=21, prompt_tokens=359, total_tokens=380, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0)))响应消息: ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_f928cc129fbe41068e83f9', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=0)])结束原因: tool_calls>>> 步骤 2.2: 模型请求调用 1 个工具。将处理第一个。--- 开始执行工具: get_stock_price (ID: call_f928cc129fbe41068e83f9) ---
--- 准备调用函数: get_stock_price 参数: {'symbol': 'MSFT'}
--- 正在调用工具: get_stock_price(symbol='MSFT') ---
--- 函数 get_stock_price 执行完毕。结果: {"symbol": "MSFT", "price": "420.72", "currency": "USD"}
--- 工具执行结束 ---
>>> 步骤 2.4: 已将工具 'get_stock_price' 的结果添加到消息历史中,准备下一轮。--- 第 3 轮 API 调用 ---
>>> 步骤 3.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_8c892135f8ff4b9a97faf2', function=Function(arguments='{"location": "北京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]), {'tool_call_id': 'call_8c892135f8ff4b9a97faf2', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "北京", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_f928cc129fbe41068e83f9', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=0)]), {'tool_call_id': 'call_f928cc129fbe41068e83f9', 'role': 'tool', 'name': 'get_stock_price', 'content': '{"symbol": "MSFT", "price": "420.72", "currency": "USD"}'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 3.1 响应: 收到模型的决策原始响应: ChatCompletion(id='chatcmpl-315fd813-5616-9cab-a9be-dab35992fb70', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_6ad4a93a60e041ecbe4d1b', function=Function(arguments='{"location": "南京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]))], created=1746515792, model='qwen-plus', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=27, prompt_tokens=411, total_tokens=438, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0)))响应消息: ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_6ad4a93a60e041ecbe4d1b', function=Function(arguments='{"location": "南京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)])结束原因: tool_calls>>> 步骤 3.2: 模型请求调用 1 个工具。将处理第一个。--- 开始执行工具: get_current_weather (ID: call_6ad4a93a60e041ecbe4d1b) ---
--- 准备调用函数: get_current_weather 参数: {'location': '南京', 'unit': 'celsius'}
--- 正在调用工具: get_current_weather(location='南京', unit='celsius') ---
--- 函数 get_current_weather 执行完毕。结果: {"location": "南京", "temperature": "18", "unit": "celsius", "forecast": "多云"}
--- 工具执行结束 ---
>>> 步骤 3.4: 已将工具 'get_current_weather' 的结果添加到消息历史中,准备下一轮。--- 第 4 轮 API 调用 ---
>>> 步骤 4.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_8c892135f8ff4b9a97faf2', function=Function(arguments='{"location": "北京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]), {'tool_call_id': 'call_8c892135f8ff4b9a97faf2', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "北京", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_f928cc129fbe41068e83f9', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=0)]), {'tool_call_id': 'call_f928cc129fbe41068e83f9', 'role': 'tool', 'name': 'get_stock_price', 'content': '{"symbol": "MSFT", "price": "420.72", "currency": "USD"}'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_6ad4a93a60e041ecbe4d1b', function=Function(arguments='{"location": "南京", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]), {'tool_call_id': 'call_6ad4a93a60e041ecbe4d1b', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "南京", "temperature": "18", "unit": "celsius", "forecast": "多云"}'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 4.1 响应: 收到模型的决策原始响应: ChatCompletion(id='chatcmpl-192fb2e9-43cd-9468-a086-ba430c9e9b54', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='今天北京的天气是15摄氏度,晴朗。微软(MSFT)的当前股价为420.72美元。南京今天的天气是18摄氏度,多云。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None))], created=1746515794, model='qwen-plus', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=46, prompt_tokens=472, total_tokens=518, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=256)))响应消息: ChatCompletionMessage(content='今天北京的天气是15摄氏度,晴朗。微软(MSFT)的当前股价为420.72美元。南京今天的天气是18摄氏度,多云。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None)结束原因: stop>>> 步骤 4.2: 模型没有请求调用工具 (结束原因: stop)。流程结束。=== 模型最终回复 ===
今天北京的天气是15摄氏度,晴朗。微软(MSFT)的当前股价为420.72美元。南京今天的天气是18摄氏度,多云。========== 对话结束 ==========

我们可以看到,LLM调用工具的模式是每次只调用一个工具,增加了交互次数,agent一共需要与LLM交互4次才得到最终答案。

测试场景二:

问题:请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?
模型:deepseek-v3

base_url: https://api.deepseek.com
model_name: deepseek-chat========== 对话开始 (顺序工具调用) ==========
初始用户请求: 请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?--- 第 1 轮 API 调用 ---
>>> 步骤 1.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取 指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 1.1 响应: 收到模型的决策原始响应: ChatCompletion(id='5cc9cb74-a325-4cde-891f-d090a7af6cc8', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_f4fab653-d221-48d5-81d7-1ccd207e6e5d', function=Function(arguments='{"location": "Beijing"}', name='get_current_weather'), type='function', index=0), ChatCompletionMessageToolCall(id='call_1_988d3173-a2e1-4ad0-a951-3b4b7282f23d', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=1), ChatCompletionMessageToolCall(id='call_2_9f1b3e7f-9b6a-447d-90a5-bf86804c1f38', function=Function(arguments='{"location": "Nanjing"}', name='get_current_weather'), type='function', index=2)]))], created=1746517433, model='deepseek-chat', object='chat.completion', service_tier=None, system_fingerprint='fp_8802369eaa_prod0425fp8', usage=CompletionUsage(completion_tokens=64, prompt_tokens=280, total_tokens=344, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0), prompt_cache_hit_tokens=0, prompt_cache_miss_tokens=280))响应消息: ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_f4fab653-d221-48d5-81d7-1ccd207e6e5d', function=Function(arguments='{"location": "Beijing"}', name='get_current_weather'), type='function', index=0), ChatCompletionMessageToolCall(id='call_1_988d3173-a2e1-4ad0-a951-3b4b7282f23d', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=1), ChatCompletionMessageToolCall(id='call_2_9f1b3e7f-9b6a-447d-90a5-bf86804c1f38', function=Function(arguments='{"location": "Nanjing"}', name='get_current_weather'), type='function', index=2)])结束原因: tool_calls>>> 步骤 1.2: 模型请求调用 3 个工具。将处理第一个。--- 开始执行工具: get_current_weather (ID: call_0_f4fab653-d221-48d5-81d7-1ccd207e6e5d) ---
--- 准备调用函数: get_current_weather 参数: {'location': 'Beijing'}
--- 正在调用工具: get_current_weather(location='Beijing', unit='celsius') ---
--- 函数 get_current_weather 执行完毕。结果: {"location": "Beijing", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}
--- 工具执行结束 ---
>>> 步骤 1.4: 已将工具 'get_current_weather' 的结果添加到消息历史中,准备下一轮。--- 开始执行工具: get_stock_price (ID: call_1_988d3173-a2e1-4ad0-a951-3b4b7282f23d) ---
--- 准备调用函数: get_stock_price 参数: {'symbol': 'MSFT'}
--- 正在调用工具: get_stock_price(symbol='MSFT') ---
--- 函数 get_stock_price 执行完毕。结果: {"symbol": "MSFT", "price": "420.72", "currency": "USD"}
--- 工具执行结束 ---
>>> 步骤 1.4: 已将工具 'get_stock_price' 的结果添加到消息历史中,准备下一轮。--- 开始执行工具: get_current_weather (ID: call_2_9f1b3e7f-9b6a-447d-90a5-bf86804c1f38) ---
--- 准备调用函数: get_current_weather 参数: {'location': 'Nanjing'}
--- 正在调用工具: get_current_weather(location='Nanjing', unit='celsius') ---
--- 函数 get_current_weather 执行完毕。结果: {"location": "Nanjing", "temperature": "18", "unit": "celsius", "forecast": "多云"}
--- 工具执行结束 ---
>>> 步骤 1.4: 已将工具 'get_current_weather' 的结果添加到消息历史中,准备下一轮。--- 第 2 轮 API 调用 ---
>>> 步骤 2.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}, ChatCompletionMessage>>> 步骤 2.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}, ChatCompletionMessage    原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?还有微软(MSFT)的股价是多少?南京天气如何?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_f4fab653-d221-48d5-81d7-1ccd207e6e5d', function=Function(arguments='{"location": "Beijing"}', name='get_current_weather'), type='function', index=0), ChatCompletionMessageToolCall(id='call_1_988d3173-a2e1-4ad0-a951-3b4b7282f23d', function=Function(arguments='{"symbol": "MSFT"}', name='get_stock_price'), type='function', index=1), ChatCompletionMessageToolCall(id='call_2_9f1b3e7f-9b6a-447d-90a5-bf86804c1f38', function=Function(arguments='{"location": "Nanjing"}', name='get_current_weather'), type='function', index=2)]), {'tool_call_id': 'call_0_f4fab653-d221-48d5-81d7-1ccd207e6e5d', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "Beijing", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}'}, {'tool_call_id': 'call_1_988d3173-a2e1-4ad0-a951-3b4b7282f23d', 'role': 'tool', 'name': 'get_stock_price', 'content': '{"symbol": "MSFT", "price": "420.72", "currency": "USD"}'}, {'tool_call_id': 'call_2_9f1b3e7f-9b6a-447d-90a5-bf86804c1f38', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "Nanjing", "temperature": "18", "unit": "celsius", "forecast": "多云"}'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 2.1 响应: 收到模型的决策原始响应: ChatCompletion(id='d36d77dd-c42d-49e7-9448-eca2b8bfe2da', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='以下是您询问的信息:\n\n1. **北京天气**:今天晴朗,气温为15°C。\n2. **微软(MSFT)股价**:当前价格为420.72美元。\n3. **南京天气**:今天多云,气温为18°C。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None))], created=1746517439, model='deepseek-chat', object='chat.completion', service_tier=None, system_fingerprint='fp_8802369eaa_prod0425fp8', usage=CompletionUsage(completion_tokens=55, prompt_tokens=430, total_tokens=485, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=320), prompt_cache_hit_tokens=320, prompt_cache_miss_tokens=110))响应消息: ChatCompletionMessage(content='以下是您询问的信息:\n\n1. **北京天气**:今天晴朗,气温为15°C。\n2. **微软(MSFT)股价**:当前价格为420.72美元。\n3. **南京天气**:今天多云,气温为18°C。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None)结束原因: stop>>> 步骤 2.2: 模型没有请求调用工具 (结束原因: stop)。流程结束。=== 模型最终回复 ===
以下是您询问的信息:1. **北京天气**:今天晴朗,气温为15°C。
2. **微软(MSFT)股价**:当前价格为420.72美元。
3. **南京天气**:今天多云,气温为18°C。========== 对话结束 ==========

可以看到,deepseek在第一次请求后返回了3个工具。客户端将3个工具都执行完后发送执行结果给LLM,LLM汇总答案。客户端与LLM一共交互两次,这样可以大大减少模型的交互次数,降低token消耗。

测试场景三:

问题:请问北京今天天气怎么样?如果北京的天气晴朗的话,就查询微软(MSFT)的股价?
模型:deepseek-v3

========== 对话开始 (顺序工具调用) ==========
初始用户请求: 请问北京今天天气怎么样?如果北京的天气晴朗的话,就查询微软(MSFT)的股价?--- 第 1 轮 API 调用 ---
>>> 步骤 1.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?如果北京的天气晴朗的话,就查询微软(MSFT)的股价?'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 1.1 响应: 收到模型的决策原始响应: ChatCompletion(id='5577b0fd-74e6-4e35-b52a-4fa3c65aeeda', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c', function=Function(arguments='{"location": "Beijing", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]))], created=1746969170, model='deepseek-chat', object='chat.completion', service_tier=None, system_fingerprint='fp_8802369eaa_prod0425fp8', usage=CompletionUsage(completion_tokens=28, prompt_tokens=282, total_tokens=310, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=256), prompt_cache_hit_tokens=256, prompt_cache_miss_tokens=26))响应消息: ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c', function=Function(arguments='{"location": "Beijing", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)])结束原因: tool_calls>>> 步骤 1.2: 模型请求调用 1 个工具。将处理第一个。--- 开始执行工具: get_current_weather (ID: call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c) ---
--- 准备调用函数: get_current_weather 参数: {'location': 'Beijing', 'unit': 'celsius'}
--- 正在调用工具: get_current_weather(location='Beijing', unit='celsius') ---
--- 函数 get_current_weather 执行完毕。结果: {"location": "Beijing", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}
--- 工具执行结束 ---
>>> 步骤 1.4: 已将工具 'get_current_weather' 的结果添加到消息历史中,准备下一轮。--- 第 2 轮 API 调用 ---
>>> 步骤 2.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?如果北京的天气晴朗的话,就查询微软(MSFT)的股价?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c', function=Function(arguments='{"location": "Beijing", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]), {'tool_call_id': 'call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "Beijing", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的 当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]      <<< 步骤 2.1 响应: 收到模型的决策原始响应: ChatCompletion(id='ed860c74-2be3-4f52-8718-83024f2491b1', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_64e2a368-b439-4abf-ae9e-0e34e6d1e886', function=Function(arguments='{"symbol":"MSFT"}', name='get_stock_price'), type='function', index=0)]))], created=1746969176, model='deepseek-chat', object='chat.completion', service_tier=None, system_fingerprint='fp_8802369eaa_prod0425fp8', usage=CompletionUsage(completion_tokens=21, prompt_tokens=341, total_tokens=362, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=256), prompt_cache_hit_tokens=256, prompt_cache_miss_tokens=85))响应消息: ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_64e2a368-b439-4abf-ae9e-0e34e6d1e886', function=Function(arguments='{"symbol":"MSFT"}', name='get_stock_price'), type='function', index=0)])结束原因: tool_calls>>> 步骤 2.2: 模型请求调用 1 个工具。将处理第一个。--- 开始执行工具: get_stock_price (ID: call_0_64e2a368-b439-4abf-ae9e-0e34e6d1e886) ---
--- 准备调用函数: get_stock_price 参数: {'symbol': 'MSFT'}
--- 正在调用工具: get_stock_price(symbol='MSFT') ---
--- 函数 get_stock_price 执行完毕。结果: {"symbol": "MSFT", "price": "420.72", "currency": "USD"}
--- 工具执行结束 ---
>>> 步骤 2.4: 已将工具 'get_stock_price' 的结果添加到消息历史中,准备下一轮。--- 第 3 轮 API 调用 ---
>>> 步骤 3.1: 向 OpenAI 模型发送当前对话历史和工具原始发送消息: messages=[{'role': 'user', 'content': '请问北京今天天气怎么样?如果北京的天气晴朗的话,就查询微软(MSFT)的股价?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c', function=Function(arguments='{"location": "Beijing", "unit": "celsius"}', name='get_current_weather'), type='function', index=0)]), {'tool_call_id': 'call_0_d0ec6750-24bb-42e4-85fb-2424d7bb782c', 'role': 'tool', 'name': 'get_current_weather', 'content': '{"location": "Beijing", "temperature": "15", "unit": "celsius", "forecast": "晴朗"}'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_64e2a368-b439-4abf-ae9e-0e34e6d1e886', function=Function(arguments='{"symbol":"MSFT"}', name='get_stock_price'), type='function', index=0)]), {'tool_call_id': 'call_0_64e2a368-b439-4abf-ae9e-0e34e6d1e886', 'role': 'tool', 'name': 'get_stock_price', 'content': '{"symbol": "MSFT", "price": "420.72", "currency": "USD"}'}], tools=[{'type': 'function', 'function': {'name': 'get_current_weather', 'description': '获取给定位置的当前天气信息', 'parameters': {'type': 'object', 'properties': {'location': {'type': 'string', 'description': '城市和省/州,例如 San Francisco, CA 或 Beijing'}, 'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'description': '温度单位'}}, 'required': ['location']}}}, {'type': 'function', 'function': {'name': 'get_stock_price', 'description': '获取指定股票代码的当前价格', 'parameters': {'type': 'object', 'properties': {'symbol': {'type': 'string', 'description': '股票代码,例如 AAPL, MSFT'}}, 'required': ['symbol']}}}]<<< 步骤 3.1 响应: 收到模型的决策原始响应: ChatCompletion(id='57754df9-ab4a-4b5e-8e01-47150149478f', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='北京今天的天气晴朗,温度为15摄氏度。微软(MSFT)的当前股价为420.72美元。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None))], created=1746969182, model='deepseek-chat', object='chat.completion', service_tier=None, system_fingerprint='fp_8802369eaa_prod0425fp8', usage=CompletionUsage(completion_tokens=23, prompt_tokens=388, total_tokens=411, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached<<< 步骤 3.1 响应: 收到模型的决策原始响应: ChatCompletion(id='57754df9-ab4a-4b5e-8e01-47150149478f', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='北京今天的天气晴朗,温度为15摄氏度。微软(MSFT)的当前股价为420.72美元。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool<<< 步骤 3.1 响应: 收到模型的决策原始响应: ChatCompletion(id='57754df9-ab4a-4b5e-8e01-47150149478f', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(co<<< 步骤 3.1 响应: 收到模型的决策
<<< 步骤 3.1 响应: 收到模型的决策
<<< 步骤 3.1 响应: 收到模型的决策原始响应: ChatCompletion(id='57754df9-ab4a-4b5e-8e01-47150149478f', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='北京今天的天气晴朗,温度为15摄氏度。微软(MSFT)的当前股价为420.72美元。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None))], created=1746969182, model='deepseek-chat', object='chat.completion', service_tier=None, system_fingerprint='fp_8802369eaa_prod0425fp8', usage=CompletionUsage(completion_tokens=23, prompt_tokens=388, total_tokens=411, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=320), prompt_cache_hit_tokens=320, prompt_cache_miss_tokens=68))响应消息: ChatCompletionMessage(content='北京今天的天气晴朗,温度为15摄氏度。微软(MSFT)的当前股价为420.72美元。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None)结束原因: stop>>> 步骤 3.2: 模型没有请求调用工具 (结束原因: stop)。流程结束。=== 模型最终回复 ===
北京今天的天气晴朗,温度为15摄氏度。微软(MSFT)的当前股价为420.72美元。========== 对话结束 ==========

我们可以看到,因为两次工具调用有因果关系。所以它返第一次返回查询天气的工具调用,当查询到天气为晴天时,才调用查询股票的工具。符合我们问题的要求。

综上,在工具调用上,deepseek-v3做得更合理一些。当多个工具调用相互之间没有因果关系时,会一次性返回多个工具调用,从而减少了Agent与大模型的交互次数。而当工具调用之间有因果关系时,会根据因果关系先后调用工具。

http://www.xdnf.cn/news/401653.html

相关文章:

  • js应用opencv
  • java每日精进 5.11【WebSocket】
  • Java后端文件类型检测(防伪造)
  • zuoyyyeee
  • 数据可视化:用一张图讲好一个故事
  • 安装Python和配置开发环境
  • 《 C++ 点滴漫谈: 三十七 》左值?右值?完美转发?C++ 引用的真相超乎你想象!
  • 创建三个网络,分别使用RIP、OSPF、静态,并每个网络10个电脑。使用DHCP分配IP
  • 第五十六篇 Java面向对象编程深度解析:构建高内聚低耦合的系统架构
  • Spring Boot中Redis序列化配置详解
  • 【美国将取消对能源之星支持 严重影响AI服务器】
  • 使用vite重构vue-cli的vue3项目
  • 基于粒子群算法的配电网重构
  • Kotlin与Qt跨平台框架深度解析:业务逻辑共享与多语言集成
  • MySQL-逻辑架构
  • python二手书交易管理系统
  • 如何调整yarn.nodemanager.vmem-pmem-ratio参数?
  • 什么是IP专线?企业数字化转型的关键网络基础设施
  • 阿里云人工智能大模型通义千问Qwen3开发部署
  • ASP.NET Core Identity框架使用指南
  • suricata增加单元测试编译失败
  • cursor 出现 unauthorized request
  • Maven私服搭建与登录全攻略
  • [redis进阶六]详解redis作为缓存分布式锁
  • 贝叶斯算法
  • 【pypi镜像源】使用devpi实现python镜像源代理(缓存加速,私有仓库,版本控制)
  • C#调用YOLOV8实现定位
  • PyCharm 快捷键指南
  • Android11.0 framework第三方无源码APP读写断电后数据丢失问题解决
  • 嵌入式系统:从基础到应用的全面解析