エージェント開発の経験がある開発者なら、この課題に直面したことがあるはずです。生成AIモデルに「ユーザーの質問に応じて、複数のツールを組み合わせて実行する」という複雑な推論を任せたい。しかし、大半のオープンウェイトモデルでは、モデルの出力を正確に制御することが困難です。
Gemma 4が2026年4月にリリースされた理由の1つは、まさにここです。オープンモデルとしてのGemma 4は、ネイティブで関数呼び出し・構造化JSON出力・システム指示に対応しており、クローズドモデルに頼らずにエージェント開発ができる環境が整いましました。
Function Calling対応が意味する開発体験の変化
従来のオープンモデル(Llama 2/3など)では、関数呼び出しを実装する方法は限定的でしました。
- プロンプトエンジニアリング頼み: 「JSONフォーマットで出力してください」とプロンプトに書くが、モデルが守らないことが多い
- 出力解析の複雑性: 不正なJSONが返ってくるたびに、リトライロジックを書く必要がある
- 精度の不安定性: モデルサイズを大きくしても、JSON形式を厳密に守る保証がない
Gemma 4では、これらの問題が一部解決されます。
Gemma 4はシステム指示(System Prompt)をサポートし、関数定義をJSONスキーマで渡すと、モデルが構造化JSON出力を返すメカニズムが組み込まれています。つまり、プロンプトエンジニアリングではなく、APIレベルで関数呼び出しの契約が定義できるということです。
APIレベルの関数定義 — tools パラメータの使い方
Gemma 4のFunction Callingは、Google Gemini APIと互換性を持つインターフェースを提供しています。
以下は、ユーザーの質問に応じて天気情報と配送状況を取得するエージェントの例です。
```python import anthropic import json
client = anthropic.Anthropic(api_key="YOUR_GEMINI_API_KEY")
tools = [ { "name": "get_weather", "description": "指定された都市の天気情報を取得する", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "都市名" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "気温の単位" } }, "required": ["city"] } }, { "name": "track_shipment", "description": "配送状況を追跡する", "input_schema": { "type": "object", "properties": { "tracking_number": { "type": "string", "description": "追跡番号" } }, "required": ["tracking_number"] } } ]
user_message = "東京の天気はどう?それと、追跡番号 SHP-12345 の荷物の状態も教えて"
response = client.messages.create( model="gemini-2.0-flash", max_tokens=1024, system="あなたはユーザーの質問に応じて、複数のツールを組み合わせて回答するアシスタントです。", tools=tools, messages=[ {"role": "user", "content": user_message} ] )
print(f"Stop Reason: {response.stop_reason}") for block in response.content: if hasattr(block, 'type'): print(f"Content Type: {block.type}") if block.type == "tool_use": print(f" Tool Name: {block.name}") print(f" Input: {json.dumps(block.input, indent=2)}") ```
ここで重要な点が3つあります。
1. `input_schema` は JSONスキーマ形式で厳密に記述する
Gemma 4は、このスキーマを解析してモデルの出力を制約します。`properties` の型定義(`string`, `number`, `array`など)や `enum` の指定が効いて、モデルが不正な出力を減らします。
2. `tools` パラメータは配列で複数の関数を同時に定義
モデルは、ユーザーの質問に応じて最適な関数を選択します。上の例では、天気と配送の両方を聞かれたので、モデルが両方の関数を呼び出す可能性があります。
3. `stop_reason` を `"tool_calls"` で検出
APIレスポンスの `stop_reason` が `"tool_calls"` なら、モデルが関数呼び出しを決めたということです。その場合、`response.content` 内の `tool_use` ブロックが実行すべき関数を含みます。
実装の落とし穴 — JSON解析と型安全性
Function Callを実装するときに直面する実際のトラブルを見てみましょう。
```python
❌ よくある間違い
if response.stop_reason == "tool_calls": for block in response.content: if block.type == "tool_use": result = execute_function(block.name, block.input) break ```
この書き方は、ユーザーが複数のツールを必要とする質問をした場合、後続のツール呼び出しを無視してしまいます。Gemma 4は複数のFunction Callを一度に返せるため、ループを途中で抜けてはいけません。
正しい実装:
```python
✅ 正しい実装
def process_tool_calls(response): results = []
if response.stop_reason == "tool_calls":
for block in response.content:
if block.type == "tool_use":
function_result = execute_function(block.name, block.input)
results.append({
"tool_use_id": block.id,
"function_name": block.name,
"result": function_result
})
return results
def run_agent_loop(user_message): messages = [{"role": "user", "content": user_message}]
while True:
response = client.messages.create(
model="gemini-2.0-flash",
max_tokens=1024,
tools=tools,
messages=messages
)
tool_results = process_tool_calls(response)
if response.stop_reason \!= "tool_calls":
for block in response.content:
if block.type == "text":
print(f"アシスタント: {block.text}")
break
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": result["tool_use_id"],
"content": str(result["result"])
}
for result in tool_results
]
})
```
このループが重要です。Gemma 4(とGemini APIの関数呼び出し)は、複数ラウンドの会話をサポートします。最初のリクエストで関数を呼び出し、その結果をモデルに返すと、モデルがさらに推論を続けて、最終的なテキスト出力を生成します。
システム指示とFunction Callingの相互作用
Gemma 4がFunction Callを適切に実行するかどうかは、システムプロンプトの質にも左右されます。
```python system_prompt = """ あなたはユーザーの質問に応じてツールを使用するアシスタントです。
重要な指示:
- ユーザーの質問を理解したら、必要なツールを全て識別してください
- 複数のツールが必要な場合、同時に実行可能なツールは1ステップで呼び出してください
- ツール実行後、結果を解釈してユーザーに分かりやすく説明してください
- 不確実な情報がある場合は、明示的に「データが不足しています」と伝えてください
- ユーザーの質問がツール実行を必要としない場合は、ツール呼び出しを避け、直接テキストで応答してください """
response = client.messages.create( model="gemini-2.0-flash", max_tokens=1024, system=system_prompt, tools=tools, messages=[{"role": "user", "content": user_message}] ) ```
ここでの工夫は「いつツールを使う/使わないか」をシステムプロンプトで明示的に指示することです。多くのオープンモデルは、ツールが定義されているとデフォルトで呼び出そうとします。しかし、ユーザーの単純な雑談には関数呼び出しは不要です。プロンプトで適切に分離することで、APIコストと推論遅延を削減できます。
Gemma 4 の26B MoEと31B Dense — どちらをFunction Callに使うか
Gemma 4には2つの主要バリアントがあります:
- 26B MoE (活性パラメータ~4B):軽量で高速。エッジデバイスでの実行が現実的
- 31B Dense:大規模で高精度。複雑なマルチステップエージェントに向く
Function Callの観点では、31B Denseを推奨します。理由は、複数ツールの選択や複合的な推論がより安定するためです。26B MoEは軽量ですが、複雑なエージェントシナリオでは関数選択の精度が低下する傾向があります。
ただし、オンデバイス実行やレイテンシー制約がある場合は、26B MoEでFunction Callを検証してから本番展開するアプローチが実用的です。
次のステップ — エージェント設計の全体像へ
ここまで、Gemma 4のFunction Calling実装の核となる部分を見てきましました。これを本番レベルのエージェントに拡張するには、以下が必要です:
- 関数実行の信頼性設計:ネットワークエラーやタイムアウト時のリトライロジック
- プロンプトキャッシング:長い会話履歴を効率的に処理するため、システムプロンプトとtoolsパラメータをキャッシュ
- ツール出力の検証:モデルが期待する形式のツール結果を常に返す
実装した関数定義とエージェントループは、さらに深く掘り下げ、プレミアム記事で詳細な設計パターンと量子化技法を解説します。今は、Gemma 4のFunction Calling基盤をしっかり理解することが、エージェント開発の成功につながります。