ANTIGRAVITY LABEN
記事一覧/AIツール
AIツール/2026-04-17中級

Antigravity Python SDK でFunction Callingを実装する:AIに外部ツールを使わせる実践ガイド

Google Antigravity Python SDKのFunction Callingを実装する方法を実践的なコード例で解説。AIに外部APIを呼ばせる仕組みと、Antigravity IDE上でのデバッグ方法まで習得できます。

python26function-calling5google-antigravity2api13gemini15

「AIにコードを書いてもらうのはできた。でも、実際に天気APIを叩いてきてほしい」

Antigravityで開発していると、こういう一歩先の要求が自然と出てきます。AIアシスタントがコードを「提案する」だけでなく、「実際のデータを使って動く」ところまで自律して動いてほしい。そのための仕組みがFunction Callingです。

PythonからGeminiのFunction Callingを実装するとき、最初は「モデルが自分でAPIを呼ぶのか?」と思いがちです。実際は少し違います。ここではその仕組みの正確な理解と、Antigravity IDE上で実際に動かすコードを一緒に確認していきます。

Function Callingの往復を理解する

コードを書く前に、仕組みを整理しておきます。

Function Callingは「モデルが自分で関数を実行する」ではなく、「モデルが呼び出しを指示し、実行はアプリ側が行う」という設計です。この往復を把握しておくと、デバッグ時に何が起きているか見通せるようになります。

  1. アプリ側が「使えるツール(関数定義)」をモデルに渡す
  2. モデルが「この関数を呼んでほしい」というレスポンスを返す(実際には実行しない)
  3. アプリ側でその関数を実行し、結果をモデルに送る
  4. モデルが結果を踏まえて最終的な回答を生成する

セキュリティ面でも、この設計は優れています。アプリ側がどの関数を公開するかを完全に制御できるため、モデルが任意のコードを実行することはありません。

環境の準備

まずパッケージをインストールします:

pip install google-generativeai python-dotenv

APIキーはGoogle AI Studioから取得します。コードに直接書かず、環境変数で管理する習慣をつけておきましょう。プロジェクトルートに .env ファイルを作成して:

GOOGLE_API_KEY=YOUR_GEMINI_API_KEY

.gitignore.env を追加するのも忘れずに。Antigravityのファイルツリーで .gitignore を開くと、インライン補完が候補を出してくれます。

最初のFunction Callingを動かす

シンプルな例として、「都市名を受け取って天気を返すツール」を定義してみます。

import google.generativeai as genai
import os
from dotenv import load_dotenv
 
load_dotenv()
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
 
# ① 実際に呼ばれる関数(ここを本物のAPIに差し替える)
def get_current_weather(city: str) -> dict:
    """指定した都市の現在の天気情報を返す(デモ用モック)"""
    mock_data = {
        "東京": {"weather": "晴れ", "temp": 22, "humidity": 45},
        "大阪": {"weather": "曇り", "temp": 20, "humidity": 58},
        "福岡": {"weather": "雨", "temp": 18, "humidity": 72},
    }
    return mock_data.get(city, {"weather": "情報なし", "temp": 0, "humidity": 0})
 
# ② モデルに渡すツールのスキーマ定義
weather_tool = genai.protos.Tool(
    function_declarations=[
        genai.protos.FunctionDeclaration(
            name="get_current_weather",
            description="指定した都市の現在の天気情報を取得する",
            parameters=genai.protos.Schema(
                type=genai.protos.Type.OBJECT,
                properties={
                    "city": genai.protos.Schema(
                        type=genai.protos.Type.STRING,
                        description="天気を調べたい都市名(例: 東京、大阪、福岡)"
                    )
                },
                required=["city"]
            )
        )
    ]
)
 
# ③ モデルとチャットセッションの初期化
model = genai.GenerativeModel(
    model_name="gemini-2.0-flash",
    tools=[weather_tool]
)
chat = model.start_chat()
 
# ④ ユーザーメッセージを送る
response = chat.send_message("東京の今日の天気を教えてください")
 
# ⑤ Function Callレスポンスを処理する
part = response.candidates[0].content.parts[0]
if hasattr(part, "function_call") and part.function_call.name:
    fc = part.function_call
    print(f"モデルが要求した関数: {fc.name}")
    print(f"引数: {dict(fc.args)}")
 
    # 関数を実行
    result = get_current_weather(**dict(fc.args))
    print(f"実行結果: {result}")
 
    # 結果をモデルに返す
    final_response = chat.send_message(
        genai.protos.Content(
            parts=[genai.protos.Part(
                function_response=genai.protos.FunctionResponse(
                    name=fc.name,
                    response={"result": result}
                )
            )]
        )
    )
    print(f"\nモデルの最終回答:\n{final_response.text}")

実行すると、次のような出力が得られます:

モデルが要求した関数: get_current_weather
引数: {'city': '東京'}
実行結果: {'weather': '晴れ', 'temp': 22, 'humidity': 45}

モデルの最終回答:
東京の現在の天気は晴れで、気温22℃、湿度45%です。...

複数ツールを組み合わせたループパターン

実用的なアプリでは、複数のツールをモデルが順番に呼び出すケースが多くなります。「天気を取得して、スケジュールと照合して、メモに保存する」のような一連の処理です。

import google.generativeai as genai
import os
from dotenv import load_dotenv
from datetime import datetime
 
load_dotenv()
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
 
# 複数のツール関数
def get_current_weather(city: str) -> dict:
    """都市の天気を返す"""
    return {"city": city, "weather": "晴れ", "temp": 22}
 
def get_today_schedule() -> list:
    """今日のスケジュールを返す(モック)"""
    return [
        {"time": "10:00", "event": "チームMTG"},
        {"time": "14:00", "event": "コードレビュー"},
    ]
 
def save_memo(title: str, content: str) -> dict:
    """メモをローカルファイルに保存する"""
    filename = f"memo_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
    try:
        with open(filename, "w", encoding="utf-8") as f:
            f.write(f"# {title}\n\n{content}")
        return {"saved": True, "filename": filename}
    except IOError as e:
        return {"saved": False, "error": str(e)}
 
# ツールディスパッチャー(関数名 → 実装の対応表)
TOOL_FUNCTIONS = {
    "get_current_weather": get_current_weather,
    "get_today_schedule": get_today_schedule,
    "save_memo": save_memo,
}
 
tools = [genai.protos.Tool(function_declarations=[
    genai.protos.FunctionDeclaration(
        name="get_current_weather",
        description="指定した都市の天気を取得する",
        parameters=genai.protos.Schema(
            type=genai.protos.Type.OBJECT,
            properties={"city": genai.protos.Schema(
                type=genai.protos.Type.STRING, description="都市名"
            )},
            required=["city"]
        )
    ),
    genai.protos.FunctionDeclaration(
        name="get_today_schedule",
        description="今日の予定一覧を取得する",
        parameters=genai.protos.Schema(
            type=genai.protos.Type.OBJECT,
            properties={}
        )
    ),
    genai.protos.FunctionDeclaration(
        name="save_memo",
        description="タイトルと内容を受け取ってメモを保存する",
        parameters=genai.protos.Schema(
            type=genai.protos.Type.OBJECT,
            properties={
                "title": genai.protos.Schema(type=genai.protos.Type.STRING, description="メモのタイトル"),
                "content": genai.protos.Schema(type=genai.protos.Type.STRING, description="メモの本文")
            },
            required=["title", "content"]
        )
    ),
])]
 
model = genai.GenerativeModel(model_name="gemini-2.0-flash", tools=tools)
chat = model.start_chat()
 
