About

Function Callingとは?LLMがJSONで外部ツールを呼ぶ仕組み

関数スキーマを渡す → モデルが引数を選ぶ → 実行結果を返す、の流れ

先に結論。Function Callingは、モデルが関数を「実行」する機能ではない。「この関数をこの引数で呼んでほしい」というJSONを返すだけで、実行するのは自分のコードだ。この記事を読めば、その往復を自分で組めるし、構造化出力・MCPとの違いも見分けられる。

1往復の流れ

リクエストにツール一覧(名前・説明・JSON Schema)を一緒に送る。モデルがツールが要ると判断すると、テキストの代わりに呼び出しを返す。Claudeはstop_reasonがtool_useで、tool_useブロックが来る。OpenAIは名前とJSON「文字列」の引数が入ったfunction callが来る。

自分のコードがそれを実際に実行し、結果に呼び出しのidを付けて送り返す(Claudeならtool_resultのtool_use_id)。モデルは結果を読んで答えるか、また呼ぶ。

The model asks. Your code runs.Your appModel API1. question + tools (name, schema)2. tool_use {name, input}3. you run it4. tool_result {tool_use_id}5. answer, or another callCap the loop (our chat stops at 5). If the arguments fail to parse, send the error back as the result.
{"type": "tool_use", "id": "toolu_01...", "name": "get_weather", "input": {"location": "Tokyo"}}

うちのコードで見たこと

このリポジトリの社内チャット機能も、この往復を回している(Azure OpenAI)。読んでみて、2か所が目に付いた。

ループの上限。 呼び出し → 結果 → また呼び出し、が延々と続きうるので、5回で打ち切っている(MAX_TOOL_ITERATIONS = 5)。これがないと、モデルが同じツールを呼び続けたときに料金だけがかさむ。

壊れた引数。 うちのコードは引数JSONのパースに失敗すると、ログだけ残して空のハッシュ{}に置き換え、そのまま実行する。rails runnerで途中で切れたJSON({"name": "nega)を入れてみると、本当に{}が返ってきた。検索ツールなら条件なしの検索が走る。

最初は「エラーなら止まるだろう」と思っていたが、止まらなかった。直すなら、パース失敗もツールの結果としてモデルに返すほうがいい。知らないツール名はすでにそうしていて、{"error": "Unknown function: ..."}を返す。いまはツール定義にstrict: trueを付けてスキーマを強制することもできる(Claude・OpenAIとも)。

構造化出力・MCPと何が違うか

Function Calling  モデルが「これを呼んで」と出す → 自分のコードが実行 → 結果を戻す
構造化出力        答えそのものをスキーマ通りのJSONで受け取る → 実行するものはない
MCP               ツールをどこからどう取ってくるかの規格 → モデルには結局ツール定義として渡る

分類や抽出のように結果がJSONならいいだけなら、構造化出力のほうが単純だ。外のシステムを読んだり変えたりするならFunction Calling。同じツールを複数のアプリやクライアントで使いたくなったら、そこでMCPで包む。MCPについてはMCPの記事にある。

気をつけること

モデルは書き込み系のツールも、もっともらしく呼ぶ。削除・決済・メールのようなツールは、人の確認を挟むか、最初から渡さない。DBを見せるときに書き込みをDB権限で止めた話はこの記事に書いた。

社内システムにAIをつなぎたいけれど、どのツールをどこまで開けるか決めかねているならnegabaroに相談してもらって構わない。ツール一覧と権限の整理から一緒にできる。

キーコンセプト

1

リクエストにツール一覧(名前・説明・JSON Schema)を一緒に送る

2

モデルがテキストの代わりに呼び出しを返す(Claude: stop_reason tool_use + tool_useブロック)

3

自分のコードが引数を確かめて実際に実行する — パース失敗を黙って{}にしない

4

結果に呼び出しidを付けて送り返す(Claude: tool_resultのtool_use_id)

5

モデルが答えるか、また呼ぶ — ループには上限を置く

メリット

  • ✓ リアルタイムデータ・計算・社内システムをツールで補う
  • ✓ 引数がJSONなのでコードで受けやすい
  • ✓ 実行権限が自分のコードにあるので、止める場所がはっきりしている

デメリット

  • ✗ モデルが間違ったツール・引数を選ぶことがある
  • ✗ 書き込み系ツールは権限・人の確認を別に設計する必要がある
  • ✗ 往復が増えるほどトークン・遅延が増える

ユースケース

Claude Tool Use・OpenAI Function Calling 社内チャットボットのDB照会・社内データ検索 AIコーディングアシスタントのファイル読み書き 複数ツールを続けて呼ぶエージェント
← Chain-of-Thought(CoT)とは?段階的に考えさせて推論を強くする 量子化(Quantization)とは?重みを低精度にしてモデルを軽くする →