◉GEMINI LABEN
●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — deep-research-pro-preview-12-2025 は 10/23 に停止、残り6日。移行先は deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●MCP — ツール結果が 8.5万トークンに膨らんだ事例を、ADK で 310 トークンに包んで抑えた報告が出ています●FLASH — gemini-3.7-flash と 3.5-flash は新しい Flash モデルに自動で回されます(10/08)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — deep-research-pro-preview-12-2025 は 10/23 に停止、残り6日。移行先は deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●MCP — ツール結果が 8.5万トークンに膨らんだ事例を、ADK で 310 トークンに包んで抑えた報告が出ています●FLASH — gemini-3.7-flash と 3.5-flash は新しい Flash モデルに自動で回されます(10/08)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…
記事一覧/API / SDK
◈ API / SDK/2026-06-23上級

Gemini 3.2 Pro の Function Calling を iOS/Android アプリに統合する実装パターン

Gemini 3.2 Pro の Function Calling を iOS/Android アプリに統合する実装ガイド。SwiftUI・Kotlin 両対応の動くコード例と、個人開発の壁紙アプリで実証した本番設計パターン(コスト・レイテンシ・段階ロールアウト・回帰テスト)を解説します。

gemini-api287function-calling20ios13android8swiftui4kotlin4indie-dev23mobile5

✦ プレミアム記事

壁紙アプリのレビューに「もっと好みを学習してほしい」というコメントが増え始めたのは、2025 年の後半からでした。

個人開発で壁紙アプリを長く運用していると、ユーザーの期待値が変わる瞬間に気づくことがあります。以前は「きれいな画像が見られれば十分」だったリクエストが、今は「自分のことを覚えていてほしい」「文脈を理解してほしい」という言葉に変わってきました。

この変化に応えようとしたとき、最初に検討したのは従来のレコメンドエンジンでした。協調フィルタリングやコンテンツベースマッチングは試したことがあります。これらは確かに機能しますが、限界があります。「いつもの系統に似ているけど少し違うものを見せて」という曖昧な意図の空間には、ルールベースのアプローチでは対応しきれません。設計時点ですべてのバリエーションを予測する必要があり、条件分岐が際限なく増えていくのです。

そこで試したのが Gemini 3.2 Pro の Function Calling です。

通常の API 呼び出しとは根本的に発想が異なります。Function Calling では「何をするか」をモデルが判断し、「どう実行するか」をアプリ側で制御できます。ルールを書くのではなく、「できること」を宣言するだけで済みます。この設計思想の転換が、個人開発のアーキテクチャを大きく変えました。

Function Calling が「命令型 API」を「意図型 API」に変えるもの

通常の API は命令型です。「style=minimal で mood=calm の画像を 10 件返せ」と明示的に指示します。パラメータはクライアントが決め、サーバーはその通りに実行します。

一方、Function Calling は意図型です。「ユーザーが落ち着く壁紙を求めている」という意図をモデルが解釈し、必要な関数を選んで呼び出します。アプリ側はどの関数を呼ぶかを決めず、「呼べる関数の一覧」を宣言するだけです。

この違いが特に重要になるのは、ユーザーの意図が曖昧なときです。「最近ちょっと疲れてる感じのやつ」「いつもと違うけど落ち着くやつ」といった表現は、ルールベースでは変換できません。Function Calling では、このような表現をモデルが文脈から解釈し、filter_wallpapers(mood='calm', style='minimal', exclude_seen=True) のような具体的な関数呼び出しに変換してくれます。

もう一つの重要な特性は、アプリを更新せずに機能を拡張できる点です。新しい関数をバックエンドに追加し、モデルへの宣言リストを更新するだけで、既存のアプリバージョンのユーザーも新機能を使えるようになります。App Store のレビューサイクルを待つ必要がありません。個人開発者にとって、このリリースの柔軟性は大きな価値があります。

Gemini 3.2 Pro では、複数の関数を連続して呼び出す「複合 Function Calling」が、以前のバージョンよりも格段に安定しています。2.5 Pro では、3 つ以上の関数を連鎖させると途中でテキスト回答に切り替わるケースが全体の 15〜20% ほど見られました。3.2 Pro ではほぼ解消されており、mode: "AUTO" でも連鎖が安定して機能します。

Function Calling の基礎は Gemini API Function Calling:ツール統合と実践的な活用法 に書き残しておりますので、前提から辿りたい方はそちらをご覧いただければと思います。

環境構築:Python バックエンドで動作確認する

iOS/Android への組み込み前に、Python でコア動作を検証する工程を必ず挟んでいます。モバイルのビルドサイクルは遅く、関数の宣言やモデルの挙動を確認するには Python の REPL が明確に速いからです。

実際の検証フロー:関数を宣言 → スタブ実装(フェイクデータを返すだけ)で各種フレーズを試す → モデルが期待通りの関数を期待通りの順序で呼ぶか確認 → OK なら Swift/Kotlin に移行、という手順をとっています。

必要なもの:

  • Python 3.11+
  • google-genai SDK (pip install google-genai)
  • Gemini API キー(Google AI Studio の無料枠で検証可能)

基本実装(コード例 1)

