モデルは、リアルタイムの質問への回答や数学的な計算などのタスクに苦労することがあります。ファンクションコーリングは、外部ツールを導入することでこの問題を解決します。これにより、モデルは通常では回答できない質問に答えることができるようになります。
仕組み
ファンクションコーリングにより、モデルはご利用のアプリケーションとモデル間の複数ステップの対話を通じて、回答のために外部ツールの情報を参照できます。
最初のモデル呼び出しの開始
ご利用のアプリケーションがモデルにリクエストを送信します。リクエストには、ユーザーの質問とモデルが呼び出すことができるツールのリストが含まれます。
モデルのツールコーリング命令の受信
モデルが外部ツールを呼び出すことを決定した場合、JSON 形式で命令を返します。この命令は、ご利用のアプリケーションにどの関数を実行し、どの入力パラメーターを使用するかを伝えます。
モデルがツールを呼び出さないと決定した場合、自然言語の応答を返します。
アプリケーションでのツールの実行
ご利用のアプリケーションがツールの命令を受信した後、ツールを実行して出力を取得できます。
2 回目のモデル呼び出しの開始
ツールの出力を取得した後、それをモデルのコンテキスト (メッセージ) に追加し、再度モデルを呼び出すことができます。
モデルからの最終応答の受信
モデルはツールの出力とユーザーの質問を組み合わせて、自然言語で最終的な応答を生成します。
以下の図は、ワークフローを示しています。
利用可能なモデル
Qwen
テキスト生成モデル
マルチモーダルモデル
DeepSeek
deepseek-v3.2
deepseek-v3.2-exp (非思考モード)
deepseek-v3.1 (非思考モード)
deepseek-r1
deepseek-r1-0528
deepseek-v3
Kimi
kimi-k2-thinking
Moonshot-Kimi-K2-Instruct
クイックスタート
まず、API キーを作成し、API キーを環境変数としてエクスポートする必要があります。OpenAI SDK または DashScope SDK を使用して呼び出しを行う場合は、SDK をインストールしてください。
このセクションでは、天候クエリのシナリオを使用して、ファンクションコーリングを迅速に使用する方法を説明します。
OpenAI 互換
from openai import OpenAI
from datetime import datetime
import json
import os
import random
client = OpenAI(
# 中国 (北京) リージョンのモデルを使用する場合は、中国 (北京) リージョンの API キーを使用する必要があります。キーは https://bailian.console.alibabacloud.com/?tab=model#/api-key から取得してください。
# 環境変数を設定していない場合は、次の行を Model Studio の API キーを使用して api_key="sk-xxx" に置き換えてください。
api_key=os.getenv("DASHSCOPE_API_KEY"),
# 中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えてください。
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
# ユーザーの質問をシミュレート
USER_QUESTION = "What's the weather like in Singapore?"
# ツールリストを定義
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "シンガポールやニューヨークなどの都市または郡。",
}
},
"required": ["location"],
},
},
},
]
# 天気クエリツールをシミュレート
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}."
# モデル応答関数をカプセル化
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 assistant_output.tool_calls is None:
print(f"No need to call the weather query tool. Direct reply: {assistant_output.content}")
else:
# ツールコーリングループに入る
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}")
# ツールを実行
tool_result = get_current_weather(arguments)
# ツールの戻りメッセージを構築
tool_message = {
"role": "tool",
"tool_call_id": tool_call_id,
"content": tool_result, # 元のツール出力を保持
}
print(f"Tool returns: {tool_message['content']}")
messages.append(tool_message)
# モデルを再度呼び出して、要約された自然言語の応答を取得
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(`No need to call the weather query tool. Direct reply: ${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(`Calling tool [${funcName}] with arguments:`, funcArgs);
// ツールを実行
const toolResult = getCurrentWeather(funcArgs);
// ツールの戻りメッセージを構築
const toolMessage = {
role: "tool",
tool_call_id: toolCallId,
content: toolResult,
};
console.log(`Tool returns: ${toolMessage.content}`);
messages.push(toolMessage);
// モデルを再度呼び出して、自然言語の要約を取得
response = await getResponse(messages);
assistantOutput = response.choices[0].message;
if (!assistantOutput.content) assistantOutput.content = "";
messages.push(assistantOutput);
}
console.log(`Assistant's final reply: ${assistantOutput.content}`);
}
};
// プログラムを開始
main().catch(console.error);DashScope
import os
from dashscope import Generation
import dashscope
import json
import random
# 中国 (北京) リージョンのモデルを使用する場合は、base_http_api_url を https://dashscope.aliyuncs.com/api/v1 に置き換えてください。
dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
# 1. ツールリストを定義
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "シンガポールやニューヨークなどの都市または郡。",
}
},
"required": ["location"],
},
},
}
]
# 2. 天気クエリツールをシミュレート
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. モデル応答関数をカプセル化
def get_response(messages):
response = Generation.call(
# 環境変数を設定していない場合は、次の行を api_key="sk-xxx" に置き換えてください。
api_key=os.getenv("DASHSCOPE_API_KEY"),
model="qwen-plus",
messages=messages,
tools=tools,
result_format="message",
)
return response
# 4. 会話履歴を初期化
messages = [
{
"role": "user",
"content": "What's the weather like in Singapore?"
}
]
# 5. モデルを初めて呼び出す
response = get_response(messages)
assistant_output = response.output.choices[0].message
messages.append(assistant_output)
# 6. ツール呼び出しが必要かどうかを判断
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. ツールコーリングループに入る
# ループ条件:最新のモデル応答にツール呼び出しリクエストが含まれている限り
while "tool_calls" in assistant_output and assistant_output["tool_calls"]:
tool_call = assistant_output["tool_calls"][0]
# ツール呼び出し情報を解析
func_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
tool_call_id = tool_call.get("id") # tool_call_id を取得
print(f"Calling tool [{func_name}] with arguments: {arguments}")
# 対応するツール関数を実行
tool_result = get_current_weather(arguments)
# ツールの戻りメッセージを構築
tool_message = {
"role": "tool",
"content": tool_result,
"tool_call_id": tool_call_id
}
print(f"Tool returns: {tool_message['content']}")
messages.append(tool_message)
# モデルを再度呼び出して、ツールの結果に基づいた応答を取得
response = get_response(messages)
assistant_output = response.output.choices[0].message
messages.append(assistant_output)
# 8. 最終的な自然言語の応答を出力
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 {
/**
* ツールのローカル実装を定義します。
* @param arguments モデルから提供される、ツールに必要なパラメーターを含む JSON 文字列。
* @return ツールの実行結果を含む文字列。
*/
public static String getCurrentWeather(String arguments) {
try {
// モデルから提供されるパラメーターは JSON 形式であり、手動で解析する必要があります。
ObjectMapper objectMapper = new ObjectMapper();
JsonNode argsNode = objectMapper.readTree(arguments);
String location = argsNode.get("location").asText();
// 実際の API 呼び出しやビジネスロジックをシミュレートするために、ランダムな結果を使用します。
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) {
// プログラムの堅牢性を確保するための例外処理。
return "Failed to parse location parameter.";
}
}
public static void main(String[] args) {
try {
// ツールをモデルに記述 (登録) します。
String weatherParamsSchema =
"{\"type\":\"object\",\"properties\":{\"location\":{\"type\":\"string\",\"description\":\"シンガポールやニューヨークなどの都市または郡。\"}},\"required\":[\"location\"]}";
FunctionDefinition weatherFunction = FunctionDefinition.builder()
.name("get_current_weather") // ツールの一意の識別子。ローカル実装と一致する必要があります。
.description("特定の都市の天気を照会する場合に便利です。") // 明確な説明は、モデルがツールを使用するタイミングをより適切に判断するのに役立ちます。
.parameters(JsonUtils.parseString(weatherParamsSchema).getAsJsonObject())
.build();
// 中国 (北京) リージョンのモデルを使用する場合は、URL を 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());
// モデルを初めて呼び出します。ユーザーのリクエストと定義されたツールリストをモデルに送信します。
GenerationParam param = GenerationParam.builder()
.model("qwen-plus") // 呼び出すモデルを指定します。
.apiKey(System.getenv("DASHSCOPE_API_KEY")) // 環境変数から API キーを取得します。
.messages(messages) // 現在の会話履歴を渡します。
.tools(Arrays.asList(ToolFunction.builder().function(weatherFunction).build())) // 利用可能なツールのリストを渡します。
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.build();
GenerationResult result = gen.call(param);
Message assistantOutput = result.getOutput().getChoices().get(0).getMessage();
messages.add(assistantOutput); // モデルの最初の応答も会話履歴に追加します。
// モデルの応答をチェックして、ツール呼び出しをリクエストしているかどうかを判断します。
if (assistantOutput.getToolCalls() == null || assistantOutput.getToolCalls().isEmpty()) {
// ケース A:モデルはツールを呼び出さず、直接的な回答を提供します。
System.out.println("No need to call the weather query tool. Direct reply: " + assistantOutput.getContent());
} else {
// ケース B:モデルはツールを呼び出すことを決定します。
// モデルが連続して複数回ツールを呼び出すシナリオを処理するために while ループを使用します。
while (assistantOutput.getToolCalls() != null && !assistantOutput.getToolCalls().isEmpty()) {
ToolCallBase toolCall = assistantOutput.getToolCalls().get(0);
// モデルの応答からツール呼び出しの特定の情報 (関数名、パラメーター) を解析します。
ToolCallFunction functionCall = (ToolCallFunction) toolCall;
String funcName = functionCall.getFunction().getName();
String arguments = functionCall.getFunction().getArguments();
System.out.println("Calling tool [" + funcName + "] with arguments: " + arguments);
// ツール名に基づいて、対応する Java メソッドをローカルで実行します。
String toolResult = getCurrentWeather(arguments);
// ツールの実行結果を含む "tool" ロールのメッセージを構築します。
Message toolMessage = Message.builder()
.role("tool")
.toolCallId(toolCall.getId())
.content(toolResult)
.build();
System.out.println("Tool returns: " + toolMessage.getContent());
messages.add(toolMessage); // ツールの戻り結果も会話履歴に追加します。
// モデルを再度呼び出します。
param.setMessages(messages);
result = gen.call(param);
assistantOutput = result.getOutput().getChoices().get(0).getMessage();
messages.add(assistantOutput);
}
// 要約後にモデルが生成した最終的な応答を出力します。
System.out.println("Assistant's final reply: " + assistantOutput.getContent());
}
} catch (NoApiKeyException | InputRequiredException e) {
System.err.println("Error: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}次の出力が返されます:
ツール [get_current_weather] を引数 {'location': 'Singapore'} で呼び出しています
ツールの戻り値:今日のシンガポールは曇りです。
アシスタントの最終応答:今日のシンガポールの天気は曇りです。実装ガイド
ファンクションコーリングは、ツール情報を渡すための 2 つのメソッドをサポートしています:
方法 1:`tools` パラメーターを介して情報を渡す (推奨)
詳細については、「実装ガイド」をご参照ください。ツールの定義、messages 配列の作成、ファンクションコーリングの開始、ツール関数の実行、モデルによるツール関数出力の要約によって関数を呼び出すことができます。
方法 2:システムメッセージを介して情報を渡す
`tools` パラメーターを使用すると、サーバー側はモデルに基づいて適切なプロンプトテンプレートを自動的に適応させて組み立てます。そのため、`tools` パラメーターを使用することを推奨します。Qwen モデルで `tools` パラメーターを使用したくない場合は、「システムメッセージを使用してツール情報を渡す」をご参照ください。
以下のセクションでは、OpenAI 互換の呼び出しメソッドを例として使用します。`tools` パラメーターを介してツール情報を渡すことで、ファンクションコーリングを段階的に使用する方法を説明します。
ビジネスシナリオでは、天気クエリと時間クエリの 2 種類の質問を受け取ると仮定します。
1. ツールの定義
ツールは、モデルと外部世界との間の架け橋です。まず、ツールを定義する必要があります。
1.1. ツール関数の作成
天気クエリツールと時間クエリツールの 2 つのツール関数を作成できます。
天気クエリツール
このツールは
argumentsパラメーターを受け入れます。argumentsの形式は{"location": "query_location"}です。ツールの出力は"Today in {location} it is {weather}"形式の文字列です。デモンストレーションのため、ここで定義されている天気クエリツールは実際には天気を照会しません。晴れ、曇り、雨の中からランダムに選択します。実際のビジネスシナリオでは、これを AMap 天気クエリなどのツールに置き換えることができます。
時間クエリツール
時間クエリツールは入力パラメーターを必要としません。ツールの出力は
"Current time: {queried_time}."形式の文字列です。Node.js を使用する場合、
npm install date-fnsを実行して、時間を取得するための date-fns パッケージをインストールできます。
## ステップ 1:ツール関数を定義
# random モジュールのインポートを追加
import random
from datetime import datetime
# 天気クエリツールをシミュレート。出力例:「今日の北京は雨です。」
def get_current_weather(arguments):
# 代替の天気条件のリストを定義
weather_conditions = ["Sunny", "Cloudy", "Rainy"]
# 天気条件をランダムに選択
random_weather = random.choice(weather_conditions)
# JSON から場所情報を抽出
location = arguments["location"]
# フォーマットされた天気情報を返す
return f"Today in {location} it is {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"Current time: {formatted_time}."
# ツール関数をテストし、結果を出力します。後続のステップを実行する際には、以下の 4 行のテストコードを削除できます。
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. ツール配列の作成
人間がツールを選択する前に、その機能、使用時期、入力パラメーターなど、ツールを包括的に理解する必要があります。モデルも、ツールをより正確に選択するためにこの情報が必要です。ツール情報は、次の JSON 形式で提供できます。
| 天気クエリツールの場合、ツール記述情報は次の形式になります: |
ファンクションコーリングを開始する前に、コード内でツール情報配列 (`tools`) を定義する必要があります。この配列には、各ツールの関数名、説明、およびパラメーター定義が含まれます。この配列は、後続のファンクションコーリングリクエストでパラメーターとして渡されます。
# ステップ 1 のコードの後に次のコードを貼り付けます
## ステップ 2:ツール配列を作成
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "現在の時刻を知りたい場合に便利です。",
"parameters": {}
}
},
{
"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"Created {len(tools)} tools: {tool_name}\n")// ステップ 1 のコードの後に次のコードを貼り付けます
// ステップ 2:ツール配列を作成
const tools = [
{
type: "function",
function: {
name: "get_current_time",
description: "現在の時刻を知りたい場合に便利です。",
parameters: {}
}
},
{
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(`Created ${tools.length} tools: ${toolNames.join(', ')}\n`);2. messages 配列の作成
ファンクションコーリングは `messages` 配列を使用して、命令とコンテキスト情報をモデルに渡します。ファンクションコーリングを開始する前に、`messages` 配列にはシステムメッセージとユーザーメッセージを含める必要があります。
システムメッセージ
ツール配列を作成する際にツールの目的と使用時期が説明されていますが、システムメッセージでツールを呼び出すタイミングを強調すると、通常、ツールコーリングの精度が向上します。現在のシナリオでは、システムプロンプトを次のように設定できます:
あなたは役立つアシスタントです。ユーザーが天気について尋ねた場合は、「get_current_weather」関数を呼び出してください。
ユーザーが時間について尋ねた場合は、「get_current_time」関数を呼び出してください。
質問にはフレンドリーな口調で答えてください。ユーザーメッセージ
ユーザーメッセージは、ユーザーの質問を渡すために使用されます。ユーザーが「上海の天気」と尋ねたと仮定すると、`messages` 配列は次のようになります:
# ステップ 3:messages 配列を作成
# ステップ 2 のコードの後に次のコードを貼り付けます
# テキスト生成モデルのユーザーメッセージの例
messages = [
{
"role": "system",
"content": """あなたは役立つアシスタントです。ユーザーが天気について尋ねた場合は、「get_current_weather」関数を呼び出してください。
ユーザーが時間について尋ねた場合は、「get_current_time」関数を呼び出してください。
質問にはフレンドリーな口調で答えてください。""",
},
{
"role": "user",
"content": "Shanghai weather"
}
]
# Qwen3-VL モデルのユーザーメッセージの例
# messages=[
# {
# "role": "system",
# "content": """あなたは役立つアシスタントです。ユーザーが天気について尋ねた場合は、「get_current_weather」関数を呼び出してください。
# ユーザーが時間について尋ねた場合は、「get_current_time」関数を呼び出してください。
# 質問にはフレンドリーな口調で答えてください。""",
# },
# {"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": "画像内の場所の現在の天気を照会してください"}]},
# ]
print("messages array created\n") // ステップ 3:messages 配列を作成
// ステップ 2 のコードの後に次のコードを貼り付けます
const messages = [
{
role: "system",
content: "あなたは役立つアシスタントです。ユーザーが天気について尋ねた場合は、「get_current_weather」関数を呼び出してください。ユーザーが時間について尋ねた場合は、「get_current_time」関数を呼び出してください。質問にはフレンドリーな口調で答えてください。",
},
{
role: "user",
content: "Shanghai weather"
}
];
// Qwen3-VL モデルのユーザーメッセージの例、
// 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: "画像に描かれているものは何ですか?"}]
// }];
console.log("messages array created\n");利用可能なツールには天気と時間のクエリが含まれているため、現在の時刻について尋ねることもできます。
3. ファンクションコーリングの開始
作成した tools と messages をモデルに渡して、関数呼び出しを開始できます。モデルはツールを呼び出すかどうかを判断します。呼び出す場合は、そのツールの関数名とパラメーターを返します。
サポートされているモデルのリストについては、「利用可能なモデル」をご参照ください。
# ステップ 4:ファンクションコーリングを開始
# ステップ 3 のコードの後に次のコードを貼り付けます
from openai import OpenAI
import os
client = OpenAI(
# 中国 (北京) リージョンのモデルを使用する場合は、中国 (北京) リージョンの API キーを使用する必要があります。キーは https://bailian.console.alibabacloud.com/?tab=model#/api-key から取得してください。
# 環境変数を設定していない場合は、次の行を Model Studio の API キーを使用して api_key="sk-xxx" に置き換えてください。
api_key=os.getenv("DASHSCOPE_API_KEY"),
# 中国 (北京) リージョンのモデルを使用する場合は、base_url を 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(
# この例では qwen-plus を使用しています。必要に応じてモデル名を変更できます。モデルのリストについては、https://www.alibabacloud.com/help/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()// ステップ 4:ファンクションコーリングを開始
// ステップ 3 のコードの後に次のコードを貼り付けます
import OpenAI from "openai";
const openai = new OpenAI(
{
// 中国 (北京) リージョンのモデルを使用する場合は、中国 (北京) リージョンの API キーを使用する必要があります。キーは https://bailian.console.alibabacloud.com/?tab=model#/api-key から取得してください。
// 環境変数を設定していない場合は、次の行を Model Studio の API キーを使用して apiKey: "sk-xxx" に置き換えてください。
apiKey: process.env.DASHSCOPE_API_KEY,
// 中国 (北京) リージョンのモデルを使用する場合は、baseURL を 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", // この例では qwen-plus を使用しています。必要に応じてモデル名を変更できます。モデルのリストについては、https://www.alibabacloud.com/help/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 パラメーターを介して直接返信することに注意してください。「こんにちは」と入力すると、tool_calls パラメーターは空になり、返されるオブジェクトは次の形式になります:
{
"content": "こんにちは!何かお手伝いできますか?特に天気や時間に関する質問が得意です。",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": null
}tool_callsパラメーターが空の場合、プログラムは後続のステップを実行せずにcontentを直接返すことができます。
各ファンクションコーリングの後にモデルに特定のツールを常に選択させたい場合は、「強制ツールコーリング」をご参照ください。
4. ツール関数の実行
ツール関数の実行は、モデルの決定を実際の操作に変換する重要なステップです。
ツール関数の実行プロセスは、モデルではなく、ご利用のコンピューティング環境によって完了します。
モデルは文字列形式のコンテンツしか出力できないため、ツール関数を実行する前に、文字列形式のツール関数と入力パラメーターを個別に解析する必要があります。
ツール関数
ツール関数名からツール関数エンティティへのマッピング
function_mapperを作成できます。これにより、返されたツール関数文字列がツール関数エンティティにマッピングされます。入力パラメーター
ファンクションコーリングによって返される入力パラメーターは JSON 文字列です。ツールを使用してそれを JSON オブジェクトに解析し、入力パラメーター情報を抽出できます。
解析後、パラメーターをツール関数に渡して実行し、出力結果を取得できます。
# ステップ 5:ツール関数を実行
# ステップ 4 のコードの後に次のコードを貼り付けます
import json
print("Running the tool function...")
# 返された結果から関数名と入力パラメーターを取得
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"Tool function output: {function_output}\n")// ステップ 5:ツール関数を実行
// ステップ 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;
// 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(`Tool function output: ${functionOutput}\n`);次の出力が返されます:
今日の上海は曇りです。実際のビジネスシナリオでは、多くのツールの主要な機能は、データのクエリではなく、メールの送信やファイルのアップロードなどの特定の操作を実行することです。これらのツールは、実行後に文字列を出力しません。モデルがツールの実行ステータスを理解できるように、このようなツールを設計する際には、「メールが正常に送信されました」や「操作に失敗しました」などのステータス説明を追加することを推奨します。
5. モデルによるツール関数出力の要約
ツール関数の出力形式は比較的固定されています。ユーザーに直接返すと、硬くて柔軟性に欠けるように聞こえる場合があります。モデルにユーザー入力とツール出力を組み合わせて自然言語の応答を生成させたい場合は、ツール出力をモデルのコンテキストに送信し、モデルに別のリクエストを送信できます。
アシスタントメッセージの追加
ファンクションコーリングを開始した後、
completion.choices[0].messageを介してアシスタントメッセージを取得できます。まず、それを `messages` 配列に追加します。ツールメッセージの追加
ツールの出力を
{"role": "tool", "content": "the tool's output","tool_call_id": completion.choices[0].message.tool_calls[0].id}として messages 配列に追加できます。説明ツールの出力が文字列形式であることを確認してください。
tool_call_idは、各ツール呼び出しリクエストに対してシステムが生成する一意の識別子です。モデルは一度に複数のツールを呼び出すようにリクエストする場合があります。複数のツール結果をモデルに返す場合、tool_call_idは、ツールの出力がその呼び出し意図と一致することを保証します。
# ステップ 6:ツール出力をモデルに送信
# ステップ 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")// ステップ 6:ツール出力をモデルに送信
// ステップ 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` 配列は次のようになります:
[
システムメッセージ -- モデルのツールコーリング戦略をガイド
ユーザーメッセージ -- ユーザーの質問
アシスタントメッセージ -- モデルから返されたツール呼び出し情報
ツールメッセージ -- ツールの出力情報 (後述の並列ツールコーリングを使用する場合、複数のツールメッセージが存在する可能性があります)
]`messages` 配列を更新した後、次のコードを実行できます。
# ステップ 7:モデルがツール出力を要約
# ステップ 6 のコードの後に次のコードを貼り付けます
print("Summarizing tool output...")
completion = function_calling()// ステップ 7:モデルがツール出力を要約
// ステップ 6 のコードの後に次のコードを貼り付けます
console.log("Summarizing tool output...");
const completion_1 = await functionCalling();content から応答内容を取得できます:「今日の上海の天気は曇りです。他に質問があれば、お気軽にお尋ねください。」
{
"content": "今日の上海の天気は曇りです。他に質問があれば、お気軽にお尋ねください。",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": null
}これで、完全なファンクションコーリングプロセスが完了しました。
高度な使用方法
ツールコーリングメソッドの指定
並列ツールコーリング
単一の都市の天気を照会するには、単一のツール呼び出しで十分です。「北京と上海の天気は?」や「杭州の天気と今の時間は?」など、入力された質問に複数のツール呼び出しが必要な場合、ファンクションコーリングを開始した後、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
}
]
}返された結果には、北京の入力パラメーター情報のみが含まれています。この問題を解決するには、ファンクションコーリングを開始する際に、リクエストパラメーター parallel_tool_calls を true に設定します。これにより、返されるオブジェクトには、呼び出す必要のあるすべてのツール関数と入力パラメーターが含まれます。
並列ツールコーリングは、依存関係のないタスクに適しています。タスク間に依存関係がある場合、たとえば、ツール A の入力がツール B の出力に依存する場合、「クイックスタート」をご参照の上、while ループを使用して直列ツールコーリング (一度に 1 つのツールを呼び出す) を実装してください。
def function_calling():
completion = client.chat.completions.create(
model="qwen-plus", # この例では qwen-plus を使用しています。必要に応じてモデル名を変更できます。
messages=messages,
tools=tools,
# 新しいパラメーター
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", // この例では qwen-plus を使用しています。必要に応じてモデル名を変更できます。
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 は引き続きツール呼び出し情報を返します。特定のツールの強制
特定の種類の質問に対して、ファンクションコーリングに特定のツールを強制的に呼び出させたい場合は、
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になります。この戦略を使用する前に、質問が選択したツールに関連していることを確認してください。そうしないと、予期しない結果を受け取る可能性があります。
ツール不使用を強制
どのような質問に対してもファンクションコーリングにツール呼び出しを一切実行させたくない場合、つまり返されるオブジェクトが
contentに応答内容を含み、tool_callsパラメーターが空であるようにしたい場合は、tool_choiceパラメーターを"none"に設定するか、toolsパラメーターを渡さないようにします。ファンクションコーリングによって返される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` 配列を維持することを推奨します。この配列に新しいユーザーメッセージを追加し、その後 ファンクションコーリングを開始して後続のステップを実行できます。`messages` の構造は次のようになります:
[
システムメッセージ -- モデルのツールコーリング戦略をガイド
ユーザーメッセージ -- ユーザーの質問
アシスタントメッセージ -- モデルから返されたツール呼び出し情報
ツールメッセージ -- ツールの出力情報
アシスタントメッセージ -- モデルによるツール呼び出し情報の要約
ユーザーメッセージ -- ユーザーの 2 ターン目の質問
]ストリーミング出力
ユーザーエクスペリエンスを向上させ、待機時間を短縮するために、ストリーミング出力を使用してツール関数名と入力パラメーター情報をリアルタイムで取得できます。この場合:
ツール呼び出しパラメーター情報:これはデータストリームとしてチャンクで返されます。
ツール関数名:これはストリーミング応答の最初のデータチャンクで返されます。
from openai import OpenAI
import os
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
# 中国 (北京) リージョンのモデルを使用する場合は、これを 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": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。",
}
},
"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(
{
// 中国 (北京) リージョンのモデルを使用する場合は、中国 (北京) リージョンの API キーを使用する必要があります。キーは次の場所で取得します: https://bailian.console.alibabacloud.com/?tab=model#/api-key
// 環境変数が設定されていない場合は、次の行をお客様のモデル Studio API キーに置き換えてください: apiKey: "sk-xxx",
apiKey: process.env.DASHSCOPE_API_KEY,
// 中国 (北京) リージョンのモデルを使用する場合は、baseURL を 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"),
# 中国 (北京) リージョンのモデルを使用する場合は、これを 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": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。",
}
},
"required": ["location"],
},
},
},
]
completion = client.chat.completions.create(
model="qwen3-omni-flash",
messages=[{"role": "user", "content": "What's the weather in Hangzhou?"}],
# 出力データのモダリティを設定します。有効な値:["text"], ["text","audio"]。["text"] に設定することを推奨します。
modalities=["text"],
# stream は True に設定する必要があります。そうしないとエラーが報告されます。
stream=True,
tools=tools
)
for chunk in completion:
# 出力に音声モダリティが含まれる場合は、次の条件を 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(
{
// 中国 (北京) リージョンのモデルを使用する場合は、中国 (北京) リージョンの API キーを使用する必要があります。キーは https://bailian.console.alibabacloud.com/?tab=model#/api-key から取得してください。
// 環境変数を設定していない場合は、次の行を Model Studio の API キーを使用して apiKey: "sk-xxx" に置き換えてください。
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": "getCurrentWeather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。"
}
},
"required": ["location"]
}
}
}
];
const stream = await openai.chat.completions.create({
model: "qwen3-omni-flash",
messages: [
{
"role": "user",
"content": "Hangzhou weather"
}],
stream: true,
// 出力データのモダリティを設定します。有効な値:["text"], ["text","audio"]。["text"] に設定することを推奨します。
modalities: ["text"],
tools:tools
});
for await (const chunk of stream) {
// 出力に音声が含まれる場合は、条件文を 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
# OpenAI クライアントを初期化し、Alibaba Cloud DashScope サービスを設定
client = OpenAI(
# 環境変数を設定していない場合は、次の行を api_key="sk-xxx" に置き換えてください。
api_key=os.getenv("DASHSCOPE_API_KEY"), # 環境変数から API キーを読み取る
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)
# 利用可能なツールのリストを定義
tools = [
# ツール 1:現在の時刻を取得
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "現在の時刻を知りたい場合に便利です。",
"parameters": {} # パラメーターは不要
}
},
# ツール 2:指定された都市の天気を取得
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。"
}
},
"required": ["location"] # 必須パラメーター
}
}
}
]
messages = [{"role": "user", "content": input("Please enter your question: ")}]
# Qwen3-VL モデルのメッセージ例
# 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": "画像内の場所の現在の天気は何ですか?"}]
# }]
completion = client.chat.completions.create(
# この例では qwen-plus を使用しています。他のディープシンキングモデルに置き換えることができます。
model="qwen-plus",
messages=messages,
extra_body={
# ディープシンキングを有効化。このパラメーターは qwen3-30b-a3b-thinking-2507、qwen3-235b-a22b-thinking-2507、および QwQ モデルでは無効です。
"enable_thinking": True
},
tools=tools,
parallel_tool_calls=True,
stream=True,
# トークン消費量情報を取得するにはコメントを解除
# stream_options={
# "include_usage": True
# }
)
reasoning_content = "" # 完全な思考プロセスを定義
answer_content = "" # 完全な応答を定義
tool_info = [] # ツール呼び出し情報を格納
is_answering = False # 思考プロセスが終了し、応答が開始されたかどうかを判断
print("="*20+"Thinking Process"+"="*20)
for chunk in completion:
if not chunk.choices:
# 使用統計を処理
print("\n"+"="*20+"Usage"+"="*20)
print(chunk.usage)
else:
delta = chunk.choices[0].delta
# AI の思考プロセス (思考の連鎖) を処理
if hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:
reasoning_content += delta.reasoning_content
print(delta.reasoning_content,end="",flush=True) # 思考プロセスをリアルタイムで出力
# 最終的な応答内容を処理
else:
if not is_answering: # 初めて応答フェーズに入るときにタイトルを出力
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) # 応答内容をストリーミング
# ツール呼び出し情報を処理 (並列ツール呼び出しをサポート)
if delta.tool_calls is not None:
for tool_call in delta.tool_calls:
index = tool_call.index # ツール呼び出しインデックス、並列呼び出し用
# ツール情報ストレージリストを動的に拡張
while len(tool_info) <= index:
tool_info.append({})
# ツール呼び出し ID を収集 (後続の関数呼び出し用)
if tool_call.id:
tool_info[index]['id'] = tool_info[index].get('id', '') + tool_call.id
# 関数名を収集 (後続の特定の関数へのルーティング用)
if tool_call.function and tool_call.function.name:
tool_info[index]['name'] = tool_info[index].get('name', '') + tool_call.function.name
# 関数引数を収集 (JSON 文字列形式、後続の解析が必要)
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)返される結果
「四つの直轄市の天気」と入力すると、次の結果が返されます:
====================思考プロセス====================
わかりました、ユーザーは「四つの直轄市の天気」を尋ねています。まず、どの四つの直轄市を指しているのかを特定する必要があります。中国の行政区画によると、直轄市には北京、上海、天津、重慶が含まれます。したがって、ユーザーはこれらの四つの都市の気象状況を知りたいのです。
次に、利用可能なツールを確認する必要があります。提供されているツールには、文字列型の場所をパラメーターとして受け取る get_current_weather 関数が含まれています。この関数は一度に 1 つの場所しか確認できないため、各都市を個別に照会する必要があります。したがって、各直轄市に対してこの関数を一度呼び出す必要があります。
次に、正しいツール呼び出しを生成する方法を検討する必要があります。各呼び出しには、パラメーターとして都市名を含める必要があります。たとえば、最初の呼び出しは北京、2 番目は上海などです。パラメーター名が `location` で、値が正しい都市名であることを確認する必要があります。
また、ユーザーは各都市の天気情報をおそらく望んでいるので、各関数呼び出しが正しいことを確認する必要があります。各都市に対して 1 回ずつ、4 回の連続した呼び出しが必要になるかもしれません。ただし、ツールの使用規則に基づくと、複数のステップで処理する必要があるか、一度に複数の呼び出しが生成される可能性があります。しかし、例に基づくと、一度に 1 つの関数しか呼び出されないようなので、段階的に行う必要があるかもしれません。
最後に、パラメーターが正しいか、都市名が正確か、都市が存在しない、API が利用できないなどのエラー状況を処理するかどうかなど、考慮すべき他の要因があるかどうかを確認する必要があります。しかし、今のところ、四つの直轄市は明確なので、問題ないはずです。
====================応答内容====================
===================ツール呼び出し情報===================
[{'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: "現在の時刻を知りたい場合に便利です。",
parameters: {}
}
},
{
type: "function",
function: {
name: "get_current_weather",
description: "特定の都市の天気を照会する場合に便利です。",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "北京、杭州、余杭区などの都市または地区。"
}
},
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 }];
// Qwen3-VL モデルのメッセージ例
// 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: "画像内の場所の天気は?"}]
// }];
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(); 返される結果
「四つの直轄市の天気」と入力すると、次の結果が返されます:
質問を入力してください:四つの直轄市の天気
====================思考プロセス====================
わかりました、ユーザーは四つの直轄市の天気について尋ねています。まず、中国のどの四つの直轄市を指しているのかを明確にする必要があります。北京、上海、天津、重慶ですね?次に、各都市の天気クエリ関数を呼び出す必要があります。
しかし、ユーザーの質問は、これらの四つの都市の気象状況を個別に取得する必要があるかもしれません。各都市は、それぞれの都市名をパラメーターとして get_current_weather 関数を呼び出す必要があります。たとえば、「北京市」、「上海市」、「天津市」、「重慶市」など、直轄市のフルネームなど、パラメーターが正しいことを確認する必要があります。
次に、これらの四つの都市の天気 API を順番に呼び出す必要があります。各呼び出しには個別の tool_call が必要です。ユーザーは各都市の現在の天気情報をおそらく望んでいるので、各呼び出しが正しいことを確認する必要があります。エラーを避けるために、各都市の正しいスペルと名前に注意を払う必要があるかもしれません。たとえば、重慶は時々省略されることがあるので、パラメーターにはフルネームを使用する必要があります。
さて、各直轄市に対して 1 つずつ、4 つの tool_call を生成する必要があります。各パラメーターが正しいかどうかを確認し、それらを順番に並べます。これにより、ユーザーは四つの直轄市すべての気象状況を取得できます。
====================応答内容====================
===================ツール呼び出し情報===================
[
{
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": "現在の時刻を知りたい場合に便利です。",
"parameters": {}
}
},
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location":{
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。"
}
},
"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": "現在の時刻を知りたい場合に便利です。",
"parameters": {} # 現在の時刻を取得するには入力パラメーターが不要なため、parameters は空の辞書です。
}
},
# ツール 2:指定された都市の天気を取得
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
# 天気を照会するには場所が必要なため、パラメーターは location に設定されます。
"location": {
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。"
}
},
"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": "画像内の場所の天気は?"}]
# }]
# Qwen3-VL モデルを使用する場合は、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)返される結果
「四つの直轄市の天気」と入力すると、次の結果が返されます:
質問を入力してください:四つの直轄市の天気
====================思考プロセス====================
わかりました、ユーザーは四つの直轄市の天気について尋ねています。まず、中国のどの四つの直轄市を指しているのかを確認する必要があります。北京、上海、天津、重慶ですね?次に、ユーザーは各都市の気象状況を必要としているので、天気クエリ関数を呼び出す必要があります。
しかし、問題が発生します:ユーザーは都市名を指定せず、「四つの直轄市」とだけ言っています。各直轄市の名前を明確にしてから、個別に照会する必要があるかもしれません。たとえば、北京、上海、天津、重慶です。各都市が正しいことを確認する必要があります。
次に、利用可能なツールを確認する必要があります。ユーザーは `location` パラメーターを持つ `get_current_weather` 関数を提供しています。したがって、各直轄市に対してこの関数を呼び出し、対応する都市名をパラメーターとして渡す必要があります。たとえば、最初の呼び出しの場所は北京、2 番目は上海、3 番目は天津、4 番目は重慶です。
ただし、注意が必要かもしれません。重慶のような直轄市では、より具体的な地区が必要な場合がありますが、ユーザーはおそらく市レベルの天気のみを必要としているでしょう。したがって、直轄市の名前を直接使用しても問題ないはずです。次に、各直轄市に対して 1 つずつ、4 つの個別の関数呼び出しを生成する必要があります。これにより、ユーザーは四つの都市すべての気象状況を取得できます。
最後に、各呼び出しのパラメーターが正しいこと、および見落としがないことを確認します。これにより、ユーザーの質問に対する完全な回答が提供されます。
===================ツール呼び出し情報===================
[{'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", "指定された地域の天気を取得", jsonSchemaWeather);
FunctionDefinition fdTime = buildFunctionDefinition(
"get_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();
}
// qwen3-vl-plus モデル用のツール呼び出しメソッドを作成
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)));
}
// ツール呼び出しをサポートする Qwen3-vl モデルのパラメーターを構築
private static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage userMsg) {
FunctionDefinition fdWeather = buildFunctionDefinition(
"get_current_weather", "指定された地域の天気を取得", jsonSchemaWeather);
FunctionDefinition fdTime = buildFunctionDefinition(
"get_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);
}
// Qwen3-VL モデルをツール呼び出しに使用する場合は、次の行のコメントを解除してください。
// 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", "画像内の場所の天気"))).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":"わかりました、ユーザーは私に"}}]}}
{"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":" 杭州の天気を教えてほしいようです。まず"}}]}}
{"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":"、関連するツールがあるかどうかを"}}]}}
{"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":"判断する必要があります。提供されている"}}]}}
{"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":"ツールを見ると、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 関数に location パラメーターがある"}}]}}
{"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":"ことがわかります。したがって、この関数を"}}]}}
{"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":"パラメーターを"}}]}}
{"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":"杭州に設定して呼び出す必要があります。他"}}]}}
{"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":"のツールは必要ありません。なぜなら"}}]}}
{"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":"ユーザーは天気についてのみ"}}]}}
{"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":"尋ねたからです。次に、tool_call を構築"}}]}}
{"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":"し、名前とパラメーターを"}}]}}
{"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":"入力します"}}]}}
{"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":"。パラメーターが"}}]}}
{"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 オブジェクトであり、location が"}}]}}
{"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":"文字列であることを確認します。エラーをチェック"}}]}}
{"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":"した後、返します。"}}]}}
{"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
# ======= 重要事項 =======
# Qwen3-VL モデルを使用する場合は、message パラメーターを変更し、URL を https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation に置き換えてください。
# シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーを取得するには、https://www.alibabacloud.com/help/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": "現在の時刻を知りたい場合に便利です。",
"parameters": {}
}
},{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の天気を照会する場合に便利です。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "北京、杭州、余杭区などの都市または地区。"
}
},
"required": ["location"]
}
}
}]
}
}'本番運用
ツールコーリング精度のテスト
評価システムの確立:
実際のビジネスシナリオを反映したテストデータセットを構築し、ツール選択の精度、パラメーター抽出の精度、エンドツーエンドの成功率など、明確な評価メトリクスを定義します。
プロンプトの最適化
テストで不適切なツール選択やパラメーターなどの問題が明らかになった場合、システムプロンプト、ツール説明、パラメーター説明を対象に最適化を行うことができます。これが主要なチューニング方法です。
モデルのアップグレード
プロンプトエンジニアリングでパフォーマンスが向上しない場合、
qwen3-max-previewのようなより高性能なモデルバージョンにアップグレードすることが、メトリクスを向上させる最も直接的で効果的な方法です。
ツール数の動的制御
アプリケーションに統合されるツールの数が数十、あるいは数百と多い場合、ツールライブラリ全体をモデルに提供すると、次の問題が発生する可能性があります:
パフォーマンスの低下:巨大なツールセットから正しいツールを選択することが、モデルにとって劇的に難しくなります。
コストとレイテンシー:多くのツール説明は多くの入力トークンを消費し、コストを増加させ、応答を遅くします。
解決策は、モデルを呼び出す前にツールルーティングまたは取得レイヤーを追加することです。このレイヤーは、ユーザーの現在のクエリに基づいて、完全なツールライブラリから関連性の高いツールの小さなサブセットを迅速かつ正確にフィルタリングし、そのサブセットをモデルに提供します。
以下は、ツールルーティングを実装するためのいくつかの主流な方法です:
セマンティック検索
埋め込みモデルを使用してすべてのツールの説明情報 (
description) をベクトルに変換し、ベクトルデータベースに保存します。ユーザーがクエリを入力すると、クエリベクトルに対してベクトル類似性検索を使用して、最も関連性の高い上位 K 個のツールを呼び出すことができます。ハイブリッド検索
セマンティック検索の「あいまい一致」機能と、従来のキーワードやメタデータタグの「完全一致」機能を組み合わせます。ツールに
tagsやkeywordsフィールドを追加し、取得時にベクトル検索とキーワードフィルタリングを同時に実行することで、高頻度または特定のシナリオでの呼び出し精度を大幅に向上させることができます。軽量 LLM ルーター
より複雑なルーティングロジックには、Qwen-Flash のような、より小さく、高速で、安価なモデルを事前ルーティングの「ルーターモデル」として使用できます。そのタスクは、ユーザーの質問に基づいて関連するツール名のリストを出力することです。
実践的な提案
候補セットを簡潔に保つ:どの方法を使用するかにかかわらず、メインモデルには20 個以下のツールを提供することを推奨します。この数は、モデルの認知負荷、コスト、レイテンシー、精度の間の最適なバランスを表します。
階層的なフィルタリング戦略:ファネルスタイルのルーティングポリシーを構築できます。たとえば、まず低コストのキーワードまたはルールマッチングを使用して初期スクリーニングを行い、無関係なツールを除外し、その後、残りのツールに対してセマンティック検索を実行して効率と品質を向上させることができます。
ツールのセキュリティ原則
モデルにツール実行機能を有効にする場合、セキュリティを最優先事項とする必要があります。中心となる原則は、最小権限の原則と人間による確認です。
最小権限の原則:モデルに提供されるツールセットは、最小権限の原則に厳密に従う必要があります。デフォルトでは、ツールは読み取り専用であるべきです。たとえば、天気のクエリやドキュメントの検索などであり、状態の変更やリソース操作を伴う「書き込み」権限を直接提供することは避けてください。
危険なツールの隔離:任意のコードを実行するツール (
code interpreter)、ファイルシステムを操作するツール (fs.delete)、データベースの削除または更新操作を実行するツール (db.drop_table)、または資金を移動するツール (payment.transfer) など、危険なツールをモデルに直接提供しないでください。人間による確認 (ヒューマンインザループ):すべての高権限または不可逆的な操作には、手動のレビューと確認ステップを導入する必要があります。モデルは操作リクエストを生成できますが、最終的な実行「ボタン」は人間のユーザーがクリックする必要があります。たとえば、モデルはメールを作成できますが、送信操作はユーザーが確認する必要があります。
ユーザーエクスペリエンスの最適化
ファンクションコーリングのチェーンは長く、どのステップで問題が発生してもユーザーエクスペリエンスが低下する可能性があります。
ツール実行失敗の処理
ツールの実行失敗はよくあることです。次の戦略を採用できます:
最大リトライ回数:たとえば 3 回など、合理的なリトライ制限を設定して、継続的な失敗による長いユーザー待機時間やシステムリソースの浪費を避けます。
フォールバック応答の提供:リトライが尽きた場合や解決不可能なエラーが発生した場合は、「申し訳ありませんが、現時点では関連情報を見つけることができません。サービスが混み合っている可能性があります。後でもう一度お試しください。」など、明確でフレンドリーなプロンプトをユーザーに返す必要があります。
処理遅延への対応
高いレイテンシーはユーザー満足度を低下させる可能性があるため、フロントエンドのインタラクションとバックエンドの最適化を通じて対処する必要があります。
タイムアウトの設定:ファンクションコーリングの各ステップに、独立した合理的なタイムアウトを設定します。タイムアウトが発生したら、操作を直ちに中断し、フィードバックを提供する必要があります。
即時フィードバックの提供:ファンクションコーリングプロセスを開始する際には、「天気を照会しています...」や「関連情報を検索しています...」など、インターフェイスにプロンプトを表示して、処理の進捗状況をリアルタイムでユーザーにフィードバックすることを推奨します。
課金説明
`messages` 配列のトークンに加えて、ツール説明は入力トークンとしてプロンプトに追加され、これも課金の対象となります。
システムメッセージによるツール情報の受け渡し
エラーコード
呼び出しが失敗した場合は、「エラーメッセージ」を参照してトラブルシューティングを行ってください。