GEMINI LABEN
AGENT — Managed AgentsがGemini APIで公開プレビュー入り。分離されたGoogleホストのLinuxサンドボックスで自律・ステートフルなエージェントを動かせますSEARCH — File Searchがマルチモーダル対応となり、gemini-embedding-2(GA)で画像をネイティブに埋め込み・検索できますTTS — gemini-3.1-flash-tts-previewが音声生成のストリーミングに対応し、逐次再生できますMODEL — Gemini 3.5 FlashがGA(正式版)となり、gemini-flash-latestの実体になりましたDEPRECATION — 画像生成モデルは2026年8月17日に提供終了予定です。依存パイプラインは移行先の確認をENTERPRISE — Gemini 3.5 FlashがGlobal・US・EUのGemini Enterpriseで一般提供されましたAGENT — Managed AgentsがGemini APIで公開プレビュー入り。分離されたGoogleホストのLinuxサンドボックスで自律・ステートフルなエージェントを動かせますSEARCH — File Searchがマルチモーダル対応となり、gemini-embedding-2(GA)で画像をネイティブに埋め込み・検索できますTTS — gemini-3.1-flash-tts-previewが音声生成のストリーミングに対応し、逐次再生できますMODEL — Gemini 3.5 FlashがGA(正式版)となり、gemini-flash-latestの実体になりましたDEPRECATION — 画像生成モデルは2026年8月17日に提供終了予定です。依存パイプラインは移行先の確認をENTERPRISE — Gemini 3.5 FlashがGlobal・US・EUのGemini Enterpriseで一般提供されました
記事一覧/高度な活用
高度な活用/2026-07-08上級

複数アプリのFAQを1つの File Search ストアに同居させる — customMetadata と chunk 設定で検索を分ける

複数アプリのFAQを1つの File Search ストアにまとめると、metadataFilter が無言で空を返したり、回答がチャンク境界で割れて引用されなかったりします。customMetadata の設計、AIP-160 フィルタ構文の落とし穴、chunkingConfig の実測チューニングを実装ベースでまとめました。

Gemini API171File Search5RAG13customMetadata個人開発78

プレミアム記事

複数のアプリのヘルプFAQを Gemini の File Search に載せようとしたとき、私は最初、アプリごとにストアを分けました。壁紙アプリ、癒し系アプリ、それぞれ別のストア。素直な発想です。

ところが運用に入ると、ストアの数だけ再インデックスのジョブとコストが増えていきました。FAQを1行直すたびに、どのストアだったかを思い出す作業も地味に効いてきます。

そこで「1つのストアに全アプリのFAQを同居させ、クエリのときだけアプリで絞る」構成に切り替えました。File Search には customMetadatametadataFilter があります。ドキュメントに app_id を付けておき、問い合わせのときに app_id で絞れば、1ストアでも回答は混ざらないはずでした。

はずでした、と書いたのは、metadataFilter が例外も警告も出さないまま、空の回答を返し続けたからです。この記事は、その原因の切り分けと、ついでに見つかった「回答がチャンク境界で割れて引用されない」問題の実測チューニングまでを、実装ベースでまとめたものです。

なぜ1ストアに寄せるのか — 個人開発での判断

ストアを分けるか、1つに寄せるか。個人開発だと、この判断は「正しさ」より「運用が続けられるか」で決まります。

File Search のストアは、埋め込みを永続保持するコンテナです。生ファイルは48時間で消えますが、ストアに取り込んだ埋め込みは手動削除するまで残ります。つまりストアは「増やしたら増えたぶんだけ、削除と再取り込みの管理対象が増える」オブジェクトです。

公式ドキュメントには、ストアのサイズは「入力データ+生成された埋め込み」でおおよそ入力の約3倍になり、1ストアあたり20GB未満を推奨、と書かれています。個人開発のFAQ程度ならサイズは問題になりません。問題になるのは数のほうです。

