Function Calling(関数呼び出し)入門ガイド — AIを実務で活用する仕組みを理解する

AI

Function Calling(関数呼び出し)入門ガイド – AIを実務で活用する仕組みを理解する

はじめに

2023年、OpenAIがGPT-4に「Function Calling」機能を追加したことで、AI開発の世界は大きく変わりました。それまで、ChatGPTは「会話するだけのAI」でしたが、Function Callingによって「外部システムと連携できるAI」へと進化したのです。

Function Callingとは何か

**Function Calling(関数呼び出し)**とは、大規模言語モデル(LLM)が外部のツールやAPIを呼び出すための仕組みです。従来、LLMはテキストを入力してテキストを出力するだけの存在でした。しかし、Function Callingを使うことで、LLMは「天気予報を取得する関数」「データベースを検索する関数」「メールを送信する関数」などを呼び出し、その結果を踏まえてより正確で実用的な回答を提供できるようになります。

なぜFunction Callingが重要なのか

Function Callingが重要な理由は、主に以下の3点に集約されます:

  1. 実務での活用が可能になる
    従来のLLMは「情報を知っている」だけで、「アクションを起こす」ことはできませんでした。Function Callingを使えば、LLMを業務システムの一部として組み込み、実際の業務フローを自動化できます。

  2. ハルシネーション(幻覚)の軽減
    LLMが苦手とする分野(最新情報、専門的な計算、社内データなど)を外部APIで補完することで、より正確な回答が可能になります。

  3. 開発の効率化
    自然言語でユーザーの意図を理解し、適切なAPIを呼び出す処理をLLMに任せられるため、開発者は複雑なパース処理を書く必要がなくなります。


Function Callingの仕組み

Function Callingの動作フローは、以下の4つのステップで構成されます:

ステップ1: プロンプトと関数定義の送信

ユーザーがLLMにメッセージを送る際、同時に「使用可能な関数の定義」も送信します。関数定義には、関数名、説明、パラメータ(引数)のスキーマが含まれます。

{
  "name": "get_weather",
  "description": "指定した都市の現在の天気を取得します",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "都市名(例: 東京、大阪)"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "温度の単位"
      }
    },
    "required": ["city"]
  }
}

ステップ2: LLMが関数呼び出しを判断

LLMはユーザーのメッセージを解析し、関数を呼び出すべきかどうかを判断します。関数呼び出しが必要な場合、LLMはテキスト応答ではなく、関数名と引数を含む構造化データを返します。

{
  "function_call": {
    "name": "get_weather",
    "arguments": "{\"city\": \"東京\", \"unit\": \"celsius\"}"
  }
}

ステップ3: 関数の実行

開発者はLLMから返された関数呼び出し情報を受け取り、実際に関数を実行します。この処理は開発者側のコードで行われます。関数の実行結果は、次のステップでLLMに送り返されます。

# 開発者側での実装例
weather_data = get_weather(city="東京", unit="celsius")
result = json.dumps(weather_data)
# {"temperature": 18, "condition": "晴れ", "humidity": 45}

ステップ4: 結果をLLMに返却して最終回答を生成

関数の実行結果をLLMに送信すると、LLMはその結果を踏まえてユーザーへの最終回答を生成します。

ユーザー: 東京の天気を教えて

アシスタント: 東京の現在の天気は晴れで、気温は18°Cです。湿度は45%と快適な状態です。

この4ステップのフローにより、LLMは単なるテキスト生成から「実世界と連携するエージェント」へと進化しました。


主要プロバイダーの比較

現在、Function Callingをサポートする主要なLLMプロバイダーは3社あります。それぞれの特徴を比較表で整理します。

比較表