import google.generativeai as genai
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
# 壁紙アプリ向け Function 定義
tools = [
    {
        "function_declarations": [
            {
                "name": "get_user_preferences",
                "description": "ユーザーの壁紙好み履歴を取得します",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "user_id": {"type": "string", "description": "ユーザーID"}
                    },
                    "required": ["user_id"]
                }
            },
            {
                "name": "filter_wallpapers",
                "description": "条件に合う壁紙一覧を返します",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "style": {
                            "type": "string",
                            "enum": ["nature", "abstract", "minimal", "art"]
                        },
                        "mood": {
                            "type": "string",
                            "enum": ["calm", "energetic", "dark", "bright"]
                        },
                        "exclude_seen": {
                            "type": "boolean",
                            "description": "True の場合、最近閲覧済みの壁紙を除外する"
                        },
                        "limit": {
                            "type": "integer",
                            "description": "返す件数(デフォルト: 10)"
                        }
                    }
                }
            }
        ]
    }
]
 
model = genai.GenerativeModel(
    model_name="gemini-3.2-pro",
    tools=tools,
    tool_config={"function_calling_config": {"mode": "AUTO"}}
)
 
def get_user_preferences(user_id: str) -> dict:
    # 実際にはデータベースから取得
    return {"preferred_styles": ["minimal", "nature"], "preferred_moods": ["calm"]}
 
def filter_wallpapers(style: str = None, mood: str = None,
                      exclude_seen: bool = False, limit: int = 10) -> list:
    # 実際にはAPIまたはDBから取得
    return [
        {"id": "w001", "title": "朝の森", "style": "nature", "mood": "calm"},
        {"id": "w002", "title": "シンプル白", "style": "minimal", "mood": "calm"},
    ][:limit]
 
def dispatch_function(function_call):
    name = function_call.name
    args = dict(function_call.args)
    if name == "get_user_preferences":
        return get_user_preferences(**args)
    elif name == "filter_wallpapers":
        return filter_wallpapers(**args)
    return {"error": f"Unknown function: {name}"}
 
def run_with_function_calling(user_message: str, user_id: str = "user_001") -> str:
    chat = model.start_chat()
    context = f"ユーザーID: {user_id}。壁紙アプリのアシスタントとして応答してください。"
    response = chat.send_message(f"{context}\n\nユーザーのリクエスト: {user_message}")
 
    # 無限ループ防止が重要 — 本番環境では必須
    max_iterations = 5
    for _ in range(max_iterations):
        function_calls = [
            part.function_call
            for part in response.candidates[0].content.parts
            if hasattr(part, "function_call") and part.function_call
        ]
        if not function_calls:
            break  # テキスト回答が来た場合はループを終了
 
        responses = [
            {
                "function_response": {
                    "name": fc.name,
                    "response": {"result": dispatch_function(fc)}
                }
            }
            for fc in function_calls
        ]
        response = chat.send_message(responses)
    else:
        # max_iterations を使い切っても終わらなかった場合のフォールバック
        return "処理が完了できませんでした。もう一度お試しください。"
 
    return "".join(
        part.text for part in response.candidates[0].content.parts
        if hasattr(part, "text")
    )
 
if __name__ == "__main__":
    # 様々な表現でモデルの挙動を確認する
    tests = [
        "落ち着く感じの壁紙を見せて",
        "いつもと違うけど同じ雰囲気のやつ",
        "最近見てないやつを見せて",
    ]
    for msg in tests:
        print(f"入力: {msg}")
        print(f"出力: {run_with_function_calling(msg)}")
        print("---")

この実装で特に重要なのは max_iterations = 5 と else ブロックです。Python の for...else は、ループが break なしで完了した場合(つまり最大回数に達した場合)に else を実行します。本番で実際に発生した問題として、モデルが同じ関数を微妙に異なる引数で繰り返し呼び出し続けるケースがありました。ループガードなしではこれが課金インシデントに繋がります。

非同期パターンとの組み合わせについては Gemini API asyncio 本番実装パターンも参考にしてください。

✦

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦Function Calling を「命令型」から「意図型」へ転換するモバイル設計の考え方
✦SwiftUI・Kotlin・Python の動くコードと、ループガード・タイムアウト・指数バックオフの実装
✦本番で実証したコスト約40%削減・段階ロールアウト・セッション時間18%増の具体データ
✦description 変更やモデル更新でルーティングが壊れるのを防ぐ回帰テストハーネス
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

◈ API / SDK2026-04-03
Gemini API × SwiftUI 本番アプリ実装ガイド:ストリーミング・マルチモーダル・エラーハンドリング・App Store対策まで
Gemini APIをSwiftUIアプリに本番レベルで統合する実装ノウハウ。ストリーミング応答・マルチモーダル入力・エラーハンドリング・テスト戦略・App Store申請対策まで、プロ向けの実装ノウハウを実例とともに整理します。
◈ API / SDK2026-05-31
Gemini 2.5 Flash で App Store のキーワード欄を多言語最適化した1ヶ月の所感
App Store Connect の100文字キーワード欄を、40本の壁紙アプリ×複数ロケールで Gemini 2.5 Flash に下書きさせた1ヶ月の運用ログです。CJK の文字数、タイトル重複の排除、禁止語の落とし穴、ロケールごとの効きどころの違いまで、現場でつまずいた点を淡々と記録します。
◈ API / SDK2026-05-16
Firebase Crashlytics のクラッシュログを Gemini API で自動分析した記録 — 個人開発アプリ v2.1.0 での実証
Firebase Crashlytics の生ログを Gemini API に渡して根本原因とコード修正案を自動生成するパイプラインを、個人開発の壁紙アプリ v2.1.0 の実開発で検証した記録です。RecyclerView クラッシュの Before/After 付き。