def run_agent(user_message: str) -> str:
    """Function Callingのループを処理して最終テキストを返す"""
    response = chat.send_message(user_message)
 
    # モデルがFunction Callを返す間ループし続ける
    for _ in range(10):  # 無限ループ防止のため最大10回
        parts = response.candidates[0].content.parts
        fc_part = next(
            (p for p in parts if hasattr(p, "function_call") and p.function_call.name),
            None
        )
 
        if fc_part is None:
            break  # テキスト回答が来たのでループ終了
 
        fc = fc_part.function_call
        func = TOOL_FUNCTIONS.get(fc.name)
 
        if func is None:
            print(f"⚠️ 未定義のツール: {fc.name}")
            break
 
        result = func(**dict(fc.args))
 
        # 結果をモデルにフィードバック
        response = chat.send_message(
            genai.protos.Content(parts=[
                genai.protos.Part(function_response=genai.protos.FunctionResponse(
                    name=fc.name,
                    response={"result": result}
                ))
            ])
        )
 
    return response.text
 
# 実行
result = run_agent(
    "東京の天気と今日の予定を確認して、「今日のブリーフィング」というタイトルでメモに保存してください"
)
print(result)

run_agent() でFunction Callingのループを一箇所に集約しているのがポイントです。モデルが複数の関数を順次呼び出すケースでも、この構造で自然に対応できます。

Antigravity IDEでデバッグするコツ

Function Callingの実装で詰まりやすいのは「モデルが関数を呼ばない」ケースです。Antigravityのインラインチャット(Cmd+I)で print(response.candidates[0].content.parts) の出力を解析すると速く解決できます。

まずレスポンス構造を丸ごと出力して確認するのが早道です:

# デバッグ用:レスポンスの構造を確認する
response = chat.send_message("東京の天気は?")
for i, part in enumerate(response.candidates[0].content.parts):
    print(f"[part {i}] type={type(part).__name__}")
    if hasattr(part, "function_call") and part.function_call.name:
        print(f"  function_call: {part.function_call.name}")
        print(f"  args: {dict(part.function_call.args)}")
    elif hasattr(part, "text"):
        print(f"  text: {part.text[:100]}")

モデルが関数を呼ばない原因は、だいたい次のどれかです。description が曖昧でモデルが「このツールを使うべき場面だ」と判断できていないか、ユーザーメッセージに関数を呼ぶべきシグナルが薄いかのどちらかです。たとえば「天気を教えて」より「天気APIを使って東京の天気を取得して」のほうが、モデルはツールを呼びやすくなります。

Antigravityのインライン補完は genai.protos.Schema の引数候補を出してくれるため、スキーマ定義時のタイポを防ぐのにも役立ちます。

次のステップ

Function Callingを一度動かしてみると、「AIに何かをさせる」ための視界が広がる感覚があります。まず手元のプロジェクトにある既存のユーティリティ関数を1つだけツールとして定義するところから始めてみてください。

Pythonでの本番環境向けのエラーハンドリングやレート制限対策については、Antigravity Python SDK 本番運用マスターガイドが参考になります。より複雑な自律エージェントに発展させたい場合は、AgentKit 2.0 完全ガイドで複数エージェントのオーケストレーションパターンを確認してみましょう。

Function Callingに慣れると、AIが「提案する」だけのツールから、「実際に動く」ツールへと使い方が変わってきます。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

AIツール2026-06-17
PyTorch・CUDAインストールエラーの直し方 — torch.cuda.is_available()がFalse・バージョン不一致の解決【2026】
PyTorchやCUDAのインストールが失敗する原因を解説し、バージョン不一致・依存関係エラー・GPUが認識されない問題をStep by Stepで解決します。
AIツール2026-04-19
Gemma 4 で日本語テキスト処理アプリを作る — 要約・感情分析を Antigravity で実装する
Gemma 4 の高い日本語対応力を活かし、Antigravity で Python アプリを実装する手順を解説。テキスト要約・感情分析のコードをステップ別に示します。
AIツール2026-04-09
Hugging Face Transformers のエラー対処ガイド — 原因の見分け方と解決手順
Hugging Face Transformersで起きやすいエラーを症状別に整理。ImportError、CUDA OOM、bf16非対応GPU、ゲート付きモデルの401、キャッシュ肥大化まで、原因の見分け方と解決手順をまとめます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →