Function calling(ツール呼び出し)とは?仕組みと実装の流れ

この記事の要点
- Function calling(tool calling)は、LLMが呼ぶべき関数と引数を返し、アプリのコードが実行する仕組みです。
- OpenAI形式では
toolsを送り、tool_callsを受け取り、結果をrole: "tool"で返します。往復は最低2回です。 - 並列呼び出しで複数の依頼が届いたら、全件の結果をそろえてから次を送ります。
- 出力の形をそろえるだけなら構造化出力、外部の処理を動かすならツール呼び出しを使います。
- 入力トークンの消費はモデルごとに違い、同じリクエストで約8倍の差が出ました(実測)。
LLMは、今日の在庫数や注文の配送状況を知りません。そこでアプリの関数を道具としてモデルに渡し、必要なときに呼び出しを依頼させます。これがFunction calling(ツール呼び出し)です。コードはFastMetalで実際に動かして確認しました。LLM APIの基本はLLM APIとはで解説しています。
Function calling(ツール呼び出し)とは
Function callingは、LLMが文章の代わりに「この関数を、この引数で呼んでください」という依頼を返す機能です。役割は次のように分かれます。
- モデル:どの関数をどの引数で呼ぶかを決める
- アプリ:関数を実行し、結果をモデルに返す
- モデル:結果を踏まえて回答を書く
データベースの検索や在庫の確認など、モデル単体では届かない処理をつなぐ入口です。検索を関数として渡せば、RAGもこの仕組みで組めます。
function calling、tool calling、tool useの違い
指している仕組みは同じです。OpenAIは2023年にfunction callingとして公開し、のちにパラメータを functions から tools に改めたため、tool callingとも呼ばれます。AnthropicはTool useと呼んでいます。古い記事の functions と function_call は旧形式です。
リクエストからレスポンスまでの流れ
OpenAI形式(Chat Completions)では、次の4段階で進みます。
- アプリが質問と
tools(使える関数の一覧)を送る - モデルが
tool_calls(関数名と引数)を返す - アプリが関数を実行し、結果を
role: "tool"で会話に加える - 会話全体を送り直し、モデルが最終的な回答を返す
OpenAIのResponses APIは形式が異なるため、ここではChat Completions形式で説明します。
リクエスト:tools と tool_choice
関数はJSON Schemaで定義します。description はモデルが呼ぶかどうかを判断する材料なので、用途がはっきり伝わる文にします。呼び出し方は tool_choice で指定できます。
| 値 | 動き |
|---|---|
"auto" | 必要なときだけ関数を呼ぶ(既定) |
"none" | 関数を呼ばずに文章で答える |
"required" | 少なくとも1つの関数を必ず呼ぶ |
{"type": "function", "function": {"name": "..."}} | 指定した関数を必ず呼ぶ |
レスポンス:finish_reason と tool_calls
関数を使うと判断したモデルは、finish_reason を "tool_calls" にして、呼び出しの一覧を返します。
"tool_calls": [{
"id": "call_...",
"type": "function",
"function": {
"name": "get_order_status",
"arguments": "{\"order_id\": \"A-1001\"}"
}
}]
argumentsはJSON形式の文字列なので、json.loads()で辞書に変換してから使います。idは結果との照合に使います。実測ではcall_、tooluse_、chatcmpl-tool-で始まる値が返り、形式はモデルごとに違いました。受け取った値をそのまま使います。finish_reasonが"stop"なら、モデルは関数を使わずに回答しています。
結果を返す:role: "tool" と tool_call_id
tool_calls を含むassistantメッセージを履歴に戻し、続けて結果を role: "tool" で加えます。tool_call_id に対応する id を入れ、会話をもう一度送ります。
Pythonでの実装例
FastMetalはOpenAI互換APIに対応しているため、OpenAIの公式SDKで base_url を差し替えるだけで呼び出せます。注文の配送状況を調べる関数を1つ渡す例です。
import json
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["FASTMETAL_API_KEY"],
base_url="https://api.fastmetal.ai/v1",
)
MODEL = "gemini-flash-lite-free"
def get_order_status(order_id: str) -> dict:
# 実際には社内の注文データベースやAPIを参照します
return {"order_id": order_id, "status": "発送済み"}
tools = [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "注文番号から、その注文の配送状況を調べる",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "注文番号(例:A-1001)"},
},
"required": ["order_id"],
},
},
}]
messages = [{"role": "user", "content": "注文A-1001とA-1002の状況を教えて"}]
# 1回目:どの関数を、どの引数で呼ぶかをモデルに決めてもらう
first = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg) # tool_calls を含む assistant メッセージを履歴に戻す
for call in msg.tool_calls: # 並列呼び出しでは複数件が入る
args = json.loads(call.function.arguments) # JSON文字列を辞書に変換
if call.function.name == "get_order_status":
result = get_order_status(args["order_id"])
else:
result = {"error": "unknown function"}
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False),
})
# 2回目:実行結果を踏まえた回答を受け取る
final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
print(final.choices[0].message.content)
else:
print(msg.content)
2026年10月6日に、このコードを gemini-flash-lite-free、deepseek-v4-flash、anthropic-claude-haiku-4-5 で実行し、3モデルとも1回目で2件の呼び出しを、2回目で回答を返しました。ループ化までの手順はツール呼び出しの実装チュートリアル、APIキーの発行はAPIの始め方で解説しています。
並列呼び出し(parallel tool calls)
上の例のように、1回の応答で複数の呼び出しが返ることを並列呼び出しといいます。互いに依存しない処理を、往復を増やさずにまとめて依頼できます。
tool_callsは複数ある前提で、ループで処理する- すべての呼び出しに、
tool_call_id付きの結果を返す - 全件の結果をそろえてから、次のリクエストを送る
結果が1件でも欠けると、エラーを返すモデルがあります。順番が大事な処理では parallel_tool_calls を false にすると、1回に呼ぶ関数を0件か1件に絞れます(効くかどうかはモデルによります)。
構造化出力とツール呼び出しの使い分け
どちらもJSONを扱いますが、目的が違います。
| 構造化出力 | ツール呼び出し | |
|---|---|---|
| 指定するもの | response_format にJSON Schema | tools に関数の定義 |
| 返ってくるもの | スキーマに沿った回答そのもの | 呼びたい関数名と引数 |
| 往復 | 1回 | 2回以上 |
| 向いている場面 | 抽出、分類、要約の形をそろえる | 検索、データベース参照、外部APIの実行 |
JSONで項目を受け取りたいだけなら、往復が1回で済む構造化出力が簡単です。外部の情報の取得や処理の実行には、ツール呼び出しを使います。書き方は構造化出力(JSON)のチュートリアルにまとめています。
対応状況とトークン消費はモデルごとに違う
FastMetalはOpenAI形式のツール呼び出しと構造化出力に対応しており、model を差し替えるだけで各社のモデルを試せます。ただし対応や精度はモデルごとに異なるため、モデル一覧から各モデルのページを開き、「サポートされているパラメータ」に tools があるかを確認してください。
関数の定義は毎回プロンプトに含まれ、入力トークンとして課金されます。上のコードの1回目のリクエストで、入力トークン数をモデルごとに比べました。
| モデル | 入力トークン(prompt_tokens) |
|---|---|
| gemini-flash-lite-free | 91 |
| deepseek-v4-flash | 319 |
| anthropic-claude-haiku-4-5 | 706 |
2026年10月6日にFastMetal経由で実測しました。条件は同じでも、定義をプロンプトに組み込む方法がモデルごとに違うため、約8倍の差が出ています。料金は100万トークンあたりの従量課金なので、ツールを多用するアプリではモデル選びがコストに響き、コンテキストウィンドウの消費も増えます。
model に "auto" を指定すると、ツールなどの要件を満たすモデルのうち最も安いものにFastMetalが振り分けます。課金は選ばれたモデルの料金です。
次のステップ:エージェントとMCP
ツール呼び出しを、モデルが関数を呼ばなくなるまで繰り返すと、エージェントの基本形になります。Claude Codeのようなコーディングエージェントもこの仕組みで動き、1つのタスクで数十回から数百回、会話を送り直しながらモデルを呼ぶため、コストの大半は入力トークンです。
MCP(Model Context Protocol)は、ツールの公開と接続の方法をそろえた共通の規格です。MCPサーバーのツールは、クライアントを通じて最終的に tools としてモデルに渡されます。詳しくはMCPとはをご覧ください。
FastMetalの組み込みMCPサーバー(https://mcp.fastmetal.ai/mcp)を使えば、他のモデルへの質問や画像生成などのツールを、Claude Codeなどにコマンド1つで追加できます。設定方法はMCPガイドにあります。
よくある失敗
arguments を文字列のまま使う
json.loads() を通さずに辞書として扱うと、その場でエラーになります。
assistantメッセージを履歴に戻し忘れる
結果より先に、tool_calls を含むassistantメッセージを履歴に入れます。独自の情報を添えるモデルもあるため、組み立て直さずにそのまま戻します。
ループに上限を付けない
同じ呼び出しが繰り返され、課金が積み上がることがあります。往復回数には上限を設けます。FastMetalならAPIキーごとに残高の上限も設定できます。
引数を検証しない
存在しない関数名や、必須項目の欠けた引数が返ることがあります。ユーザーの入力と同じように検証し、送金や削除のような処理には人の確認を挟みます。渡す関数も、その場面で必要なものに絞ると選び間違いが減ります。
よくある質問
モデルが関数を実行するのですか
いいえ。モデルが返すのは「どの関数を、どの引数で呼ぶか」という依頼だけです。実行するのはアプリ側のコードで、その結果を返すと、モデルが最終的な回答をまとめます。
RAGとFunction callingの違いは何ですか
RAGは、関連する文書を検索してプロンプトに加え、回答させる手法です。Function callingは、モデルが関数の実行を依頼する仕組みです。検索を関数として渡せば、RAGをFunction callingで組むこともできます。
Function callingとMCPはどう違いますか
Function callingは、モデルとアプリが関数の呼び出しをやり取りするAPIの仕組みです。MCPは、ツールの公開と接続を標準化したプロトコルで、MCPでつないだツールも最終的にはtoolsとしてモデルに渡されます。
無料で試せますか
アカウントの作成は無料で、gemini-flash-lite-freeなどの無料モデルは¥0で使えます。この記事のコードも同じモデルで確認しました。有料モデルは¥500から購入できるクレジットによる従量課金です。
FastMetalで試す
FastMetalは、95以上のLLM・生成AIモデルをOpenAI互換APIで呼び出せる、日本のAIゲートウェイです。同じツール呼び出しのコードのまま、各社のモデルを比べられます。円建てのプリペイドで、クレジット購入ごとに適格請求書を発行します。
無料でアカウントを作成 | 料金を見る | OpenAI互換APIとは