powered by TechFeed
表示モード
Deep Dive

AIエージェントは「自分でツールを実行しない」 — LLMが判断しコードが動くツールコーリングの仕組みを図解

6月22日、Toward Data Scienceが「Tool Calling, Explained: How AI Agents Decide What to Do Next」と題した記事を公開した。「AIエージェントがツールを使う」という表現は広く普及しているが、モデル自身がAPIを叩いていると思っているなら、それは誤解だ。LLMはあくまで「何をどう呼ぶか」を判断するだけで、実行するのは別のコードである——この構造的分離を正確に理解しているかどうかが、エージェント設計の精度を大きく左右する。

6月22日、Toward Data Scienceが「Tool Calling, Explained: How AI Agents Decide What to Do Next」と題した記事を公開した。「AIエージェントがツールを使う」という表現は広く普及しているが、モデル自身がAPIを叩いていると思っているなら、それは誤解だ。LLMはあくまで「何をどう呼ぶか」を判断するだけで、実行するのは別のコードである——この構造的分離を正確に理解しているかどうかが、エージェント設計の精度を大きく左右する。


LLMは「テキストを返す機械」から「行動する機械」へ

LLMをチャットボット的な用途で使う場合、モデルは「質問を受け取り、答えを返す」受動的な役割を担う。しかし、ツールコーリング(Tool Calling)という仕組みを使うと、モデルはリアルタイムデータの取得、外部APIの呼び出し、データベースへのクエリなど、実際のアクションをトリガーできるようになる。

ここで最も重要な点を押さえておきたい。モデル自身はツールを実行しない。モデルが行うのは「どのツールを、どの引数で呼ぶか」という判断だけだ。実際の実行はアプリケーション側のコードが担う。

ツールコーリングのループは以下の4ステップで構成される:

  1. ユーザーがメッセージを送信する
  2. モデルがメッセージを受け取り、「どのツールをどの引数で呼ぶか」を決定する(テキスト応答ではなく、構造化された「ツール呼び出し指示」を返す)
  3. アプリケーション側のコードがその指示に従ってツールを実行し、結果をモデルに渡す
  4. モデルがツールの実行結果を踏まえて、ユーザー向けの最終的なテキスト応答を生成する


実装の核心:モデルに「ツールの説明」を渡す

ツールをモデルに登録する際、実際のAPI実装はここには登場しない。モデルが参照するのは関数名・説明文・パラメータのスキーマだけだ。

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "Get the current weather for a given city",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "The name of the city, e.g. Athens"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "The temperature unit to use"
                    }
                },
                "required": ["city"]
            }
        }
    }
]

モデルはこの説明文だけを手がかりに、ユーザーのメッセージに対してどのツールを呼ぶべきかを判断する。descriptionの質がそのまま判断精度に直結するため、説明文の書き方は実装上の重要なポイントになる。

モデルへのリクエストに対して返ってくるレスポンスはこうなる:

ChatCompletionMessage(
    content=None,
    role='assistant',
    tool_calls=[
        ChatCompletionMessageToolCall(
            id='call_abc123',
            type='function',
            function=Function(
                name='get_current_weather',
                arguments='{"city": "Athens", "unit": "celsius"}'
            )
        )
    ]
)

contentNoneになっている点が重要だ。モデルはテキストではなく、ツール呼び出しの指示を返している。アプリ側はこれを受け取り、実際にAPIを叩いて結果をモデルに返す。最終的にモデルは以下のような自然言語応答を生成する:

It's currently 29°C in Athens. Sounds like a great day to be outside!

なお、天気データの取得にはOpen-Meteo(APIキー不要のオープンソース天気API)が使用されている。


複数ツールの選択と並列呼び出し

実際のエージェントでは、モデルは複数のツールにアクセスする。記事では天気APIに加えて通貨換算ツール(Frankfurter)を追加した例を紹介している。

ユーザーが「100ドルは何ユーロ?」と聞けばモデルはconvert_currencyを選び、天気を聞けばget_current_weatherを選ぶ。どちらにも関係しない質問ならツールを呼ばずにテキストだけで応答する。この自律的なツール選択の仕組みこそが、エージェント的なシステムの基盤になる。

さらにgpt-4oなどのモデルは、1回のレスポンスで複数のツールを同時に呼び出すパラレルツールコーリングにも対応している。「アテネの天気と100ドルのユーロ換算を教えて」という1つのリクエストに対して、モデルはtool_calls配列に複数のエントリを同時に返す:

tool_calls=[
    ChatCompletionMessageToolCall(
        id='call_def456',
        type='function',
        function=Function(
            name='get_current_weather',
            arguments='{"city": "Athens"}'
        )
    ),
    ChatCompletionMessageToolCall(
        id='call_ghi789',
        type='function',
        function=Function(
            name='convert_currency',
            arguments='{"amount": 100, "from_currency": "USD", "to_currency": "EUR"}'
        )
    )
]

これにより、ツールを逐次実行するよりもレスポンスタイムを短縮できる。


なぜ今ツールコーリングを理解すべきか

OpenAIのFunction Callingはすでに広く知られているが、「モデルがツールを実行する」という誤解は依然として多い。モデルは判断し、コードが実行するというアーキテクチャの分離を正確に把握していないと、エラーの原因究明やセキュリティ設計で躓く。LangChainLlamaIndexなどのエージェントフレームワークが内部でこの仕組みを使っているため、フレームワークを使う前にプリミティブな動作を理解しておく価値は大きい。

詳細はTool Calling, Explained: How AI Agents Decide What to Do Nextを参照していただきたい。