Gemini の Function Calling を最初に試したとき、正直「JSON を返してもらえばいいだけでは」と思っていました。しかし、実際に本番環境で使い始めると、Function Calling と単なる JSON モードの差が明確に見えてきます。
最大の違いは「ツールを呼ぶタイミングをモデルが判断する」という点です。プロンプトの文脈によって必要なデータを選んで取得し、結果を統合して応答を構成する — この一連の流れを Gemini が自律的に実行します。今回は、この仕組みを実用的なコードで説明します。
Function Calling の基本構造
Function Calling は三段階のサイクルで動きます。
- ツール定義をモデルに渡してリクエストを送る
- モデルが
function_callを返してくる(この時点ではツールはまだ実行されていない) - ツールを実際に実行して結果をモデルに戻す
この「モデルはツールを呼ぶ指示を出すだけで、実行するのはアプリ側」という分離が重要です。
import google.generativeai as genai
genai.configure(api_key="YOUR_GEMINI_API_KEY")
# ツール定義
tools = [
{
"function_declarations": [
{
"name": "get_weather",
"description": "指定した都市の現在の天気を取得する",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "都市名(例: Tokyo, Osaka)"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度の単位"
}
},
"required": ["city"]
}
}
]
}
]
model = genai.GenerativeModel("gemini-2.0-flash", tools=tools)
response = model.generate_content("東京の今日の天気は?")
# Function Call が含まれているか確認
for part in response.candidates[0].content.parts:
if hasattr(part, "function_call"):
print(f"呼び出し: {part.function_call.name}")
print(f"引数: {dict(part.function_call.args)}")ツール定義を書くときのコツ
description の質がモデルの判断精度に直接影響します。公式ドキュメントでは軽く触れられている点ですが、実際に試してみると差が歴然としています。
悪い例: "description": "天気を取得する"
良い例: "description": "指定した都市の現在の気温・天気状況・湿度を取得する。ユーザーが天候について質問したとき、または天気情報が意思決定に必要なときに使用する"
条件部分(「〜なときに使用する」)を書くと、モデルが不必要にツールを呼ぶ過検出を抑えられます。複数のツールが似た機能を持つ場合、この使い分けの指示が特に効果的です。
enum を使って選択肢を制限することも重要です。unit パラメータに enum: ["celsius", "fahrenheit"] を指定しておくと、モデルが予期しない値を渡してくるリスクがなくなります。
複数ツールを組み合わせる
実用的なアプリケーションでは、複数のツールを組み合わせて使うことがほとんどです。Gemini は一つのリクエストで複数のツール呼び出しを返すことがあります(parallel function calling)。
def handle_function_calls(response, tool_implementations):
"""Function Call を処理して結果を返す"""
function_results = []
for part in response.candidates[0].content.parts:
if not hasattr(part, "function_call"):
continue
fc = part.function_call
func_name = fc.name
func_args = dict(fc.args)
if func_name not in tool_implementations:
function_results.append({
"function_response": {
"name": func_name,
"response": {"error": f"Unknown function: {func_name}"}
}
})
continue
try:
result = tool_implementations[func_name](**func_args)
function_results.append({
"function_response": {
"name": func_name,
"response": {"result": result}
}
})
except Exception as e:
function_results.append({
"function_response": {
"name": func_name,
"response": {"error": str(e)}
}
})
return function_results
# 実際のツール実装
def get_weather(city: str, unit: str = "celsius") -> dict:
# 実際の天気APIを呼ぶ想定
return {"city": city, "temperature": 22, "condition": "晴れ", "unit": unit}
def get_news(topic: str, max_results: int = 3) -> list:
# 実際のニュースAPIを呼ぶ想定
return [{"title": f"{topic}のニュース{i}", "url": f"https://example.com/{i}"} for i in range(max_results)]
tool_implementations = {
"get_weather": get_weather,
"get_news": get_news
}一つ注意点があります。Gemini が複数のツール呼び出しを一度に返した場合、それぞれの実行は独立しているため、並列実行しても問題ありません。asyncio.gather() で同時実行すると応答時間を短縮できます。
エラーと不確実性への対処
ツールがエラーを返した場合、Gemini はそれを踏まえて応答を修正します。ただし、エラーの情報を適切に伝えないと、モデルが憶測で回答してしまうことがあります。
def safe_tool_response(func_name: str, result=None, error=None) -> dict:
"""ツール応答を構造化して返す"""
if error:
return {
"function_response": {
"name": func_name,
"response": {
"success": False,
"error": str(error),
"suggestion": "別の方法で試してください"
}
}
}
return {
"function_response": {
"name": func_name,
"response": {
"success": True,
"data": result
}
}
}success フラグと suggestion を含めると、モデルがエラーを適切に処理して「このツールが失敗したが、代替手段を試みる」という判断ができるようになります。
実プロジェクトでの活用例
私が実際に使った事例として、「アプリのレビュー分析ツール」があります。App Store のレビューテキストを Gemini に渡し、Function Calling で以下のツールを定義しました。
categorize_review— レビューをカテゴリに分類(UI/バグ/機能要望/など)extract_sentiment— 感情スコアと主要キーワードを抽出flag_urgent— 緊急対応が必要なレビュー(クラッシュ報告など)にフラグを立てる
これを単純な JSON モードで実装しようとすると、1レビューに対して 3 回 API を呼ぶ必要があります。Function Calling では、Gemini が文脈から「このレビューはこの 3 つのツールを使って処理すべき」と判断して一度にまとめて実行します。API 呼び出し回数が 1/3 になり、コストも大幅に下がりました。
はじめの一歩
まずは単一ツールで試してみてください。description の書き方を変えながら、モデルがツールを呼ぶタイミングがどう変わるかを観察するのが一番の学習になります。
公式の Gemini API ドキュメント には基本的な使い方が整理されています。ここに書いた「複数ツールの並列実行」と「エラーレスポンスの構造化」は、実際に使って気づいた実践的な補足として参考にしてください。