私の判断はこうでした。データ量ではなく、更新頻度と分離要件で分ける。FAQのように頻繁に直し、アプリ間で厳密に混ざってはいけないものは、1ストアに同居させて app_id で論理分離します。逆に、埋め込みモデルを変えたい・再インデックス戦略が違う塊は、物理的にストアを分けます。この「物理分離は最小限、論理分離はメタデータで」という線引きが、私には一番続けやすいものでした。

ストアの陳腐化そのものは別の論点で、File Search のストアが本番で静かに陳腐化する運用メモにドリフト検知の設計を書いています。本記事は「1ストア同居」に絞ります。

customMetadata でアプリを区別する

分離の起点は、取り込み時に付ける customMetadata です。キーと値のペアで、1ドキュメントあたり最大20件まで付けられます。

from google import genai
import time
 
client = genai.Client()
 
# マルチモーダル対応の埋め込みモデルでストアを作成(画像も同居させたいため)
store = client.file_search_stores.create(
    config={
        "display_name": "app-faqs-shared",
        "embedding_model": "models/gemini-embedding-2",
    }
)
 
def import_faq(path: str, app_id: str, kind: str, lang: str):
    # まず Files API にアップロード → ストアへ import
    src = client.files.upload(file=path, config={"name": f"faq-{app_id}"})
    op = client.file_search_stores.import_file(
        file_search_store_name=store.name,
        file_name=src.name,
        # ここが分離の鍵。app_id / kind / lang を付けておく
        custom_metadata=[
            {"key": "app_id", "string_value": app_id},
            {"key": "kind", "string_value": kind},
            {"key": "lang", "string_value": lang},
        ],
    )
    while not op.done:
        time.sleep(5)
        op = client.operations.get(op)
    return op
 
import_faq("faq_wallpaper_ja.md", app_id="wallpaper", kind="faq", lang="ja")
import_faq("faq_healing_ja.md",   app_id="healing",   kind="faq", lang="ja")
# 期待: 2ドキュメントが同一ストアに入り、各チャンクに app_id が紐づく

キー設計で一点だけ、後悔しないための注意があります。値の型を最初に決めておくことです。app_id を文字列にするか数値にするかで、後述の metadataFilter の書き方が変わります。私は識別子は常に string_value、しきい値で絞りたい年や版番号だけ numeric_value にする、と決めました。混在させると、フィルタ側で型を思い出せなくなります。

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

この記事の続きを読む

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

この記事で得られること
アプリごとに File Search ストアを増やして管理が膨らんでいた人が、1ストア同居+メタデータ分離の設計に切り替えられる
metadataFilter が例外を出さずに空の grounding を返す原因を、AIP-160 構文の切り分け手順で自力で特定できるようになる
FAQ の回答がチャンク境界で割れて引用されない問題を、max_tokens_per_chunk と overlap の実測調整で減らせる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

高度な活用2026-07-01
Managed Agents の隔離サンドボックスから成果物を安全に持ち出す — スコープ限定クレデンシャルと egress の設計
Gemini API の Managed Agents はGoogleホストの隔離サンドボックスで動きます。生成した成果物をそこから自分のリポジトリへ安全に戻すための、短命・最小権限クレデンシャルとegress境界の実装をまとめました。
高度な活用2026-06-01
Gemini Embedding の次元を 3072 から 768 へ切り詰める — ベクトルDBのコストとレイテンシを下げる Matryoshka 設計
gemini-embedding-001 は 3072 次元の埋め込みを返しますが、Matryoshka 表現のおかげで前方だけを切り出しても精度がほとんど落ちません。次元を 768 へ削ってベクトルDBのストレージとレイテンシを下げる設計を、再正規化の落とし穴と粗密二段検索のコード付きで組み立てます。
高度な活用2026-05-31
Gemini Embedding モデルを切り替える日:無停止リインデックスの設計
埋め込みモデルを新しくすると、過去に作った全ベクトルが使えなくなります。サービスを止めずに数十万件のベクトルを作り直す二重インデックス方式を、再開可能な再生成ジョブとクエリ側の抽象化層のコード付きで設計します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →