テーマ
言語
·2 分で読めます

LLM APIでの関数呼び出し:完全に動作するループ

OpenAI互換APIで関数呼び出し(ツール使用)がどのように機能するかを解説します。GPT-6 Luna、DeepSeek V4.1 Flash、Claude Haiku 5.5で実行した完全なPythonループ、tool_choiceによる呼び出しの強制、Anthropic Messages形式を紹介します。

LLM APIでの関数呼び出し:完全に動作するループ

Function calling(tool callingまたはtool useとも呼ばれます)は、モデルにコードへのアクセス権を与える方法です。「注文を検索する」や「配送料を見積もる」といった関数を説明すると、モデルが呼び出す関数と引数を決定し、コードがそれを実行して結果を返します。ストアのサポートボットから Claude Code まで、あらゆるエージェントはこのループを基盤に構築されています。

GetVibe APIでは、Function callingはOpenAI形式の標準/v1/chat/completionsエンドポイントと、Anthropic形式の/v1/messagesを通じて利用できます。以下は、3つの異なるメーカーの3つのモデルで実行した完全なループです。

ループの仕組み

  1. toolsのリストとともにメッセージを送信します。各ツールには、名前、説明、パラメータ用のJSON Schemaが含まれます。
  2. モデルはテキストの代わりにtool_callsを返します。そこには、呼び出す関数と引数が含まれます。finish_reasonはtool_callsです。
  3. コードで関数を実行し、呼び出しごとに、同じtool_call_idを持つtoolロールのメッセージを1つ追加します。
  4. 履歴を再び送信します。モデルは追加の呼び出しを求めるか、テキストでユーザーに回答します。

モデル自身が何かを実行することはありません。モデルは呼び出しを要求するだけです。実際に何を実行するか、どの権限で実行するかは、コードによって決まります。

完全な例:ストアのサポートアシスタント

2つの関数を用意します。注文状況の確認と、配送料の見積もりです。ユーザーが両方について一度に質問し、モデルが1ターンで両方を呼び出します。

import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://getvibeapi.com/v1", api_key=os.environ["GETVIBE_API_KEY"])
MODEL = "gpt-6-luna"

def get_order_status(order_id: str) -> dict:
    # データベースまたはCRMでの検索処理をここに記述します
    return {"order_id": order_id, "status": "out for delivery", "eta": "2026-10-24"}

def get_shipping_quote(zip_code: str) -> dict:
    return {"zip_code": zip_code, "price_usd": 7.5, "days": 2}

TOOLS = [
    {"type": "function", "function": {
        "name": "get_order_status",
        "description": "Look up an order by its ID",
        "parameters": {"type": "object",
                       "properties": {"order_id": {"type": "string", "description": "Order ID, e.g. A-1042"}},
                       "required": ["order_id"]}}},
    {"type": "function", "function": {
        "name": "get_shipping_quote",
        "description": "Courier shipping price and delivery time to a US ZIP code",
        "parameters": {"type": "object",
                       "properties": {"zip_code": {"type": "string"}},
                       "required": ["zip_code"]}}},
]
FUNCTIONS = {"get_order_status": get_order_status, "get_shipping_quote": get_shipping_quote}

messages = [
    {"role": "system", "content": "あなたはストアのサポートアシスタントです。簡潔に回答してください。"},
    {"role": "user", "content": "注文 A-1042 はどこですか?また、94110 への送料はいくらですか?"},
]

for _ in range(5):  # ラウンド数の上限
    resp = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
    msg = resp.choices[0].message
    if not msg.tool_calls:
        print(msg.content)
        break
    messages.append(msg.model_dump(exclude_none=True))
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = FUNCTIONS[call.function.name](**args)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

このコードを変更せずにgpt-6-luna、deepseek-v4.1-flash、claude-haiku-5.5で実行し、変更したのはMODELだけです。最初のラウンドでは、3つのモデルすべてが両方の関数を呼び出しました。get_order_statusにはA-1042を、get_shipping_quoteには94110を渡しています。2回目のラウンドでは、3つのモデルすべてがテキストで回答し、配送状況、到着予定時刻、7.50の料金、2日間の配送時間を返しました。

