ブログに戻る
コラム

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

FastMetal

Function calling(ツール呼び出し)とは、LLMが自然言語で答える代わりに「この関数を、この引数で呼んでほしい」という構造化されたリクエストを返す仕組みです。 天気の取得、DB検索、社内APIの実行など、モデル単体ではできない処理を、あなたのコードに橋渡しするための機能です。

大事な点を先に言うと、モデルは何も実行しません。実行するのは常にあなたのコードで、モデルは「呼ぶべき関数と引数」を決めるだけです。この記事では、OpenAI互換APIでのリクエストとレスポンスの形、2往復の実装手順、そしてMCPとの関係を整理します。

Function calling とは

通常のChat Completions APIでは、モデルは messages を受け取って文章を返します。Function calling では、リクエストに tools(呼び出せる関数の一覧) を添えます。モデルは質問に答えるために関数が必要だと判断すると、文章ではなく tool_calls(関数名と引数のJSON) を返します。

流れは次の2往復です。

  1. あなた → モデル:質問と tools の定義を送る
  2. モデル → あなた:「get_weather{"city": "東京"} で呼んで」と返す
  3. あなた:実際に関数を実行し、結果を role: "tool" のメッセージとして追加
  4. あなた → モデル:会話全体を再送し、最終的な回答文を受け取る

つまり「モデルが決め、コードが実行し、モデルがまとめる」という分業です。

リクエストの形:tools と tool_choice

関数は JSON Schema で定義します。description はモデルが「いつ呼ぶか」を判断する材料になるので、具体的に書くほど精度が上がります。

curl https://api.fastmetal.ai/v1/chat/completions \
  -H "Authorization: Bearer $FASTMETAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-haiku-4-5",
    "max_tokens": 100,
    "messages": [{"role": "user", "content": "東京の天気を教えて"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "指定した都市の現在の天気を取得する",
        "parameters": {
          "type": "object",
          "properties": {"city": {"type": "string"}},
          "required": ["city"]
        }
      }
    }],
    "tool_choice": "auto"
  }'

tool_choice は次のように使い分けます。

挙動
"auto"必要なときだけ関数を呼ぶ(既定)
"none"関数を呼ばず文章で答える
{"type": "function", "function": {"name": "get_weather"}}指定した関数を必ず呼ぶ

レスポンスの形:tool_calls を読む

上のcurlを実際にFastMetal経由で送ると、モデルは文章ではなく次のような応答を返しました。

{
  "choices": [{
    "finish_reason": "tool_calls",
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "tooluse_zkeBIqkFBMVBb1LFnySfQu",
        "type": "function",
        "function": {
          "name": "get_weather",
          "arguments": "{\"city\": \"東京\"}"
        }
      }]
    }
  }],
  "usage": {"prompt_tokens": 634, "completion_tokens": 66}
}

読み方のポイントは3つです。

  • finish_reason"tool_calls" なら、モデルは関数の実行を求めています。"stop" なら通常の回答です。
  • **arguments はJSONオブジェクトではなく「JSON文字列」**です。必ず json.loads などでパースしてから使います。
  • id は次の往復で必要です。実行結果を返すときに、どの呼び出しへの答えかを tool_call_id で示します。

もう一つ、usage に注目してください。「東京の天気を教えて」という短い質問なのに prompt_tokens が634あります。tools の定義はプロンプトの一部として毎回送られ、入力トークンとして課金されます。 関数を何十個も登録すると、質問が一言でも毎回それなりの入力量になる点は、設計時に覚えておくと良いでしょう。

実装の流れ:2往復をPythonで書く

OpenAI SDK の base_url を差し替えるだけで、そのままFastMetalに向けられます。

import json
from openai import OpenAI

client = OpenAI(
    api_key="<FASTMETAL_API_KEY>",
    base_url="https://api.fastmetal.ai/v1",
)

def get_weather(city: str) -> dict:
    # 実際には天気APIなどを呼ぶ
    return {"city": city, "weather": "晴れ", "temp_c": 31}

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "指定した都市の現在の天気を取得する",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "東京の天気を教えて"}]

# 1往復目:モデルに「どの関数を呼ぶか」を決めてもらう
first = client.chat.completions.create(
    model="anthropic-claude-haiku-4-5",
    messages=messages,
    tools=tools,
    tool_choice="auto",
)
msg = first.choices[0].message

if first.choices[0].finish_reason == "tool_calls":
    # assistant のメッセージ(tool_calls 入り)をそのまま履歴に追加
    messages.append(msg)

    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)  # 文字列 → dict
        result = get_weather(**args)                # 実行するのは自分のコード
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result, ensure_ascii=False),
        })

    # 2往復目:結果を踏まえた最終回答をもらう
    final = client.chat.completions.create(
        model="anthropic-claude-haiku-4-5",
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)
else:
    print(msg.content)

複数の tool_calls が一度に返ることもあるので、ループで全件処理してから2往復目に進むのが基本形です。

MCP との関係

Function calling と混同されやすいのがMCP(Model Context Protocol)です。役割は次のように分かれます。

  • Function calling:1回のリクエストの中で「関数をどう呼ぶか」を表現する仕組み。APIのパラメータそのもの。
  • MCP:ツールをどう公開し、どう発見し、どう接続するかを標準化したプロトコル。エージェントやエディタが外部ツールを共通の方法で扱うための「規格」。

ざっくり言えば、MCPで接続したツールの一覧が、最終的には tools としてモデルに渡され、Function calling で呼び出されます。FastMetalもMCPサーバーを提供しており、Claude Code などのエージェントから同じAPIキーで利用できます。

使うときの注意点

  • 対応状況はモデルごとに異なります。 互換APIでも、ツール呼び出しの精度や tool_choice の細かな挙動はモデル依存です。本番で使う前に、対象モデルで一度実際に呼んで確認してください。利用できるモデルはモデルカタログにまとめています。
  • 引数の検証は自分で行う。 モデルが返す arguments はスキーマに沿う「はず」ですが、必須項目の欠落や型の揺れは起こりえます。実行前にバリデーションを挟むのが安全です。
  • 副作用のある関数は慎重に。 送金や削除のような処理は、モデルの判断だけで実行させず、確認ステップを入れましょう。

よくある質問

Q. モデルが関数を実行してくれるのですか? いいえ。モデルは「どの関数を、どの引数で呼ぶべきか」を返すだけです。実行するのはあなたのコードで、結果を role: "tool" のメッセージとして返すことで、モデルが最終回答をまとめます。

Q. arguments はそのまま使えますか? 使えません。arguments はJSON形式の「文字列」なので、json.loads などでパースしてから関数に渡します。パース後に型や必須項目の検証も行うと安全です。

Q. Function calling と MCP はどう違いますか? Function calling は1回のリクエスト内で関数呼び出しを表現するAPIの仕組み、MCP はツールの公開・発見・接続を標準化するプロトコルです。MCPで接続したツールが、最終的に tools としてモデルに渡されるという関係です。

まとめ

Function calling は「モデルが決め、コードが実行し、モデルがまとめる」2往復の仕組みです。tools の定義、finish_reason: "tool_calls" の判定、arguments のパース、role: "tool" での結果返却──この4点を押さえれば、OpenAI互換APIのどのモデルでも同じコードで扱えます。まずはドキュメントを参考に、上のcurlをそのまま送ってみてください。

最新のAIモデルを今すぐ試す

最新のAIモデルはFastMetalのAPIキー1つで利用できます。ブラウザですぐに試す、またはOpenAI SDKからそのまま呼び出せます。