Gemini Embedding 2で作るネイティブマルチモーダルRAG
はじめに
こんにちは、AI Shift AIチームの林崎です。
本記事では先日一般提供となったGemini Embedding 2でシンプルなマルチモーダルRAGを構築し、その実用性や使用時のTipsについてご紹介します。
従来のマルチモーダルRAGでは、画像ならOCR(光学文字認識)、音声なら文字起こし(ASR)など、メディアごとに異なる前処理やモデルを組み合わせる必要があり、パイプラインが複雑化したり、メディア特有の情報が欠落することが課題でした。Gemini Embedding 2の登場によって、これらの異なるモダリティを同一の埋め込み空間に写像することが可能になりました。
本記事では、この「ネイティブ」なマルチモーダル埋め込みを活用したRAGの構築方法を解説します。
Gemini Embedding 2 とは?
Gemini Embedding 2は、テキスト・画像・音声・動画といった多様なモダリティを区別することなく、単一のモデルで高次元の埋め込みに変換できるモデルです。OCRを使用することによってPDFファイルにも対応しています。
image**
*Gemini Embedding 2の概要*
Gemini Embedding 2 [[1]](https://arxiv.org/abs/2605.27295) のテクニカルレポートによると、Amazon Nova MME・Voyage-3.5-multimodal・gemini-embeddingと比較して、マルチモーダル検索タスクにおいて優れた性能を示しています。
マルチモーダルに拡張しながらも、MTEBベンチマークでも従来のGemini Embeddingの性能を上回っている点が特徴的かと思います。

*Gemini Embedding 2は、画像・テキスト・動画・ドキュメントといった多様なモダリティにわたるマルチモーダル検索タスクにおいて、優れた性能を発揮している*

*Massive Text Embedding Benchmarkにおけるマルチモーダル埋め込みモデルとテキスト専用埋め込みモデルの比較*
Gemini Embedding 2 [[1]](https://arxiv.org/abs/2605.27295) は、Geminiから初期化され、ノイズ対照推定(NCE)損失によるファインチューニングを経て構築されます。負例の選択方法については明示されていませんが、MM-Embed [[3]](http://arxiv.org/abs/2411.02571) のように「意味はそっくりだが、モダリティが異なる」データを負例として選択しているのではないかと推測しています。学習データについても言及はありませんでした。
Gemini Embedding 2 を使用する際には、モダリティごとに API の入力制限に注意が必要です。主要な注意点は以下の通りです。
モダリティ 注意点
全体 最大入力トークン数は 8192 までで、すべてのモダリティで共有される**
画像 最大 16384x16384 px
1 回のリクエストで入力できるのは 6 枚まで
音声 1 回のリクエストあたり 180 秒まで
動画 音声なしの動画は 120 秒・音声ありの動画は 80 秒まで
最大 120 フレーム
ドキュメント (PDF ファイル) 最大 6 ページ (ファイルごとに 1 ページ推奨)
料金は入力データごとに課されます。テキストに関しては従来通りトークン単位での請求になりますが、画像は枚数・動画はフレーム・音声は秒数単位での請求となります。動画と音声はフレームや秒数を意識しないと料金が高くなりやすいので注意しましょう。
マルチモーダル RAG の構築
本記事では、Gemini Embedding 2 でシンプルなマルチモーダル RAG を構築します。
環境構築
今回の実装では、Gemini API を呼び出すために google-genaiSDKを使用します。また、ベクトルデータベースにはローカルで手軽に動作する Chroma DB**を選定しました。Chroma DB はマルチモーダル埋め込みの管理にも対応しており、今回の用途に適していると思います。より大規模なサービス・ワークロードになる場合は他のベクトルデータベースを推奨します。
ベクトルデータベースの比較については、以下の記事がわかりやすいかと思います。
必要なライブラリは事前にインストールしておきます。
uv add google-genai chromadb python-dotenv tqdm
クライアントの初期化
まずはクライアントの初期化を行います。Google Cloud の Vertex AI 経由で使用するので.env など**で環境変数を設定しておきます。
GOOGLE_CLOUD_PROJECT=YOUR_GCP_PROJECT
GOOGLE_CLOUD_LOCATION=YOUR_LOCATION
google-genaiSDK クライアントの初期化を行います。
import os
from google import genai
from dotenv import load_dotenv
load_dotenv()
PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT", "YOUR_PROJECT_ID")
LOCATION = os.getenv("GOOGLE_CLOUD_LOCATION", "global")
gemini_client = genai.Client(vertexai=True, project=PROJECT_ID, location=LOCATION)
ChromaDB の初期化を行います。CHROMADB_PATH がデータの保存先となります。PersistentClient**を使うことでデータの永続化を行うようにします。
import chromadb
CHROMADB_PATH = "./chromadb"
chroma_client = chromadb.PersistentClient(path=CHROMADB_PATH)
collection = chroma_client.get_or_create_collection(name="gemini_embedding_2")
マルチモーダルデータの埋め込みと保存
今回の実装では、ローカルファイルを表す簡易的な LocalFile エンティティを定義しています。Gemini Embedding 2 が対応しているモダリティはテキスト・画像・音声・動画・PDF の 5 種類です。
from dataclasses import dataclass, field
from pathlib import Path
from typing import ClassVar
@dataclass(frozen=True)
class LocalFile:
path: Path
bytes: int = field(init=False)
mime_type: str = field(init=False)
SUPPORTED_MIME_TYPES: ClassVar[dict[str, str]] = {
".txt": "text/plain",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".wav": "audio/wav",
".mp4": "video/mp4",
".pdf": "application/pdf",
}
def __post_init__(self):
if not self.path.is_file():
raise FileNotFoundError(f"File not found: {self.path}")
mime_type = self.SUPPORTED_MIME_TYPES.get(self.path.suffix.lower())
if mime_type is None:
raise ValueError(f"Unsupported file type: {self.path}")
object.__setattr__(self, "bytes", self.path.stat().st_size)
object.__setattr__(self, "mime_type", mime_type)
@property
def is_text(self) -> bool:
return self.mime_type == "text/plain"
def read_text(self) -> str:
return self.path.read_text(encoding="utf-8")
def read_bytes(self) -> bytes:
return self.path.read_bytes()
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールド (technical_terms 等) は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
google-genai SDK クライアントでリクエストを送信する際には、SDK が提供する Content 型に整形する必要があるので、データの変換を担う Adapter を定義しておきます。
from google.genai import types
class GoogleContentAdapter:
def to_content(self, obj: str | LocalFile) -> types.Content:
if isinstance(obj, str):
part = types.Part.from_text(text=obj)
elif isinstance(obj, LocalFile) and obj.is_text:
part = types.Part.from_text(text=obj.read_text())
elif isinstance(obj, LocalFile):
part = types.Part.from_bytes(
data=obj.read_bytes(),
mime_type=obj.mime_type,
)
else:
raise ValueError(f"Unsupported content type: {type(obj)}")
return types.Content(
role="user",
parts=[part],
)
./data ディレクトリのファイルを走査し、対象となるファイルがあった場合に gemini-embedding-2 で埋め込み(embedding)を取得するようリクエストを送信します。**取得した埋め込みは Chroma DB に保存します。ここでは ids や metadatas プロパティを使用して、元のファイル名やファイル形式の情報を保持するようにしています。
from google.genai import types
from tqdm import tqdm
content_adapter = GoogleContentAdapter()
for path in tqdm(Path("./data").glob("*")):
try:
file = LocalFile(path)
except ValueError:
continue
embedding = gemini_client.models.embed_content(
model="gemini-embedding-2",
contents=[content_adapter.to_content(file)],
config=types.EmbedContentConfig(output_dimensionality=768),
)
collection.add(
ids=[f"{file.path.stem}_{file.path.suffix.lower().lstrip('.')}"],
embeddings=[embedding.embeddings[0].values],
documents=[file.path.stem],
metadatas=[
{
"path": str(file.path),
"mime_type": file.mime_type,
}
],
)
検索と回答の生成
ユーザークエリから埋め込み(embedding)を生成し、Chroma DB で類似度検索を行うことで上位 3 件のファイルを取得します。
取得したファイルはそれぞれプロンプトと Content 型に変換し、マルチモーダルな入力に対応している gemini-3.5-flash にユーザークエリと一緒に入力します。
最後の LLM(大規模言語モデル)による回答生成のときも、動画や PDF をテキストに変換することなくそのまま LLM に入力できるため、パイプライン全体で一切の前処理が不要になっています。
def generate(query: str) -> str:
content_adapter = GoogleContentAdapter()
query_embeddings = gemini_client.models.embed_content(
model="gemini-embedding-2",
contents=[
content_adapter.to_content(
f"task: question answering | query: {query}"
)
],
config=types.EmbedContentConfig(output_dimensionality=768),
)
retrieved = collection.query(
query_embeddings=[query_embeddings.embeddings[0].values],
n_results=3,
include=["documents", "metadatas", "distances"],
)
contexts = []
parts = []
for metadata, distance, document in zip(
retrieved["metadatas"][0],
retrieved["distances"][0],
retrieved["documents"][0],
strict=True,
):
source_file = LocalFile(Path(metadata["path"]))
翻訳全文
hit: kk20-1-1 (application/pdf)
...
「技術革新と銀行業・金融政策―電子決済技術と金融政策運営との関連を考えるフォーラム」報告書の図表4(a)によると、日本のB to C 電子商取引の市場規模は、1998年の0.06兆円から2004年の6.66兆円へと、一貫して右肩上がりに急拡大(増加)しています。
従来の手法では、テキスト抽出 (PyPDFなど) やOCRでテキストに変換してからベクトル化する煩雑な処理が必要でした。対してGemini Embedding 2ではPDF全体をそのままベクトル化することができ、開発者体験が大きく向上します。
ただし、推論の処理は重くなるので、キャッシュを用意するなどの工夫をするとより良いかと思います。
動画ファイルの情報検索
視覚情報と音声情報が混在する動画ファイル (MP4) に対する検証です。

query = "地球がズームアウトしている動画のパスと対応する区間を教えて"
answer = generate(query)
print(answer)
結果
hit: finevideo_028_ed1jhrcny_w (video/mp4)
...
地球がズームアウトしている動画のパスと対応する区間は以下の通りです。
- パス:
finevideo_028_ed1jhrcny_w - 区間: 0:00〜0:09
動画ファイルを扱うには、事前にフレーム画像に分解したり、キャプションを生成するなどの煩雑な処理が必要となります。Gemini Embedding 2を使えば、複雑で重いパイプラインを構築することなくベクトル検索 (vector search) を機能させることができます。
Gemini Embedding 2のTips
Gemini Embedding 2を使用するにあたり、役に立ちそうなTipsを紹介します。
タスク文字列を指定して精度を上げる
Gemini Embedding 2の学習は、質問応答 (question answering) やコード検索 (code retrieval) などの複数のタスクを同時に学習するマルチタスク学習の設定で行われています [[1]](https://arxiv.org/abs/2605.27295)。**
私たちがこのモデルを使う時も、ユーザークエリに適切なタスク文字列**を付与することによって、出力される埋め込み (embedding) を最適化できるとされています。
具体的には、ユーザークエリの形式を以下のような形に変更することで適用できます。
f"task: {タスク文字列} | query: {コンテンツ}"
公式では、タスク文字列は以下の7つが紹介されています。
ユースケース
タスク文字列
検索クエリ
search result
質問応答
question answering
ファクト チェック
fact checking
コードの取得
code retrieval
分類
classification
クラスタリング
clustering
意味的類似度
sentence similarity
埋め込み次元を最適化する
必ずJSON形式で返してください。translation フィールドのみ。他のフィールド(technical_terms 等)は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
{"translation": "翻訳全文"}
Gemini Embedding 2 は Matryoshka Representation Learning [[2]](https://arxiv.org/abs/2205.13147) を用いて学習されているため、複数の埋め込み次元を選択することができます(本ブログの実装でも使用しました)。
必要な精度に合わせて適切な埋め込み次元を output_dimensionality から選択することにより、埋め込みの保存に必要なストレージ費用を節約することができます。
response = client.models.embed_content(
model="gemini-embedding-2",
contents=[content],
config=types.EmbedContentConfig(output_dimensionality=768),
)
テクニカルレポート [[1]](https://arxiv.org/abs/2605.27295) では 768・1536・3072 の 3 種類の次元に対して最適化されているとの記述がありましたので、まずはこちらから試してみるのが良いと思います。
まとめ
本記事では Gemini Embedding 2 でシンプルなマルチモーダル RAG を構築し、その実用性や使用時の TIP についてご紹介しました。
マルチモーダルデータをネイティブに扱うことができる Gemini Embedding 2 のおかげで処理が非常に楽になったとはいえ、チャンク化やチューニングの部分で工夫の余地はまだまだ残されている印象です。また、精度検証は十分に行われているとはいえ、実際に運用した場合にどのような課題が発生しうるかエラー分析をしっかり実施していきたいところです。
ご覧いただきありがとうございました!
参考文献
[1] Gemini Embedding 2: A Native Multimodal Embedding Model from Gemini
[2] Matryoshka Representation Learning
[3] MM-Embed: Universal Multimodal Retrieval with Multimodal LLMs
原文を表示
はじめに
こんにちは、AI Shift AIチームの林崎です。
本記事では先日一般提供となったGemini Embedding 2でシンプルなマルチモーダルRAGを構築し、その実用性や使用時のTipsについてご紹介します。
従来のマルチモーダルRAGでは、画像ならOCR、音声なら文字起こし(ASR)など、メディアごとに異なる前処理やモデルを組み合わせる必要があり、パイプラインが複雑化したり、メディア特有の情報が欠落することが課題でした。Gemini Embedding 2の登場によって、これらの異なるモダリティを同一の埋め込み空間に写像することが可能になりました。
本記事では、この「ネイティブ」なマルチモーダル埋め込みを活用したRAGの構築方法を解説します。
Gemini Embedding 2 とは?
Gemini Embedding 2は、テキスト・画像・音声・動画といった多様なモダリティを区別することなく、単一のモデルで高次元の埋め込みに変換できるモデルです。OCRを使用することによってPDFファイルにも対応しています。

**
*Gemini Embedding 2の概要*
Gemini Embedding 2 [[1]](https://arxiv.org/abs/2605.27295) のテクニカルレポートによると、Amazon Nova MME・Voyage-3.5-multimodal・gemini-embeddingと比較して、マルチモーダル検索タスクにおいて優れた性能を示しています。
マルチモーダルに拡張しながらも、MTEBベンチマークでも従来のGemini Embeddingの性能を上回っている点が特徴的かと思います。

*Gemini Embedding 2は、画像・テキスト・動画・ドキュメントといった多様なモダリティにわたるマルチモーダル検索タスクにおいて、優れた性能を発揮している*

*Massive Text Embedding Benchmarkにおけるマルチモーダル埋め込みモデルとテキスト専用埋め込みモデルの比較*
Gemini Embedding 2 [[1]](https://arxiv.org/abs/2605.27295) は、Geminiから初期化され、ノイズ対照推定(NCE)損失によるファインチューニングを経て構築されます。負例の選択方法については明示されていませんが、MM-Embed [[3]](http://arxiv.org/abs/2411.02571) のように「意味はそっくりだが、モダリティが異なる」データを負例として選択しているのではないかと推測しています。学習データについても言及はありませんでした。
Gemini Embedding 2を使用する時には、モダリティごとにAPIの入力制限に注意が必要です。主要な注意点は以下の通りです。
モダリティ
注意点
全体
最大入力トークン数は8192までで、すべてのモダリティで共有される**
画像
最大16384x16384 px
1回のリクエストで入力できるのは6枚まで
音声
1回のリクエストあたり180秒まで
動画
音声なしの動画は120秒・音声ありの動画は80秒まで
最大120フレーム
ドキュメント (PDFファイル)
最大6ページ (ファイルごとに1ページ推奨)
料金は入力データごとに課されます。テキストに関しては従来通りトークン単位での請求になりますが、画像は枚数・動画はフレーム・音声は秒数単位での請求となります。動画と音声はフレームや秒数を意識しないと料金が高くなりやすいので注意しましょう。
マルチモーダルRAGの構築
本記事では、Gemini Embedding 2でシンプルなマルチモーダルRAGを構築します。
環境構築
今回の実装では、Gemini APIを呼び出すために google-genaiSDKを使用します。**
また、ベクトルデータベースにはローカルで手軽に動作するChroma DB**を選定しました。Chroma DBはマルチモーダル埋め込みの管理にも対応しており、今回の用途に適していると思います。より大規模なサービス・ワークロードになる場合は他のベクトルデータベースを推奨します。
ベクトルデータベースの比較については、以下の記事がわかりやすいかと思います。
必要なライブラリは事前にインストールしておきます。
uv add google-genai chromadb python-dotenv tqdm
クライアントの初期化
まずはクライアントの初期化を行います。Google CloudのVertex AI経由で使用するので.envなどで環境変数を設定しておきます。
GOOGLE_CLOUD_PROJECT=YOUR_GCP_PROJECT
GOOGLE_CLOUD_LOCATION=YOUR_LOCATION
google-genaiSDKクライアントの初期化を行います。
import os
from google import genai
from dotenv import load_dotenv
load_dotenv()
PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT", "YOUR_PROJECT_ID")
LOCATION = os.getenv("GOOGLE_CLOUD_LOCATION", "global")
gemini_client = genai.Client(vertexai=True, project=PROJECT_ID, location=LOCATION)
ChromaDBの初期化を行います。CHROMADB_PATHがデータの保存先となります。PersistentClientを使うことでデータの永続化を行うようにします。
import chromadb
CHROMADB_PATH = "./chromadb"
chroma_client = chromadb.PersistentClient(path=CHROMADB_PATH)
collection = chroma_client.get_or_create_collection(name="gemini_embedding_2")
マルチモーダルデータの埋め込みと保存
今回の実装では、ローカルファイルを表す簡易的な LocalFile エンティティを定義しています。Gemini Embedding 2が対応しているモダリティはテキスト・画像・音声・動画・PDFの5種類です。
from dataclasses import dataclass, field
from pathlib import Path
from typing import ClassVar
@dataclass(frozen=True)
class LocalFile:
path: Path
bytes: int = field(init=False)
mime_type: str = field(init=False)
SUPPORTED_MIME_TYPES: ClassVar[dict[str, str]] = {
".txt": "text/plain",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".wav": "audio/wav",
".mp4": "video/mp4",
".pdf": "application/pdf",
}
def __post_init__(self):
if not self.path.is_file():
raise FileNotFoundError(f"File not found: {self.path}")
mime_type = self.SUPPORTED_MIME_TYPES.get(self.path.suffix.lower())
if mime_type is None:
raise ValueError(f"Unsupported file type: {self.path}")
object.__setattr__(self, "bytes", self.path.stat().st_size)
object.__setattr__(self, "mime_type", mime_type)
@property
def is_text(self) -> bool:
return self.mime_type == "text/plain"
def read_text(self) -> str:
return self.path.read_text(encoding="utf-8")
def read_bytes(self) -> bytes:
return self.path.read_bytes()
google-genaiSDKクライアントでリクエストを送る際には、SDKが提供しているContent型に整形する必要があるので、データの変換を担うAdapterを定義しておきます。
from google.genai import types
class GoogleContentAdapter:
def to_content(self, obj: str | LocalFile) -> types.Content:
if isinstance(obj, str):
part = types.Part.from_text(text=obj)
elif isinstance(obj, LocalFile) and obj.is_text:
part = types.Part.from_text(text=obj.read_text())
elif isinstance(obj, LocalFile):
part = types.Part.from_bytes(
data=obj.read_bytes(),
mime_type=obj.mime_type,
)
else:
raise ValueError(f"Unsupported content type: {type(obj)}")
return types.Content(
role="user",
parts=[part],
)
./dataディレクトリのファイルを走査し、対象となるファイルがあった場合にgemini-embedding-2で埋め込みを取得するようリクエストを送信します。**
取得した埋め込みはChroma DBに保存します。ここではidsやmetadatasプロパティを使用して、元のファイル名やファイル形式の情報を保持するようにしています。
from google.genai import types
from tqdm import tqdm
content_adapter = GoogleContentAdapter()
for path in tqdm(Path("./data").glob("*")):
try:
file = LocalFile(path)
except ValueError:
continue
embedding = gemini_client.models.embed_content(
model="gemini-embedding-2",
contents=[content_adapter.to_content(file)],
config=types.EmbedContentConfig(output_dimensionality=768),
)
collection.add(
ids=[f"{file.path.stem}_{file.path.suffix.lower().lstrip('.')}"],
embeddings=[embedding.embeddings[0].values],
documents=[file.path.stem],
metadatas=[
{
"path": str(file.path),
"mime_type": file.mime_type,
}
],
)
検索と回答の生成
ユーザークエリから埋め込みを生成し、Chroma DBで類似度検索をすることによって上位3件のファイルを取得します。
取得したファイルはそれぞれプロンプトとContent型に変換し、マルチモーダルな入力に対応しているgemini-3.5-flashにユーザークエリと一緒に入力します。
最後のLLMによる回答生成のときも、動画やPDFをテキストに変換することなくそのまま LLM に入力できるため、パイプライン全体で一切の前処理が不要になっています。
def generate(query: str) -> str:
content_adapter = GoogleContentAdapter()
query_embeddings = gemini_client.models.embed_content(
model="gemini-embedding-2",
contents=[
content_adapter.to_content(
f"task: question answering | query: {query}"
)
],
config=types.EmbedContentConfig(output_dimensionality=768),
)
retrieved = collection.query(
query_embeddings=[query_embeddings.embeddings[0].values],
n_results=3,
include=["documents", "metadatas", "distances"],
)
contexts = []
parts = []
for metadata, distance, document in zip(
retrieved["metadatas"][0],
retrieved["distances"][0],
retrieved["documents"][0],
strict=True,
):
source_file = LocalFile(Path(metadata["path"]))
contexts.append(f"distance={distance}\n{document}")
parts.extend(content_adapter.to_content(source_file).parts)
print(f"hit: {document} ({source_file.mime_type})")
prompt = f"""
以下の検索結果と添付ファイルを根拠に、日本語で簡潔に回答してください。
分からない場合は、分からないと答えてください。
# 質問
{query}
# 検索結果
{"\n".join(contexts)}
""".strip()
response = gemini_client.models.generate_content(
model="gemini-3.5-flash",
contents=[
types.Content(
role="user",
parts=[types.Part.from_text(text=prompt), *parts],
)
],
)
return response.text or ""
検証
構築したパイプラインが、テキスト以外の各モダリティから正しく情報を検索し、回答を生成できるか検証を行います。データにはFineVideoデータセットの一部動画 (33件; train-00000-of-01357.parquetに含まれるデータ) と、それを音声・画像・テキストに変換したもの、およびOCR Task JAデータセットの一部PDFファイル (5件) を使用しています。
PDFファイルの情報検索
複雑なレイアウトや表組みを含むPDFドキュメントに対する検索精度を検証します。
今回はOCR Task JAデータセットに含まれる以下の図表の情報を正しく取得・認識できるか確認します。

*日本銀行金融研究所/金融研究/2001.1 「技術革新と銀行業・金融政策―電子決済技術と金融政運営との関連を考えるフォーラム」報告書より*
query = "B to C 電子商取引の市場規模は1998年から2004年にかけてどのように変化していますか?"
answer = generate(query)
print(answer)
結果**
hit: kk20-1-1 (application/pdf)
...
「技術革新と銀行業・金融政策―電子決済技術と金融政策運営との関連を考えるフォーラム」報告書の図表4(a)によると、日本のB to C 電子商取引の市場規模は、1998年の0.06兆円から2004年の6.66兆円へと、一貫して右肩上がりに急拡大(増加)しています。
従来の手法では、テキスト抽出 (PyPDFなど) やOCRでテキストに変換してからベクトル化する煩雑な処理が必要でした。対してGemini Embedding 2ではPDF全体をそのままベクトル化することができ、開発者体験が大きく向上します。
ただし、推論の処理は重くなるので、キャッシュを用意するなどの工夫をするとより良いかと思います。
動画ファイルの情報検索
視覚情報と音声情報が混在する動画ファイル (MP4) に対する検証です。

query = "地球がズームアウトしている動画のパスと対応する区間を教えて"
answer = generate(query)
print(answer)
結果
hit: finevideo_028_ed1jhrcny_w (video/mp4)
...
地球がズームアウトしている動画のパスと対応する区間は以下の通りです。
* **パス:** `finevideo_028_ed1jhrcny_w`
* **区間:** 0:00〜0:09
動画ファイルを扱うには、事前にフレーム画像に分解したり、キャプションを生成するなどの煩雑な処理が必要となります。Gemini Embedding 2を使えば、複雑で重いパイプラインを構築することなくベクトル検索を機能させることができます。
Gemini Embedding 2のTips
Gemini Embedding 2を使用するにあたり、役に立ちそうなTipsを紹介します。
タスク文字列を指定して精度を上げる
Gemini Embedding 2の学習は、質問応答 (question answering) やコード検索 (code retrieval) などの複数のタスクを同時に学習するマルチタスク学習の設定で行われています [[1]](https://arxiv.org/abs/2605.27295)。**
私たちがこのモデルを使う時も、ユーザークエリに適切なタスク文字列**を付与することによって、出力される埋め込みを最適化できるとされています。
具体的には、ユーザークエリの形式を以下のような形に変更することで適用できます。
f"task: {タスク文字列} | query: {コンテンツ}"
公式では、タスク文字列は以下の7つが紹介されています。
ユースケース
タスク文字列
検索クエリ
search result
質問応答
question answering
ファクト チェック
fact checking
コードの取得
code retrieval
分類
classification
クラスタリング
clustering
意味的類似度
sentence similarity
埋め込み次元を最適化する
Gemini Embedding 2はMatryoshka Representation Learning [[2]](https://arxiv.org/abs/2205.13147)を使用して学習されているため、複数の埋め込み次元を選択することができます (本ブログの実装でも使用しました)。
必要な精度に合わせて適切な埋め込み次元をoutput_dimensionalityから選択することにより、埋め込みの保存に必要なストレージ費用を節約することができます。
response = client.models.embed_content(
model="gemini-embedding-2",
contents=[content],
config=types.EmbedContentConfig(output_dimensionality=768),
)
テクニカルレポート[[1]](https://arxiv.org/abs/2605.27295) では768・1536・3072の3種類の次元に対して最適化されているとの記述がありましたので、まずはこちらから試してみるのが良いと思います。
まとめ
本記事ではGemini Embedding 2でシンプルなマルチモーダルRAGを構築し、その実用性や使用時のTIPについてご紹介しました。
マルチモーダルデータをネイティブに扱うことができるGemini Embedding 2のおかげで処理が非常に楽になったとはいえ、チャンク化やチューニングの部分で工夫の余地はまだまだ残されている印象です。また、精度検証は十分に行われているとはいえ、実際に運用した場合にどのような課題が発生しうるかエラー分析をしっかり実施していきたいところです。
ご覧いただきありがとうございました!
参考文献
[1] Gemini Embedding 2: A Native Multimodal Embedding Model from Gemini
[2] Matryoshka Representation Learning
[3] MM-Embed: Universal Multimodal Retrieval with Multimodal LLMs
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み