Function Callingとは何か
Gemini APIのFunction Calling(ツール呼び出し)は、AIモデルが会話の中で外部の関数やAPIを呼び出せるようにする機能です。これにより、AIは単なる文章生成にとどまらず、リアルタイムのデータ取得、計算処理、外部サービスとの連携など、現実世界のアクションを実行できるようになります。
2026年時点でGemini APIのFunction Callingは大きく成熟し、並列ツール呼び出し、強制ツール使用モード、構造化されたツール定義など、本番利用に十分な機能が揃っています。ここで扱うのは初めてFunction Callingを使う方から、より高度な活用を目指す方まで、体系的に学べる内容をお届けします。
Function Callingの基本的な仕組み
呼び出しフローの全体像
Function Callingは、以下のフローで動作します。
開発者が使用可能なツール(関数)をAPIリクエストと共に定義する
ユーザーがリクエストを送信する
Geminiモデルがリクエストにどのツールをどの引数で呼び出すべきかを判断する
モデルがツール呼び出しの指示(tool_calls)をレスポンスとして返す
アプリケーションがツールを実際に実行し、結果をモデルに渡す
モデルがツールの結果を踏まえて最終的な回答を生成する
重要なのは、Geminiモデル自体がツールを実行するわけではないという点です。モデルは「どのツールを、どんな引数で呼ぶべきか」を判断するだけで、実際の実行はアプリケーション側が担います。これにより、セキュリティと制御性が保たれます。
ツール定義の基本構造
import google.generativeai as genai
# ツールの定義
weather_function = {
"name" : "get_current_weather" ,
"description" : "指定した都市の現在の天気を取得する。温度の単位は摂氏または華氏を選択できる。" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"location" : {
"type" : "string" ,
"description" : "都市名と国コード(例: 東京, JP)"
},
"unit" : {
"type" : "string" ,
"enum" : [ "celsius" , "fahrenheit" ],
"description" : "温度の単位"
}
},
"required" : [ "location" ]
}
}
# ツールをモデルに渡す
model = genai.GenerativeModel(
model_name = "gemini-2.0-flash" ,
tools = [weather_function]
)
ツール定義のポイントは「description」の品質です。モデルはdescriptionを参考にして、いつそのツールを使うべきかを判断します。曖昧な説明は誤ったツール選択につながるため、「何をするツールか」「いつ使うべきか」「入力と出力の形式」を明確に記述する点が肝心です。
実践的なツール実装
基本的な単一ツール呼び出し
import google.generativeai as genai
import json
genai.configure( api_key = "YOUR_GEMINI_API_KEY" )
def get_current_weather (location: str , unit: str = "celsius" ) -> dict :
"""実際の天気APIを呼び出す関数(ここではダミーデータ)"""
return {
"location" : location,
"temperature" : 22 if unit == "celsius" else 71.6 ,
"unit" : unit,
"condition" : "晴れ" ,
"humidity" : 65
}
def run_function_call_example ():
model = genai.GenerativeModel(
model_name = "gemini-2.0-flash" ,
tools = [get_current_weather] # 関数を直接渡せる(自動でスキーマ生成)
)
chat = model.start_chat()
response = chat.send_message( "東京の今の天気を教えてください" )
# Function Callが発生した場合の処理
while response.candidates[ 0 ].content.parts[ 0 ].function_call.name:
fc = response.candidates[ 0 ].content.parts[ 0 ].function_call
# ツールを実行
if fc.name == "get_current_weather" :
result = get_current_weather( ** fc.args)
# 結果をモデルに返す
response = chat.send_message(
genai.protos.Content(
parts = [genai.protos.Part(
function_response = genai.protos.FunctionResponse(
name = fc.name,
response = { "result" : json.dumps(result, ensure_ascii = False )}
)
)]
)
)
return response.text
並列ツール呼び出しの実装
Gemini 2.0以降では、複数のツールを並列で呼び出す機能がサポートされています。これにより、独立した複数の情報を同時に取得できるようになりましました。
def handle_parallel_function_calls (response, tools_map):
"""並列ツール呼び出しを処理する汎用関数"""
function_calls = [
part.function_call
for part in response.candidates[ 0 ].content.parts
if hasattr (part, 'function_call' ) and part.function_call.name
]
if not function_calls:
return None
# 全ツールを並列実行(実際にはasyncioやThreadPoolを使う)
results = []
for fc in function_calls:
if fc.name in tools_map:
result = tools_map[fc.name]( ** fc.args)
results.append(
genai.protos.Part(
function_response = genai.protos.FunctionResponse(
name = fc.name,
response = { "result" : json.dumps(result, ensure_ascii = False )}
)
)
)
return genai.protos.Content( parts = results)
高度なFunction Calling設計パターン
ツール選択モードの制御
Gemini APIは、ツール使用のモードを制御するための設定を提供しています。
from google.generativeai.types import ToolConfig, FunctionCallingConfig
# モード1: AUTO(デフォルト)- モデルが自動判断
auto_config = ToolConfig(
function_calling_config = FunctionCallingConfig( mode = "AUTO" )
)
# モード2: ANY - 必ず何かのツールを使う(ツール強制)
forced_config = ToolConfig(
function_calling_config = FunctionCallingConfig(
mode = "ANY" ,
allowed_function_names = [ "get_current_weather" , "search_database" ]
)
)
# モード3: NONE - ツールを使わない(テキストのみ)
no_tools_config = ToolConfig(
function_calling_config = FunctionCallingConfig( mode = "NONE" )
)
「ANY」モードは、必ずツールを使わせたい場合(例:ユーザーの入力を必ず構造化データに変換したい場合)に特に有効です。
ステートフルなマルチターン会話での活用
Function Callingの真価は、複数ターンにわたる会話の中で発揮されます。以下は、データ分析アシスタントの実装例です。
class DataAnalysisAssistant :
def __init__ (self):
self .tools = [
self .query_database,
self .calculate_statistics,
self .create_visualization,
self .export_report
]
self .model = genai.GenerativeModel(
model_name = "gemini-2.0-pro" ,
tools = self .tools,
system_instruction = """
あなたはデータ分析の専門家です。
ユーザーの質問に答えるため、必要に応じてツールを使用してください。
複数のツールが必要な場合は、論理的な順序で使用してください。
"""
)
self .chat = self .model.start_chat()
def analyze (self, user_query: str ) -> str :
response = self .chat.send_message(user_query)
# ツール呼び出しが終わるまでループ
while True :
function_calls = self ._extract_function_calls(response)
if not function_calls:
break
results = self ._execute_function_calls(function_calls)
response = self .chat.send_message(results)
return response.text
エラーハンドリングとセキュリティ
堅牢なエラーハンドリング
本番環境では、ツール実行中に様々なエラーが発生する可能性があります。適切なエラーハンドリングにより、AIが状況を正しく認識して代替策を取れるようにします。
def safe_execute_tool (tool_name: str , args: dict , tools_map: dict ) -> dict :
"""エラーを適切に処理するツール実行ラッパー"""
try :
if tool_name not in tools_map:
return {
"error" : f "ツール ' { tool_name } ' が見つかりません" ,
"available_tools" : list (tools_map.keys())
}
result = tools_map[tool_name]( ** args)
return { "success" : True , "result" : result}
except ValueError as e:
return {
"error" : "引数の値が不正です" ,
"details" : str (e),
"suggestion" : "引数の型と範囲を確認してください"
}
except TimeoutError :
return {
"error" : "ツールの実行がタイムアウトしました" ,
"suggestion" : "後でもう一度試すか、別のアプローチを検討してください"
}
except Exception as e:
return {
"error" : "予期しないエラーが発生しました" ,
"details" : str (e)
}
セキュリティの考慮事項
Function Callingを本番環境で使用する際には、セキュリティに特に注意が必要です。
入力検証の徹底 : AIが生成したツール引数を、そのままシステムに渡すことは危険です。特に、ファイルパス、SQLクエリ、シェルコマンドなどを含む可能性がある引数は、必ずバリデーションと サニタイズを行います。
権限の最小化 : 各ツールが持つ権限は、必要最小限に絞ります。データ読み取りのみ必要なツールに書き込み権限を与えないよう注意します。
レート制限 : AIが大量のAPIコールを発生させないよう、ツールの実行にレート制限を設けます。特に外部APIを呼び出すツールでは重要です。
監査ログ : 本番環境では、どのツールがいつどんな引数で呼ばれたかを記録します。問題発生時のデバッグと、異常なパターンの早期検出に役立ちます。
import logging
from functools import wraps
def audit_tool_call (func):
"""ツール呼び出しを記録するデコレータ"""
@wraps (func)
def wrapper ( * args, ** kwargs):
logging.info(
f "Tool called: { func. __name__ } , "
f "args: { args } , kwargs: { kwargs } "
)
try :
result = func( * args, ** kwargs)
logging.info( f "Tool { func. __name__ } succeeded" )
return result
except Exception as e:
logging.error( f "Tool { func. __name__ } failed: { e } " )
raise
return wrapper
@audit_tool_call
def sensitive_database_query (query: str ) -> list :
# データベースクエリの実装
pass
実際のユースケース
ユースケース1:インテリジェントなカスタマーサポート
customer_support_tools = [
{
"name" : "get_order_status" ,
"description" : "注文番号から注文状況、配送状況、予定到着日を取得する" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"order_id" : { "type" : "string" , "description" : "注文番号(例: ORD-2026-12345)" }
},
"required" : [ "order_id" ]
}
},
{
"name" : "process_return_request" ,
"description" : "返品・交換リクエストを処理する。ユーザーの明示的な承認が得られた場合のみ使用する" ,
"parameters" : {
"type" : "object" ,
"properties" : {
"order_id" : { "type" : "string" },
"reason" : { "type" : "string" },
"type" : { "type" : "string" , "enum" : [ "return" , "exchange" ]}
},
"required" : [ "order_id" , "reason" , "type" ]
}
}
]
ユースケース2:コードレビューアシスタント
code_review_tools = [
"analyze_code_complexity" , # コードの複雑度分析
"check_security_vulnerabilities" , # セキュリティ脆弱性チェック
"suggest_refactoring" , # リファクタリング提案
"run_tests" , # テスト実行
"check_dependency_updates" # 依存関係の更新確認
]
コードレビューアシスタントの場合、これらのツールをオーケストレートすることで、コードの提出から包括的なレビューレポートの生成まで、一連のフローを自動化できます。
パフォーマンスの最適化
ツール定義のキャッシング
同じツールセットを繰り返し使う場合、ツール定義のキャッシングが効果的です。Gemini APIは、ツール定義を含むシステムプロンプトをキャッシュする機能を提供しており、大量のツールを使う場合のコストを削減できます。
非同期処理による高速化
複数のツールが独立して実行できる場合、非同期処理で並列実行することでレスポンスタイムを大幅に短縮できます。
import asyncio
async def execute_parallel_tools (function_calls: list , tools_map: dict ) -> list :
"""複数のツールを非同期で並列実行"""
async def execute_single (fc):
tool = tools_map.get(fc.name)
if not tool:
return { "error" : f "Unknown tool: { fc.name } " }
# I/O待機が多いツールはasync化で高速化
if asyncio.iscoroutinefunction(tool):
result = await tool( ** fc.args)
else :
# 同期関数はスレッドプールで実行
loop = asyncio.get_event_loop()
result = await loop.run_in_executor( None , lambda : tool( ** fc.args))
return result
return await asyncio.gather( * [execute_single(fc) for fc in function_calls])
個人開発者の視点から(実体験メモ)
ここまでの要点
Gemini APIのFunction Callingは、AIアプリケーションに現実世界への窓口を開く強力な機能です。適切に設計されたツール定義、堅牢なエラーハンドリング、セキュリティを考慮した実装を組み合わせることで、真に役立つAIアシスタントを構築できます。
まずは単一ツールのシンプルな実装から始め、慣れてきたら並列呼び出しや複雑なワークフローへと発展させていくことをお勧めします。Function Callingを使いこなせるようになれば、AIアプリケーション開発の可能性が大きく広がります。
皆さんが実用的なAIアプリケーションを作り上げることを、心から応援しています。
ストリーミングレスポンスの基本
通常のAPIリクエストでは、モデルがレスポンス全体を生成し終えてからクライアントに返します。ストリーミングでは、生成途中のテキストを逐次的に受け取れるため、ユーザー体験が大幅に向上します。
Python でのストリーミング実装
import google.generativeai as genai
# APIキーの設定
genai.configure( api_key = "YOUR_API_KEY" )
# モデルの初期化
model = genai.GenerativeModel( "gemini-2.5-pro" )
# ストリーミングでレスポンスを受信
response = model.generate_content(
"Pythonでウェブスクレイパーを実装する方法を、ステップバイステップで解説してください。" ,
stream = True
)
# チャンクごとにリアルタイム出力
for chunk in response:
if chunk.text:
print (chunk.text, end = "" , flush = True )
print () # 最後に改行
# 期待される動作:
# テキストが一文字ずつ(実際にはトークン単位で)リアルタイムに表示される
# 全文が生成されるのを待つ必要がない
TypeScript/JavaScript でのストリーミング
import { GoogleGenerativeAI } from "@google/generative-ai" ;
const genAI = new GoogleGenerativeAI ( "YOUR_API_KEY" );
const model = genAI. getGenerativeModel ({ model: "gemini-2.5-pro" });
async function streamResponse ( prompt : string ) {
const result = await model. generateContentStream (prompt);
// チャンクを逐次処理
for await ( const chunk of result.stream) {
const text = chunk. text ();
process.stdout. write (text);
}
// 最終的な完全レスポンスも取得可能
const finalResponse = await result.response;
console. log ( " \n\n Total tokens:" , finalResponse.usageMetadata?.totalTokenCount);
}
// 使用例
streamResponse ( "TypeScriptでREST APIを設計するベストプラクティスを教えてください" );
// 期待される出力:
// (リアルタイムにテキストが出力される)
// Total tokens: 1234
Function Calling の仕組み
Function Callingは、Geminiモデルに「使えるツール(関数)」を教え、必要に応じてモデルがそのツールを呼び出すよう指示する仕組みです。モデル自体がコードを実行するのではなく、「この関数をこの引数で呼んでほしい」というリクエストを返します。
Function Calling の実装手順
import google.generativeai as genai
genai.configure( api_key = "YOUR_API_KEY" )
# 1. 関数の定義(モデルに教えるツール)
def get_weather (city: str , unit: str = "celsius" ) -> dict :
"""指定された都市の天気情報を取得する"""
# 実際にはAPIを呼び出す
weather_data = {
"Tokyo" : { "temp" : 18 , "condition" : "晴れ" , "humidity" : 45 },
"Osaka" : { "temp" : 20 , "condition" : "曇り" , "humidity" : 60 },
"New York" : { "temp" : 12 , "condition" : "雨" , "humidity" : 75 },
}
data = weather_data.get(city, { "temp" : 15 , "condition" : "不明" , "humidity" : 50 })
if unit == "fahrenheit" :
data[ "temp" ] = data[ "temp" ] * 9 / 5 + 32
return { "city" : city, ** data}
def search_restaurants (location: str , cuisine: str = "any" , budget: str = "moderate" ) -> dict :
"""指定された場所のレストランを検索する"""
return {
"location" : location,
"cuisine" : cuisine,
"results" : [
{ "name" : f " { cuisine } レストラン A" , "rating" : 4.5 , "budget" : budget},
{ "name" : f " { cuisine } レストラン B" , "rating" : 4.2 , "budget" : budget},
]
}
# 2. ツール定義をモデルに渡す
tools = [get_weather, search_restaurants]
model = genai.GenerativeModel(
model_name = "gemini-2.5-pro" ,
tools = tools
)
# 3. チャットセッションを開始
chat = model.start_chat()
# 4. ユーザーの質問を送信
response = chat.send_message(
"東京の今の天気と、おすすめのイタリアンレストランを教えてください"
)
# 5. Function Callリクエストを処理
for part in response.parts:
if hasattr (part, 'function_call' ):
func_name = part.function_call.name
func_args = dict (part.function_call.args)
# 実際に関数を実行
if func_name == "get_weather" :
result = get_weather( ** func_args)
elif func_name == "search_restaurants" :
result = search_restaurants( ** func_args)
# 結果をモデルに返す
response = chat.send_message(
genai.protos.Content(
parts = [genai.protos.Part(
function_response = genai.protos.FunctionResponse(
name = func_name,
response = { "result" : result}
)
)]
)
)
print (response.text)
# 期待される出力例:
# 東京の現在の天気は晴れで、気温は18°Cです。湿度は45%と快適ですね。
#
# おすすめのイタリアンレストランは以下の2件です:
# 1. イタリアンレストラン A(評価: 4.5)
# 2. イタリアンレストラン B(評価: 4.2)
ストリーミング × Function Calling の組み合わせ
ストリーミングとFunction Callingを組み合わせることで、リアルタイムに応答しながら外部データも取得する高度なアプリケーションが実現できます。
import google.generativeai as genai
genai.configure( api_key = "YOUR_API_KEY" )
model = genai.GenerativeModel(
model_name = "gemini-2.5-pro" ,
tools = [get_weather]
)
# ストリーミング + Function Calling
response = model.generate_content(
"明日のピクニックの計画を立ててください。東京の天気を確認して、適切な持ち物リストを作ってください。" ,
stream = True
)
for chunk in response:
# Function Callリクエストが含まれる場合
for part in chunk.parts:
if hasattr (part, 'function_call' ):
result = get_weather( city = "Tokyo" )
print ( f " \n [天気データ取得: { result } ] \n " )
# テキストレスポンスの場合
if chunk.text:
print (chunk.text, end = "" , flush = True )
全体を振り返って
Gemini APIのストリーミングとFunction Callingは、リアルタイムAIアプリケーションを構築するための強力な機能です。ストリーミングでユーザー体験を向上させ、Function Callingで外部データやツールとシームレスに連携することで、実用的で高度なAIアプリケーションを開発できます。
まずはシンプルなストリーミングチャットから始めて、Function Callingで天気やニュースなどの外部APIと連携する機能を追加していくのがお勧めです。