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-05-15中級

Gemini API Embedding で踏んだ3つの地雷 — 壁紙アプリのカテゴリ自動分類で遭遇したエラーと対処法

Gemini API Embedding を壁紙アプリのカテゴリ自動分類に組み込んだ際に踏んだ3つのエラー(INVALID_ARGUMENT・RESOURCE_EXHAUSTED 429・RAG精度低下)と実際の修正コードを紹介します。

Gemini API191Embedding3RAG15エラー3Python38個人開発91トラブルシューティング30

Beautiful HD Wallpapers(iOS / Android、累計5,000万DL超)のバックエンドに、Gemini API の Embedding を使ったカテゴリ自動分類機能を追加しようとしたときのことです。公式ドキュメントのサンプルコードは数行で動いたのですが、実際に壁紙画像の説明文を数百件処理し始めた途端に、3つの問題が重なって出てきました。

個人開発でモバイルアプリを2014年から運営していると、こうした「ドキュメントには書かれていない落とし穴」に繰り返しぶつかります。エラーメッセージだけでは原因を特定しにくいものが多いので、実際に踏んだ手順と修正の流れをそのまま記録しておきます。同じ状況で悩んでいる方の参考になれば幸いです。

INVALID_ARGUMENT — 途中で次元数を変えると既存インデックスが壊れる

Gemini の text-embedding-004 モデルはデフォルトで768次元のベクトルを返します。output_dimensionality パラメータを使えば任意の次元数に変更できるのですが、一度インデックスを構築した後に次元数を変えると、INVALID_ARGUMENT エラーが発生して処理が止まります。

私が実際にぶつかったのは、最初に output_dimensionality=3072 でインデックスを作成し、後でコスト削減のために768次元に変更しようとしたケースでした。エラーメッセージは「引数が間違っている」としか出ないため、最初はAPIの呼び出し方が悪いのかと思い、30分ほど公式ドキュメントを読み直しました。次元数の不一致が原因だと気づいたのは、ChromaDBのコレクション設定を改めて確認したときでした。

原因が分かれば対処は単純で、インデックスと output_dimensionality を一致させるか、新しい次元数でインデックスを作り直すかのどちらかです。コスト削減を優先するなら768次元でインデックスを再構築する必要があります。壁紙アプリでは件数が多かったため、週末の深夜に再生成バッチを走らせて対応しました。

import google.generativeai as genai
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
# ❌ 既存の3072次元インデックスに768次元ベクトルを投げると INVALID_ARGUMENT
result = genai.embed_content(
    model="models/text-embedding-004",
    content="美しい山の景色",
    output_dimensionality=768,  # インデックスと不一致
)
 
# ✅ インデックスと次元数を揃える
result = genai.embed_content(
    model="models/text-embedding-004",
    content="美しい山の景色",
    output_dimensionality=3072,  # 既存インデックスに合わせる
)

次元数の選び方について補足すると、768次元と3072次元の検索精度の差は、個人開発規模のデータ量では体感しにくいほど小さいことがあります。精度よりもストレージコストを優先するなら768次元で十分です。いずれにせよ、最初に決めた次元数は変えないようにしましょう。output_dimensionality は「後から調整できるパラメータ」ではなく「インデックスと一緒に固定する設定」と理解しておくと、このエラーを防げます。

RESOURCE_EXHAUSTED(429)— バッチ処理でレートリミットに詰まる

カテゴリ自動分類のために壁紙の説明文を500件一気に処理しようとして、RESOURCE_EXHAUSTED エラーが出続けました。Gemini API の Embedding エンドポイントには1分あたりの呼び出し制限があります。

最初は50msのインターバルを入れれば大丈夫だろうと思っていたのですが、それでも429が続きました。特にフリープランでは制限が厳しく、連続呼び出しではあっという間に上限に達してしまいます。

指数バックオフを実装することで安定しました。エラーが発生するたびに待機時間を倍にしていく方法で、最初は1秒、次が2秒、その次が4秒と増えていきます。5回試みてもダメなら例外を投げる設計にしています。

import time
import google.generativeai as genai
 
def embed_with_backoff(content: str, max_retries: int = 5) -> list[float]:
    """指数バックオフ付きの Embedding 呼び出し"""
    for attempt in range(max_retries):
        try:
            result = genai.embed_content(
                model="models/text-embedding-004",
                content=content,
                task_type="RETRIEVAL_DOCUMENT",
            )
            return result["embedding"]
        except Exception as e:
            if "429" in str(e) or "RESOURCE_EXHAUSTED" in str(e):
                wait_sec = 2 ** attempt  # 1, 2, 4, 8, 16 秒
                print(f"Rate limit: {wait_sec}s 待機({attempt + 1}回目)")
                time.sleep(wait_sec)
            else:
                raise
    raise RuntimeError("最大リトライ回数を超過しました")

呼び出しの間には最低でも1秒のインターバルを入れることをおすすめします。100msでは不十分でした。また、数百件を超えるバッチ処理は、昼間の処理よりも夜間に分散して実行する方がレートリミットに引っかかりにくいです。

もう一つ、バッチ全体でリトライ設計をする場合は、途中で失敗しても最初からやり直さないよう、処理済みのインデックスをファイルに保存しておく必要があります。私は500件の処理が400件目で失敗したとき、最初からやり直す羽目になりました。それ以来、チェックポイントのファイル保存を必ず実装するようにしています。

task_type を指定しないと RAG の精度が低いままになる

エラーが出なくなった後も、カテゴリ分類の検索精度が思ったより出ないという問題が残りました。「自然な山の風景」で検索しても、関係のない壁紙が上位に来てしまう状況が続きました。