項目OpenAIAnthropic (Claude)Google (Gemini)
対応モデルGPT-4, GPT-4o, GPT-3.5-TurboClaude 3.5 Sonnet, Claude 3 OpusGemini 1.5 Pro, Gemini 1.5 Flash
機能名Function CallingTool UseFunction Calling
並列呼び出し✅ 対応✅ 対応✅ 対応
ストリーミング✅ 対応✅ 対応✅ 対応
関数定義形式JSON SchemaJSON SchemaJSON Schema
最大関数数128個128個以上64個
無料枠での利用一部対応一部対応✅ 対応

OpenAI (GPT-4 / GPT-4o)

特徴:

  • 最も早くFunction Callingを提供(2023年6月)
  • 豊富なドキュメントとコミュニティサポート
  • 並列関数呼び出しに最適化
  • GPT-4oでは高速かつ低コストで利用可能

適しているケース:

  • 本格的なプロダクション環境
  • 複雑なマルチステップのワークフロー
  • 既存のOpenAI APIユーザー

Anthropic (Claude 3.5 Sonnet)

特徴:

  • 「Tool Use」という名称で提供
  • 高度な推論能力を活かした関数選択
  • 複雑な指示に従う能力が高い
  • コンテキストウィンドウが広い(200K tokens)

適しているケース:

  • 複雑な判断が必要なタスク
  • 長文のコンテキストを扱う場合
  • エラーハンドリングが重要なシステム

Google (Gemini 1.5 Pro / Flash)

特徴:

  • Google Cloudとの親和性が高い
  • 無料枠で試しやすい
  • マルチモーダル対応(画像入力からの関数呼び出し)
  • Flashモデルは高速かつ低コスト

適しているケース:

  • Google Cloud環境での開発
  • コストを抑えたPoC(概念実証)
  • 画像を含む関数呼び出し

実装例(Python)

ここでは、最も一般的なOpenAIのFunction Callingを使った実装例を紹介します。

基本的な実装

import openai
import json

# APIキーの設定
client = openai.OpenAI(api_key="your-api-key")

# 関数定義
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "指定した都市の現在の天気を取得します",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "都市名(例: 東京、大阪)"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "温度の単位"
                    }
                },
                "required": ["city"]
            }
        }
    }
]

# 天気取得関数(ダミー実装)
def get_weather(city: str, unit: str = "celsius") -> dict:
    """実際のAPIを呼び出す代わりにダミーデータを返す"""
    weather_data = {
        "東京": {"temperature": 18, "condition": "晴れ", "humidity": 45},
        "大阪": {"temperature": 20, "condition": "曇り", "humidity": 60},
        "札幌": {"temperature": 5, "condition": "雪", "humidity": 80}
    }
    
    result = weather_data.get(city, {"temperature": 15, "condition": "不明", "humidity": 50})
    
    if unit == "fahrenheit":
        result["temperature"] = result["temperature"] * 9/5 + 32
    
    return result

# メイン処理
def chat_with_tools(user_message: str) -> str:
    # ステップ1: メッセージと関数定義を送信
    messages = [{"role": "user", "content": user_message}]
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )
    
    # ステップ2: 関数呼び出しの確認
    message = response.choices[0].message
    
    if message.tool_calls:
        # ステップ3: 関数を実行
        tool_call = message.tool_calls[0]
        function_name = tool_call.function.name
        arguments = json.loads(tool_call.function.arguments)
        
        if function_name == "get_weather":
            function_result = get_weather(**arguments)
        
        # ステップ4: 結果を送信して最終回答を取得
        messages.append(message)
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(function_result, ensure_ascii=False)
        })
        
        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages
        )
        
        return final_response.choices[0].message.content
    
    return message.content

# 実行例
result = chat_with_tools("東京の天気を教えて")
print(result)
# 出力: 東京の現在の天気は晴れで、気温は18°Cです。湿度は45%と快適な状態です。

並列関数呼び出しの実装

OpenAIのFunction Callingは、複数の関数を同時に呼び出すことができます。

