GEMINI LABEN
NANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定ですNANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定です
記事一覧/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-api279function-calling20ios12android7swiftui4kotlin4indie-dev21mobile5

プレミアム記事

壁紙アプリのレビューに「もっと好みを学習してほしい」というコメントが増え始めたのは、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 = 5else ブロックです。Python の for...else は、ループが break なしで完了した場合(つまり最大回数に達した場合)に else を実行します。本番で実際に発生した問題として、モデルが同じ関数を微妙に異なる引数で繰り返し呼び出し続けるケースがありました。ループガードなしではこれが課金インシデントに繋がります。

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

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

この記事の続きを読む

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

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

この記事を購入する

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

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

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

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

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

関連記事

API / SDK2026-05-25
Gemini 2.5 Flash で個人開発アプリのヘルプ翻訳を3ヶ月運用した所感
iOS / Android の個人開発アプリで提供してきた多言語ヘルプを、Gemini 2.5 Flash を中心とした翻訳パイプラインで運用し始めて3ヶ月が経ちました。Pro との使い分け、訳文ドリフトへの備え、AdMob 収益に与えた小さな効果まで、運用ログに残った所感を淡々と記録します。
API / SDK2026-05-05
Gemini APIキーをモバイルアプリに埋め込んではいけない:Firebase App Check で実現する多層防御アーキテクチャ
モバイルアプリでGemini APIを安全に使うためのバックエンド設計パターン。Firebase App Check・Cloud Functions・レートリミット・異常検知を組み合わせた本番グレードの多層防御実装ガイド。
API / SDK2026-04-03
Gemini API × SwiftUI 本番アプリ実装ガイド:ストリーミング・マルチモーダル・エラーハンドリング・App Store対策まで
Gemini APIをSwiftUIアプリに本番レベルで統合する実装ノウハウ。ストリーミング応答・マルチモーダル入力・エラーハンドリング・テスト戦略・App Store申請対策まで、プロ向けの実装ノウハウを実例とともに整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →