跳到主要内容

R1-0528 Function calling功能实现方法

课程说明:

  体验课时间有限,若想深度学习大模型技术,欢迎大家报名由我主讲的《2025大模型Agent智能体开发实战》(MCP强化班)

d0c81dfe43a1becced8c07db33c3a787_

《2025大模型Agent智能体开发实战》(MCP强化班) 为【100+小时】体系大课,总共20大模块精讲精析,零基础直达大模型企业级应用!

img

同时,5月班重磅新增DeepSeek+Agents SDK+谷歌ADK+MCP技术应用与Qwen3智能体开发相关实战内容:

34533e2c95414b3dc5ab1131d9d1e38

部分项目成果演示

from IPython.display import Video
  • MateGen项目演示
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/4.MateGen%20Pro%20%E9%A1%B9%E7%9B%AE%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4", width=800, height=400)
  • 智能客服项目演示
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/%E6%99%BA%E8%83%BD%E5%AE%A2%E6%9C%8D%E6%A1%88%E4%BE%8B%E6%BC%94%E7%A4%BA.mp4", width=800, height=400)
  • Dify项目演示
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/2f1b47f42c65fd59e8d3a83e6cb9f13b_raw.mp4", width=800, height=400)
  • LangChain&LangGraph搭建Multi-Agnet
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/%E5%8F%AF%E8%A7%86%E5%8C%96%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90Multi-Agent%E6%95%88%E6%9E%9C%E6%BC%94%E7%A4%BA%E6%95%88%E6%9E%9C.mp4", width=800, height=400)

此外,若是对大模型底层原理感兴趣,也欢迎报名由我和菜菜老师共同主讲的《2025大模型原理与实战课程》(5月班)

da5d51c998df07d747cd223c1ed25f7

两门大模型课程5月班目前上新特惠中,立减2000起,合购还有更多优惠哦~详细信息扫码添加助教,回复“大模型”,即可领取课程大纲&查看课程详情👇

ca76dfaf224da7825b4fa3e9c6ab435

DeepSeek-R1-0528模型Agent开发实战

Part 2.R1-0528 Function calling功能实现方法

一、DeepSeek-R1 Function calling功能详解

1.Function calling技术概念介绍

  我们都知道,能调用外部工具,是大模型进化为智能体Agent的关键,如果不能使用外部工具,大模型就只能是个简单的聊天机器人,甚至连查询天气都做不到。由于底层技术限制啊,大模型本身是无法和外部工具直接通信的,因此Function calling的思路,就是创建一个外部函数(function)作为中介,一边传递大模型的请求,另一边调用外部工具,最终让大模型能够间接的调用外部工具。

image-20250318202017508

例如,当我们要查询当前天气时,让大模型调用外部工具的function calling的过程就如图所示:

image-20250318202029130

而完整的一次Function calling执行流程如下:

202412191720637

需要注意的是,对于大模型来说,Function calling的本质,是当模型在特殊情况下的一种特殊响应形式: image-20250327181953725

而要拥有Function calling功能,其实是需要在模型指令微调阶段进行训练的,具体原理详见视频:https://www.bilibili.com/video/BV1w6dBYxELA/ image-20250529172520098

【选学】2.外部工具OpenWeather注册及API key获取方法

  接下来,我们以经典的查询天气为例,为大家演示DeepSeek-R1-0528模型的Function calling功能实现方法。

2.1 OpenWeather API获取流程

  OpenWeather是一家提供全球范围内的气象数据服务的公司,该公司的服务包括实时天气信息、天气预报、历史天气数据以及各种气象相关的报告等,并且OpenWeather开放了一定使用限度内完全免费的API,即我们可以在代码环境中通过调用OpenWeather API来进行实时天气查询、天气预报等功能,这意味着开发者可以将OpenWeather的天气预报功能加入到他们自己的应用或网站中。

  为了能够调用OpenWeather服务,和OpenAI的API使用过程类似,我们首先需要先注册OpenWeather账号,并获取OpenWeather API Key。这里需要注意的是,对于大多数在线服务的API来说,都需要通过API key来进行身份验证,尽管OpenWeather相对更加Open,有非常多的免费使用的次数,但身份验证仍然是必要的防止API被滥用的有效手段。OpenWeather API key获取流程如下:

  • Step 1.登录OpenWeather官网并点击Sign—>create account完成注册。该网站无需魔法即可直接登录,可以使用国内邮箱或者QQ邮箱均可进行注册,官网地址为:https://openweathermap.org/
e9a6286c483ccf21ab96af1972a918b 577e19b46f4c124b50a0455ccc132e9
  • Step 2.获取API-key:注册完成后,即可在API keys页面查看当前账户的API key:
f44ba05a810500a61516caa28a4fcb4 e497a7ebb4f8d50ff3b6e362e4b569a

一般来说完成注册后,就会有一个已经激活的API-key。和OpenAI一样,OpenWeather的API key也创建多个。

  • Step 3.将其设置为环境变量:和OpenAI API key类似,为了方便后续调用,我们也可以直接将OpenWeather API key设置为环境变量,变量名为OPENWEATHER_API_KEY。具体设置环境变量的方法参考Ch.1中OpenAI APkey设置环境变量流程,此处不再赘述。
aa0f15de151921727c20918fccc8de0

设置完了环境变量之后,接下来即可按照如下方式创建OpenWeather API key变量:

import os
from dotenv import load_dotenv
load_dotenv(override=True)

WEATHER_API_KEY = os.getenv("OPENWEATHER_API_KEY")

2.2 利用OpenWeather API获取实时天气信息

  接下来我们通过一个简单的示例,来介绍如何通过OpenWeather API获取实时天气信息:

import requests
import json
# Step 1.构建请求
url = "https://api.openweathermap.org/data/2.5/weather"

# Step 2.设置查询参数
params = {
"q": "Beijing", # 查询北京实时天气
"appid": WEATHER_API_KEY, # 输入API key
"units": "metric", # 使用摄氏度而不是华氏度
"lang":"zh_cn" # 输出语言为简体中文
}

# Step 3.发送GET请求
response = requests.get(url, params=params)

# Step 4.解析响应
data = response.json()

这里需要注意的是,城市名必须输入英文名,否则无法正确识别。接下来查看返回结果。首先我们先查看response结果:

response
type(response)

在未解析之前,我们只能查看到基本请求结果状态,这里的200代表成功相应,即本次发送请求获得了对应的响应,且响应内容包含在response中。考虑到默认情况下返回结果是JSON格式,因此后续代码使用了response.json()对其进行解析。解析内容如下:

data
def get_weather(loc):
"""
查询即时天气函数
:param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称,\
注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,则loc参数需要输入'Beijing';
:return:OpenWeather API查询即时天气的结果,具体URL请求地址为:https://api.openweathermap.org/data/2.5/weather\
返回结果对象类型为解析之后的JSON格式对象,并用字符串形式进行表示,其中包含了全部重要的天气信息
"""
# Step 1.构建请求
url = "https://api.openweathermap.org/data/2.5/weather"

# Step 2.设置查询参数
params = {
"q": loc,
"appid": WEATHER_API_KEY, # 输入API key
"units": "metric", # 使用摄氏度而不是华氏度
"lang":"zh_cn" # 输出语言为简体中文
}

# Step 3.发送GET请求
response = requests.get(url, params=params)

# Step 4.解析响应
data = response.json()
return json.dumps(data)
get_weather(loc="Beijing")

3.R1-0528模型Function calling完整执行流程

  在准备好外部函数及函数库之后,接下来非常重要的一步就是需要将外部函数的信息以某种形式传输给R1模型。此时就需要使用到ChatCompletion.create函数的functions参数,类似于messages参数是用于向模型传输消息,functions参数专门用于向模型传递当前可以调用的外部函数信息。并且,从参数的具体形式来看,functions参数和messages参数也是非常类似的——都是包含多个字典的list。对于messages来说,每个字典都是一条信息,而对于functions参数来说,每个字典都是一个函数。在大语言模型实际进行问答时,会根据functions参数提供的信息对各函数进行检索。

  很明显,functions参数对于R1模型的Function calling功能的实现至关重要。接下来我们详细解释functions中每个用于描述函数的字典编写方法。总的来说,每个字典都有三个参数(三组键值对),各参数(Key)名称及解释如下:

  • name:代表函数函数名称字的符串,必选参数,按照要求函数名称必须是 a-z、A-Z、0-9,或包含下划线和破折号,最大长度为 64。需要注意的是,name必须输入函数名称,而后续模型将根据函数名称在外部函数库中进行函数筛选;
  • description:用于描述函数功能的字符串,虽然是可选参数,但该参数传递的信息实际上是Chat模型对函数功能识别的核心依据。即Chat函数实际上是通过每个函数的description来判断当前函数的实际功能的,若要实现多个备选函数的智能挑选,则需要严谨详细的描述函数功能;(需要注意的是,在某些情况下,我们会通过其他函数标注本次对话特指的函数,此时模型就不会执行这个根据描述信息进行函数挑选的过程,此时是可以不设置description的。)
  • parameters:函数参数,必选参数,要求遵照JSON Schema格式进行输入,JSON Schema是一种特殊的JSON对象,专门用于验证JSON数据格式是否满足要求。

  例如,对于get_weather函数,我们需要创建如下字典来对其进行完整描述:

tools = [
{
"type": "function",
"function":{
'name': 'get_weather',
'description': '查询即时天气函数,根据输入的城市名称,查询对应城市的实时天气,一次只能输入一个城市名称',
'parameters': {
'type': 'object',
'properties': {
'loc': {
'description': "城市名称,注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,则loc参数需要输入'Beijing'",
'type': 'string'
}
},
'required': ['loc']
}
}
}
]

同时还需要封装外部函数库,用于关联外部函数名称和外部函数对象

available_functions = {
"get_weather": get_weather,
}

而一轮完整的Function calling执行流程如下:

image-20250529172814974

3.1 First response

  在进行了一系列基础准备工作之后,接下来我们尝试在R1模型对话执行Function calling功能。这里我们创建如下messages:

import os
from dotenv import load_dotenv
load_dotenv(override=True)


DS_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DS_BASE_URL = os.getenv("DEEPSEEK_API_BASE")


print(DS_BASE_URL)
from openai import OpenAI

# 实例化客户端
client = OpenAI(api_key=DS_API_KEY,
base_url=DS_BASE_URL)
messages=[
{"role": "user", "content": "请帮我查询北京地区今日天气情况"}
]

首先我们测试如果只输入这个信息而不输入外部函数库的时候,模型能否知道如何查询天气:

response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages
)
response
response.choices[0].message.content
response.choices[0].message.reasoning_content
response.choices[0].finish_reason

很明显,模型无法进行回答。接下来开启Function calling功能:

response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[
{"role": "user", "content": "请帮我查询北京地区今日天气情况"}
],
tools=tools,
)

观察此时response结果:

response

与对话类模型不一样(比如DeepSeek-v3),对话模型当触发函数调用时模型回复结果为空,但是deepseek-r1即使触发了函数调用,其content中依然会返回响应内容。如下所示:

response.choices[0].message.content

而模型停止输出的原因是发起了tool_calls

response.choices[0].finish_reason

而此时模型tool_calls的全部信息都保存在message.tool_calls中:

response.choices[0].message.tool_calls

该对象是一个列表,如果此时只有一次工具调用,则只会有一个ChatCompletionMessageToolCall对象。

response_message = response.choices[0].message
response_message

除此以外,R1 在执行解析参数的时候,生成tool_calls的同时,content 并不为空。生成的"tool_calls"的list,该list就包含了当前调用外部函数的全部信息:

response_message.tool_calls
response_message.tool_calls[0]

对于当前CompletionMessageToolCall对象,id为外部函数调用发起请求id,function则表示调用外部函数基本信息,而type则代表了当前当前调用外部函数类型,function代表调用自定义的外部函数。

response_message.tool_calls[0].id
response_message.tool_calls[0].function

我们可以在此基础上分别提取调用外部函数名称信息和参数信息,分别保存为function_name和function_args对象:

# 完成对话需要调用的函数名称
function_name = response_message.tool_calls[0].function.name
function_name
# 具体的函数对象
fuction_to_call = available_functions[function_name]
fuction_to_call
response_message.tool_calls[0].function.arguments
# 执行该函数所需要的参数
function_args = json.loads(response_message.tool_calls[0].function.arguments)
function_args

需要注意的是,外部函数的计算过程仍然是在本地执行,即Chat模型并不会将代码读取到服务器上再进行在线计算,因此接下来我们需要根据模型返回的函数和函数参数,在本地完成函数计算,然后再将计算过程和结果保存为message并追加到messages后面,并第二次调用Chat模型分析函数的计算结果,并最终根据函数计算结果输出用户问题的答案。

202412191720637

3.2 Second response

  这里我们只需要借助**方法,直接将function_args对象传入fuction_to_call中,即可一次性传输全部参数,**方法的功能可以参考如下示例:

def function_to_call_test(a, b, c):
return a + b + c

function_args_test = {'a': 1, 'b': 2, 'c': 3}

result = function_to_call_test(**function_args_test)

print(result)

**方法其实是一种较为特殊、但同时也非常便捷的参数传递方法吗,该方法会将字典中的每个key对应的value传输到同名参数位中。接下来我们将function_args对象传入fuction_to_call中并完成计算:

function_response = fuction_to_call(**function_args)
function_response

能够发现,模型已经顺利完成计算。接下来我们在messages对象中追加两条消息,第一条消息是第一次模型返回的结果(即调用模型的assistant message),第二条消息则是外部函数计算结果,该条消息的role为function,且name为函数名称。这也是我们首次接触function message,和user、system、assistant message不同,function message必须要输入关键词name,且function message的内容源于外部函数执行的计算结果,并且需要手动进行输入。具体添加过程如下:

messages

然后使用如下方法,将第一轮响应结果转化为message格式:

response_message.model_dump()
# 追加第一次模型返回结果消息
messages.append(response_message.model_dump())
messages
function_response
# 追加function返回消息
messages.append({
"role": "tool",
"content": function_response,
"tool_call_id":response_message.tool_calls[0].id
})
messages

接下来,再次调用DeepSeek R1模型来围绕messages进行回答。需要注意的是,此时我们不再需要向模型重复提问,只需要简单的将我们已经准备好的messages传入Chat模型即可:

second_response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages,
tools=tools)

报错提示表明 reasoning_content 是为了展示中间结果而设计的内容,它不应当包含在消息中参与推理,应该从消息中移除。这个字段本身并不参与模型推理,因此与常规的对话模型不同,需要在将 messages 传递给模型之前,移除所有包含 reasoning_content 的数据字段。这里我们直接过滤掉包含 reasoning_content 字段来解决这个问题,即在拼接 messages 时加入一个步骤来确保这些字段被排除:

# 删除包含 'reasoning_content' 的字段
for message in messages:
if 'reasoning_content' in message:
del message['reasoning_content']
messages

再次进行调用:

second_response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages,
tools=tools)
second_response.choices[0].message

能够发现,模型最终做出了准确回答。并且此时finish_reason为stop

second_response.choices[0].finish_reason
202412191720637

3.3 完整函数封装

import json
from IPython.display import display, Markdown
from openai import OpenAI

def run_conv(messages,
api_key,
tools=None,
functions_list=None,
model="deepseek-reasoner"): # 这里是DeepSeek-R1 模型
"""
能够自动执行外部函数调用的Chat对话模型
:param messages: 必要参数,输入到Chat模型的messages参数对象
:param api_key: 必要参数,调用模型的API-KEY
:param tools: 可选参数,默认为None,可以设置为包含全部外部函数的列表对象
:param model: Chat模型,可选参数,默认模型为deepseek-chat
:return:Chat模型输出结果
"""
user_messages = messages

client = OpenAI(api_key=api_key,
base_url="https://api.deepseek.com")

# 如果没有外部函数库,则执行普通的对话任务
if tools == None:
response = client.chat.completions.create(
model=model,
messages=user_messages
)
final_response = response.choices[0].message.content

# 若存在外部函数库,则需要灵活选取外部函数并进行回答
else:
# 创建外部函数库字典
available_functions = {func.__name__: func for func in functions_list}

# 创建包含用户问题的message
messages = user_messages

# first response
response = client.chat.completions.create(
model=model,
messages=user_messages,
tools=tools,
)
response_message = response.choices[0].message

# 获取函数名
function_name = response_message.tool_calls[0].function.name
# 获取函数对象
fuction_to_call = available_functions[function_name]
# 获取函数参数
function_args = json.loads(response_message.tool_calls[0].function.arguments)

# 将函数参数输入到函数中,获取函数计算结果
function_response = fuction_to_call(**function_args)

# messages中拼接first response消息
user_messages.append(response_message.model_dump())

# messages中拼接外部函数输出结果
user_messages.append(
{
"role": "tool",
"content": function_response,
"tool_call_id":response_message.tool_calls[0].id
}
)

# 删除包含 'reasoning_content' 的字段
for message in user_messages:
if 'reasoning_content' in message:
del message['reasoning_content']

# 第二次调用模型
second_response = client.chat.completions.create(
model=model,
messages=user_messages)

# 获取最终结果
final_response = second_response.choices[0].message.content
return display(Markdown(f"Assistant: {final_response}"))
messages = [{"role": "user", "content": "请问什么是机器学习?"}]
run_conv(messages=messages,
api_key = DS_API_KEY)
messages = [{"role": "user", "content": "请问北京今天天气如何?"}]
run_conv(messages=messages,
api_key = DS_API_KEY,
tools=tools,
functions_list=[get_weather])

4、更多外部工具调用流程

def python_inter(py_code):
"""
运行用户提供的 Python 代码,并返回执行结果。

:param py_code: 字符串形式的 Python 代码
:return: 代码运行的最终结果
"""
g = globals()

try:
# 若是表达式,直接运行并返回
result = eval(py_code, g)
return json.dumps(str(result), ensure_ascii=False)

except Exception:
global_vars_before = set(g.keys())
try:
exec(py_code, g)
except Exception as e:
return json.dumps(f"代码执行时报错: {e}", ensure_ascii=False)

global_vars_after = set(g.keys())
new_vars = global_vars_after - global_vars_before

if new_vars:
# 只返回可序列化的变量值
safe_result = {}
for var in new_vars:
try:
json.dumps(g[var]) # 尝试序列化,确保可以转换为 JSON
safe_result[var] = g[var]
except (TypeError, OverflowError):
safe_result[var] = str(g[var]) # 如果不能序列化,则转换为字符串

return json.dumps(safe_result, ensure_ascii=False)

else:
return json.dumps("已经顺利执行代码", ensure_ascii=False)
tools = [
{
"type": "function",
"function":{
'name': 'python_inter',
'description': '运行用户提供的 Python 代码,并返回执行结果。',
'parameters': {
'type': 'object',
'properties': {
'py_code': {
'description': "字符串形式的 Python 代码",
'type': 'string'
}
},
'required': ['py_code']
}
}
}
]
messages = [{"role": "user", "content": "请帮我用Python代码模拟一组数据,来绘制核密度分布图。"}]
run_conv(messages=messages,
api_key = DS_API_KEY,
tools=tools,
functions_list=[python_inter])

三、R1-0528模型多函数调用模式

  在使用 LLM 构建应用时,我们建议尽可能选择最简单的解决方案,只有在确实需要时才增加复杂性。这意味着,在某些情况下,可能根本不需要构建代理系统。代理系统(Agentic Systems)通常会牺牲响应速度(latency)和成本(cost),以换取更好的任务执行能力。因此,在使用代理之前,你需要考虑这种权衡是否合理。   当应用场景需要更复杂的逻辑时:

  • 工作流(Workflows) 提供了可预测性和一致性,适用于任务流程清晰的情况。
  • 代理(Agents) 更适用于需要灵活性和大规模模型驱动决策的场景。

  然而,对于许多应用来说,优化单次 LLM 调用(例如结合检索增强(RAG)上下文示例(incontext examples))通常已经足够,无需使用复杂的代理系统。

  分发模式:将任务分发(Fan-out)给多个子代理(sub-agents),然后汇总(Fan-in)结果。每个子任务都是一个 AugmentedLLM,整个 Parallel 工作流本身也是如此,这意味着每个子任务可以选择性地成为一个更复杂的工作流。

image-20250320184527687

  路由模式:对于给定的输入,系统会将其路由(分配)到最相关的 top_k 个类别。其中,每个类别(category)可以是:

  1. Agent(智能代理):可能是一个 AI 代理(如 LLM 驱动的任务处理单元)。
  2. MCP 服务器(MCP Server):可以是基于 Model Context Protocol (MCP) 的服务器,用于处理特定任务或提供外部数据支持。
  3. 常规函数(Regular Function):即普通的代码函数,可能是执行计算、数据处理等任务的函数
image-20250320184527687

  编排模式:一个更高层次的 LLM(大语言模型)负责生成任务计划(plan),然后将各个子任务分配给子代理(sub-agents),并最终整合(synthesize)这些子任务的结果。其中:

  • 高层 LLM 生成计划:这个 LLM 充当“指挥官”,根据输入任务制定执行步骤。
  • 子代理(sub-agents)执行任务:每个子任务被分配给不同的子代理,可能是不同的 AI 组件、MCP 服务器或特定函数。
  • 整合(synthesize)结果:在所有子任务执行完毕后,系统会将它们的结果合并,生成最终输出
image-20250320184527687

  接下来我们可以通过Qwen3的Function Calling功能,实现分发模式和路由模式,并据此搭建一个NL2SQL+NL2Python的初级数据分析智能体。

image-20250529173807316

1. R1-0528多外部函数并联调用流程

import os
from dotenv import load_dotenv
load_dotenv(override=True)


DS_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DS_BASE_URL = os.getenv("DEEPSEEK_API_BASE")


print(DS_BASE_URL)
from openai import OpenAI