def chat_with_parallel_tools(user_message: str) -> str:
    messages = [{"role": "user", "content": user_message}]
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )
    
    message = response.choices[0].message
    
    if message.tool_calls:
        messages.append(message)
        
        # 複数の関数呼び出しを処理
        for tool_call in message.tool_calls:
            function_name = tool_call.function.name
            arguments = json.loads(tool_call.function.arguments)
            
            if function_name == "get_weather":
                result = get_weather(**arguments)
            
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result, ensure_ascii=False)
            })
        
        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages
        )
        
        return final_response.choices[0].message.content
    
    return message.content

# 実行例: 複数都市の天気を一度に取得
result = chat_with_parallel_tools("東京と大阪の天気を比較して")
print(result)

実務ユースケース

Function Callingは、様々な実務シーンで活用されています。ここでは、代表的なユースケースを紹介します。

1. 天気情報の取得

概要:
ユーザーが自然言語で天気を尋ねると、LLMが天気APIを呼び出して最新の気象情報を提供します。

活用シーン:

  • カスタマーサポートでの旅行アドバイス
  • イベント予定の立案支援
  • 農業・物流業界での気象データ活用

実装のポイント:

  • 都市名の正規化(「東京」「とうきょう」の統一)
  • 緯度経度への変換が必要な場合も

2. データベース検索

概要:
ユーザーの質問に基づいて、LLMがSQLクエリや検索APIを生成・実行し、データベースから情報を取得します。

tools = [
    {
        "type": "function",
        "function": {
            "name": "search_products",
            "description": "商品データベースを検索します",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "検索キーワード"},
                    "category": {"type": "string", "description": "カテゴリ"},
                    "max_price": {"type": "number", "description": "最大価格"}
                },
                "required": ["query"]
            }
        }
    }
]

活用シーン:

  • ECサイトの検索機能
  • 社内ナレッジベースの検索
  • カスタマーサポートでの注文履歴照会

注意点:

  • SQLインジェクション対策
  • 機密データへのアクセス制御

3. 外部API連携

概要:
各種SaaSや外部サービスのAPIをLLM経由で呼び出し、業務プロセスを自動化します。

活用シーン:

  • カレンダー管理: 予定の追加・確認・変更
  • メール送信: メールの下書き・送信
  • Slack/Teams通知: チームへの自動通知
  • CRM連携: 顧客情報の登録・更新
tools = [
    {
        "type": "function",
        "function": {
            "name": "create_calendar_event",
            "description": "Googleカレンダーに予定を追加します",
            "parameters": {
                "type": "object",
                "properties": {
                    "title": {"type": "string", "description": "予定のタイトル"},
                    "date": {"type": "string", "description": "日付(YYYY-MM-DD)"},
                    "time": {"type": "string", "description": "時刻(HH:MM)"},
                    "attendees": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "参加者のメールアドレス"
                    }
                },
                "required": ["title", "date", "time"]
            }
        }
    }
]

4. 計算・データ処理

概要:
LLMが苦手とする正確な計算や複雑なデータ処理を、専用の関数に委譲します。

活用シーン:

  • 金融計算(利息、為替変換)
  • 統計分析
  • 日付・時刻の計算

5. マルチモーダル処理

概要:
画像や音声データを処理する関数を呼び出し、分析結果をLLMに統合します。

活用シーン:

  • 画像認識(商品画像の分析)
  • OCR(画像からテキスト抽出)
  • 音声認識結果の要約

ベストプラクティス

Function Callingを効果的に活用するための、実践的なベストプラクティスを紹介します。

エラーハンドリング

1. タイムアウトの設定

外部APIを呼び出す場合、必ずタイムアウトを設定しましょう。

import requests
from requests.exceptions import Timeout

def get_weather_with_timeout(city: str) -> dict:
    try:
        response = requests.get(
            f"https://api.weather.com/{city}",
            timeout=5  # 5秒でタイムアウト
        )
        return response.json()
    except Timeout:
        return {"error": "天気情報の取得がタイムアウトしました"}
    except Exception as e:
        return {"error": f"エラーが発生しました: {str(e)}"}

