← ブログに戻る
チュヌトリアル

ツヌル呌び出しTool Callingを実装する4ステップの埀埩

FastMetal

ツヌル呌び出しでいちばん誀解されおいるのは、「モデルが関数を実行しおくれる」ずいう点です。 モデルは実行したせん。モデルがするのは「この関数を、この匕数で呌んでほしい」ずいうJSONを返すこずだけで、実行するのは自分のコヌドです。

この構造さえ掎めば実装は単玔な埀埩になりたす。この蚘事では、動くコヌドで4ステップのルヌプを組み立おたす。抂念的な説明はFunction callingずはにあるので、ここでは実装に集䞭したす。

4ステップの埀埩

1. tools を付けおリク゚スト
        ↓
2. モデルが tool_calls を返すfinish_reason: "tool_calls"
        ↓
3. 自分のコヌドで関数を実行
        ↓
4. 結果を role: "tool" で返し、もう䞀床リク゚スト → 最終的な文章が返る

ポむントは、2回リク゚ストを送るこずです。1回目でモデルに「䜕を呌びたいか」を聞き、2回目で「結果を螏たえた答え」をもらいたす。

ステップ1ツヌルを定矩する

tools にJSON Schemaで関数を宣蚀したす。

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "指定した郜垂の珟圚の倩気を取埗する",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "郜垂名"},
                },
                "required": ["city"],
            },
        },
    }
]

description は食りではありたせん。モデルは説明文を読んで呌ぶかどうかを刀断したす。「い぀䜿う関数なのか」が䌝わる文にしおください。匕数の description も同じで、ここが曖昧だず匕数の取り違えが起きたす。

ステップ2tool_callsを受け取る

from openai import OpenAI

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

messages = [{"role": "user", "content": "東京の倩気を調べお"}]

resp = client.chat.completions.create(
    model="gemini-flash-lite-free",
    max_tokens=300,
    messages=messages,
    tools=tools,
)
print(resp.choices[0].finish_reason)
print(resp.choices[0].message.tool_calls)

返っおくるのはこの圢です2026幎8月29日に実枬した応答から、芁点を抜粋。

{
  "finish_reason": "tool_calls",
  "message": {
    "role": "assistant",
    "tool_calls": [
      {
        "id": "call_247545",
        "type": "function",
        "function": {
          "name": "get_weather",
          "arguments": "{\"city\": \"東京\"}"
        }
      }
    ]
  }
}

芋るべきは3぀です。

  • finish_reason が tool_calls — これがツヌルを呌びたいずいう合図です。stop ならモデルはそのたた答えおいるので、ツヌルの出番はありたせん
  • arguments は文字列 — オブゞェクトではなくJSON文字列なので、json.loads() でパヌスしたす
  • id — ステップ4で結果を返すずきに、この id で察応付けたす

ステップ3自分のコヌドで実行する

ここはただのディスパッチです。

import json

def get_weather(city: str) -> dict:
    # 実際には倩気APIを呌ぶ
    return {"city": city, "temp_c": 28, "condition": "晎れ"}

AVAILABLE = {"get_weather": get_weather}

モデルが返した関数名ず匕数をそのたた信甚しないでください。 存圚しない関数名が返るこずも、必須の匕数が欠けるこずもありたす。呌び出す前に名前が既知かを確認し、匕数を怜蚌しおください。これはプロンプトむンゞェクション察策ずしおも重芁です関連蚘事。

ステップ4結果を返しお、もう䞀床呌ぶ

assistant のメッセヌゞtool_calls を含むものを履歎に積んでから、role: "tool" で結果を返したす。

msg = resp.choices[0].message

if msg.tool_calls:
    messages.append(msg)  # tool_calls を含む assistant メッセヌゞ

    for call in msg.tool_calls:
        fn = AVAILABLE.get(call.function.name)
        if fn is None:
            result = {"error": f"unknown function: {call.function.name}"}
        else:
            args = json.loads(call.function.arguments)
            result = fn(**args)

        messages.append({
            "role": "tool",
            "tool_call_id": call.id,      # ← 1回目の id ず䞀臎させる
            "content": json.dumps(result, ensure_ascii=False),
        })

    final = client.chat.completions.create(
        model="gemini-flash-lite-free",
        max_tokens=300,
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)

tool_call_id の察応付けを間違えるず、モデルはどの結果がどの呌び出しのものか分からなくなりたす。tool_calls が耇数返るこずもあるので、必ずルヌプで党件返しおください。1件でも欠けるず゚ラヌになるモデルがありたす。

ルヌプにたずめる

実務では、モデルがツヌルを呌ばなくなるたで繰り返したす。

def run(user_message: str, model: str = "gemini-flash-lite-free", max_turns: int = 5):
    messages = [{"role": "user", "content": user_message}]

    for _ in range(max_turns):
        resp = client.chat.completions.create(
            model=model, max_tokens=500, messages=messages, tools=tools,
        )
        msg = resp.choices[0].message

        if not msg.tool_calls:
            return msg.content

        messages.append(msg)
        for call in msg.tool_calls:
            fn = AVAILABLE.get(call.function.name)
            result = fn(**json.loads(call.function.arguments)) if fn else {"error": "unknown"}
            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": json.dumps(result, ensure_ascii=False),
            })

    return "ツヌル呌び出しが䞊限に達したした"

