AI にツール呼び出し機能が必要な理由

大規模言語モデルは強力ですが、本質的な限界があります。リアルタイム情報を取得できず、コードを実行できず、外部システムを操作できません。Function Calling(関数呼び出し)は、まさにこれらの問題を解決するために生まれました。AI が人間がツールを使うように、外部 API や関数を自律的に選択して呼び出し、モデルの境界を突破できるようにします。

次のシナリオを想像してください。ユーザーが「今日の北京の天気は?」と尋ねます。純粋なテキストモデルは、トレーニングデータが特定の日付で終了しているため、答えることができません。しかし、Function Calling を備えた AI は次のように行動します。天気 API を呼び出す必要があると認識 → 正しい API リクエストを構築 → 返された JSON データを解析 → 自然言語でユーザーに返答します。これがツール呼び出しループの魅力です。

Function Calling の仕組み

Function Calling は、AI が実際に関数を呼び出すのではなく、巧妙に設計されたプロトコルです。

  1. ツールの定義:開発者はモデルに利用可能な関数(名前、パラメータ、目的)を記述します。
  2. モデルの決定:AI はユーザー入力を分析し、ツールを呼び出すかどうか、どのツールを呼び出すか、どのパラメータを渡すかを決定します。
  3. 開発者の実行:開発者のコードが実際の関数呼び出しを実行します。
  4. 結果のフィードバック:実行結果がモデルに返され、モデルはそれに基づいて最終応答を生成します。

このプロトコルの巧妙さは、AI が「何をするかを決定」する一方で、実際の実行権限は常に開発者にあるため、安全性と制御性が保証される点です。

スキルチェーン分解:ツールオーケストレーションチェーン

「ツールオーケストレーションチェーン」スキルチェーンを例に、各ノードがツール呼び出しフローで果たす役割を分解します。

ノード 1:要件理解(sp-188)—AI はまずユーザーの意図を正確に理解する必要があります。ユーザーが「最近のフライトを調べて」と言った場合、AI はこれが外部ツールの呼び出しを必要とするタスクであり、単純なテキストの Q&A ではないと認識する必要があります。

ノード 2:ツール選択(sp-179)—利用可能なツールセットから最も適切なツールを選択します。ユーザーがフライトを調べたい場合、天気 API ではなくフライト検索 API を呼び出す必要があります。このノードでは、AI に「ツールマッチング」能力が求められます。

ノード 3:ツール呼び出し(sp-181)—正しいパラメータを構築して呼び出しを実行します。AI はユーザーの曖昧な要求(例:「最近のフライト」)を正確な API パラメータ(例:date=2026-07-13, from=北京, to=上海)に変換する必要があります。

ノード 4:結果解析(sp-187)—API が返した構造化データを、ユーザーにわかりやすい自然言語の応答に変換します。フライト検索では数十件の JSON データが返されるかもしれませんが、ユーザーが必要とするのは最も関連性の高い 2〜3 件だけです。

実践:マルチツール Agent の構築

以下のコードは、複数のツールを備えた Agent Loop の実装を示しています。

import json
from openai import OpenAI
import requests

client = OpenAI(
    api_key="your-deepseek-api-key",
    base_url="https://api.deepseek.com"
)

# 利用可能なツールを定義
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "指定された都市のリアルタイムの天気情報を取得します",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "都市名、例:北京"}
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "インターネットで最新情報を検索します",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "検索キーワード"},
                    "num_results": {"type": "integer", "description": "返す結果の数"}
                },
                "required": ["query"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "数学計算を実行します",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {"type": "string", "description": "数式"}
                },
                "required": ["expression"]
            }
        }
    }
]

# ツール実装関数
def execute_tool(tool_name, arguments):
    if tool_name == "get_weather":
        city = arguments.get("city")
        # 実際のプロジェクトでは天気 API を呼び出します
        return f"{city} は今日晴れ、気温 25°C、湿度 60%"
    elif tool_name == "search_web":
        query = arguments.get("query")
        return f"'{query}' の検索結果:関連情報が 3 件見つかりました..."
    elif tool_name == "calculate":
        expression = arguments.get("expression")
        try:
            result = eval(expression)
            return f"計算結果:{expression} = {result}"
       except:
            return "計算式が無効です"
    return "不明なツール"

class ToolCallingAgent:
    def __init__(self, max_iterations=5):
        self.max_iterations = max_iterations
        self.messages = []

    def run(self, user_input):
        self.messages = [{
            "role": "system",
            "content": "あなたはタスクを完了するためにツールを使用できるインテリジェントアシスタントです。段階的に考え、適切にツールを使用してください。"
        }, {
            "role": "user",
            "content": user_input
        }]

        for i in range(self.max_iterations):
            print(f"=== 第 {i+1} ラウンド ===")

            response = client.chat.completions.create(
                model="deepseek-chat",
                messages=self.messages,
                tools=tools
            )

            msg = response.choices[0].message

            # モデルが直接返答する場合
            if msg.content and not msg.tool_calls:
                return msg.content

            # モデルがツールを呼び出す場合
            if msg.tool_calls:
                self.messages.append(msg)

                for tool_call in msg.tool_calls:
                    func_name = tool_call.function.name
                    func_args = json.loads(tool_call.function.arguments)
                    print(f"ツール呼び出し: {func_name}({func_args})")

                    result = execute_tool(func_name, func_args)

                    self.messages.append({
                        "role": "tool",
                        "tool_call_id": tool_call.id,
                        "content": result
                    })

        return "最大反復回数に達しました"

# 使用例
agent = ToolCallingAgent(max_iterations=5)
result = agent.run("今日の北京の天気は?また、156 * 23 + 89 を計算して。")
print(f"最終返答: {result}")

re>

ツール呼び出しのベストプラクティス

ツールの説明を正確に:モデルのツール選択は、ツールの説明に完全に依存します。説明が明確であればあるほど、選択は正確になります。各ツールの説明には、機能説明、適用シナリオ、パラメータの詳細、戻り値の形式を含めることをお勧めします。

パラメータ検証は必須:モデルが不合理なパラメータを生成する可能性があります。execute_tool では常にパラメータ検証を行い、パラメータエラーによるツール呼び出しの失敗を防ぎます。

エラーをモデルにフィードバック:ツール呼び出しが失敗した場合、単にエラーメッセージを返すのではなく、構造化されたエラー説明をモデルに返し、戦略を調整する機会を与えます。例:「天気 API の呼び出しに失敗:都市名「北惊」は存在しません。「北京」を使用することをお勧めします」。

ツールの数を制御:利用可能なツールが多すぎると、モデルの選択が難しくなります。ツールの数を10個以内に抑えるか、ツールをグループ化し、コンテキストに応じて動的に提供することをお勧めします。

ツール呼び出しとエージェントループの深い統合

ツール呼び出しは一度きりの操作ではなく、エージェントループに組み込まれた継続的なプロセスです。1回のツール呼び出しの結果が次のツール呼び出しを引き起こす可能性があります。例えば、まず「AI分野の最新論文」を検索し、検索結果の論文タイトルに基づいて、PDF解析ツールを呼び出して論文の詳細を取得します。このようなチェーン型ツール呼び出しは、エージェントループの強力な能力の表れです。

このスキルチェーンを自分で編成してみませんか?

スキルチェーンで開く →