2. 再試行(リトライ)処理

一時的なエラーに対応するため、リトライ処理を実装します。

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def get_weather_with_retry(city: str) -> dict:
    response = requests.get(f"https://api.weather.com/{city}", timeout=5)
    response.raise_for_status()
    return response.json()

3. エラーのLLMへの伝達

関数実行でエラーが発生した場合、その情報をLLMに返すことで、適切なエラーメッセージを生成できます。

if function_result.get("error"):
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": f"エラー: {function_result['error']}"
    })

セキュリティ

1. 入力値の検証

LLMが生成した引数をそのまま使用せず、必ず検証します。

def validate_city(city: str) -> str:
    """都市名のバリデーション"""
    # 許可リスト方式
    allowed_cities = ["東京", "大阪", "名古屋", "福岡", "札幌"]
    if city not in allowed_cities:
        raise ValueError(f"対応していない都市です: {city}")
    return city

2. 機密データの保護

APIキーやパスワードは環境変数で管理し、ログに出力しないよう注意します。

import os
from dotenv import load_dotenv

load_dotenv()

API_KEY = os.getenv("WEATHER_API_KEY")  # 環境変数から取得

3. アクセス権限の制御

ユーザーごとにアクセス可能なデータを制限します。

def search_orders(user_id: str, query: str) -> list:
    """ユーザー自身の注文のみを検索"""
    # user_idでフィルタリング
    return database.query(
        "SELECT * FROM orders WHERE user_id = ? AND product_name LIKE ?",
        [user_id, f"%{query}%"]
    )

最適化

1. 関数定義の最適化

関数の説明は明確かつ簡潔に記述します。LLMが理解しやすい説明を書くことで、関数選択の精度が向上します。

# 良い例
"description": "指定した都市の現在の天気を取得します。都市名は日本語で指定してください。"

# 悪い例
"description": "天気を取得"  # 情報不足

2. キャッシング

頻繁に呼び出される関数の結果をキャッシュします。

from functools import lru_cache
import time

@lru_cache(maxsize=100)
def get_weather_cached(city: str) -> dict:
    # キャッシュの有効期限を考慮した実装
    return get_weather(city)

3. 並列実行

複数の関数を並列で実行し、レスポンス時間を短縮します。

import asyncio
import aiohttp

async def fetch_multiple_cities(cities: list) -> list:
    async with aiohttp.ClientSession() as session:
        tasks = [get_weather_async(session, city) for city in cities]
        return await asyncio.gather(*tasks)

FAQ(よくある質問)

Function Callingについて、よく寄せられる質問とその回答をまとめました。

Q1. Function Callingは無料で使える?

A. プロバイダーによります。

  • OpenAI: Function Calling自体は追加料金なしで利用可能ですが、API利用料金はかかります。GPT-3.5-Turboなら比較的低コストで試せます。
  • Anthropic: Claude 3.5 Sonnetなどで利用可能。無料トライアル枠があります。
  • Google Gemini: Gemini 1.5 Flashは無料枠で利用可能。PoCに最適です。

Q2. どのLLMがFunction Callingに対応している?

A. 主要なLLMのほとんどが対応しています:

  • OpenAI: GPT-4, GPT-4o, GPT-3.5-Turbo
  • Anthropic: Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku
  • Google: Gemini 1.5 Pro, Gemini 1.5 Flash
  • その他: Mistral AI, Cohere, Amazon Bedrock (Claude, Llama)

Q3. 複数の関数を同時に呼び出せる?

A. はい、可能です。

OpenAI、Anthropic、Googleすべてのプロバイダーで「並列関数呼び出し」に対応しています。例えば、「東京と大阪の天気を教えて」という質問に対して、2つの天気取得関数を同時に呼び出せます。

Q4. エラー時の挙動は?

A. エラー情報をLLMに返すことで、適切に処理されます。

