ツールが呼ばれないとき、どこを疑うか
スキーマを定義してリクエストを投げたのに、モデルは普通のテキストを返してくるだけ。レスポンスに function_call は現れず、エラーも出ません。Function Calling でつまずくときの多くは、こうした「何も起きない」状態から始まります。
原因はスキーマの書き方、モデルの選択、レスポンスの読み取り方など複数の層に分かれており、エラーメッセージだけでは切り分けが進みません。実際に遭遇しやすい5つの症状を入り口に、それぞれの原因と対処を順に確認します。
Function Callingの基本的な仕組みを確認する
トラブルシューティングの前に、動作の流れを整理しておきます。
- アプリがツール定義(スキーマ)とユーザーメッセージをAPIに送信する
- モデルがツールを呼び出すべきと判断すると、
function_callを含むレスポンスを返す - アプリがツールを実行し、結果を
function_responseとしてAPIに送り返す - モデルがツール結果を踏まえて最終的な回答を生成する
この4ステップのどこかに問題があることがほとんどです。以下の症状ごとに確認していきましょう。
症状1: ツールが一切呼び出されない
原因の分析
モデルがツールをまったく使わない場合、以下の原因が考えられます。
- ツール説明文が曖昧: モデルはツールの
descriptionを読んで使用判断をするため、説明が不明確だと使われません - ユーザーメッセージとツールの関係が薄い: 質問とツールの用途が合致していないケース
- モデルが対応していない: Function Callingは全モデルで使えるわけではありません
- tool_choice の設定漏れ: 必ずツールを呼ぶよう強制する設定ができます
解決手順
まずツールの description を改善します。悪い例と良い例を比較してみましょう。
import google.generativeai as genai
genai.configure(api_key="YOUR_GEMINI_API_KEY")
# ❌ 悪い例:説明が抽象的すぎてモデルが使用タイミングを判断できない
bad_tool = {
"name": "get_weather",
"description": "天気を取得する",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
# ✅ 良い例:いつ・どこで使うかが明確
good_tool = {
"name": "get_weather",
"description": (
"指定した都市または地域の現在の天気情報を取得します。"
"ユーザーが天気、気温、降水確率、風速など気象情報を尋ねたときに使用してください。"
"例: 東京の天気、大阪の明日の気温"
),
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "都市名または地域名(例: 東京、大阪、北海道)"
}
},
"required": ["location"]
}
}
# tool_choice で強制的にツールを使わせる(デバッグに有効)
model = genai.GenerativeModel(
model_name="gemini-2.5-pro",
tools=[good_tool],
tool_config={"function_calling_config": {"mode": "ANY"}} # 必ずツールを使う
)
response = model.generate_content("東京の今日の天気を教えてください")
print(response.candidates[0].content.parts)
# 期待する出力: [function_call { name: "get_weather", args: { location: "東京" } }]tool_config の mode には3種類あります。
AUTO(デフォルト): モデルが判断してツールを使うANY: 必ずいずれかのツールを使うNONE: ツールを使わない
症状2: スキーマ定義エラーが発生する
原因の分析
400 Bad Request や Invalid argument エラーが出る場合、ツールのスキーマ定義に問題があります。よくあるミスは以下の通りです。
requiredフィールドにプロパティ名のタイポ- サポートされていない型(例:
integerの代わりにint) - ネストしたオブジェクトの型定義漏れ
enumの値をpropertiesに入れ忘れ
解決手順
スキーマを構造化して明示的に定義するのが確実です。
import google.generativeai as genai
from google.ai.generativelanguage_v1beta import FunctionDeclaration, Schema, Type
genai.configure(api_key="YOUR_GEMINI_API_KEY")
# ✅ 型安全にスキーマを定義する方法(ネストオブジェクト対応)
search_products_tool = FunctionDeclaration(
name="search_products",
description="商品データベースを検索し、条件に合う商品一覧を返します",
parameters=Schema(
type=Type.OBJECT,
properties={
"query": Schema(
type=Type.STRING,
description="検索キーワード"
),
"category": Schema(
type=Type.STRING,
description="商品カテゴリ",
enum=["electronics", "clothing", "food", "books"] # enumはここで指定
),
"price_range": Schema(
type=Type.OBJECT,
description="価格範囲",
properties={
"min": Schema(type=Type.NUMBER, description="最低価格(円)"),
"max": Schema(type=Type.NUMBER, description="最高価格(円)")
}
# ネストオブジェクトはrequiredなし = すべてオプション
),
"limit": Schema(
type=Type.INTEGER, # int ではなく INTEGER
description="取得件数の上限(デフォルト: 10)"
)
},
required=["query"] # プロパティ名のスペルを必ず確認
)
)
model = genai.GenerativeModel(
model_name="gemini-2.5-pro",
tools=[search_products_tool]
)
response = model.generate_content("電子機器で1万円以下の商品を5件探して")
print(response.candidates[0].content.parts)
# 期待する出力:
# function_call {
# name: "search_products"
# args { fields { key: "query" value { string_value: "電子機器" } }
# fields { key: "category" value { string_value: "electronics" } }
# fields { key: "price_range" value { struct_value { ... max: 10000 } } }
# fields { key: "limit" value { number_value: 5 } } }
# }症状3: function_callレスポンスのパースに失敗する
原因の分析
AttributeError: 'Part' object has no attribute 'function_call' や KeyError が出る場合、レスポンスの構造を正しく理解していない可能性があります。
解決手順
レスポンスの構造を確認し、安全にパースする関数を作りましょう。
import google.generativeai as genai
import json
genai.configure(api_key="YOUR_GEMINI_API_KEY")
def safe_parse_function_call(response):
"""
Function Callingのレスポンスを安全にパースするユーティリティ関数
戻り値: (tool_name, tool_args) のタプル。ツール呼び出しでない場合は (None, None)
"""
if not response.candidates:
print("⚠️ candidatesが空です")
return None, None
candidate = response.candidates[0]
# finish_reasonを確認(STOP以外は異常)
print(f"finish_reason: {candidate.finish_reason}")
for part in candidate.content.parts:
# function_callがあるかチェック
if hasattr(part, "function_call") and part.function_call:
fc = part.function_call
tool_name = fc.name
# argsはMapCompositで直接dict変換できる
tool_args = dict(fc.args)
print(f"✅ ツール呼び出し検出: {tool_name}({tool_args})")
return tool_name, tool_args
elif hasattr(part, "text") and part.text:
print(f"📝 テキストレスポンス: {part.text}")
return None, None
# マルチターン会話でFunction Callingを実装する例
def run_weather_chat():
get_weather_tool = {
"name": "get_weather",
"description": "指定した都市の現在の天気を取得します",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "都市名"}
},
"required": ["city"]
}
}
model = genai.GenerativeModel(
model_name="gemini-2.5-pro",
tools=[get_weather_tool]
)
chat = model.start_chat()
# ユーザーメッセージを送信
response = chat.send_message("大阪の天気を教えてください")
tool_name, tool_args = safe_parse_function_call(response)
if tool_name == "get_weather":
# 実際のツール実行(ここでは仮のデータを返す)
weather_result = {
"city": tool_args.get("city", "大阪"),
"temperature": 22,
"condition": "晴れ",
"humidity": 55
}
print(f"🔧 ツール実行結果: {weather_result}")
# ツール結果をモデルに返す
final_response = chat.send_message(
genai.protos.Content(
parts=[genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name=tool_name,
response={"result": weather_result}
)
)]
)
)
print(f"🤖 最終回答: {final_response.text}")
run_weather_chat()
# 期待する出力:
# finish_reason: FinishReason.STOP
# ✅ ツール呼び出し検出: get_weather({'city': '大阪'})
# 🔧 ツール実行結果: {'city': '大阪', 'temperature': 22, 'condition': '晴れ', 'humidity': 55}
# 🤖 最終回答: 大阪の現在の天気は晴れで、気温は22℃、湿度は55%です。...症状4: 複数ツールで意図しないツールが選ばれる
原因の分析
複数のツールを定義すると、モデルが誤ったツールを選択することがあります。
- ツール名・説明が似すぎている
- 呼び出してほしいツールの説明が具体的でない
allowed_function_namesで制限していない
解決手順
import google.generativeai as genai
genai.configure(api_key="YOUR_GEMINI_API_KEY")
# 複数ツールのうち特定のツールだけ使わせる
tools = [
{
"name": "search_database",
"description": "社内データベースから顧客情報を検索します",
"parameters": {
"type": "object",
"properties": {"customer_id": {"type": "string"}},
"required": ["customer_id"]
}
},
{
"name": "search_web",
"description": "インターネット上の一般的な情報を検索します",
"parameters": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"]
}
}
]
# allowed_function_names で使えるツールを限定する
model = genai.GenerativeModel(
model_name="gemini-2.5-pro",
tools=tools,
tool_config={
"function_calling_config": {
"mode": "ANY",
"allowed_function_names": ["search_database"] # これだけ使う
}
}
)
response = model.generate_content("顧客ID C-12345 の情報を調べて")
print(response.candidates[0].content.parts)
# 期待する出力: search_database が呼ばれる(search_web は呼ばれない)症状5: JavaScriptでFunction Callingがうまくいかない
原因の分析
Python以外のSDKでは、APIの呼び出し方や型指定が異なります。Node.js(Google AI SDK)でのよくあるミスを確認しましょう。
import { GoogleGenerativeAI } from "@google/generative-ai";
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
// ✅ JavaScript での正しいFunction Calling実装
const getStockPriceTool = {
functionDeclarations: [
{
name: "get_stock_price",
description: "指定した銘柄コードの現在の株価を取得します",
parameters: {
type: "OBJECT", // JavaScriptでは大文字
properties: {
symbol: {
type: "STRING", // 大文字
description: "銘柄コード(例: GOOGL, AAPL)"
}
},
required: ["symbol"]
}
}
]
};
async function runFunctionCalling() {
const model = genAI.getGenerativeModel({
model: "gemini-2.5-pro",
tools: [getStockPriceTool]
});
const chat = model.startChat();
const result = await chat.sendMessage("Googleの株価を教えて");
// レスポンスのパース
const response = result.response;
const candidate = response.candidates[0];
for (const part of candidate.content.parts) {
if (part.functionCall) {
const { name, args } = part.functionCall;
console.log(`✅ ツール呼び出し: ${name}`, args);
// ツール実行
const toolResult = { price: 175.42, currency: "USD" };
// ツール結果を返す
const followUp = await chat.sendMessage([{
functionResponse: {
name: name,
response: { result: toolResult }
}
}]);
console.log("🤖 最終回答:", followUp.response.text());
}
}
}
runFunctionCalling();
// 期待する出力:
// ✅ ツール呼び出し: get_stock_price { symbol: 'GOOGL' }
// 🤖 最終回答: Googleの現在の株価は175.42ドルです。確認方法: 解決できたか検証する
以下のチェックリストで動作を確認しましょう。
import google.generativeai as genai
genai.configure(api_key="YOUR_GEMINI_API_KEY")
def verify_function_calling():
"""Function Callingが正しく動作するか確認するテスト"""
test_tool = {
"name": "add_numbers",
"description": "2つの数値を足し算します。数値計算が必要な場合に使用してください。",
"parameters": {
"type": "object",
"properties": {
"a": {"type": "number", "description": "1つ目の数値"},
"b": {"type": "number", "description": "2つ目の数値"}
},
"required": ["a", "b"]
}
}
model = genai.GenerativeModel(
model_name="gemini-2.5-pro",
tools=[test_tool],
tool_config={"function_calling_config": {"mode": "ANY"}}
)
response = model.generate_content("3 + 5 を計算して")
part = response.candidates[0].content.parts[0]
assert hasattr(part, "function_call"), "❌ function_callが含まれていません"
assert part.function_call.name == "add_numbers", "❌ ツール名が正しくありません"
args = dict(part.function_call.args)
assert "a" in args and "b" in args, "❌ 引数が正しくありません"
print(f"✅ テスト成功: add_numbers(a={args['a']}, b={args['b']})")
print(f" 期待する計算結果: {args['a'] + args['b']}")
verify_function_calling()予防策: 再発防止のベストプラクティス
トラブルを未然に防ぐために、以下の点を実装に組み込みましょう。
1. ツール定義のバリデーション: スキーマを一元管理してテストを書く
def validate_tool_schema(tool: dict) -> bool:
"""ツールスキーマの基本チェック"""
required_keys = ["name", "description", "parameters"]
for key in required_keys:
if key not in tool:
print(f"❌ '{key}' が必要です")
return False
params = tool["parameters"]
if "required" in params:
props = params.get("properties", {})
for req_field in params["required"]:
if req_field not in props:
print(f"❌ required フィールド '{req_field}' が properties に存在しません")
return False
print(f"✅ ツール '{tool['name']}' のスキーマは正常です")
return True2. finish_reason の監視: MAX_TOKENS や SAFETY で打ち切られていないか確認する
3. 再試行ロジック: ツールが呼ばれなかった場合はメッセージを具体化して再試行する
4. ログ記録: すべてのfunction_callとfunction_responseを記録して異常検知に使う
まとめ
Gemini APIのFunction Callingトラブルは、多くの場合以下のいずれかが原因です。
- ツールの
descriptionが不明確で、モデルが使用を判断できない - スキーマの型名やフィールド名にタイポがある
- レスポンスのパース方法がAPIの構造と合っていない
- 複数ツールの競合を
allowed_function_namesで解決していない
デバッグの際は tool_config の mode: ANY でツール呼び出しを強制し、スキーマが正しく渡っているかを確認するのが最短の道です。問題が解消しない場合は、最小限のシンプルなツールで再現確認してから複雑な実装に戻りましょう。
Function Callingのさらなる活用法については、Gemini APIのFunction Calling完全ガイドも合わせてご覧ください。
本記事の実装