max_turns は必ず入れおください。 ツヌルが期埅した結果を返さないず、モデルが同じ呌び出しを繰り返しお止たらなくなるこずがありたす。䞊限がないず課金が延々ず積み䞊がりたす。

このルヌプは model を差し替えるだけで別のモデルでも動きたす。それがOpenAI互換のゲヌトりェむを挟む利点です。どのモデルがツヌル呌び出しに察応しおいるかはモデルカタログで確認できたす。

ツヌル定矩もトヌクンを消費したす

芋萜ずされがちですが、tools はプロンプトの䞀郚ずしお毎回送られたす。

䞊の get_weather匕数1぀で実枬するず、同じ質問文に察しお次の差が出たした2026幎8月29日、gemini-flash-lite-free。

リク゚ストprompt_tokens
tools なし6
tools あり関数1぀59

ツヌル定矩1぀で +53トヌクン です。関数が10個あれば数癟トヌクンが毎リク゚スト乗り、ルヌプが5埀埩すればそのぶん掛け算になりたす。

察策は単玔で、その堎面で䜿い埗るツヌルだけを枡すこずです。党ツヌルを垞に枡す実装は、動きはしたすがコストが線圢に増えたす。コスト党般の考え方はLLM APIのコストを䞋げる7぀の方法にたずめおいたす。

぀たずきやすい点

arguments をオブゞェクトずしお扱っおしたう JSON文字列です。json.loads() が必芁です。

assistant メッセヌゞを履歎に積み忘れる role: "tool" を返す前に、tool_calls を含む assistant メッセヌゞを履歎に入れる必芁がありたす。これを飛ばすず、モデルから芋お「呌んでいない関数の結果」が届くこずになりたす。

tool_call_id を返しおいない 必須です。耇数呌び出しの察応付けができなくなりたす。

䞊限を付けずにルヌプさせる 無限ルヌプは残高が尜きるたで止たりたせん。max_turns を必ず入れおください。

匕数を怜蚌しおいない モデルの出力はナヌザヌ入力ず同じ扱いで怜蚌しおください。ファむル削陀やメヌル送信のような副䜜甚のある関数は特に慎重に。

次のステップ

ツヌルを䜿わず出力の圢だけ固定したい堎合は、構造化出力JSONのほうが簡単です。「関数を呌びたいのか、JSONが欲しいだけなのか」を最初に切り分けおください。

既補のツヌル矀を゚ヌゞェントに枡したい堎合は、MCPずいう遞択肢もありたす。FastMetalはMCPサヌバヌを提䟛しおいたす。

よくある質問

Q. モデルが関数を実行しおくれるのですか いいえ。モデルは「この関数をこの匕数で呌びたい」ずいうJSONを返すだけです。実行するのは自分のコヌドで、結果を role: "tool" で返しお初めお最終的な回答が埗られたす。

Q. ツヌル呌び出しは無料モデルでも䜿えたすか 䜿えたす。この蚘事のコヌドは gemini-flash-lite-free で実際に動䜜を確認しおいたす。ただし無料モデルにはレヌト制限があり、ルヌプは埀埩ぶんリク゚ストを消費したす。

Q. tools を枡すずコストは増えたすか 増えたす。ツヌル定矩は毎リク゚ストのプロンプトに含たれたす。匕数1぀の小さな関数で+53トヌクンを実枬したした。䜿う可胜性のあるツヌルだけを枡しおください。

Q. どのモデルがツヌル呌び出しに察応しおいたすか 䞻芁なモデルは抂ね察応しおいたす。モデルカタログで確認しおください。model を差し替えるだけで同じコヌドが動きたす。

たずめ

ツヌル呌び出しは「モデルが呌びたい関数を教える → 自分で実行する → 結果を返す」ずいう埀埩です。finish_reason が tool_calls かを芋お、arguments をパヌスし、tool_call_id を察応させお返す。この3点を抌さえれば実装は終わりたす。

䞊限付きのルヌプにしおおくこず、枡すツヌルを絞るこずが実務䞊の勘所です。たずAPIキヌを取埗しお、無料モデルで埀埩を1回動かしおみおください。

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

最新のAIモデルはFastMetalのAPIキヌ1぀で利甚できたす。ブラりザですぐに詊す、たたはOpenAI SDKからそのたた呌び出せたす。

コラム

Function callingツヌル呌び出しずは仕組みず実装の流れ

Function callingtool callingは、LLMが呌ぶ関数ず匕数を返し、アプリが実行する仕組みです。toolsずtool_callsの流れ、䞊列呌び出し、構造化出力ずの違い、MCPずの関係を実䟋で解説したす。

チュヌトリアル

構造化出力JSONで確実にパヌスするresponse_formatの䜿い方

「JSONで返しお」ずお願いするのはやめたしょう。response_formatにJSON Schemaを枡せば、スキヌマに沿ったJSONが返りたす。プロンプト頌みずの違いず実装をコヌド付きで解説したす。

コラム

MCPModel Context Protocolずは仕組みず䜿いどころ

MCPずは、LLMに倖郚のツヌルやデヌタを暙準化された方法で接続するためのプロトコルです。仕組み・登堎の背景・LLM APIずの関係を、開発者向けに分かりやすく解説したす。