関数実行でエラーが発生した場合、そのエラーメッセージをLLMに送信すると、LLMは「申し訳ありません。天気情報の取得に失敗しました。しばらく待ってから再試行してください」のように、ユーザーに分かりやすいエラーメッセージを生成します。

Q5. セキュリティ上の注意点は?

A. 以下の点に注意が必要です:

  1. 入力値の検証: LLMが生成した引数を検証する
  2. SQLインジェクション対策: パラメータ化クエリを使用する
  3. アクセス制御: ユーザー権限に基づいたデータアクセス
  4. APIキーの管理: 環境変数で管理し、ログに出力しない
  5. 機密データの保護: PII(個人識別情報)の取り扱いに注意

Q6. レスポンス時間は通常より長い?

A. はい、通常のテキスト生成より長くなります。

Function Callingは以下の処理が発生するため、通常より時間がかかります:

  1. 最初のLLM呼び出し(関数呼び出しの判断)
  2. 関数の実行
  3. 2回目のLLM呼び出し(最終回答の生成)

目安として、通常の2〜3倍の時間がかかると想定してください。

Q7. 関数の定義に制限はある?

A. いくつかの制限があります:

  • パラメータのネスト: 深いネストは避ける(2〜3階層まで)
  • パラメータ数: 多すぎるとLLMが混乱する(10個以内推奨)
  • 関数の数: OpenAIは最大128個まで定義可能
  • 説明文の長さ: 簡潔かつ明確に(100文字程度推奨)

Q8. ストリーミング対応している?

A. はい、主要プロバイダーはすべて対応しています。

ストリーミングを使用すると、関数呼び出しの判断から結果の生成まで、リアルタイムで進捗を表示できます。ユーザー体験の向上に有効です。

Q9. 呼び出し回数に制限はある?

A. APIのレート制限が適用されます。

Function Callingは通常のAPI呼び出しとしてカウントされます。各プロバイダーのレート制限(RPM: Requests Per Minute)に従う必要があります。大量の呼び出しが必要な場合は、プロプランへのアップグレードやキャッシングを検討してください。

Q10. どうやってデバッグする?

A. 以下の方法が有効です:

  1. ログ出力: 関数呼び出しの内容と結果をログに記録
  2. モック関数: 実際のAPIの代わりにモックを使用
  3. Playground使用: OpenAI Playgroundで関数定義をテスト
  4. 段階的なテスト: 単純な関数から始めて複雑な関数へ
# デバッグ用ログ出力
import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

def debug_function_call(function_name: str, arguments: dict):
    logger.debug(f"関数呼び出し: {function_name}")
    logger.debug(f"引数: {json.dumps(arguments, ensure_ascii=False, indent=2)}")

まとめ

Function Callingは、LLMを「会話するAI」から「行動するAI」へと進化させる重要な技術です。このガイドで紹介した内容を要約すると:

Function Callingの核心:

  • LLMが外部ツールやAPIを呼び出す仕組み
  • プロンプト→関数定義→実行→結果返却の4ステップフロー
  • ハルシネーションの軽減と実務活用の実現

実装のポイント:

  • 明確な関数定義を記述する
  • 適切なエラーハンドリングを実装する
  • セキュリティ対策を講じる

実務への応用:

  • 天気情報、DB検索、API連携、計算処理など幅広い活用
  • カスタマーサポート、業務自動化、データ分析など

これからFunction Callingを学ぶ方は、まず無料枠のあるGeminiやGPT-3.5-Turboで小さなサンプルを作ってみることをお勧めします。実際に動くコードを体験することで、理解が深まります。

Function Callingを使いこなすことで、AIを実務に活用する幅が大きく広がります。ぜひ、このガイドを参考に、最初のFunction Callingを実装してみてください。


参考リソース


最終更新: 2026年3月

この記事は、Function Callingを初めて学ぶ方向けの入門ガイドです。より高度なトピック(エージェントフレームワーク、マルチエージェントシステムなど)については、別途専門の記事を参照してください。

コメント

タイトルとURLをコピーしました