大模型在面对实时性问题、数学计算等问题时可能效果不佳。您可以使用 Function Calling 功能,通过引入外部工具,使得大模型可以与外部世界进行交互。
支持的模型
当前支持通义千问的大语言模型。支持的模型为:
QwQ 模型支持 Function Calling,但使用方法与以上模型略有不同,请参见QwQ 工具调用。
暂不支持通义千问多模态模型。
建议您优先选择通义千问-Plus,它在效果、速度和成本上相对均衡。
如果您对响应的速度与成本控制有较高要求,商业版模型建议使用通义千问-Turbo系列,开源版模型建议使用Qwen2.5 系列的小参数模型;
如果您对响应的准确率有较高要求,商业版模型建议使用通义千问-Max系列,开源版模型建议使用 qwen2.5-72b-instruct 模型。
概述
如果直接向通义千问 API 提问“阿里云最近有什么新闻?”,大模型并不能准确回答:
我无法提供实时信息,因为我的数据只更新到2021年。
如果这个问题需要人类帮助大模型来解决,那么一个有效的操作步骤为:
选择工具
由于问题是关于实时新闻的,打开浏览器工具;
提取参数
由于提问的问题是“阿里云最近有什么新闻?”,用浏览器输入框查询“阿里云新闻”;
运行工具
浏览器返回了许多网页,如“阿里云成为总台《2025年春节联欢晚会》云计算AI独家合作伙伴”等;
将工具的输出提供给大模型
将网页内容输入到提示词对通义千问 API 进行提问:“这是查询到的信息:阿里云成为总台《2025年春节联欢晚会》云计算AI独家合作伙伴......。请总结并回答:阿里云最近有什么新闻?”由于向大模型提供了足够的参考信息,可以得到类似的回复:
阿里云最近的重要新闻是它成为了中央广播电视总台《2025年春节联欢晚会》的云计算AI独家合作伙伴。
...
这些信息表明,阿里云不仅在技术基础设施方面具有优势,而且也在积极探索如何将AI技术应用于大型文化活动中,以创造新的用户体验。
大模型此时可以回答关于实时新闻的问题了,然而这个过程需要人的参与(选择工具、提取参数、运行工具),无法实现自动化运行的效果。
Function Calling(工具调用)可以自动化完成以上流程,在接收到提问后可以自动选择工具、提取参数、运行工具并总结工具的输出。效果对比如下所示:
以上组件仅供您参考,并未真实发送请求。
工作流程示意图如下所示:
前提条件
您需要已 获取API Key并 配置API Key到环境变量。如果通过 OpenAI SDK 或 DashScope SDK 进行调用,需要 安装SDK。如果您是子业务空间的成员,请确保超级管理员已为该业务空间进行 模型授权操作。
如何使用
本部分以 OpenAI 兼容调用方式为例,向您分步骤介绍 Function Calling 的详细用法,备选的工具为天气查询与时间查询。
如果您使用 DashScope SDK,或需要直接获取完整代码,请点击下表的对应位置。
DashScope | |
OpenAI 兼容 | |
1. 定义工具
工具是连接大模型与外部世界的桥梁,它是实现 Function Calling 的关键,您首先需要对工具进行定义。
1.1. 定义工具函数
您需要定义两个工具函数:天气查询工具与时间查询工具。
天气查询工具
天气查询工具接收
arguments
参数,arguments
格式为{"location": "查询的地点"}
。工具的输出为字符串,格式为:“{位置}今天是{天气}。”
。为了便于演示,此处定义的天气查询工具并不真正查询天气,会从晴天、多云、雨天随机选择。在您的实际业务中可以使用如高德天气查询等工具进行替换。
时间查询工具
时间查询工具不需要输入参数。工具的输出为字符串,格式为:
“当前时间:{查询到的时间}。”
。如果您使用 Node.js,请使用以下命令安装获取时间的工具包 date-fns:
npm install date-fns
## 步骤1:定义工具函数
# 添加导入random模块
import random
from datetime import datetime
# 模拟天气查询工具。返回结果示例:“北京今天是雨天。”
def get_current_weather(arguments):
# 定义备选的天气条件列表
weather_conditions = ["晴天", "多云", "雨天"]
# 随机选择一个天气条件
random_weather = random.choice(weather_conditions)
# 从 JSON 中提取位置信息
location = arguments["location"]
# 返回格式化的天气信息
return f"{location}今天是{random_weather}。"
# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
# 获取当前日期和时间
current_datetime = datetime.now()
# 格式化当前日期和时间
formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
# 返回格式化后的当前时间
return f"当前时间:{formatted_time}。"
# 测试工具函数并输出结果,运行后续步骤时可以去掉以下四句测试代码
print("测试工具输出:")
print(get_current_weather({"location": "上海"}))
print(get_current_time())
print("\n")
// 步骤1:定义工具函数
// 导入时间查询工具
import { format } from 'date-fns';
function getCurrentWeather(args) {
// 定义备选的天气条件列表
const weatherConditions = ["晴天", "多云", "雨天"];
// 随机选择一个天气条件
const randomWeather = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
// 从 JSON 中提取位置信息
const location = args.location;
// 返回格式化的天气信息
return `${location}今天是${randomWeather}。`;
}
function getCurrentTime() {
// 获取当前日期和时间
const currentDatetime = new Date();
// 格式化当前日期和时间
const formattedTime = format(currentDatetime, 'yyyy-MM-dd HH:mm:ss');
// 返回格式化后的当前时间
return `当前时间:${formattedTime}。`;
}
// 测试工具函数并输出结果,运行后续步骤时可以去掉以下四句测试代码
console.log("测试工具输出:")
console.log(getCurrentWeather({location:"上海"}));
console.log(getCurrentTime());
console.log("\n")
运行工具后,得到输出:
测试工具输出:
上海今天是多云。
当前时间:2025-01-08 20:21:45。
1.2 创建 tools 数组
人类在选择工具之前,需要对工具有全面的了解,包括工具的功能、何时使用以及输入参数等。大模型也需要这些信息才能更准确地选择工具。在使用 Function Calling 时,请根据以下的 JSON 格式提供工具信息。
| 对于天气查询工具来说,工具描述信息的格式如下:
|
在发起 Function Calling 前,您需要通过 tools
参数传入工具的描述信息。tools
为 JSON Array 类型,Array 中的元素为创建好的工具描述信息。
tools 参数在发起 Function Calling时进行指定。
# 请将以下代码粘贴到步骤1代码后
## 步骤2:创建 tools 数组
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
}
},
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。",
}
},
"required": ["location"]
}
}
}
]
tool_name = [tool["function"]["name"] for tool in tools]
print(f"创建了{len(tools)}个工具,为:{tool_name}\n")
// 请将以下代码粘贴到步骤1代码后
// 步骤2:创建 tools 数组
const tools = [
{
type: "function",
function: {
name: "get_current_time",
description: "当你想知道现在的时间时非常有用。",
}
},
{
type: "function",
function: {
name: "get_current_weather",
description: "当你想查询指定城市的天气时非常有用。",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "城市或县区,比如北京市、杭州市、余杭区等。",
}
},
required: ["location"]
}
}
}
];
const toolNames = tools.map(tool => tool.function.name);
console.log(`创建了${tools.length}个工具,为:${toolNames.join(', ')}\n`);
2. 创建messages数组
与直接向通义千问 API 提问类似,您同样需要维护一个 messages 数组来向大模型传入指令与上下文信息。发起 Function Calling 前,messages 数组需要包含 System Message 与 User Message。
System Message
尽管在创建 tools 数组时已经对工具的作用与何时使用工具进行了描述,但在 System Message 中强调何时调用工具通常会提高工具调用的准确率。在当前场景下,我们可以将 System Prompt 设置为:
你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;
如果用户提问关于时间的问题,请调用‘get_current_time’函数。
请以友好的语气回答问题。
User Message
User Message 用于传入用户提问的问题。假设用户提问“上海天气”,此时的 messages 数组为:
# 步骤3:创建messages数组
# 请将以下代码粘贴到步骤2 代码后
messages = [
{
"role": "system",
"content": """你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;
如果用户提问关于时间的问题,请调用‘get_current_time’函数。
请以友好的语气回答问题。""",
},
{
"role": "user",
"content": "上海天气"
}
]
print("messages 数组创建完成\n")
// 步骤3:创建messages数组
// 请将以下代码粘贴到步骤2 代码后
const messages = [
{
role: "system",
content: "你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数; 如果用户提问关于时间的问题,请调用‘get_current_time’函数。请以友好的语气回答问题。",
},
{
role: "user",
content: "上海天气"
}
];
console.log("messages 数组创建完成\n");
3. 发起 Function Calling
在完成 tools 与 messages 的创建后,您可以参考以下代码发起 Function Calling,让大模型“决策”是否需要调用工具,如果需要,大模型会输出需要调用的工具函数与入参信息。
# 步骤4:发起 function calling
# 请将以下代码粘贴到步骤3 代码后
from openai import OpenAI
import os
client = OpenAI(
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
def function_calling():
completion = client.chat.completions.create(
model="qwen-plus", # 此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages=messages,
tools=tools
)
print("返回对象:")
print(completion.choices[0].message.model_dump_json())
print("\n")
return completion
print("正在发起function calling...")
completion = function_calling()
// 步骤4:发起 function calling
// 请将以下代码粘贴到步骤3 代码后
import OpenAI from "openai";
const openai = new OpenAI(
{
// 若没有配置环境变量,请用百炼API Key将下行替换为:apiKey: "sk-xxx",
apiKey: process.env.DASHSCOPE_API_KEY,
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
}
);
async function functionCalling() {
const completion = await openai.chat.completions.create({
model: "qwen-plus", // 此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages: messages,
tools: tools
});
console.log("返回对象:");
console.log(JSON.stringify(completion.choices[0].message));
console.log("\n");
return completion;
}
const completion = await functionCalling();
大模型通过返回对象的tool_calls
参数,指定需要使用的工具函数名称为:"get_current_weather"
,并指定函数的入参为:"{\"location\": \"上海\"}"
。
{
"content": "",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": [
{
"id": "call_6596dafa2a6a46f7a217da",
"function": {
"arguments": "{\"location\": \"上海\"}",
"name": "get_current_weather"
},
"type": "function",
"index": 0
}
]
}
需要注意的是,如果提问的问题被大模型判断为无需使用工具,则不会返回tool_calls
参数,并会通过content
参数直接进行回复。在输入“你好”时,tool_calls
参数为空,返回对象格式为:
{
"content": "你好!有什么可以帮助你的吗?如果你有关于天气或者时间的问题,我特别擅长回答。",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": null
}
如果没有返回tool_calls
参数,您的程序可以在此处直接返回content
字段,无需运行以下步骤。
如果您希望每次发起 Function Calling 后大模型都可以选择工具,请参见:强制工具调用。
4. 运行工具函数
在Function Calling流程中,运行工具函数是将大模型的决策转化为实际操作的关键步骤。就像在天气查询工具输入“上海”来获取天气一样,您在得到工具函数以及函数的入参后,可以运行工具函数来得到工具的输出。
运行工具函数的过程由您的计算环境而非大模型来完成。
由于大模型只可以输出字符串格式的内容,因此在运行工具函数前,您需要针对字符串格式的工具函数与入参分别进行解析。
工具函数
您需要建立一个工具函数名称到工具函数实体的映射
function_mapper
,将返回的工具函数字符串映射到工具函数实体;入参
Function Calling 返回的入参为 JSON 字符串,您可以使用 JSON 字符串解析工具将其解析为 JSON 对象,提取出入参信息。
# 步骤5:运行工具函数
# 请将以下代码粘贴到步骤4 代码后
import json
print("正在执行工具函数...")
# 从返回的结果中获取函数名称和入参
function_name = completion.choices[0].message.tool_calls[0].function.name
arguments_string = completion.choices[0].message.tool_calls[0].function.arguments
# 使用json模块解析参数字符串
arguments = json.loads(arguments_string)
# 创建一个函数映射表
function_mapper = {
"get_current_weather": get_current_weather,
"get_current_time": get_current_time
}
# 获取函数实体
function = function_mapper[function_name]
# 如果入参为空,则直接调用函数
if arguments == {}:
function_output = function()
# 否则,传入参数后调用函数
else:
function_output = function(arguments)
# 打印工具的输出
print(f"工具函数输出:{function_output}\n")
// 步骤5:运行工具函数
// 请将以下代码粘贴到步骤4 代码后
console.log("正在执行工具函数...");
const function_name = completion.choices[0].message.tool_calls[0].function.name;
const arguments_string = completion.choices[0].message.tool_calls[0].function.arguments;
// 使用JSON模块解析参数字符串
const args = JSON.parse(arguments_string);
// 创建一个函数映射表
const functionMapper = {
"get_current_weather": getCurrentWeather,
"get_current_time": getCurrentTime
};
// 获取函数实体
const func = functionMapper[function_name];
// 如果入参为空,则直接调用函数
let functionOutput;
if (Object.keys(args).length === 0) {
functionOutput = func();
} else {
// 否则,传入参数后调用函数
functionOutput = func(args);
}
// 打印工具的输出
console.log(`工具函数输出:${functionOutput}\n`);
运行以上代码可以得到如下输出:
上海今天是多云。
您可以直接将工具输出作为最终的结果。如果您希望返回结果更符合人类语气,可以参见 大模型总结工具函数输出。
进阶用法
流式输出
为了提升用户体验和减少等待时间,您可以使用流式输出快速获取所需调用的工具函数名称。其中:
工具函数名称:仅在第一个流式返回的对象中出现。
入参信息:以持续的流式方式输出。
流式输出方式能让您更灵活地处理 Function Calling 的结果。您可以参考以下代码,将发起 Function Calling修改为流式输出方式。
def function_calling():
completion = client.chat.completions.create(
model="qwen-plus",
messages=messages,
tools=tools,
stream=True
)
for chunk in completion:
print(chunk.model_dump_json())
function_calling()
async function functionCalling() {
const completion = await openai.chat.completions.create({
model: "qwen-plus",
messages: messages,
tools: tools,
stream: true
});
for await (const chunk of completion) {
console.log(JSON.stringify(chunk))
}
}
functionCalling();
从第一个返回的流式输出对象可以获得工具函数名称,入参信息则需要您进行拼接,拼接完成后再运行工具函数。
{"id":"chatcmpl-3f8155c3-e96f-95bc-a2a6-8e48537a0893","choices":[{"delta":{"content":null,"function_call":null,"refusal":null,"role":"assistant","tool_calls":[{"index":0,"id":"call_5507104cabae4f64a0fdd3","function":{"arguments":"{\"location\":","name":"get_current_weather"},"type":"function"}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1736251532,"model":"qwen-plus","object":"chat.completion.chunk","service_tier":null,"system_fingerprint":null,"usage":null}
{"id":"chatcmpl-3f8155c3-e96f-95bc-a2a6-8e48537a0893","choices":[{"delta":{"content":null,"function_call":null,"refusal":null,"role":null,"tool_calls":[{"index":0,"id":"","function":{"arguments":" \"上海\"}","name":""},"type":"function"}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1736251532,"model":"qwen-plus","object":"chat.completion.chunk","service_tier":null,"system_fingerprint":null,"usage":null}
{"id":"chatcmpl-3f8155c3-e96f-95bc-a2a6-8e48537a0893","choices":[{"delta":{"content":null,"function_call":null,"refusal":null,"role":null,"tool_calls":[{"index":0,"id":"","function":{"arguments":null,"name":null},"type":"function"}]},"finish_reason":"tool_calls","index":0,"logprobs":null}],"created":1736251532,"model":"qwen-plus","object":"chat.completion.chunk","service_tier":null,"system_fingerprint":null,"usage":null}
如果您需要使用大模型总结工具函数输出,添加的 Assistant Message 需要符合下方格式。
{
"content": "",
"refusal": None,
"role": "assistant",
"audio": None,
"function_call": None,
"tool_calls": [
{
"id": "call_xxx",
"function": {
"arguments": '{"location": "上海"}',
"name": "get_current_weather",
},
"type": "function",
"index": 0,
}
],
}
您需要对以下元素进行替换:
id
将
tool_calls
的id
替换为第一个返回的流式输出对象中的choices[0].delta.tool_calls[0].id
;arguments
将入参信息拼接后,替换
tool_calls
的arguments
;name
将
tool_calls
的name
替换为第一个返回的流式输出对象中的choices[0].delta.tool_calls[0].function.name
。
指定工具调用方式
并行工具调用
上文中的问题“上海天气”只需经过一次工具调用即可得到准确回复,如果输入问题需要调用多次工具,如“四个直辖市的天气如何”或“杭州天气,以及现在几点了”,发起 Function Calling 后只会返回一个工具调用信息,以提问“四个直辖市的天气如何”为例:
{
"content": "",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": [
{
"id": "call_61a2bbd82a8042289f1ff2",
"function": {
"arguments": "{\"location\": \"北京市\"}",
"name": "get_current_weather"
},
"type": "function",
"index": 0
}
]
}
返回结果中只有北京市的入参信息。为了解决这一问题,您可以在发起 Function Calling时,将请求参数parallel_tool_calls
设置为true
,这样返回对象中将包含所有需要调用的工具函数与入参信息。
def function_calling():
completion = client.chat.completions.create(
model="qwen-plus", # 此处以 qwen-plus 为例,可按需更换模型名称
messages=messages,
tools=tools,
# 新增参数
parallel_tool_calls=True
)
print("返回对象:")
print(completion.choices[0].message.model_dump_json())
print("\n")
return completion
print("正在发起function calling...")
completion = function_calling()
async function functionCalling() {
const completion = await openai.chat.completions.create({
model: "qwen-plus", // 此处以qwen-plus为例,可按需更换模型名称
messages: messages,
tools: tools,
parallel_tool_calls: true
});
console.log("返回对象:");
console.log(JSON.stringify(completion.choices[0].message));
console.log("\n");
return completion;
}
const completion = await functionCalling();
在返回对象的tool_calls
数组中包含了四个直辖市的入参信息:
{
"content": "",
"role": "assistant",
"tool_calls": [
{
"function": {
"name": "get_current_weather",
"arguments": "{\"location\": \"北京市\"}"
},
"index": 0,
"id": "call_c2d8a3a24c4d4929b26ae2",
"type": "function"
},
{
"function": {
"name": "get_current_weather",
"arguments": "{\"location\": \"天津市\"}"
},
"index": 1,
"id": "call_dc7f2f678f1944da9194cd",
"type": "function"
},
{
"function": {
"name": "get_current_weather",
"arguments": "{\"location\": \"上海市\"}"
},
"index": 2,
"id": "call_55c95dd718d94d9789c7c0",
"type": "function"
},
{
"function": {
"name": "get_current_weather",
"arguments": "{\"location\": \"重庆市\"}"
},
"index": 3,
"id": "call_98a0cc7fded64b3ba88251",
"type": "function"
}
]
}
强制工具调用
大模型生成内容具有不确定性,有时会选择错误的工具进行调用。如果您希望对于某一类问题,大模型能够采取制定好的工具选择策略(如强制使用某个工具、强制不使用工具),可以通过修改tool_choice
参数来强制指定工具调用的策略。
tool_choice
参数的默认值为"auto"
,表示由大模型自主判断如何进行工具调用。
如果需要 大模型总结工具函数输出,请在发起总结的请求时将tool_choice
参数去除,否则大模型 API 仍会返回工具调用信息。
强制使用某个工具
如果您希望对于某一类问题,Function Calling 能够强制调用某个工具,可以设定
tool_choice
参数为{"type": "function", "function": {"name": "the_function_to_call"}}
,大模型将不参与工具的选择,只参与输入参数的选择。假设当前场景中只包含天气查询的问题,您可以修改 function_calling 代码为:
PythonNode.jsdef function_calling(): completion = client.chat.completions.create( model="qwen-plus", messages=messages, tools=tools, tool_choice={"type": "function", "function": {"name": "get_current_weather"}} ) print(completion.model_dump_json()) function_calling()
∂async function functionCalling() { const response = await openai.chat.completions.create({ model: "qwen-plus", messages: messages, tools: tools, tool_choice: {"type": "function", "function": {"name": "get_current_weather"}} }); console.log("返回对象:"); console.log(JSON.stringify(response.choices[0].message)); console.log("\n"); return response; } const response = await functionCalling();
无论输入什么问题,返回对象的工具函数都会是
get_current_weather
。使用该策略前请确保问题与选择的工具相关,否则可能返回不符合预期的结果。
强制不使用工具
如果您希望无论输入什么问题,Function Calling 都不会进行工具调用(返回对象中包含回复内容
content
而tool_calls
参数为空),可以设定tool_choice
参数为"none"
,或不传入tools
参数,Function Calling 返回的tool_calls
参数将始终为空。假设当前场景中的问题均无需调用工具,您可以修改 function_calling 代码为:
PythonNode.jsdef function_calling(): completion = client.chat.completions.create( model="qwen-plus", messages=messages, tools=tools, tool_choice="none" ) print(completion.model_dump_json()) function_calling()
async function functionCalling() { const completion = await openai.chat.completions.create({ model: "qwen-plus", messages: messages, tools: tools, tool_choice: "none" }); console.log("返回对象:"); console.log(JSON.stringify(completion.choices[0].message)); console.log("\n"); return completion; } const completion = await functionCalling();
如何计费
在发起 Function Calling 时,您需要提供 tools 和 messages 参数。输入内容的计费不仅包含 messages 的 Token,还包括 tools 参数中工具描述信息转化后的 Token。
完整代码
您可以通过OpenAI SDK或OpenAI兼容的HTTP方式调用通义千问模型,体验Function Call的功能。
示例代码
from openai import OpenAI
from datetime import datetime
import json
import os
import random
client = OpenAI(
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", # 填写DashScope SDK的base_url
)
# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [
# 工具1 获取当前时刻的时间
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
# 因为获取当前时间无需输入参数,因此parameters为空字典
"parameters": {}
}
},
# 工具2 获取指定城市的天气
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
"type": "object",
"properties": {
# 查询天气时需要提供位置,因此参数设置为location
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。"
}
}
},
"required": [
"location"
]
}
}
]
# 模拟天气查询工具。返回结果示例:“北京今天是雨天。”
def get_current_weather(arguments):
# 定义备选的天气条件列表
weather_conditions = ["晴天", "多云", "雨天"]
# 随机选择一个天气条件
random_weather = random.choice(weather_conditions)
# 从 JSON 中提取位置信息
location = arguments["location"]
# 返回格式化的天气信息
return f"{location}今天是{random_weather}。"
# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
# 获取当前日期和时间
current_datetime = datetime.now()
# 格式化当前日期和时间
formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
# 返回格式化后的当前时间
return f"当前时间:{formatted_time}。"
# 封装模型响应函数
def get_response(messages):
completion = client.chat.completions.create(
model="qwen-plus", # 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages=messages,
tools=tools
)
return completion
def call_with_messages():
print('\n')
messages = [
{
"content": input('请输入:'), # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?"
"role": "user"
}
]
print("-"*60)
# 模型的第一轮调用
i = 1
first_response = get_response(messages)
assistant_output = first_response.choices[0].message
print(f"\n第{i}轮大模型输出信息:{first_response}\n")
if assistant_output.content is None:
assistant_output.content = ""
messages.append(assistant_output)
# 如果不需要调用工具,则直接返回最终答案
if assistant_output.tool_calls == None: # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用
print(f"无需调用工具,我可以直接回复:{assistant_output.content}")
return
# 如果需要调用工具,则进行模型的多轮调用,直到模型判断无需调用工具
while assistant_output.tool_calls != None:
# 如果判断需要调用查询天气工具,则运行查询天气工具
tool_info = {"content": "","role": "tool", "tool_call_id": assistant_output.tool_calls[0].id}
if assistant_output.tool_calls[0].function.name == "get_current_weather":
# 提取位置参数信息
argumens = json.loads(assistant_output.tool_calls[0].function.arguments)
tool_info["content"] = get_current_weather(argumens)
# 如果判断需要调用查询时间工具,则运行查询时间工具
elif assistant_output.tool_calls[0].function.name == 'get_current_time':
tool_info["content"] = get_current_time()
tool_output = tool_info["content"]
print(f"工具输出信息:{tool_output}\n")
print("-"*60)
messages.append(tool_info)
assistant_output = get_response(messages).choices[0].message
if assistant_output.content is None:
assistant_output.content = ""
messages.append(assistant_output)
i += 1
print(f"第{i}轮大模型输出信息:{assistant_output}\n")
print(f"最终答案:{assistant_output.content}")
if __name__ == '__main__':
call_with_messages()
返回结果
当输入:几点了?
时,程序会进行如下输出:
以下是发起Function Call流程(模型的第一轮调用)时模型的返回信息。当输入“杭州天气”时,模型会返回tool_calls参数;当输入“你好”时,模型判断无需调用工具,模型不会返回tool_calls参数。
{
'id': 'chatcmpl-e2f045fd-2604-9cdb-bb61-37c805ecd15a',
'choices': [
{
'finish_reason': 'tool_calls',
'index': 0,
'logprobs': None,
'message': {
'content': '',
'role': 'assistant',
'function_call': None,
'tool_calls': [
{
'id': 'call_7a33ebc99d5342969f4868',
'function': {
'arguments': '{
"location": "杭州市"
}',
'name': 'get_current_weather'
},
'type': 'function',
'index': 0
}
]
}
}
],
'created': 1726049697,
'model': 'qwen-max',
'object': 'chat.completion',
'service_tier': None,
'system_fingerprint': None,
'usage': {
'completion_tokens': 18,
'prompt_tokens': 217,
'total_tokens': 235
}
}
{
'id': 'chatcmpl-5d890637-9211-9bda-b184-961acf3be38d',
'choices': [
{
'finish_reason': 'stop',
'index': 0,
'logprobs': None,
'message': {
'content': '你好!有什么可以帮助你的吗?',
'role': 'assistant',
'function_call': None,
'tool_calls': None
}
}
],
'created': 1726049765,
'model': 'qwen-max',
'object': 'chat.completion',
'service_tier': None,
'system_fingerprint': None,
'usage': {
'completion_tokens': 7,
'prompt_tokens': 216,
'total_tokens': 223
}
}
示例代码
import OpenAI from "openai";
import { format } from 'date-fns';
import readline from 'readline';
function getCurrentWeather(location) {
return `${location}今天是雨天。`;
}
function getCurrentTime() {
// 获取当前日期和时间
const currentDatetime = new Date();
// 格式化当前日期和时间
const formattedTime = format(currentDatetime, 'yyyy-MM-dd HH:mm:ss');
// 返回格式化后的当前时间
return `当前时间:${formattedTime}。`;
}
const openai = new OpenAI(
{
// 若没有配置环境变量,请用百炼API Key将下行替换为:apiKey: "sk-xxx",
apiKey: process.env.DASHSCOPE_API_KEY,
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
}
);
const tools = [
// 工具1 获取当前时刻的时间
{
"type": "function",
"function": {
"name": "getCurrentTime",
"description": "当你想知道现在的时间时非常有用。",
// 因为获取当前时间无需输入参数,因此parameters为空
"parameters": {}
}
},
// 工具2 获取指定城市的天气
{
"type": "function",
"function": {
"name": "getCurrentWeather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
"type": "object",
"properties": {
// 查询天气时需要提供位置,因此参数设置为location
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。"
}
},
"required": ["location"]
}
}
}
];
async function getResponse(messages) {
const response = await openai.chat.completions.create({
model: "qwen-plus", // 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages: messages,
tools: tools,
});
return response;
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("user: ", async (question) => {
const messages = [{"role": "user","content": question}];
let i = 1;
const firstResponse = await getResponse(messages);
let assistantOutput = firstResponse.choices[0].message;
console.log(`第${i}轮大模型输出信息:${JSON.stringify(assistantOutput)}`);
if (Object.is(assistantOutput.content,null)){
assistantOutput.content = "";
}
messages.push(assistantOutput);
if (! ("tool_calls" in assistantOutput)) {
console.log(`无需调用工具,我可以直接回复:${assistantOutput.content}`);
rl.close();
} else{
while ("tool_calls" in assistantOutput) {
let toolInfo = {};
if (assistantOutput.tool_calls[0].function.name == "getCurrentWeather" ) {
toolInfo = {"role": "tool"};
let location = JSON.parse(assistantOutput.tool_calls[0].function.arguments)["location"];
toolInfo["content"] = getCurrentWeather(location);
} else if (assistantOutput.tool_calls[0].function.name == "getCurrentTime" ) {
toolInfo = {"role":"tool"};
toolInfo["content"] = getCurrentTime();
}
console.log(`工具输出信息:${JSON.stringify(toolInfo)}`);
console.log("=".repeat(100));
messages.push(toolInfo);
assistantOutput = (await getResponse(messages)).choices[0].message;
if (Object.is(assistantOutput.content,null)){
assistantOutput.content = "";
}
messages.push(assistantOutput);
i += 1;
console.log(`第${i}轮大模型输出信息:${JSON.stringify(assistantOutput)}`)
}
console.log("=".repeat(100));
console.log(`最终大模型输出信息:${JSON.stringify(assistantOutput.content)}`);
rl.close();
}});
返回结果
输入四个直辖市的天气如何?
,输出结果为:
第1轮大模型输出信息:{"content":"","role":"assistant","tool_calls":[{"function":{"name":"getCurrentWeather","arguments":"{\"location\": \"北京市\"}"},"index":0,"id":"call_d2aff21240b24c7291db6d","type":"function"}]}
工具输出信息:{"role":"tool","content":"北京市今天是雨天。"}
====================================================================================================
第2轮大模型输出信息:{"content":"","role":"assistant","tool_calls":[{"function":{"name":"getCurrentWeather","arguments":"{\"location\": \"天津市\"}"},"index":0,"id":"call_bdcfa937e69b4eae997b5e","type":"function"}]}
工具输出信息:{"role":"tool","content":"天津市今天是雨天。"}
====================================================================================================
第3轮大模型输出信息:{"content":"","role":"assistant","tool_calls":[{"function":{"name":"getCurrentWeather","arguments":"{\"location\": \"上海市\"}"},"index":0,"id":"call_bbf22d017e8e439e811974","type":"function"}]}
工具输出信息:{"role":"tool","content":"上海市今天是雨天。"}
====================================================================================================
第4轮大模型输出信息:{"content":"","role":"assistant","tool_calls":[{"function":{"name":"getCurrentWeather","arguments":"{\"location\": \"重庆市\"}"},"index":0,"id":"call_f4f8e149af01492fb60162","type":"function"}]}
工具输出信息:{"role":"tool","content":"重庆市今天是雨天。"}
====================================================================================================
第5轮大模型输出信息:{"content":"所有四个直辖市(北京市、天津市、上海市、重庆市)今天的天气都是雨天。别忘了带伞!","role":"assistant"}
====================================================================================================
最终大模型输出信息:"所有四个直辖市(北京市、天津市、上海市、重庆市)今天的天气都是雨天。别忘了带伞!"
示例代码
import requests
import os
from datetime import datetime
import json
# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [
# 工具1 获取当前时刻的时间
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
"parameters": {} # 因为获取当前时间无需输入参数,因此parameters为空字典
}
},
# 工具2 获取指定城市的天气
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": { # 查询天气时需要提供位置,因此参数设置为location
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。"
}
}
},
"required": [
"location"
]
}
}
]
# 模拟天气查询工具。返回结果示例:“北京今天是晴天。”
def get_current_weather(location):
return f"{location}今天是晴天。 "
# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
# 获取当前日期和时间
current_datetime = datetime.now()
# 格式化当前日期和时间
formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
# 返回格式化后的当前时间
return f"当前时间:{formatted_time}。"
def get_response(messages):
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
api_key = os.getenv("DASHSCOPE_API_KEY")
url = 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions'
headers = {'Content-Type': 'application/json',
'Authorization':f'Bearer {api_key}'}
body = {
'model': 'qwen-plus',
"messages": messages,
"tools":tools
}
response = requests.post(url, headers=headers, json=body)
return response.json()
def call_with_messages():
messages = [
{
"content": input('请输入:'), # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?"
"role": "user"
}
]
# 模型的第一轮调用
first_response = get_response(messages)
print(f"\n第一轮调用结果:{first_response}")
assistant_output = first_response['choices'][0]['message']
if assistant_output['content'] is None:
assistant_output['content'] = ""
messages.append(assistant_output)
if 'tool_calls' not in assistant_output: # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用
print(f"最终答案:{assistant_output['content']}")
return
# 如果模型选择的工具是get_current_weather
elif assistant_output['tool_calls'][0]['function']['name'] == 'get_current_weather':
tool_info = {"name": "get_current_weather", "role":"tool"}
location = json.loads(assistant_output['tool_calls'][0]['function']['arguments'])['location']
tool_info['content'] = get_current_weather(location)
# 如果模型选择的工具是get_current_time
elif assistant_output['tool_calls'][0]['function']['name'] == 'get_current_time':
tool_info = {"name": "get_current_time", "role":"tool"}
tool_info['content'] = get_current_time()
print(f"工具输出信息:{tool_info['content']}")
messages.append(tool_info)
# 模型的第二轮调用,对工具的输出进行总结
second_response = get_response(messages)
print(f"第二轮调用结果:{second_response}")
print(f"最终答案:{second_response['choices'][0]['message']['content']}")
if __name__ == '__main__':
call_with_messages()
返回结果
当输入:杭州天气
时,程序会进行如下输出:
以下是发起Function Call流程(模型的第一轮调用)时模型的返回信息。当输入“杭州天气”时,模型会返回tool_calls参数;当输入“你好”时,模型判断无需调用工具,模型不会返回tool_calls参数。
{
'choices': [
{
'message': {
'content': '',
'role': 'assistant',
'tool_calls': [
{
'function': {
'name': 'get_current_weather',
'arguments': '{
"location": "杭州市"
}'
},
'index': 0,
'id': 'call_416cd81b8e7641edb654c4',
'type': 'function'
}
]
},
'finish_reason': 'tool_calls',
'index': 0,
'logprobs': None
}
],
'object': 'chat.completion',
'usage': {
'prompt_tokens': 217,
'completion_tokens': 18,
'total_tokens': 235
},
'created': 1726050222,
'system_fingerprint': None,
'model': 'qwen-max',
'id': 'chatcmpl-61e30855-ee69-93ab-98d5-4194c51a9980'
}
{
'choices': [
{
'message': {
'content': '你好!有什么可以帮助你的吗?',
'role': 'assistant'
},
'finish_reason': 'stop',
'index': 0,
'logprobs': None
}
],
'object': 'chat.completion',
'usage': {
'prompt_tokens': 216,
'completion_tokens': 7,
'total_tokens': 223
},
'created': 1726050238,
'system_fingerprint': None,
'model': 'qwen-max',
'id': 'chatcmpl-2f2f86d1-bc4e-9494-baca-aac5b0555091'
}
您可以通过DashScope SDK或HTTP方式调用通义千问模型,体验Function Call的功能。
示例代码
import os
from dashscope import Generation
from datetime import datetime
import random
import json
# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [
# 工具1 获取当前时刻的时间
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
"parameters": {} # 因为获取当前时间无需输入参数,因此parameters为空字典
}
},
# 工具2 获取指定城市的天气
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
# 查询天气时需要提供位置,因此参数设置为location
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。"
}
}
},
"required": [
"location"
]
}
}
]
# 模拟天气查询工具。返回结果示例:“北京今天是晴天。”
def get_current_weather(location):
return f"{location}今天是晴天。 "
# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
# 获取当前日期和时间
current_datetime = datetime.now()
# 格式化当前日期和时间
formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
# 返回格式化后的当前时间
return f"当前时间:{formatted_time}。"
# 封装模型响应函数
def get_response(messages):
response = Generation.call(
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"),
model='qwen-plus', # 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages=messages,
tools=tools,
seed=random.randint(1, 10000), # 设置随机数种子seed,如果没有设置,则随机数种子默认为1234
result_format='message' # 将输出设置为message形式
)
return response
def call_with_messages():
print('\n')
messages = [
{
"content": input('请输入:'), # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?"
"role": "user"
}
]
# 模型的第一轮调用
first_response = get_response(messages)
assistant_output = first_response.output.choices[0].message
print(f"\n大模型第一轮输出信息:{first_response}\n")
messages.append(assistant_output)
if 'tool_calls' not in assistant_output: # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用
print(f"最终答案:{assistant_output.content}")
return
# 如果模型选择的工具是get_current_weather
elif assistant_output.tool_calls[0]['function']['name'] == 'get_current_weather':
tool_info = {"name": "get_current_weather", "role":"tool"}
location = json.loads(assistant_output.tool_calls[0]['function']['arguments'])['location']
tool_info['content'] = get_current_weather(location)
# 如果模型选择的工具是get_current_time
elif assistant_output.tool_calls[0]['function']['name'] == 'get_current_time':
tool_info = {"name": "get_current_time", "role":"tool"}
tool_info['content'] = get_current_time()
print(f"工具输出信息:{tool_info['content']}\n")
messages.append(tool_info)
# 模型的第二轮调用,对工具的输出进行总结
second_response = get_response(messages)
print(f"大模型第二轮输出信息:{second_response}\n")
print(f"最终答案:{second_response.output.choices[0].message['content']}")
if __name__ == '__main__':
call_with_messages()
返回结果
通过运行以上代码,您可以输入问题,得到在工具辅助条件下模型的输出结果。使用过程示例如下图所示:
以下是发起Function Call流程(模型的第一轮调用)时模型的返回信息。当输入“杭州天气”时,模型会返回tool_calls参数;当输入“你好”时,模型判断无需调用工具,模型不会返回tool_calls参数。
{
"status_code": 200,
"request_id": "33cf0a53-ea38-9f47-8fce-b93b55d86573",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"function": {
"name": "get_current_weather",
"arguments": "{\"location\": \"杭州市\"}"
},
"index": 0,
"id": "call_9f62f52f3a834a8194f634",
"type": "function"
}
]
}
}
]
},
"usage": {
"input_tokens": 217,
"output_tokens": 18,
"total_tokens": 235
}
}
{
"status_code": 200,
"request_id": "4818ce03-e7c9-96de-a7bc-781649d98465",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "你好!有什么可以帮助你的吗?"
}
}
]
},
"usage": {
"input_tokens": 216,
"output_tokens": 7,
"total_tokens": 223
}
}
示例代码
// Copyright (c) Alibaba, Inc. and its affiliates.
// version >= 2.12.0
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.alibaba.dashscope.aigc.conversation.ConversationParam.ResultFormat;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationOutput.Choice;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.tools.FunctionDefinition;
import com.alibaba.dashscope.tools.ToolCallBase;
import com.alibaba.dashscope.tools.ToolCallFunction;
import com.alibaba.dashscope.tools.ToolFunction;
import com.alibaba.dashscope.utils.JsonUtils;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.victools.jsonschema.generator.Option;
import com.github.victools.jsonschema.generator.OptionPreset;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.github.victools.jsonschema.generator.SchemaVersion;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class Main {
public static class GetWeatherTool {
private String location;
public GetWeatherTool(String location) {
this.location = location;
}
public String callWeather() {
// 假设location是一个JSON字符串,例如{"location": "北京"}
// 需要提取其中的"location"的值
try {
// 使用Jackson库解析JSON
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(location);
String locationName = jsonNode.get("location").asText();
return locationName + "今天是晴天";
} catch (Exception e) {
// 如果解析失败,返回原始字符串
return location + "今天是晴天";
}
}
}
public static class GetTimeTool {
public String getCurrentTime() {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return "当前时间:" + now.format(formatter) + "。";
}
}
private static ObjectNode generateSchema(Class<?> clazz) {
SchemaGeneratorConfigBuilder configBuilder =
new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON);
SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES)
.without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build();
SchemaGenerator generator = new SchemaGenerator(config);
return generator.generateSchema(clazz);
}
public static void selectTool()
throws NoApiKeyException, ApiException, InputRequiredException {
ObjectNode jsonSchemaWeather = generateSchema(GetWeatherTool.class);
ObjectNode jsonSchemaTime = generateSchema(GetTimeTool.class);
FunctionDefinition fdWeather = FunctionDefinition.builder().name("get_current_weather")
.description("获取指定地区的天气")
.parameters(JsonUtils.parseString(jsonSchemaWeather.toString()).getAsJsonObject()).build();
FunctionDefinition fdTime = FunctionDefinition.builder().name("get_current_time")
.description("获取当前时刻的时间")
.parameters(JsonUtils.parseString(jsonSchemaTime.toString()).getAsJsonObject()).build();
Message systemMsg = Message.builder().role(Role.SYSTEM.getValue())
.content("You are a helpful assistant. When asked a question, use tools wherever possible.")
.build();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String userInput = scanner.nextLine();
Message userMsg = Message.builder().role(Role.USER.getValue()).content(userInput).build();
List<Message> messages = new ArrayList<>(Arrays.asList(systemMsg, userMsg));
GenerationParam param = GenerationParam.builder()
// 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
.model("qwen-plus")
// 若没有配置环境变量,请用百炼API Key将下行替换为:.apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.messages(messages).resultFormat(ResultFormat.MESSAGE)
.tools(Arrays.asList(
ToolFunction.builder().function(fdWeather).build(),
ToolFunction.builder().function(fdTime).build()
)).build();
Generation gen = new Generation();
GenerationResult result = gen.call(param);
System.out.println("首轮输出:" + JsonUtils.toJson(result));
boolean needToolCall = true;
while (needToolCall) {
needToolCall = false;
for (Choice choice : result.getOutput().getChoices()) {
messages.add(choice.getMessage());
if (choice.getMessage().getToolCalls() != null) {
for (ToolCallBase toolCall : choice.getMessage().getToolCalls()) {
if (toolCall.getType().equals("function")) {
String functionName = ((ToolCallFunction) toolCall).getFunction().getName();
String functionArgument = ((ToolCallFunction) toolCall).getFunction().getArguments();
if (functionName.equals("get_current_weather")) {
GetWeatherTool weatherTool = new GetWeatherTool(functionArgument);
String weather = weatherTool.callWeather();
Message toolResultMessage = Message.builder().role("tool")
.content(weather).toolCallId(toolCall.getId()).build();
messages.add(toolResultMessage);
System.out.println("工具输出信息:" + weather);
} else if (functionName.equals("get_current_time")) {
GetTimeTool timeTool = new GetTimeTool();
String time = timeTool.getCurrentTime();
Message toolResultMessage = Message.builder().role("tool")
.content(time).toolCallId(toolCall.getId()).build();
messages.add(toolResultMessage);
System.out.println("工具输出信息:" + time);
}
needToolCall = true;
}
}
} else {
System.out.println("最终答案:" + choice.getMessage().getContent());
return;
}
}
if (needToolCall) {
param.setMessages(messages);
result = gen.call(param);
System.out.println("下一轮输出:" + JsonUtils.toJson(result));
}
}
System.out.println("最终答案:" + result.getOutput().getChoices().get(0).getMessage().getContent());
}
public static void main(String[] args) {
try {
selectTool();
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
System.out.println(String.format("Exception: %s", e.getMessage()));
} catch (Exception e) {
System.out.println(String.format("Exception: %s", e.getMessage()));
}
System.exit(0);
}
}
返回结果
通过运行以上代码,您可以输入问题,得到在工具辅助条件下模型的输出结果。使用过程示例如下图所示:
以下是发起Function Call流程(模型的第一轮调用)时模型的返回信息。当输入“杭州天气”时,模型会返回tool_calls参数;当输入“你好”时,模型判断无需调用工具,模型不会返回tool_calls参数。
{
"requestId": "e2faa5cf-1707-973b-b216-36aa4ef52afc",
"usage": {
"input_tokens": 254,
"output_tokens": 19,
"total_tokens": 273
},
"output": {
"choices": [
{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"type": "function",
"id": "",
"function": {
"name": "get_current_whether",
"arguments": "{\"location\": \"杭州\"}"
}
}
]
}
}
]
}
}
{
"requestId": "f6ca3828-3b5f-99bf-8bae-90b4aa88923f",
"usage": {
"input_tokens": 253,
"output_tokens": 7,
"total_tokens": 260
},
"output": {
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "你好!有什么可以帮助你的吗?"
}
}
]
}
}
示例代码
import requests
import os
from datetime import datetime
import json
# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [
# 工具1 获取当前时刻的时间
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
"parameters": {} # 因为获取当前时间无需输入参数,因此parameters为空字典
}
},
# 工具2 获取指定城市的天气
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": { # 查询天气时需要提供位置,因此参数设置为location
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。"
}
}
},
"required": [
"location"
]
}
}
]
# 模拟天气查询工具。返回结果示例:“北京今天是晴天。”
def get_current_weather(location):
return f"{location}今天是晴天。 "
# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
# 获取当前日期和时间
current_datetime = datetime.now()
# 格式化当前日期和时间
formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
# 返回格式化后的当前时间
return f"当前时间:{formatted_time}。"
def get_response(messages):
api_key = os.getenv("DASHSCOPE_API_KEY")
url = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation'
headers = {'Content-Type': 'application/json',
'Authorization':f'Bearer {api_key}'}
body = {
'model': 'qwen-plus',
"input": {
"messages": messages
},
"parameters": {
"result_format": "message",
"tools": tools
}
}
response = requests.post(url, headers=headers, json=body)
return response.json()
def call_with_messages():
messages = [
{
"content": input('请输入:'), # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?"
"role": "user"
}
]
# 模型的第一轮调用
first_response = get_response(messages)
print(f"\n第一轮调用结果:{first_response}")
assistant_output = first_response['output']['choices'][0]['message']
messages.append(assistant_output)
if 'tool_calls' not in assistant_output: # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用
print(f"最终答案:{assistant_output['content']}")
return
# 如果模型选择的工具是get_current_weather
elif assistant_output['tool_calls'][0]['function']['name'] == 'get_current_weather':
tool_info = {"name": "get_current_weather", "role":"tool"}
location = json.loads(assistant_output['tool_calls'][0]['function']['arguments'])['location']
tool_info['content'] = get_current_weather(location)
# 如果模型选择的工具是get_current_time
elif assistant_output['tool_calls'][0]['function']['name'] == 'get_current_time':
tool_info = {"name": "get_current_time", "role":"tool"}
tool_info['content'] = get_current_time()
print(f"工具输出信息:{tool_info['content']}")
messages.append(tool_info)
# 模型的第二轮调用,对工具的输出进行总结
second_response = get_response(messages)
print(f"第二轮调用结果:{second_response}")
print(f"最终答案:{second_response['output']['choices'][0]['message']['content']}")
if __name__ == '__main__':
call_with_messages()
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.json.JSONArray;
import org.json.JSONObject;
public class Main {
private static final String userAGENT = "Java-HttpURLConnection/1.0";
public static void main(String[] args) throws Exception {
// 用户输入问题
Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String UserInput = scanner.nextLine();
// 初始化messages
JSONArray messages = new JSONArray();
// 定义系统信息system_message
JSONObject systemMessage = new JSONObject();
systemMessage.put("role","system");
systemMessage.put("content","You are a helpful assistant.");
// 根据用户的输入构造user_message
JSONObject userMessage = new JSONObject();
userMessage.put("role","user");
userMessage.put("content",UserInput);
// 将system_message和user_message依次添加到messages中
messages.put(systemMessage);
messages.put(userMessage);
// 进行模型的第一轮调用,并打印出结果
JSONObject responseJson = getResponse(messages);
System.out.println("第一轮调用结果:"+responseJson);
// 获取助手信息assistant_message
JSONObject assistantMessage = responseJson.getJSONObject("output").getJSONArray("choices").getJSONObject(0).getJSONObject("message");
// 初始化工具信息tool_message
JSONObject toolMessage = new JSONObject();
// 如果assistant_message没有tool_calls参数,则直接打印出assistant_message中的响应信息并返回
if (! assistantMessage.has("tool_calls")){
System.out.println("最终答案:"+assistantMessage.get("content"));
return;
}
// 如果assistant_message有tool_calls参数,说明模型判断需要调用工具
else {
// 将assistant_message添加到messages中
messages.put(assistantMessage);
// 如果模型判断需要调用get_current_weather函数
if (assistantMessage.getJSONArray("tool_calls").getJSONObject(0).getJSONObject("function").getString("name").equals("get_current_weather")) {
// 获取参数arguments信息,并提取出location参数
JSONObject argumentsJson = new JSONObject(assistantMessage.getJSONArray("tool_calls").getJSONObject(0).getJSONObject("function").getString("arguments"));
String location = argumentsJson.getString("location");
// 运行工具函数,得到工具的输出,并打印
String toolOutput = getCurrentWeather(location);
System.out.println("工具输出信息:"+toolOutput);
// 构造tool_message信息
toolMessage.put("name","get_current_weather");
toolMessage.put("role","tool");
toolMessage.put("content",toolOutput);
}
// 如果模型判断需要调用get_current_time函数
if (assistantMessage.getJSONArray("tool_calls").getJSONObject(0).getJSONObject("function").getString("name").equals("get_current_time")) {
// 运行工具函数,得到工具的输出,并打印
String toolOutput = getCurrentTime();
System.out.println("工具输出信息:"+toolOutput);
// 构造tool_message信息
toolMessage.put("name","get_current_time");
toolMessage.put("role","tool");
toolMessage.put("content",toolOutput);
}
}
// 将tool_message添加到messages中
messages.put(toolMessage);
// 进行模型的第二轮调用,并打印出结果
JSONObject secondResponse = getResponse(messages);
System.out.println("第二轮调用结果:"+secondResponse);
System.out.println("最终答案:"+secondResponse.getJSONObject("output").getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"));
}
// 定义获取天气的函数
public static String getCurrentWeather(String location) {
return location+"今天是晴天";
}
// 定义获取当前时间的函数
public static String getCurrentTime() {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String currentTime = "当前时间:" + now.format(formatter) + "。";
return currentTime;
}
// 封装模型响应函数,输入:messages,输出:json格式化后的http响应
public static JSONObject getResponse(JSONArray messages) throws Exception{
// 初始化工具库
JSONArray tools = new JSONArray();
// 定义工具1:获取当前时间
String jsonStringTime = "{\"type\": \"function\", \"function\": {\"name\": \"get_current_time\", \"description\": \"当你想知道现在的时间时非常有用。\", \"parameters\": {}}}";
JSONObject getCurrentTimeJson = new JSONObject(jsonStringTime);
// 定义工具2:获取指定地区天气
String jsonString_weather = "{\"type\": \"function\", \"function\": {\"name\": \"get_current_weather\", \"description\": \"当你想查询指定城市的天气时非常有用。\", \"parameters\": {\"type\": \"object\", \"properties\": {\"location\": {\"type\": \"string\", \"description\": \"城市或县区,比如北京市、杭州市、余杭区等。\"}}}, \"required\": [\"location\"]}}";
JSONObject getCurrentWeatherJson = new JSONObject(jsonString_weather);
// 将两个工具添加到工具库中
tools.put(getCurrentTimeJson);
tools.put(getCurrentWeatherJson);
String toolsString = tools.toString();
// 接口调用URL
String urlStr = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation";
// 通过环境变量获取DASHSCOPE_API_KEY
String apiKey = System.getenv("DASHSCOPE_API_KEY");
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
// 定义请求头信息
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + apiKey);
connection.setDoOutput(true);
// 定义请求体信息
String jsonInputString = String.format("{\"model\": \"qwen-max\", \"input\": {\"messages\":%s}, \"parameters\": {\"result_format\": \"message\",\"tools\":%s}}",messages.toString(),toolsString);
// 获取http响应response
try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
wr.write(jsonInputString.getBytes(StandardCharsets.UTF_8));
wr.flush();
}
StringBuilder response = new StringBuilder();
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
}
connection.disconnect();
// 返回json格式化后的response
return new JSONObject(response.toString());
}
}
返回结果
当输入:杭州天气
时,程序会进行如下输出:
以下是发起Function Call流程(模型的第一轮调用)时模型的返回信息。当输入“杭州天气”时,模型会返回tool_calls参数;当输入“你好”时,模型判断无需调用工具,模型不会返回tool_calls参数。
{
'output': {
'choices': [
{
'finish_reason': 'tool_calls',
'message': {
'role': 'assistant',
'tool_calls': [
{
'function': {
'name': 'get_current_weather',
'arguments': '{
"location": "杭州市"
}'
},
'index': 0,
'id': 'call_240d6341de4c484384849d',
'type': 'function'
}
],
'content': ''
}
}
]
},
'usage': {
'total_tokens': 235,
'output_tokens': 18,
'input_tokens': 217
},
'request_id': '235ed6a4-b6c0-9df0-aa0f-3c6dce89f3bd'
}
{
'output': {
'choices': [
{
'finish_reason': 'stop',
'message': {
'role': 'assistant',
'content': '你好!有什么可以帮助你的吗?'
}
}
]
},
'usage': {
'total_tokens': 223,
'output_tokens': 7,
'input_tokens': 216
},
'request_id': '42c42853-3caf-9815-96e8-9c950f4c26a0'
}
错误码
如果模型调用失败并返回报错信息,请参见错误信息进行解决。
- 本页导读 (1)
- 支持的模型
- 概述
- 前提条件
- 如何使用
- 1. 定义工具
- 2. 创建messages数组
- 3. 发起 Function Calling
- 4. 运行工具函数
- 5. 大模型总结工具函数输出(可选)
- 进阶用法
- 流式输出
- 指定工具调用方式
- 如何计费
- 完整代码
- 错误码