このコードで重要な点

  • モデルのtool-callメッセージ全体を履歴に追加します。これを行わないと、toolメッセージがモデルから見えない呼び出しに回答することになります。その結果、多くのモデルは同じ関数を再び呼び出すだけになり、ループが無限に繰り返されます。
  • 呼び出しごとに、対応するtool_call_idを持つtoolメッセージを1つ送信します。今回の例のように、モデルが一度に複数の呼び出しを求める場合があります。
  • 引数は文字列として届きます。argumentsは文字列内のJSONです。モデルが値を間違える可能性があるため、解析して検証してください。
  • ラウンド数に上限を設定します。上限がないと、関数のバグによってループが無限に続き、トークン料金も無限に発生する可能性があります。

tool_choice:呼び出しを必須にする場合

デフォルトでは、ツールを呼び出すかテキストで回答するかをモデルが判断します("auto")。tool_choiceを使うと、この動作を変更できます。

  • "none" — ツールを呼び出しません。
  • "required" — 少なくとも1つのツールを呼び出します。
  • {"type": "function", "function": {"name": "..."}} — 指定した関数を呼び出します。

最後の形式は、データ抽出に便利です。関数のパラメータスキーマが回答の形式になります。

curl https://getvibeapi.com/v1/chat/completions \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [{"role": "user", "content": "Jane Doe, [email protected], wants a demo on Thursday"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "save_lead",
        "description": "Save a sales lead to the CRM",
        "parameters": {
          "type": "object",
          "properties": {"name": {"type": "string"}, "email": {"type": "string"}, "request": {"type": "string"}},
          "required": ["name", "email", "request"]
        }
      }
    }],
    "tool_choice": {"type": "function", "function": {"name": "save_lead"}}
  }'

レスポンスはsave_leadの呼び出しとなり、nameは「Jane Doe」、emailは「[email protected]」、requestは「Wants a demo on Thursday」でした。

注意点が1つあります。Claude Sonnet 5.5やClaude Opus 5.5など、一部のClaudeモデルは強制されたtool choiceを受け付けません。GetVibeはこのようなリクエストを、同じツールを使うautoに変換します。そのためエラーの代わりに回答を得られますが、その後に呼び出しを行うかどうかはモデル自身が判断します。これらのモデルから厳密なJSONを取得するには、structured outputsを使用してください。

Anthropic形式:/v1/messages

Anthropic SDKでは、ツールの形式が少し異なります。パラメータスキーマはinput_schemaに指定し、呼び出しはtool_useのcontent blockとして返されます。

curl https://getvibeapi.com/v1/messages \
  -H "x-api-key: $GETVIBE_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-haiku-5.5",
    "max_tokens": 512,
    "tools": [{
      "name": "get_order_status",
      "description": "Look up an order by its ID",
      "input_schema": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}
    }],
    "messages": [{"role": "user", "content": "Where is order A-1042?"}]
  }'

レスポンスのstop_reasonはtool_useで、order_idにA-1042を指定してget_order_statusを呼び出すtool_useブロックが含まれていました。結果は、次のユーザーメッセージ内のtool_resultブロックとして、同じtool_use_idを付けて返します。

ツールにはどのモデルを使うべきか

  • 大量トラフィックのボットやシンプルなツール — DeepSeek V4.1 Flash($0.0112 入力 · $0.0445 出力 100万トークンあたり)またはClaude Haiku 5.5($0.0267 入力 · $0.1334 出力 100万トークンあたり)。
  • 多数のツールと長い計画を扱うエージェント — GPT-6 Luna($0.0055 入力 · $0.0274 出力 100万トークンあたり)またはClaude Sonnet 5.5。

エージェントのループでは、ラウンドごとに同じ長いプレフィックスを再送信するため、ここではprompt cachingが非常に重要です。リクエストフィールドの詳細については、tool callingのドキュメントをご覧ください。

関数呼び出し APILLMのツール呼び出しOpenAI 関数呼び出し サンプルtool_choiceAnthropic ツール使用LLMエージェント ツール

GetVibe APIを無料で試す

1つのOpenAI互換APIでGPT、Claude、Geminiなどを利用できます。カードまたは暗号資産で米ドル払いに対応しています。

関連記事

LLM APIでの関数呼び出し:完全に動作するループ | GetVibe API