モデルは、リアルタイムの質問への回答や数学的計算などのタスクに苦労することがあります。Function calling は外部ツールを導入することでこの問題を解決し、モデルがそれ以外では回答できない質問に答えることを可能にします。
仕組み
Function calling により、アプリケーションとモデル間の複数ステップのやり取りを通じて、モデルが回答のために外部ツール情報を参照できるようになります。
最初のモデル呼び出しを開始
アプリケーションは、ユーザーの質問とモデルが呼び出せるツール一覧を含むリクエストをモデルに送信します。
モデルからのツール呼び出し命令を受信
モデルが外部ツールを呼び出すと判断した場合、JSON 形式で命令を返します。この命令により、アプリケーションが実行すべき関数と使用すべき入力パラメーターが指定されます。
モデルがツールを呼び出さないと判断した場合は、自然言語での応答を返します。
アプリケーション内でツールを実行
アプリケーションがツール命令を受信すると、そのツールを実行して出力を取得できます。
2 回目のモデル呼び出しを開始
ツールの出力を取得したら、それをモデルのコンテキスト(messages)に追加して、再度モデルを呼び出します。
モデルから最終的な応答を受信
モデルは、ツールの出力とユーザーの質問を組み合わせて、自然言語による最終的な応答を生成します。
次の図はワークフローを示しています。
モデルの可用性
Qwen
テキスト生成モデル
マルチモーダルモデル
DeepSeek
deepseek-v3.2
deepseek-v3.2-exp (non-thinking mode)
deepseek-v3.1 (non-thinking mode)
deepseek-r1
deepseek-r1-0528
deepseek-v3
Kimi
Kimi-K2.5
kimi-k2-thinking
Moonshot-Kimi-K2-Instruct
クイックスタート
まず、API キーを作成し、API キーを環境変数としてエクスポートする必要があります。OpenAI SDK または DashScope SDK を使用して呼び出しを行う場合は、SDK をインストールしてください。
このセクションでは、天気照会のシナリオを使用して、Function calling を迅速に使用する方法を説明します。
OpenAI 互換
from openai import OpenAI
from datetime import datetime
import json
import os
import random
client = OpenAI(
# If you use a model in the China (Beijing) region, you need to use an API Key for the China (Beijing) region. Get the key from: https://bailian.console.alibabacloud.com/?tab=model#/api-key
# If you have not configured the environment variable, replace the following line with: api_key="sk-xxx", using your model Studio API key.
api_key=os.getenv("DASHSCOPE_API_KEY"),
# If you use a model in the China (Beijing) region, replace the base_url with: https://dashscope.aliyuncs.com/compatible-mode/v1
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
# Simulate a user question
USER_QUESTION = "What's the weather like in Singapore?"
# Define the tool list
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or county, such as Singapore or New York.",
}
},
"required": ["location"],
},
},
},
]
# Simulate a weather query tool
def get_current_weather(arguments):
weather_conditions = ["Sunny", "Cloudy", "Rainy"]
random_weather = random.choice(weather_conditions)
location = arguments["location"]
return f"Today in {location} it is {random_weather}."
# Encapsulate the model response function
def get_response(messages):
completion = client.chat.completions.create(
model="qwen-plus",
messages=messages,
tools=tools,
)
return completion
messages = [{"role": "user", "content": USER_QUESTION}]
response = get_response(messages)
assistant_output = response.choices[0].message
if assistant_output.content is None:
assistant_output.content = ""
messages.append(assistant_output)
# If no tool call is needed, output the content directly
if assistant_output.tool_calls is None:
print(f"No need to call the weather query tool. Direct reply: {assistant_output.content}")
else:
# Enter the tool calling loop
while assistant_output.tool_calls is not None:
tool_call = assistant_output.tool_calls[0]
tool_call_id = tool_call.id
func_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
print(f"Calling tool [{func_name}] with arguments: {arguments}")
# Run the tool
tool_result = get_current_weather(arguments)
# Construct the tool return message
tool_message = {
"role": "tool",
"tool_call_id": tool_call_id,
"content": tool_result, # Keep the original tool output
}
print(f"Tool returns: {tool_message['content']}")
messages.append(tool_message)
# Call the model again to get a summarized natural language reply
response = get_response(messages)
assistant_output = response.choices[0].message
if assistant_output.content is None:
assistant_output.content = ""
messages.append(assistant_output)
print(f"Assistant's final reply: {assistant_output.content}")import OpenAI from 'openai';
// クライアントを初期化
const openai = new OpenAI({
apiKey: process.env.DASHSCOPE_API_KEY,
// 中国 (北京) リージョンのモデルを使用する場合は、baseURL を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えます
baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
});
// ツールリストを定義
const tools = [
{
type: "function",
function: {
name: "get_current_weather",
description: "特定の都市の天気をクエリする場合に便利です。",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "シンガポールやニューヨークなどの都市または郡。",
},
},
required: ["location"],
},
},
},
];
// 天気クエリツールをシミュレート
const getCurrentWeather = (args) => {
const weatherConditions = ["Sunny", "Cloudy", "Rainy"];
const randomWeather = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
const location = args.location;
return `Today in ${location} it is ${randomWeather}.`;
};
// モデル応答関数をカプセル化
const getResponse = async (messages) => {
const response = await openai.chat.completions.create({
model: "qwen-plus",
messages: messages,
tools: tools,
});
return response;
};
const main = async () => {
const input = "What's the weather like in Singapore?";
let messages = [
{
role: "user",
content: input,
}
];
let response = await getResponse(messages);
let assistantOutput = response.choices[0].message;
// content が null でないことを確認
if (!assistantOutput.content) assistantOutput.content = "";
messages.push(assistantOutput);
// ツールを呼び出すかどうかを判断
if (!assistantOutput.tool_calls) {
console.log(`天気クエリツールを呼び出す必要はありません。直接の返信: ${assistantOutput.content}`);
} else {
// ツール呼び出しループに入る
while (assistantOutput.tool_calls) {
const toolCall = assistantOutput.tool_calls[0];
const toolCallId = toolCall.id;
const funcName = toolCall.function.name;
const funcArgs = JSON.parse(toolCall.function.arguments);
console.log(`ツール [${funcName}] を引数で呼び出し中:`, funcArgs);
// ツールを実行
const toolResult = getCurrentWeather(funcArgs);
// ツールの戻りメッセージを構築
const toolMessage = {
role: "tool",
tool_call_id: toolCallId,
content: toolResult,
};
console.log(`ツールの戻り値: ${toolMessage.content}`);
messages.push(toolMessage);
// モデルを再度呼び出して自然言語の概要を取得
response = await getResponse(messages);
assistantOutput = response.choices[0].message;
if (!assistantOutput.content) assistantOutput.content = "";
messages.push(assistantOutput);
}
console.log(`アシスタントの最終返信: ${assistantOutput.content}`);
}
};
// プログラムを開始
main().catch(console.error);DashScope
import os
from dashscope import Generation
import dashscope
import json
import random
# If you use a model in the China (Beijing) region, replace base_http_api_url with: https://dashscope.aliyuncs.com/api/v1
dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
# 1. Define the tool list
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or county, such as Singapore or New York.",
}
},
"required": ["location"],
},
},
}
]
# 2. Simulate a weather query tool
def get_current_weather(arguments):
weather_conditions = ["Sunny", "Cloudy", "Rainy"]
random_weather = random.choice(weather_conditions)
location = arguments["location"]
return f"Today in {location} it is {random_weather}."
# 3. Encapsulate the model response function
def get_response(messages):
response = Generation.call(
# If you have not configured the environment variable, replace the following line with api_key="sk-xxx"
api_key=os.getenv("DASHSCOPE_API_KEY"),
model="qwen-plus",
messages=messages,
tools=tools,
result_format="message",
)
return response
# 4. Initialize the conversation history
messages = [
{
"role": "user",
"content": "What's the weather like in Singapore?"
}
]
# 5. Call the model for the first time
response = get_response(messages)
assistant_output = response.output.choices[0].message
messages.append(assistant_output)
# 6. Determine if a tool call is needed
if "tool_calls" not in assistant_output or not assistant_output["tool_calls"]:
print(f"No tool call needed. Direct reply: {assistant_output['content']}")
else:
# 7. Enter the tool calling loop
# Loop condition: As long as the latest model response includes a tool call request
while "tool_calls" in assistant_output and assistant_output["tool_calls"]:
tool_call = assistant_output["tool_calls"][0]
# Parse the tool call information
func_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
tool_call_id = tool_call.get("id") # Get the tool_call_id
print(f"Calling tool [{func_name}] with arguments: {arguments}")
# Run the corresponding tool function
tool_result = get_current_weather(arguments)
# Construct the tool return message
tool_message = {
"role": "tool",
"content": tool_result,
"tool_call_id": tool_call_id
}
print(f"Tool returns: {tool_message['content']}")
messages.append(tool_message)
# Call the model again to get a response based on the tool result
response = get_response(messages)
assistant_output = response.output.choices[0].message
messages.append(assistant_output)
# 8. Output the final natural language reply
print(f"Assistant's final reply: {assistant_output['content']}")import com.alibaba.dashscope.aigc.generation.Generation;
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.protocol.Protocol;
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.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class Main {
/**
* Define the local implementation of the tool.
* @param arguments A JSON string from the model containing the required parameters for the tool.
* @return A string with the result of the tool's execution.
*/
public static String getCurrentWeather(String arguments) {
try {
// The parameters provided by the model are in JSON format and need to be parsed manually.
ObjectMapper objectMapper = new ObjectMapper();
JsonNode argsNode = objectMapper.readTree(arguments);
String location = argsNode.get("location").asText();
// Use a random result to simulate a real API call or business logic.
List<String> weatherConditions = Arrays.asList("Sunny", "Cloudy", "Rainy");
String randomWeather = weatherConditions.get(new Random().nextInt(weatherConditions.size()));
return "Today in " + location + " it is " + randomWeather + ".";
} catch (Exception e) {
// Exception handling to ensure program robustness.
return "Failed to parse location parameter.";
}
}
public static void main(String[] args) {
try {
// Describe (register) our tool to the model.
String weatherParamsSchema =
"{\"type\":\"object\",\"properties\":{\"location\":{\"type\":\"string\",\"description\":\"A city or county, such as Singapore or New York.\"}},\"required\":[\"location\"]}";
FunctionDefinition weatherFunction = FunctionDefinition.builder()
.name("get_current_weather") // The unique identifier of the tool, which must correspond to the local implementation.
.description("This is useful when you want to query the weather in a specific city.") // A clear description helps the model better decide when to use the tool.
.parameters(JsonUtils.parseString(weatherParamsSchema).getAsJsonObject())
.build();
// If you use a model in the China (Beijing) region, replace the URL with: https://dashscope.aliyuncs.com/api/v1
Generation gen = new Generation(Protocol.HTTP.getValue(), "https://dashscope-intl.aliyuncs.com/api/v1");
String userInput = "What's the weather like in Singapore?";
List<Message> messages = new ArrayList<>();
messages.add(Message.builder().role(Role.USER.getValue()).content(userInput).build());
// Call the model for the first time. Send the user's request and the defined tool list to the model.
GenerationParam param = GenerationParam.builder()
.model("qwen-plus") // Specify the model to call.
.apiKey(System.getenv("DASHSCOPE_API_KEY")) // Get the API key from the environment variable.
.messages(messages) // Pass in the current conversation history.
.tools(Arrays.asList(ToolFunction.builder().function(weatherFunction).build())) // Pass in the list of available tools.
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.build();
GenerationResult result = gen.call(param);
Message assistantOutput = result.getOutput().getChoices().get(0).getMessage();
messages.add(assistantOutput); // Add the model's first reply to the conversation history as well.
// Check the model's reply to determine if it requests a tool call.
if (assistantOutput.getToolCalls() == null || assistantOutput.getToolCalls().isEmpty()) {
// Case A: The model does not call a tool, but provides a direct answer.
System.out.println("No need to call the weather query tool. Direct reply: " + assistantOutput.getContent());
} else {
// Case B: The model decides to call a tool.
// Use a while loop to handle scenarios where the model calls tools multiple times in a row.
while (assistantOutput.getToolCalls() != null && !assistantOutput.getToolCalls().isEmpty()) {
ToolCallBase toolCall = assistantOutput.getToolCalls().get(0);
// Parse the specific information of the tool call (function name, parameters) from the model's reply.
ToolCallFunction functionCall = (ToolCallFunction) toolCall;
String funcName = functionCall.getFunction().getName();
String arguments = functionCall.getFunction().getArguments();
System.out.println("Calling tool [" + funcName + "] with arguments: " + arguments);
// Run the corresponding Java method locally based on the tool name.
String toolResult = getCurrentWeather(arguments);
// Construct a message with role "tool" that contains the tool's execution result.
Message toolMessage = Message.builder()
.role("tool")
.toolCallId(toolCall.getId())
.content(toolResult)
.build();
System.out.println("Tool returns: " + toolMessage.getContent());
messages.add(toolMessage); // Add the tool's return result to the conversation history as well.
// Call the model again.
param.setMessages(messages);
result = gen.call(param);
assistantOutput = result.getOutput().getChoices().get(0).getMessage();
messages.add(assistantOutput);
}
// Print the final reply generated by the model after summarization.
System.out.println("Assistant's final reply: " + assistantOutput.getContent());
}
} catch (NoApiKeyException | InputRequiredException e) {
System.err.println("Error: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}次の出力が返されます。
Calling tool [get_current_weather] with arguments: {'location': 'Singapore'}
Tool returns: Today in Singapore it is Cloudy.
Assistant's final reply: Today in Singapore, the weather is cloudy.実装ガイド
Function calling では、ツール情報を渡す方法として以下の 2 つの方法がサポートされています。
方法 1:`tools` パラメーター経由で情報を渡す(推奨)
詳細については、「実装ガイド」をご参照ください。この方法では、ツールを定義し、messages 配列を作成し、Function calling を開始し、ツール関数を実行し、モデルにツール関数の出力を要約させることで、関数を呼び出せます。
方法 2:システムメッセージ経由で情報を渡す
`tools` パラメーターを使用すると、サーバー側で自動的に適切なプロンプトテンプレートがモデルに応じて調整・構築されます。そのため、`tools` パラメーターの使用を推奨します。Qwen モデルで `tools` パラメーターを使用したくない場合は、「システムメッセージを使用してツール情報を渡す」をご参照ください。
以下のセクションでは、OpenAI 互換の呼び出し方法を例として、`tools` パラメーター経由でツール情報を渡すことで、Function calling をステップごとに使用する方法を説明します。
ビジネスシナリオでは、天気照会と時刻照会の 2 種類の質問を受け付けるものと仮定します。
1. ツールの定義
ツールは、モデルと外部世界をつなぐブリッジです。まず、ツールを定義する必要があります。
1.1. ツール関数の作成
天気照会ツールと時刻照会ツールの 2 つのツール関数を作成できます。
天気照会ツール
このツールは
argumentsパラメーターを受け取ります。argumentsの形式は{"location": "query_location"}です。ツールの出力は"Today in {location} it is {weather}"形式の文字列です。デモンストレーション目的で、ここで定義された天気照会ツールは実際には天気を照会しません。「晴れ」「曇り」「雨」の中からランダムに選択します。実際のビジネスシナリオでは、これを高徳地図の天気照会などのツールに置き換えることができます。
時刻照会ツール
時刻照会ツールは入力パラメーターを必要としません。ツールの出力は
"Current time: {queried_time}."形式の文字列です。Node.js を使用する場合、
npm install date-fnsを実行して date-fns パッケージをインストールし、時刻を取得できます。
## Step 1: Define tool functions
# Add import for the random module
import random
from datetime import datetime
# Simulate a weather query tool. Example output: "Today in Beijing it is Rainy."
def get_current_weather(arguments):
# Define a list of alternative weather conditions
weather_conditions = ["Sunny", "Cloudy", "Rainy"]
# Randomly select a weather condition
random_weather = random.choice(weather_conditions)
# Extract location information from JSON
location = arguments["location"]
# Return formatted weather information
return f"Today in {location} it is {random_weather}."
# Tool to query the current time. Example output: "Current time: 2024-04-15 17:15:18."
def get_current_time():
# Get the current date and time
current_datetime = datetime.now()
# Format the current date and time
formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
# Return the formatted current time
return f"Current time: {formatted_time}."
# Test the tool functions and print the results. You can remove the following four lines of test code when running subsequent steps.
print("Testing tool output:")
print(get_current_weather({"location": "Shanghai"}))
print(get_current_time())
print("\n")// ステップ 1: ツール関数を定義する
// 時刻クエリツールをインポートする
import { format } from 'date-fns';
function getCurrentWeather(args) {
// 代替の天気条件のリストを定義する
const weatherConditions = ["Sunny", "Cloudy", "Rainy"];
// 天気条件をランダムに選択する
const randomWeather = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
// JSON から位置情報を抽出する
const location = args.location;
// フォーマット済みの天気情報を返す
return `Today in ${location} it is ${randomWeather}.`;
}
function getCurrentTime() {
// 現在の日時を取得する
const currentDatetime = new Date();
// 現在の日時をフォーマットする
const formattedTime = format(currentDatetime, 'yyyy-MM-dd HH:mm:ss');
// フォーマット済みの現在時刻を返す
return `Current time: ${formattedTime}.`;
}
// ツール関数をテストして結果を出力します。後続の手順を実行する際は、以下の 4 行のテストコードを削除できます。
console.log("Testing tool output:")
console.log(getCurrentWeather({location:"Shanghai"}));
console.log(getCurrentTime());
console.log("\n")ツールを実行すると、次の出力が表示されます。
Testing tool output:
Today in Shanghai it is Cloudy.
Current time: 2025-01-08 20:21:45.1.2 tools 配列の作成
人間がツールを選択する前に、その機能、使用タイミング、入力パラメーターなどについて包括的な理解が必要です。モデルも同様に、より正確にツールを選択するためにこの情報が必要です。次の JSON 形式でツール情報を提供できます。
| 天気照会ツールの場合、ツール記述情報は次の形式になります。 |
Function calling を開始する前に、コード内でツール情報配列(`tools`)を定義する必要があります。この配列には、各ツールの関数名、説明、パラメーター定義が含まれます。この配列は、後続の Function calling リクエストのパラメーターとして渡されます。
# Paste the following code after the code from Step 1
## Step 2: Create the tools array
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "This is useful when you want to know the current time.",
"parameters": {}
}
},
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District.",
}
},
"required": ["location"]
}
}
}
]
tool_name = [tool["function"]["name"] for tool in tools]
print(f"Created {len(tools)} tools: {tool_name}\n")// Paste the following code after the code from Step 1
// Step 2: Create the tools array
const tools = [
{
type: "function",
function: {
name: "get_current_time",
description: "This is useful when you want to know the current time.",
parameters: {}
}
},
{
type: "function",
function: {
name: "get_current_weather",
description: "This is useful when you want to query the weather in a specific city.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "A city or district, such as Beijing, Hangzhou, or Yuhang District.",
}
},
required: ["location"]
}
}
}
];
const toolNames = tools.map(tool => tool.function.name);
console.log(`Created ${tools.length} tools: ${toolNames.join(', ')}\n`);2. messages 配列の作成
Function calling では、`messages` 配列を使用してモデルに命令とコンテキスト情報を渡します。Function calling を開始する前に、`messages` 配列にはシステムメッセージとユーザーメッセージを含める必要があります。
システムメッセージ
tools 配列を作成する際に、ツールの目的と使用タイミングが記述されていますが、システムメッセージでツールを呼び出すタイミングを強調することで、通常はツール呼び出しの精度が向上します。現在のシナリオでは、システムプロンプトを次のように設定できます。
You are a helpful assistant. If the user asks about the weather, call the 'get_current_weather' function.
If the user asks about the time, call the 'get_current_time' function.
Please answer the questions in a friendly tone.ユーザーメッセージ
ユーザーメッセージは、ユーザーの質問を渡すために使用されます。「上海の天気」と質問された場合、`messages` 配列は次のようになります。
# Step 3: Create the messages array
# Paste the following code after the code from Step 2
# Example of a User Message for a text generation model
messages = [
{
"role": "system",
"content": """You are a helpful assistant. If the user asks about the weather, call the 'get_current_weather' function.
If the user asks about the time, call the 'get_current_time' function.
Please answer the questions in a friendly tone.""",
},
{
"role": "user",
"content": "Shanghai weather"
}
]
# Example of a User Message for multimodal model
# messages=[
# {
# "role": "system",
# "content": """You are a helpful assistant. If the user asks about the weather, call the 'get_current_weather' function.
# If the user asks about the time, call the 'get_current_time' function.
# Please answer the questions in a friendly tone.""",
# },
# {"role": "user",
# "content": [{"type": "image_url","image_url": {"url": "https://img.alicdn.com/imgextra/i2/O1CN01FbTJon1ErXVGMRdsN_!!6000000000405-0-tps-1024-683.jpg"}},
# {"type": "text", "text": "Query the current weather for the location in the image"}]},
# ]
print("messages array created\n") // Step 3: Create the messages array
// Paste the following code after the code from Step 2
const messages = [
{
role: "system",
content: "You are a helpful assistant. If the user asks about the weather, call the 'get_current_weather' function. If the user asks about the time, call the 'get_current_time' function. Please answer the questions in a friendly tone.",
},
{
role: "user",
content: "Shanghai weather"
}
];
// Example of a User Message for multimodal model,
// const messages: [{
// role: "user",
// content: [{type: "image_url", image_url: {"url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241022/emyrja/dog_and_girl.jpeg"}},
// {type: "text", text: "What is depicted in the image?"}]
// }];
console.log("messages array created\n");利用可能なツールには天気と時刻の照会が含まれているため、「現在時刻は?」と質問することもできます。
3. Function calling の開始
作成した tools と messages をモデルに渡して、Function calling を開始できます。モデルはツールを呼び出すかどうかを判断します。呼び出す場合は、そのツールの関数名とパラメーターを返します。
サポートされているモデルの一覧については、「モデルの可用性」をご参照ください。
# Step 4: Initiate function calling
# Paste the following code after the code from Step 3
from openai import OpenAI
import os
client = OpenAI(
# If you use a model in the China (Beijing) region, you need to use an API Key for the China (Beijing) region. Get the key from: https://bailian.console.alibabacloud.com/?tab=model#/api-key
# If you have not configured the environment variable, replace the following line with: api_key="sk-xxx", using your model Studio API key.
api_key=os.getenv("DASHSCOPE_API_KEY"),
# If you use a model in the China (Beijing) region, replace the base_url with: https://dashscope.aliyuncs.com/compatible-mode/v1
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
def function_calling():
completion = client.chat.completions.create(
# This example uses qwen-plus. You can change the model name as needed. For a list of models, see https://www.alibabacloud.com/help/en/model-studio/getting-started/models
model="qwen-plus",
messages=messages,
tools=tools
)
print("Returned object:")
print(completion.choices[0].message.model_dump_json())
print("\n")
return completion
print("Initiating function calling...")
completion = function_calling()// Step 4: Initiate function calling
// Paste the following code after the code from Step 3
import OpenAI from "openai";
const openai = new OpenAI(
{
// If you use a model in the China (Beijing) region, you need to use an API Key for the China (Beijing) region. Get the key from: https://bailian.console.alibabacloud.com/?tab=model#/api-key
// If you have not configured the environment variable, replace the following line with: apiKey: "sk-xxx", using your model Studio API key.
apiKey: process.env.DASHSCOPE_API_KEY,
// If you use a model in the China (Beijing) region, replace the baseURL with: https://dashscope.aliyuncs.com/compatible-mode/v1
baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
}
);
async function functionCalling() {
const completion = await openai.chat.completions.create({
model: "qwen-plus", // This example uses qwen-plus. You can change the model name as needed. For a list of models, see https://www.alibabacloud.com/help/en/model-studio/getting-started/models
messages: messages,
tools: tools
});
console.log("Returned object:");
console.log(JSON.stringify(completion.choices[0].message));
console.log("\n");
return completion;
}
const completion = await functionCalling();ユーザーが上海の天気について質問したため、モデルは使用するツール関数の名前を "get_current_weather" と指定し、関数の入力パラメーターを "{\"location\": \"Shanghai\"}" としました。
{
"content": "",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": [
{
"id": "call_6596dafa2a6a46f7a217da",
"function": {
"arguments": "{\"location\": \"Shanghai\"}",
"name": "get_current_weather"
},
"type": "function",
"index": 0
}
]
}モデルが質問に対してツールが不要だと判断した場合、content パラメーターを通じて直接応答します。「Hello」と入力すると、tool_calls パラメーターは空になり、返されるオブジェクトは次の形式になります。
{
"content": "Hello! How can I help you? I'm particularly good at answering questions about weather or time.",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": null
}tool_callsパラメーターが空の場合、プログラムは以降のステップを実行せずに直接contentを返すことができます。
Function calling のたびに特定のツールを必ず選択させたい場合は、「強制的なツール呼び出し」をご参照ください。
4. ツール関数の実行
ツール関数の実行は、モデルの決定を実際の操作に変換するための重要なステップです。
ツール関数の実行プロセスは、モデルではなくご利用のコンピューティング環境によって完了します。
モデルは文字列形式でのみ出力を生成できるため、ツール関数と入力パラメーターを個別に解析してから、ツール関数を実行する必要があります。
ツール関数
ツール関数名からツール関数エンティティへのマッピング
function_mapperを作成できます。これにより、返されたツール関数文字列をツール関数エンティティにマッピングします。入力パラメーター
Function calling によって返される入力パラメーターは JSON 文字列です。ツールを使用して JSON オブジェクトに解析し、入力パラメーター情報を抽出できます。
解析後、パラメーターをツール関数に渡して実行し、出力結果を取得できます。
# Step 5: Run the tool function
# Paste the following code after the code from Step 4
import json
print("Running the tool function...")
# Get the function name and input parameters from the returned result
function_name = completion.choices[0].message.tool_calls[0].function.name
arguments_string = completion.choices[0].message.tool_calls[0].function.arguments
# Use the json module to parse the parameter string
arguments = json.loads(arguments_string)
# Create a function mapping table
function_mapper = {
"get_current_weather": get_current_weather,
"get_current_time": get_current_time
}
# Get the function entity
function = function_mapper[function_name]
# If the input parameters are empty, call the function directly
if arguments == {}:
function_output = function()
# Otherwise, pass the parameters and then call the function
else:
function_output = function(arguments)
# Print the tool's output
print(f"Tool function output: {function_output}\n")// Step 5: Run the tool function
// Paste the following code after the code from Step 4
console.log("Running the tool function...");
const function_name = completion.choices[0].message.tool_calls[0].function.name;
const arguments_string = completion.choices[0].message.tool_calls[0].function.arguments;
// Use the JSON module to parse the parameter string
const args = JSON.parse(arguments_string);
// Create a function mapping table
const functionMapper = {
"get_current_weather": getCurrentWeather,
"get_current_time": getCurrentTime
};
// Get the function entity
const func = functionMapper[function_name];
// If the input parameters are empty, call the function directly
let functionOutput;
if (Object.keys(args).length === 0) {
functionOutput = func();
} else {
// Otherwise, pass the parameters and then call the function
functionOutput = func(args);
}
// Print the tool's output
console.log(`Tool function output: ${functionOutput}\n`);次の出力が返されます。
Today in Shanghai it is Cloudy.実際のビジネスシナリオでは、多くのツールのコア機能はメール送信やファイルアップロードなどの特定の操作を実行することであり、データを照会することではありません。これらのツールは実行後に文字列を出力しません。モデルがツールの実行状況を理解できるようにするため、このようなツールを設計する際に「メール送信成功」や「操作失敗」などのステータス記述を追加することを推奨します。
5. モデルによるツール関数出力の要約
ツール関数の出力形式は比較的固定されています。これをそのままユーザーに返すと、硬く不自然に聞こえる可能性があります。ユーザー入力とツール出力を組み合わせて自然言語の応答を生成させたい場合は、ツール出力をモデルのコンテキストに送信し、モデルに再度リクエストを送信できます。
アシスタントメッセージの追加
Function calling を開始した後、
completion.choices[0].messageからアシスタントメッセージを取得できます。まず、これを `messages` 配列に追加します。ツールメッセージの追加
ツールの出力を `messages` 配列に
{"role": "tool", "content": "the tool's output","tool_call_id": completion.choices[0].message.tool_calls[0].id}として追加できます。説明ツールの出力が文字列形式であることを確認してください。
tool_call_idは、各ツール呼び出しリクエストに対してシステムによって生成される 一意の識別子 です。 モデルは、一度に複数のツールを呼び出すようにリクエストすることがあります。 モデルに複数のツール結果を返す場合、tool_call_idによって、ツールの出力とその呼び出しの意図を確実に一致させることができます。
# Step 6: Submit the tool output to the Model
# Paste the following code after the code from Step 5
messages.append(completion.choices[0].message)
print("Assistant message added")
messages.append({"role": "tool", "content": function_output, "tool_call_id": completion.choices[0].message.tool_calls[0].id})
print("Tool message added\n")// Step 6: Submit the tool output to the Model
// Paste the following code after the code from Step 5
messages.push(completion.choices[0].message);
console.log("Assistant message added")
messages.push({
"role": "tool",
"content": functionOutput,
"tool_call_id": completion.choices[0].message.tool_calls[0].id
});
console.log("Tool message added\n");この時点で、`messages` 配列は次のようになります。
[
System Message -- Guides the model's tool calling strategy
User Message -- The user's question
Assistant Message -- The tool call information returned by the model
Tool Message -- The tool's output information (there may be multiple Tool Messages if parallel tool calling, as described below, is used)
]`messages` 配列を更新した後、次のコードを実行できます。
# Step 7: The model summarizes the tool output
# Paste the following code after the code from Step 6
print("Summarizing tool output...")
completion = function_calling()// Step 7: The model summarizes the tool output
// Paste the following code after the code from Step 6
console.log("Summarizing tool output...");
const completion_1 = await functionCalling();content から応答内容を取得できます。「今日の上海の天気は曇りです。他にもご質問がありましたら、お気軽にお尋ねください。」
{
"content": "Today in Shanghai, the weather is cloudy. If you have any other questions, feel free to ask.",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": null
}これで、Function calling の一連のプロセスが完了しました。
高度な使用方法
ツール呼び出し方法の指定
並列ツール呼び出し
単一都市の天気を照会するには、単一のツール呼び出しで十分です。入力質問が複数のツール呼び出しを必要とする場合(例:「北京と上海の天気はどうですか?」または「杭州の天気と現在時刻を教えてください」)は、Function calling を開始しても、1 つのツール呼び出し命令しか返されません。たとえば、「北京と上海の天気はどうですか?」と質問した場合、次の結果が返されます。
{
"content": "",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": [
{
"id": "call_61a2bbd82a8042289f1ff2",
"function": {
"arguments": "{\"location\": \"Beijing\"}",
"name": "get_current_weather"
},
"type": "function",
"index": 0
}
]
}返された結果には北京の入力パラメーター情報のみが含まれています。この問題を解決するには、Function calling を開始する際にリクエストパラメーター parallel_tool_calls を true に設定します。これにより、返されるオブジェクトに呼び出す必要のあるすべてのツール関数と入力パラメーターが含まれるようになります。
並列ツール呼び出しは、依存関係のないタスクに適しています。タスク間に依存関係がある場合(例:ツール A の入力がツール B の出力に依存する)、下記の「クイックスタート」を参照し、while ループを使用して逐次ツール呼び出し(一度に 1 つのツールを呼び出す)を実装してください。
def function_calling():
completion = client.chat.completions.create(
model="qwen-plus", # This example uses qwen-plus. You can change the model name as needed.
messages=messages,
tools=tools,
# New parameter
parallel_tool_calls=True
)
print("Returned object:")
print(completion.choices[0].message.model_dump_json())
print("\n")
return completion
print("Initiating function calling...")
completion = function_calling()async function functionCalling() {
const completion = await openai.chat.completions.create({
model: "qwen-plus", // This example uses qwen-plus. You can change the model name as needed.
messages: messages,
tools: tools,
parallel_tool_calls: true
});
console.log("Returned object:");
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\": \"Beijing\"}"
},
"index": 0,
"id": "call_c2d8a3a24c4d4929b26ae2",
"type": "function"
},
{
"function": {
"name": "get_current_weather",
"arguments": "{\"location\": \"Shanghai\"}"
},
"index": 1,
"id": "call_dc7f2f678f1944da9194cd",
"type": "function"
}
]
}強制的なツール呼び出し
モデルはコンテンツ生成においてある程度の不確実性を持ち、誤ったツールを呼び出すことがあります。特定のタイプの質問に対して手動で設定した戦略を採用させたい場合(例:特定のツールを強制的に使用させる、またはツールを使用させない)、tool_choice パラメーターを変更できます。tool_choice パラメーターのデフォルト値は "auto" で、これはモデルがツール呼び出し方法を独立して決定することを意味します。
モデルがツール関数出力を要約する際は、tool_choice パラメーターを削除してください。削除しないと、API は引き続きツール呼び出し情報を返します。特定のツールを強制
特定のタイプの質問に対して Function calling で特定のツールを強制的に呼び出させたい場合、
tool_choiceパラメーターを{"type": "function", "function": {"name": "the_function_to_call"}}に設定できます。この場合、モデルはツール選択に参加せず、入力パラメーター情報のみを出力します。現在のシナリオが天気照会質問のみを扱うと仮定すると、function_calling コードを次のように変更できます。
def 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("Returned object:"); 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 コードを次のように変更できます。
def 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("Returned object:"); console.log(JSON.stringify(completion.choices[0].message)); console.log("\n"); return completion; } const completion = await functionCalling();
マルチターン対話
ユーザーが最初のターンで「北京の天気はどうですか?」と質問し、2 番目のターンで「上海はどうですか?」と質問する場合があります。モデルのコンテキストに最初のターンの情報が含まれていないと、どのツールを呼び出すかを判断できません。マルチターン対話シナリオでは、各ターン後に `messages` 配列を維持することを推奨します。新しいユーザーメッセージをこの配列に追加し、Function calling を開始して後続のステップを実行できます。`messages` 構造は次のようになります。
[
System Message -- Guides the model's tool calling strategy
User Message -- The user's question
Assistant Message -- The tool call information returned by the model
Tool Message -- The tool's output information
Assistant Message -- The model's summary of the tool call information
User Message -- The user's second-turn question
]ストリーミング出力
ユーザーエクスペリエンスを向上させ、待ち時間を短縮するために、ストリーミング出力を使用してツール関数名と入力パラメーター情報をリアルタイムで取得できます。この場合:
ツール呼び出しパラメーター情報:データストリームとしてチャンク単位で返されます。
ツール関数名:ストリーミング応答の最初のデータチャンクで返されます。
from openai import OpenAI
import os
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
# If you use a model in the China (Beijing) region, replace this with: https://dashscope.aliyuncs.com/compatible-mode/v1
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District.",
}
},
"required": ["location"],
},
},
},
]
stream = client.chat.completions.create(
model="qwen-plus",
messages=[{"role": "user", "content": "What's the weather in Hangzhou?"}],
tools=tools,
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta
print(delta.tool_calls)import { OpenAI } from "openai";
const openai = new OpenAI(
{
// If you use a model in the China (Beijing) region, you must use an API key from the China (Beijing) region. Obtain the key at: https://bailian.console.alibabacloud.com/?tab=model#/api-key
// If the environment variable is not configured, replace the following line with your model Studio API key: apiKey: "sk-xxx",
apiKey: process.env.DASHSCOPE_API_KEY,
// If you use a model in the China (Beijing) region, replace the baseURL with: https://dashscope.aliyuncs.com/compatible-mode/v1
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
}
);
const tools = [
{
"type": "function",
"function": {
"name": "getCurrentWeather",
"description": "Useful for querying the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
"required": ["location"]
}
}
}
];
const stream = await openai.chat.completions.create({
model: "qwen-plus",
messages: [{ role: "user", content: "Beijing weather" }],
tools: tools,
stream: true,
});
for await (const chunk of stream) {
const delta = chunk.choices[0].delta;
console.log(delta.tool_calls);
}出力は次のようになります。
[ChoiceDeltaToolCall(index=0, id='call_8f08d2b0fc0c4d8fab7123', function=ChoiceDeltaToolCallFunction(arguments='{"location":', name='get_current_weather'), type='function')]
[ChoiceDeltaToolCall(index=0, id='', function=ChoiceDeltaToolCallFunction(arguments=' "Hangzhou"}', name=None), type='function')]
None次のコードを実行して、入力パラメーター(arguments)を組み立てます。
tool_calls = {}
for response_chunk in stream:
delta_tool_calls = response_chunk.choices[0].delta.tool_calls
if delta_tool_calls:
for tool_call_chunk in delta_tool_calls:
call_index = tool_call_chunk.index
tool_call_chunk.function.arguments = tool_call_chunk.function.arguments or ""
if call_index not in tool_calls:
tool_calls[call_index] = tool_call_chunk
else:
tool_calls[call_index].function.arguments += tool_call_chunk.function.arguments
print(tool_calls[0].model_dump_json())const toolCalls = {};
for await (const responseChunk of stream) {
const deltaToolCalls = responseChunk.choices[0]?.delta?.tool_calls;
if (deltaToolCalls) {
for (const toolCallChunk of deltaToolCalls) {
const index = toolCallChunk.index;
toolCallChunk.function.arguments = toolCallChunk.function.arguments || "";
if (!toolCalls[index]) {
toolCalls[index] = { ...toolCallChunk };
if (!toolCalls[index].function) {
toolCalls[index].function = { name: '', arguments: '' };
}
}
else if (toolCallChunk.function?.arguments) {
toolCalls[index].function.arguments += toolCallChunk.function.arguments;
}
}
}
}
console.log(JSON.stringify(toolCalls[0]));次の出力が返されます。
{"index":0,"id":"call_16c72bef988a4c6c8cc662","function":{"arguments":"{\"location\": \"Hangzhou\"}","name":"get_current_weather"},"type":"function"}モデルがツール関数出力を要約する際、追加するアシスタントメッセージは次の形式を使用する必要があります。 tool_calls 要素を前の出力の内容に置き換えます。
{
"content": "",
"refusal": None,
"role": "assistant",
"audio": None,
"function_call": None,
"tool_calls": [
{
"id": "call_xxx",
"function": {
"arguments": '{"location": "xx"}',
"name": "get_current_weather",
},
"type": "function",
"index": 0,
}
],
}Qwen3-Omni-Flash 向け
ツール情報取得ステージでは、Qwen3-Omni-Flash モデルの使用方法が他のモデルと次のように異なります。
ストリーミング出力が必須:
Qwen3-Omni-Flashはストリーミング出力のみをサポートしています。ツール情報を取得する際は、必ずstream=Trueを設定する必要があります。テキスト専用出力を推奨:モデルは関数名やパラメーターなどのツール情報を取得するためにテキスト情報のみを必要とします。不要な音声を生成しないようにするため、
modalities=["text"]を設定することを推奨します。出力にテキストと音声の両方のモダリティが含まれる場合、ツール情報を取得する際に音声データチャンクをスキップする必要があります。
Qwen3-Omni-Flash の詳細については、「オムニモーダル」をご参照ください。
from openai import OpenAI
import os
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
# If you use a model in the China (Beijing) region, replace this with: https://dashscope.aliyuncs.com/compatible-mode/v1
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District.",
}
},
"required": ["location"],
},
},
},
]
completion = client.chat.completions.create(
model="qwen3-omni-flash",
messages=[{"role": "user", "content": "What's the weather in Hangzhou?"}],
# Set the modality of the output data. Valid values: ["text"], ["text","audio"]. We recommend setting this to ["text"].
modalities=["text"],
# stream must be set to True, otherwise an error will be reported.
stream=True,
tools=tools
)
for chunk in completion:
# If the output includes the audio modality, change the following condition to: if chunk.choices and not hasattr(chunk.choices[0].delta, "audio"):
if chunk.choices:
delta = chunk.choices[0].delta
print(delta.tool_calls)import { OpenAI } from "openai";
const openai = new OpenAI(
{
// If you use a model in the China (Beijing) region, you need to use an API Key for the China (Beijing) region. Get the key from: https://bailian.console.alibabacloud.com/?tab=model#/api-key
// If you have not configured the environment variable, replace the following line with: apiKey: "sk-xxx", using your model Studio API key.
apiKey: process.env.DASHSCOPE_API_KEY,
// If you use a model in the China (Beijing) region, replace the baseURL with: https://dashscope.aliyuncs.com/compatible-mode/v1
baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
}
);
const tools = [
{
"type": "function",
"function": {
"name": "getCurrentWeather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
"required": ["location"]
}
}
}
];
const stream = await openai.chat.completions.create({
model: "qwen3-omni-flash",
messages: [
{
"role": "user",
"content": "Hangzhou weather"
}],
stream: true,
// Set the modality of the output data. Valid values: ["text"], ["text","audio"]. We recommend setting this to ["text"].
modalities: ["text"],
tools:tools
});
for await (const chunk of stream) {
// If the output includes audio, replace the conditional statement with: if (chunk.choices?.length && chunk.choices[0].delta && !('audio' in chunk.choices[0].delta))
if (chunk.choices?.length){
const delta = chunk.choices[0].delta;
console.log(delta.tool_calls);
}}次の出力が返されます。
[ChoiceDeltaToolCall(index=0, id='call_391c8e5787bc4972a388aa', function=ChoiceDeltaToolCallFunction(arguments=None, name='get_current_weather'), type='function')]
[ChoiceDeltaToolCall(index=0, id='call_391c8e5787bc4972a388aa', function=ChoiceDeltaToolCallFunction(arguments=' {"location": "Hangzhou"}', name=None), type='function')]
None入力パラメーター(arguments)を構築するコードについては、「ストリーミング出力」をご参照ください。
ディープシンキングモデル向け
ディープシンキングモデルは、ツール呼び出し情報を出力する前に思考を行います。これにより、意思決定の解釈可能性と信頼性が向上します。
思考プロセス
モデルは段階的にユーザーの意図を分析し、必要なツールを特定し、パラメーターの合法性を検証し、呼び出し戦略を計画します。
ツール呼び出し
モデルは構造化された形式で 1 つ以上の関数呼び出しリクエストを出力します。
並列ツール呼び出しがサポートされています。
次のセクションでは、ディープシンキングモデルへのストリーミング呼び出しによるツール呼び出しの例を示します。
テキスト生成シンキングモデルについては、「ディープシンキング」をご参照ください。マルチモーダルシンキングモデルについては、「視覚的理解」および「オムニモーダル」をご参照ください。
tool_choiceパラメーターは、"auto"(デフォルトで、モデルがツールを独立して選択)または"none"(モデルにツールを選択させないことを強制)にのみ設定できます。
OpenAI 互換
Python
サンプルコード
import os
from openai import OpenAI
# Initialize the OpenAI client and configure the Alibaba Cloud DashScope service
client = OpenAI(
# If you have not configured the environment variable, replace the following line with: api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"), # Read API key from environment variable
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
# Define the list of available tools
tools = [
# Tool 1: Get the current time
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "This is useful when you want to know the current time.",
"parameters": {} # No parameters needed
}
},
# Tool 2: Get the weather for a specified city
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
"required": ["location"] # Required parameter
}
}
}
]
messages = [{"role": "user", "content": input("Please enter your question: ")}]
# Example message for multimodal model
# messages = [{
# "role": "user",
# "content": [
# {"type": "image_url","image_url": {"url": "https://img.alicdn.com/imgextra/i4/O1CN014CJhzi20NOzo7atOC_!!6000000006837-2-tps-2048-1365.png"}},
# {"type": "text", "text": "What is the current weather at the location in the image?"}]
# }]
completion = client.chat.completions.create(
# This example uses qwen-plus. It can be replaced with other deep thinking models.
model="qwen-plus",
messages=messages,
extra_body={
# Enable deep thinking. This parameter is invalid for qwen3-30b-a3b-thinking-2507, qwen3-235b-a22b-thinking-2507, and QwQ models.
"enable_thinking": True
},
tools=tools,
parallel_tool_calls=True,
stream=True,
# Uncomment to get token consumption information
# stream_options={
# "include_usage": True
# }
)
reasoning_content = "" # Defines the complete thinking process
answer_content = "" # Defines the complete reply
tool_info = [] # Stores tool call information
is_answering = False # Determines if the thinking process has ended and the reply has begun
print("="*20+"Thinking Process"+"="*20)
for chunk in completion:
if not chunk.choices:
# Process usage statistics
print("\n"+"="*20+"Usage"+"="*20)
print(chunk.usage)
else:
delta = chunk.choices[0].delta
# Process the AI's thinking process (chain of thought)
if hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:
reasoning_content += delta.reasoning_content
print(delta.reasoning_content,end="",flush=True) # Output the thinking process in real time
# Process the final reply content
else:
if not is_answering: # Print the title when entering the reply phase for the first time
is_answering = True
print("\n"+"="*20+"Reply Content"+"="*20)
if delta.content is not None:
answer_content += delta.content
print(delta.content,end="",flush=True) # Stream the reply content
# Process tool call information (supports parallel tool calls)
if delta.tool_calls is not None:
for tool_call in delta.tool_calls:
index = tool_call.index # Tool call index, for parallel calls
# Dynamically expand the tool information storage list
while len(tool_info) <= index:
tool_info.append({})
# Collect the tool call ID (for subsequent function calls)
if tool_call.id:
tool_info[index]['id'] = tool_info[index].get('id', '') + tool_call.id
# Collect the function name (for subsequent routing to a specific function)
if tool_call.function and tool_call.function.name:
tool_info[index]['name'] = tool_info[index].get('name', '') + tool_call.function.name
# Collect function arguments (in JSON string format, requires subsequent parsing)
if tool_call.function and tool_call.function.arguments:
tool_info[index]['arguments'] = tool_info[index].get('arguments', '') + tool_call.function.arguments
print(f"\n"+"="*19+"Tool Call Information"+"="*19)
if not tool_info:
print("No tool calls")
else:
print(tool_info)返された結果
「4つの市区町村の天気」と入力すると、以下の結果が返されます:
====================Thinking Process====================
Okay, the user is asking for the "weather in the four municipalities". First, I need to identify which four municipalities are being referred to. According to China's administrative divisions, the municipalities include Beijing, Shanghai, Tianjin, and Chongqing. So the user wants to know the weather conditions in these four cities.
Next, I need to check the available tools. The provided tools include the get_current_weather function, which takes a location of type string as a parameter. Each city needs to be queried separately because the function can only check one location at a time. Therefore, I need to call this function once for each municipality.
Then, I need to consider how to generate the correct tool calls. Each call should include the city name as a parameter. For example, the first call is for Beijing, the second for Shanghai, and so on. I need to make sure the parameter name is `location` and the value is the correct city name.
Also, the user probably wants the weather information for each city, so I need to ensure each function call is correct. It might require four consecutive calls, one for each city. However, based on the tool usage rules, it might need to be handled in multiple steps, or multiple calls might be generated at once. But based on the example, it seems only one function is called at a time, so it might need to be done step by step.
Finally, I need to confirm if there are any other factors to consider, such as whether the parameters are correct, the city names are accurate, and whether to handle possible error situations, like the city not existing or the API being unavailable. But for now, the four municipalities are clear, so it should be fine.
====================Reply Content====================
===================Tool Call Information===================
[{'id': 'call_767af2834c12488a8fe6e3', 'name': 'get_current_weather', 'arguments': '{"location": "Beijing"}'}, {'id': 'call_2cb05a349c89437a947ada', 'name': 'get_current_weather', 'arguments': '{"location": "Shanghai"}'}, {'id': 'call_988dd180b2ca4b0a864ea7', 'name': 'get_current_weather', 'arguments': '{"location": "Tianjin"}'}, {'id': 'call_4e98c57ea96a40dba26d12', 'name': 'get_current_weather', 'arguments': '{"location": "Chongqing"}'}]Node.js
サンプルコード
import OpenAI from "openai";
import readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';
const openai = new OpenAI({
apiKey: process.env.DASHSCOPE_API_KEY,
baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
});
const tools = [
{
type: "function",
function: {
name: "get_current_time",
description: "This is useful when you want to know the current time.",
parameters: {}
}
},
{
type: "function",
function: {
name: "get_current_weather",
description: "This is useful when you want to query the weather in a specific city.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "A city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
required: ["location"]
}
}
}
];
async function main() {
const rl = readline.createInterface({ input, output });
const question = await rl.question("Please enter your question: ");
rl.close();
const messages = [{ role: "user", content: question }];
// マルチモーダルモデルのメッセージ例
// const messages= [{
// role: "user",
// content: [{type: "image_url", image_url: {url: "https://img.alicdn.com/imgextra/i2/O1CN01FbTJon1ErXVGMRdsN_!!6000000000405-0-tps-1024-683.jpg"}},
// {type: "text", text: "What's the weather at the location in the image?"}]
// }];
let reasoningContent = "";
let answerContent = "";
const toolInfo = [];
let isAnswering = false;
console.log("=".repeat(20) + "Thinking Process" + "=".repeat(20));
try {
const stream = await openai.chat.completions.create({
// この例では qwen-plus を使用しています。他のディープシンキングモデルに置き換えることができます。
model: "qwen-plus",
messages,
// ディープシンキングを有効にします。このパラメーターは qwen3-30b-a3b-thinking-2507、qwen3-235b-a22b-thinking-2507、および QwQ モデルでは無効です。
enable_thinking: true,
tools,
stream: true,
parallel_tool_calls: true
});
for await (const chunk of stream) {
if (!chunk.choices?.length) {
console.log("\n" + "=".repeat(20) + "Usage" + "=".repeat(20));
console.log(chunk.usage);
continue;
}
const delta = chunk.choices[0]?.delta;
if (!delta) continue;
// 思考プロセスを処理
if (delta.reasoning_content) {
reasoningContent += delta.reasoning_content;
process.stdout.write(delta.reasoning_content);
}
// 応答内容を処理
else {
if (!isAnswering) {
isAnswering = true;
console.log("\n" + "=".repeat(20) + "Reply Content" + "=".repeat(20));
}
if (delta.content) {
answerContent += delta.content;
process.stdout.write(delta.content);
}
// ツール呼び出しを処理
if (delta.tool_calls) {
for (const toolCall of delta.tool_calls) {
const index = toolCall.index;
// 配列の長さが十分であることを確認
while (toolInfo.length <= index) {
toolInfo.push({});
}
// ツール ID を更新
if (toolCall.id) {
toolInfo[index].id = (toolInfo[index].id || "") + toolCall.id;
}
// 関数名を更新
if (toolCall.function?.name) {
toolInfo[index].name = (toolInfo[index].name || "") + toolCall.function.name;
}
// パラメーターを更新
if (toolCall.function?.arguments) {
toolInfo[index].arguments = (toolInfo[index].arguments || "") + toolCall.function.arguments;
}
}
}
}
}
console.log("\n" + "=".repeat(19) + "Tool Call Information" + "=".repeat(19));
console.log(toolInfo.length ? toolInfo : "No tool calls");
} catch (error) {
console.error("An error occurred:", error);
}
}
main(); 返された結果
「四大直轄市の天気」と入力すると、次の結果が返されます。
Please enter your question: Weather in the four municipalities
====================Thinking Process====================
Okay, the user is asking about the weather in the four municipalities. First, I need to clarify which four municipalities in China are being referred to. Beijing, Shanghai, Tianjin, and Chongqing, right? Next, I need to call the weather query function for each city.
However, the user's question may require me to get the weather conditions for these four cities separately. Each city requires a call to the get_current_weather function, with its respective city name as the parameter. I need to make sure the parameters are correct, such as the full names of the municipalities, for example, "Beijing Municipality", "Shanghai Municipality", "Tianjin Municipality", and "Chongqing Municipality".
Then, I need to call the weather API for these four cities in sequence. Each call requires a separate tool_call. The user probably wants the current weather information for each city, so I need to ensure each call is correct. I might need to pay attention to the correct spelling and name of each city to avoid errors. For example, Chongqing is sometimes abbreviated, so the full name should be used in the parameter.
Now, I need to generate four tool_calls, one for each municipality. I will check if each parameter is correct and then arrange them in order. This way, the user will get the weather data for all four municipalities.
====================Reply Content====================
===================Tool Call Information===================
[
{
id: 'call_21dc802e717f491298d1b2',
name: 'get_current_weather',
arguments: '{"location": "Beijing"}'
},
{
id: 'call_2cd3be1d2f694c4eafd4e5',
name: 'get_current_weather',
arguments: '{"location": "Shanghai"}'
},
{
id: 'call_48cf3f78e02940bd9085e4',
name: 'get_current_weather',
arguments: '{"location": "Tianjin"}'
},
{
id: 'call_e230a2b4c64f4e658d223e',
name: 'get_current_weather',
arguments: '{"location": "Chongqing"}'
}
]HTTP
サンプルコード
curl
curl -X POST https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-plus",
"messages": [
{
"role": "user",
"content": "What is the weather like in Hangzhou?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "This is useful when you want to know the current time.",
"parameters": {}
}
},
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location":{
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
"required": ["location"]
}
}
}
],
"enable_thinking": true,
"stream": true
}'DashScope
Python
サンプルコード
import dashscope
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1/"
tools = [
# ツール 1:現在時刻の取得
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "This is useful when you want to know the current time.",
"parameters": {} # 現在時刻の取得には入力パラメーターが不要なため、parameters は空の辞書です。
}
},
# ツール 2:指定された都市の天気の取得
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
# 天気照会には location が必要なため、パラメーターは location に設定されます。
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
"required": ["location"]
}
}
}
]
# 質問を定義
messages = [{"role": "user", "content": input("Please enter your question: ")}]
# Qwen3-VL のメッセージ例
# messages = [
# {
# "role": "user",
# "content": [
# {"image": "https://img.alicdn.com/imgextra/i2/O1CN01FbTJon1ErXVGMRdsN_!!6000000000405-0-tps-1024-683.jpg"},
# {"text": "Weather at the image location?"}]
# }]
# マルチモーダルモデルを使用する場合は、Generation を MultiModalConversation インターフェイスに置き換えてください。
completion = dashscope.Generation.call(
# この例では qwen-plus を使用しています。他のディープシンキングモデルに置き換えることができます。
model="qwen-plus",
messages=messages,
enable_thinking=True,
tools=tools,
parallel_tool_calls=True,
stream=True,
incremental_output=True,
result_format="message"
)
reasoning_content = ""
answer_content = ""
tool_info = []
is_answering = False
print("="*20+"Thinking Process"+"="*20)
for chunk in completion:
if chunk.status_code == 200:
msg = chunk.output.choices[0].message
# 思考プロセスを処理
if 'reasoning_content' in msg and msg.reasoning_content:
reasoning_content += msg.reasoning_content
print(msg.reasoning_content, end="", flush=True)
# 応答内容を処理
if 'content' in msg and msg.content:
if not is_answering:
is_answering = True
print("\n"+"="*20+"Reply Content"+"="*20)
answer_content += msg.content
print(msg.content, end="", flush=True)
# ツール呼び出しを処理
if 'tool_calls' in msg and msg.tool_calls:
for tool_call in msg.tool_calls:
index = tool_call['index']
while len(tool_info) <= index:
tool_info.append({'id': '', 'name': '', 'arguments': ''}) # すべてのフィールドを初期化
# ツール ID を増分更新
if 'id' in tool_call:
tool_info[index]['id'] += tool_call.get('id', '')
# 関数情報を増分更新
if 'function' in tool_call:
func = tool_call['function']
# 関数名を増分更新
if 'name' in func:
tool_info[index]['name'] += func.get('name', '')
# パラメーターを増分更新
if 'arguments' in func:
tool_info[index]['arguments'] += func.get('arguments', '')
print(f"\n"+"="*19+"Tool Call Information"+"="*19)
if not tool_info:
print("No tool calls")
else:
print(tool_info)返された結果
「四大直轄市の天気」と入力すると、次の結果が返されます。
Please enter your question: Weather in the four municipalities
====================Thinking Process====================
Okay, the user is asking about the weather in the four municipalities. First, I need to confirm which four municipalities in China are being referred to. Beijing, Shanghai, Tianjin, and Chongqing, right? Next, the user needs the weather conditions for each city, so I need to call the weather query function.
However, a problem arises: the user did not specify the city names, only "the four municipalities". I might need to clarify the name of each municipality and then query them separately. For example, Beijing, Shanghai, Tianjin, and Chongqing. I need to make sure each city is correct.
Then, I need to check the available tools. The user has provided the `get_current_weather` function with a `location` parameter. Therefore, I need to call this function for each municipality, passing the corresponding city name as the parameter. For example, the first call's location is Beijing, the second is Shanghai, the third is Tianjin, and the fourth is Chongqing.
However, I might need to be careful. For a municipality like Chongqing, a more specific district might sometimes be needed, but the user probably only needs the city-level weather. So, using the municipality name directly should be fine. Next, I need to generate four separate function calls, one for each municipality. This way, the user will get the weather conditions for all four cities.
Finally, I will ensure that the parameters for each call are correct and that none are missed. This will provide a complete answer to the user's question.
===================Tool Call Information===================
[{'id': 'call_2f774ed97b0e4b24ab10ec', 'name': 'get_current_weather', 'arguments': '{"location": "Beijing"}'}, {'id': 'call_dc3b05b88baa48c58bc33a', 'name': 'get_current_weather', 'arguments': '{"location": "Shanghai"}}'}, {'id': 'call_249b2de2f73340cdb46cbc', 'name': 'get_current_weather', 'arguments': '{"location": "Tianjin"}'}, {'id': 'call_833333634fda49d1b39e87', 'name': 'get_current_weather', 'arguments': '{"location": "Chongqing"}}'}]Java
サンプルコード
// dashscope SDK バージョン >= 2.19.4
import java.util.Arrays;
import com.alibaba.dashscope.exception.UploadFileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.aigc.generation.Generation;
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.utils.Constants;
import com.alibaba.dashscope.utils.JsonUtils;
import com.alibaba.dashscope.tools.ToolFunction;
import com.alibaba.dashscope.tools.FunctionDefinition;
import io.reactivex.Flowable;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.lang.System;
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.Collections;
public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
private static ObjectNode jsonSchemaWeather;
private static ObjectNode jsonSchemaTime;
static {Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";}
static class TimeTool {
public String call() {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return "Current time: " + now.format(formatter) + ".";
}
}
static class WeatherTool {
private String location;
public WeatherTool(String location) {
this.location = location;
}
public String call() {
return this.location + " is sunny today";
}
}
static {
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);
jsonSchemaWeather = generator.generateSchema(WeatherTool.class);
jsonSchemaTime = generator.generateSchema(TimeTool.class);
}
private static void handleGenerationResult(GenerationResult message) {
System.out.println(JsonUtils.toJson(message));
}
// テキスト生成モデル用のツール呼び出しメソッドを作成
public static void streamCallWithMessage(Generation gen, Message userMsg)
throws NoApiKeyException, ApiException, InputRequiredException {
GenerationParam param = buildGenerationParam(userMsg);
Flowable<GenerationResult> result = gen.streamCall(param);
result.blockingForEach(message -> handleGenerationResult(message));
}
// ツール呼び出しをサポートするテキスト生成モデルのパラメーターを構築
private static GenerationParam buildGenerationParam(Message userMsg) {
FunctionDefinition fdWeather = buildFunctionDefinition(
"get_current_weather", "Get the weather for a specified region", jsonSchemaWeather);
FunctionDefinition fdTime = buildFunctionDefinition(
"get_current_time", "Get the current time", jsonSchemaTime);
return GenerationParam.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model("qwen-plus")
.enableThinking(true)
.messages(Arrays.asList(userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.incrementalOutput(true)
.tools(Arrays.asList(
ToolFunction.builder().function(fdWeather).build(),
ToolFunction.builder().function(fdTime).build()))
.build();
}
// マルチモーダルモデル用のツール呼び出しメソッドを作成
public static void streamCallWithMultiModalMessage(MultiModalConversation conv, MultiModalMessage userMsg)
throws NoApiKeyException, ApiException, UploadFileException {
MultiModalConversationParam param = buildMultiModalConversationParam(userMsg);
Flowable<MultiModalConversationResult> result = conv.streamCall(param);
result.blockingForEach(message -> System.out.println(JsonUtils.toJson(message)));
}
// ツール呼び出しをサポートするマルチモーダルモデルのパラメーターを構築
private static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage userMsg) {
FunctionDefinition fdWeather = buildFunctionDefinition(
"get_current_weather", "Get the weather for a specified region", jsonSchemaWeather);
FunctionDefinition fdTime = buildFunctionDefinition(
"get_current_time", "Get the current time", jsonSchemaTime);
return MultiModalConversationParam.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model("qwen3-vl-plus") // マルチモーダルモデル Qwen3-vl を使用
.enableThinking(true)
.messages(Arrays.asList(userMsg))
.tools(Arrays.asList( // ツールリストを設定
ToolFunction.builder().function(fdWeather).build(),
ToolFunction.builder().function(fdTime).build()))
.build();
}
private static FunctionDefinition buildFunctionDefinition(
String name, String description, ObjectNode schema) {
return FunctionDefinition.builder()
.name(name)
.description(description)
.parameters(JsonUtils.parseString(schema.toString()).getAsJsonObject())
.build();
}
public static void main(String[] args) {
try {
Generation gen = new Generation();
Message userMsg = Message.builder()
.role(Role.USER.getValue())
.content("Please tell me the weather in Hangzhou")
.build();
try {
streamCallWithMessage(gen, userMsg);
} catch (InputRequiredException e) {
throw new RuntimeException(e);
}
// マルチモーダルモデルでツール呼び出しを使用する場合は、次の行のコメントを解除してください。
// MultiModalConversation conv = new MultiModalConversation();
// MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
// .content(Arrays.asList(Collections.singletonMap("image", "https://img.alicdn.com/imgextra/i2/O1CN01FbTJon1ErXVGMRdsN_!!6000000000405-0-tps-1024-683.jpg"),
// Collections.singletonMap("text", "Weather at the location in the image"))).build();
// try {
// streamCallWithMultiModalMessage(conv,userMessage);
// } catch (UploadFileException e) {
// throw new RuntimeException(e);
// }
} catch (ApiException | NoApiKeyException e) {
logger.error("An exception occurred: {}", e.getMessage());
}
System.exit(0);
}
}
返された結果
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":6,"total_tokens":244},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":"Okay, the user wants me"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":12,"total_tokens":250},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" to tell them the weather in Hangzhou. I"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":16,"total_tokens":254},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" need to first determine if"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":22,"total_tokens":260},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" there are any relevant tools available. Looking at the provided"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":28,"total_tokens":266},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" tools, I see there is a get_current"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":34,"total_tokens":272},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":"_weather function with a location parameter"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":38,"total_tokens":276},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":". So I should call"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":43,"total_tokens":281},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" this function with the parameter"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":48,"total_tokens":286},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" set to Hangzhou. No"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":52,"total_tokens":290},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" other tools are needed because"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":56,"total_tokens":294},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" the user only asked"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":60,"total_tokens":298},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" about the weather. Next, I will construct"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":64,"total_tokens":302},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" the tool_call, filling in"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":68,"total_tokens":306},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" the name and parameters"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":73,"total_tokens":311},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":". I will make sure the parameter is a"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":78,"total_tokens":316},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" JSON object and location is a"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":82,"total_tokens":320},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":" string. After checking for errors"}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":88,"total_tokens":326},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":", I will return."}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":106,"total_tokens":344},"output":{"choices":[{"finish_reason":"null","message":{"role":"assistant","content":"","reasoning_content":"","tool_calls":[{"type":"function","id":"call_ecc41296dccc47baa01567","function":{"name":"get_current_weather","arguments":"{\"location\": \"Hangzhou"}}]}}]}}
{"requestId":"4edb81cd-4647-9d5d-88f9-a4f30bc6d8dd","usage":{"input_tokens":238,"output_tokens":108,"total_tokens":346},"output":{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","content":"","reasoning_content":"","tool_calls":[{"type":"function","id":"","function":{"arguments":"\"}"}}]}}]}}HTTP
サンプルコード
curl
# ======= 重要事項 =======
# マルチモーダルモデルを使用する場合は、message パラメーターを変更し、URL を https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation に置き換えてください。
# シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーを取得するには、https://www.alibabacloud.com/help/ja/model-studio/get-api-key をご参照ください。
# 北京リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation に置き換えてください。
# === 実行前にこのコメントを削除してください ===
curl -X POST "https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/text-generation/generation" \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-DashScope-SSE: enable" \
-d '{
"model": "qwen-plus",
"input":{
"messages":[
{
"role": "user",
"content": "Hangzhou weather"
}
]
},
"parameters": {
"enable_thinking": true,
"incremental_output": true,
"result_format": "message",
"tools": [{
"type": "function",
"function": {
"name": "get_current_time",
"description": "This is useful when you want to know the current time.",
"parameters": {}
}
},{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "This is useful when you want to query the weather in a specific city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "A city or district, such as Beijing, Hangzhou, or Yuhang District."
}
},
"required": ["location"]
}
}
}]
}
}'本番運用
ツール呼び出し精度のテスト
評価システムの確立:
実際のビジネスシナリオを反映したテストデータセットを構築し、ツール選択の精度、パラメーター抽出の精度、エンドツーエンドの成功率などの明確な評価メトリクスを定義します。
プロンプトの最適化
テストでツールの選択やパラメーターが不正確であるなどの問題が明らかになった場合、システムプロンプト、ツールの説明、パラメーターの説明に対して的を絞った最適化を実行できます。これがコアとなるチューニング方法です。
モデルのアップグレード
プロンプトエンジニアリングでパフォーマンスが向上しない場合、
qwen3-max-previewのようなより高性能なモデルバージョンにアップグレードすることが、メトリクスを改善するための最も直接的で効果的な方法です。
ツール数の動的制御
アプリケーションに統合されるツールの数が数十、数百と多い場合、ツールライブラリ全体をモデルに提供すると、次のような問題が発生する可能性があります。
パフォーマンスの低下:膨大なツールセットから正しいツールを選択することが、モデルにとって劇的に難しくなります。
コストとレイテンシー:多くのツールの説明は多くの入力トークンを消費するため、コストが増加し、応答が遅くなります。
解決策は、モデルを呼び出す前にツールルーティングまたは取得レイヤーを追加することです。このレイヤーは、ユーザーの現在のクエリに基づいて、完全なツールライブラリから関連性の高いツールの小さなサブセットを迅速かつ正確にフィルタリングし、そのサブセットをモデルに提供します。
ツールルーティングを実装するための主流な方法をいくつか紹介します。
セマンティック検索
すべてのツールの説明情報(
description)を埋め込みモデルを使用してベクトルに変換し、ベクトルデータベースに保存します。ユーザーがクエリを入力すると、クエリベクトルに対してベクトル類似性検索を使用して、最も関連性の高い上位 K 個のツールを呼び出すことができます。ハイブリッド検索
セマンティック検索の「あいまい一致」機能と、従来のキーワードやメタデータタグの「完全一致」機能を組み合わせます。ツールに
tagsやkeywordsフィールドを追加し、検索時にベクトル検索とキーワードフィルタリングを同時に実行することで、高頻度または特定のシナリオでの再現率を大幅に向上させることができます。軽量 LLM ルーター
より複雑なルーティングロジックには、Qwen-Flash のような、より小さく、高速で、安価なモデルを事前ルーティングの「ルーターモデル」として使用できます。そのタスクは、ユーザーの質問に基づいて関連するツール名のリストを出力することです。
実践的な提案
候補セットを簡潔に保つ:使用する方法に関係なく、メインモデルには20 個以下のツールを提供することを推奨します。この数は、モデルの認知負荷、コスト、レイテンシー、精度の間の最適なバランスを表します。
階層型フィルタリング戦略:ファネルスタイルのルーティングポリシーを構築できます。たとえば、まず低コストのキーワードまたはルールマッチングを使用して初期スクリーニングを行い、無関係なツールを除外し、その後、残りのツールに対してセマンティック検索を実行して効率と品質を向上させることができます。
ツールのセキュリティ原則
モデルにツール実行機能を有効にする場合、セキュリティが最優先事項となります。コアとなる原則は、最小権限の原則と人間による確認です。
最小権限の原則:モデルに提供されるツールセットは、最小権限の原則に厳密に従う必要があります。デフォルトでは、ツールは天気照会やドキュメント検索などの読み取り専用であるべきで、状態変更やリソース操作を伴う「書き込み」権限を直接提供することは避けるべきです。
危険なツールを隔離する:任意コードの実行(
code interpreter)、ファイルシステムの操作(fs.delete)、データベースの削除または更新操作(db.drop_table)、資金の送金(payment.transfer)などの危険なツールをモデルに直接提供しないでください。人間による介在:すべての高権限または不可逆的な操作には、手動によるレビューと確認のステップを導入する必要があります。モデルは操作リクエストを生成できますが、最終的な実行「ボタン」は人間のユーザーがクリックする必要があります。たとえば、モデルはメールを作成できますが、送信操作はユーザーが確認する必要があります。
ユーザーエクスペリエンスの最適化
Function calling のチェーンは長く、どのステップで問題が発生してもユーザーエクスペリエンスが低下する可能性があります。
ツール実行失敗の処理
ツールの実行失敗はよくあることです。次の戦略を採用できます。
最大リトライ回数:たとえば 3 回など、合理的なリトライ制限を設定して、継続的な失敗によるユーザーの長い待ち時間やシステムリソースの無駄を避けます。
フォールバック応答の提供:リトライが尽きた場合や解決不可能なエラーが発生した場合は、「申し訳ありませんが、現時点では関連情報を見つけることができません。サービスが混み合っている可能性があります。後でもう一度お試しください。」など、明確でフレンドリーなプロンプトをユーザーに返す必要があります。
処理遅延への対応
高いレイテンシーはユーザー満足度を低下させる可能性があり、フロントエンドのインタラクションとバックエンドの最適化によって対処する必要があります。
タイムアウトの設定:Function calling の各ステップに独立した合理的なタイムアウトを設定します。タイムアウトが発生したら、操作を直ちに中断し、フィードバックを提供する必要があります。
即時フィードバックの提供:Function calling プロセスを開始する際、「天気を照会しています...」や「関連情報を検索しています...」などのプロンプトをインターフェイスに表示して、処理の進捗状況をリアルタイムでユーザーにフィードバックすることを推奨します。
課金の説明
`messages` 配列のトークンに加えて、ツールの説明が入力トークンとしてプロンプトに追加され、これも課金の対象となります。
システムメッセージ経由でツール情報を渡す
エラーコード
呼び出しが失敗した場合は、「エラーメッセージ」を参照してトラブルシューティングを行ってください。