# 实例化客户端
client = OpenAI(api_key=DS_API_KEY,
base_url=DS_BASE_URL)
messages2=[
{"role": "user", "content": "请问北京和杭州今天天气如何?"}
]
response2 = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages2,
tools=tools,

)

response2.choices[0].message
response2.choices[0].message.tool_calls
function_call_messages = response2.choices[0].message.tool_calls
function_call_messages
response2.choices[0].message.model_dump()
image-20250529173933461

  创建create_function_response_messages函数,一次性构建完整回复:

import json
import requests

def create_function_response_messages(messages, response):
function_call_messages = response.choices[0].message.tool_calls
messages.append(response.choices[0].message.model_dump())
for function_call_message in function_call_messages:
tool_name = function_call_message.function.name
tool_args = json.loads(function_call_message.function.arguments)

# 运行外部函数
fuction_to_call = available_functions[tool_name]
try:
function_response = fuction_to_call(**tool_args)
except Exception as e:
function_response = "函数运行报错如下:" + str(e)

# 拼接消息队列
messages.append(
{
"role": "tool",
"content": function_response,
"tool_call_id": function_call_message.id,
}
)

# 删除reasoning_content字段
for message in messages:
if 'reasoning_content' in message:
del message['reasoning_content']
return messages
messages2 = create_function_response_messages(messages2, response2)
messages2
# 第二次响应
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages2,
tools=tools,
)
response.choices[0].message.content
response.choices[0].message.reasoning_content
response.choices[0].finish_reason

2. R1-0528模型多外部函数串联调用流程

image-20250320184527687
def write_file(content):
"""
将指定内容写入本地文件。
:param content: 必要参数,字符串类型,用于表示需要写入文档的具体内容。
:return:是否成功写入
"""

return "已成功写入本地文件。"
write_file(content="某地天气信息")
available_functions = {
"get_weather": get_weather,
"write_file": write_file
}
tools = [
{
"type": "function",
"function":{
'name': 'get_weather',
'description': '查询即时天气函数,根据输入的城市名称,查询对应城市的实时天气,一次只能输入一个城市名称',
'parameters': {
'type': 'object',
'properties': {
'loc': {
'description': "城市名称,注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,则loc参数需要输入'Beijing'",
'type': 'string'
}
},
'required': ['loc']
}
}
},
{
"type": "function",
"function":{
'name': 'write_file',
'description': '将指定内容写入本地文件。',
'parameters': {
'type': 'object',
'properties': {
'content': {
'description': "用于表示需要写入文档的具体内容。",
'type': 'string'
}
},
'required': ['content']
}
}
}
]
messages3=[
{"role": "user", "content": "请问北京今天天气如何?并将北京天气信息写入本地文档。"}
]
response3 = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages3,
tools=tools,
)
response3.choices[0].message
response3.choices[0].message.tool_calls
messages3 = create_function_response_messages(messages3, response3)
messages3
response3 = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages3,
tools=tools,
)
response3.choices[0].message
response3.choices[0].message.tool_calls
response3.choices[0].finish_reason
messages3 = create_function_response_messages(messages3, response3)
messages3
response3 = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages3,
tools=tools,
)
response3.choices[0].message
response3.choices[0].finish_reason

至此,我们就完成了一次多工具的串联调用。

据此,我们可以常见一个用于自动调用外部工具的对话工具:

def chat_base(messages):
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages,
tools=tools,
)

if response.choices[0].finish_reason == "tool_calls":
while True:
messages = create_function_response_messages(messages, response)
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages,
tools=tools,
)
if response.choices[0].finish_reason != "tool_calls":
break
return response

3. 多工具并联、串联联合调用

image-20250529175422143
messages=[
{"role": "user", "content": "请问北京和杭州天气如何?并帮我将两地天气写入本地文档。"}
]
response = chat_base(messages)
response
response.choices[0].message.content
response.choices[0].message.reasoning_content
  • 更多测试问题如下:
messages1=[
{"role": "user", "content": "请问北京今天天气如何?"}
]
messages2=[
{"role": "user", "content": "请问北京和杭州今天天气如何?"}
]
messages3=[
{"role": "user", "content": "请问北京今天天气如何?并将北京天气信息写入本地文档。"}
]
response1 = chat_base(messages1)
response1.choices[0].message
response2 = chat_base(messages2)
response2.choices[0].message
response3 = chat_base(messages3)
response3.choices[0].message
response3.choices[0].message.content
response3.choices[0].message