調べてみると、原因は task_type の指定漏れでした。Gemini API の Embedding モデルは用途に応じて最適なベクトル空間を使い分けます。検索クエリとインデックスに格納するドキュメントで、それぞれ異なる task_type を指定しないと、モデルが汎用のベクトル空間を使ってしまい、検索精度が落ちます。

# ❌ task_type 未指定 — 汎用ベクトル空間で精度が落ちる
result = genai.embed_content(
    model="models/text-embedding-004",
    content="ナチュラルな壁紙を探しています",
)
 
# ✅ 検索クエリには RETRIEVAL_QUERY
query_result = genai.embed_content(
    model="models/text-embedding-004",
    content="ナチュラルな壁紙を探しています",
    task_type="RETRIEVAL_QUERY",
)
 
# ✅ ドキュメント格納時は RETRIEVAL_DOCUMENT
doc_result = genai.embed_content(
    model="models/text-embedding-004",
    content="緑の葉と木漏れ日が差し込む自然の景色",
    task_type="RETRIEVAL_DOCUMENT",
)

task_type を正しく設定した後、コサイン類似度ベースの検索精度が実測で15〜20%改善されました。この変更の良いところは、クエリ側だけ変えれば既存インデックスを作り直さずに効果を確認できる点です。まずクエリに RETRIEVAL_QUERY を設定して精度を計測し、改善を確認してからドキュメント側も RETRIEVAL_DOCUMENT で再生成するという順番が現実的です。

3点を最初に決めておくと後が楽になる

これらのエラーを一通り経験した後は、Embedding を組み込む前に次の3点を必ず最初に決めるようにしています。次元数・task_type の用途分け・バックオフの設計は、後から変えようとすると既存データの再生成が必要になることが多く、最初に設計しておいた方が明確に楽です。

# 壁紙アプリで採用した Embedding 設定(参考)
EMBEDDING_CONFIG = {
    "model": "models/text-embedding-004",
    "output_dimensionality": 768,        # 最初に決めて変更しない
    "query_task_type": "RETRIEVAL_QUERY",
    "doc_task_type": "RETRIEVAL_DOCUMENT",
    "batch_interval_sec": 1.0,           # 本番は 1 秒インターバル
    "max_retries": 5,                    # 指数バックオフ 5 回まで
}

廣川政樹(Dolice)は個人開発でこうした実運用上の問題を一つひとつ解決しながら、2014年からiOS/Androidアプリを運営してきました。公式ドキュメントには書かれていない落とし穴が多い分野だからこそ、実際に踏んだエラーと対処法を残しておくことに意味があると感じています。

まず試すなら task_type から

クエリ側に RETRIEVAL_QUERY を設定するだけなら数分で終わります。インデックスの再構築も不要なため、変更コストが最も低い改善策です。Gemini API Embedding を使った RAG 実装で精度に悩んでいる場合は、ここから試してみてください。

Embedding モデルの選択について補足

text-embedding-004 以外に gemini-embedding-exp-03-07 など実験的なモデルも存在しますが、個人開発の本番環境では安定稼働を優先して text-embedding-004 を使い続けています。実験モデルは精度が高い反面、予告なく挙動が変わることがあるため、特に数百件以上のデータを一度に処理するバッチ処理では、本番モデルの方が扱いやすいと感じています。

モデルの選定は最初の設計段階で決めてしまうのが賢明です。後からモデルを切り替えると、新しいモデルのベクトル空間が既存モデルと異なるため、インデックスの全データを再生成する必要が出てきます。次元数の変更と同じく、「後から変えると影響が大きい」判断の一つです。

RAG の精度をさらに上げるために

task_type の設定で精度が改善された後、さらに精度を上げるために試したことがあります。一つは、カテゴリ名だけでなく説明文を一緒に Embedding すること。「自然」というカテゴリ名だけより、「山・森・湖・空など自然の景色を収録した壁紙」という説明文を含めた方が、クエリとの類似度が高くなりました。

もう一つは、検索クエリを前処理することです。ユーザーが入力する検索語はバラエティがあるため、クエリをそのまま Embedding するより、短い説明文に変換してから Embedding した方が精度が安定しました。これはGemini API を使ったプロンプトで行っており、壁紙アプリの検索体験の改善につながっています。

Gemini Embedding API は、設定を正しく整えれば個人開発のスケールでも十分に実用できます。最初の3つのエラーさえ乗り越えれば、その後の開発体験はかなりスムーズです。

シェア

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

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

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

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

関連記事

API / SDK2026-05-11
Gemini 3.2 API に切り替えたら動かなくなった — 私が実際にぶつかったエラーパターンと対処法
Gemini 3.2 API への移行後に頻発するエラー5種を実例コード付きで解説。モデルID誤り・レート制限・コンテキスト超過・ストリーミング断裂・Function Calling スキーマ違反の診断と修正方法を紹介します。
API / SDK2026-07-16
Gemini にスクリーンショットを採点させたら、全部78〜85点だった — 絶対スコアを捨ててペア比較に切り替えるまで
Gemini Vision に App Store スクリーンショットを100点満点で採点させると、良い案も崩した案も78〜85点に潰れます。弁別能を実測して絶対スコアを捨て、位置バイアスを除いたペア比較でランキングを作るまでの実装記録です。
API / SDK2026-06-03
Gemini Live API の応答音声が速回しに聞こえる — サンプルレート取り違えの直し方
Gemini Live API の応答音声が甲高く速回しに聞こえる、あるいはノイズ混じりになる症状は、ほとんどが 24kHz の出力を別のサンプルレートで再生していることが原因です。ブラウザと iOS の両方で、取り違えを直す具体的なコードを記録します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →