过去一年我越来越确定:很多 RAG/语义搜索体验差,不是因为 LLM 不够强,而是你的“向量层”不够统一。
我们一直在用“文本 embedding + OCR + ASR + 图片特征/字幕拼装”的方式,把世界强行压成一堆文本再检索。管线越长,误差越多;多模态数据越丰富,工程越痛苦。
2026 年 3 月 10 日,Google 发布 Gemini Embedding 2,主打一个事情:原生多模态 embedding,把文本、图片、音频、视频、PDF 直接映射进同一个向量空间(Public Preview)。对做多媒体检索、跨模态推荐、以及“真正的多模态 RAG”的团队来说,这可能是你今年最值得试的一块基础设施。
说明:本文以工程落地为中心,不复述宣传词;所有规格与限制以官方文档为准(预览期随时可能调整)。
Gemini Embedding 2 的核心价值不是“更高分”,而是减少管线与对齐成本:
| 项目 | Gemini API / Vertex AI(官方信息) |
|---|---|
| 模型 ID | gemini-embedding-2-preview |
| 输入模态 | Text / Image / Video / Audio / PDF |
| 输入 token 上限 | 8,192 |
| 输出维度 | 支持 128–3072(默认/推荐 3072;常用推荐 3072/1536/768) |
| 图片限制 | 最多 6 张/次(PNG/JPEG) |
| PDF 限制 | 1 个文件/次,最多 6 页 |
| 视频限制 | 官方博文给到最长 120 秒;Vertex AI 进一步区分:带音频 80s / 无音频 120s |
| 音频限制 | 1 个/次,最长 80 秒(MP3/WAV) |
| 状态与可用区域 | Public Preview;Vertex AI 文档显示可用区域为 us-central1 |
| 知识截止(Vertex) | 2025 年 11 月 |
如果你以前做过多模态检索,大概率遇到过两类痛:
Gemini Embedding 2 的做法是:把多种媒体都映射到同一个 embedding space——这让你在系统层面更像在维护一个“统一向量索引”,而不是维护一堆互不兼容的特征管线。
官方给了一个很实用的方向:默认 3072 维质量最好,同时支持缩维,并建议优先尝试 3072/1536/768 这三个档位。
我的工程建议是:
重要提醒:一旦你切换维度(或切换模型),旧向量通常需要重新生成。工程上建议在向量元数据里记录
model_id与dim,避免“混库”。
一个可落地的最小闭环通常是:
Keyword 博文也列出了常见生态入口:LangChain、LlamaIndex、Haystack、Weaviate、Qdrant、ChromaDB,以及 Vertex Vector Search 等,你可以按你现有栈“就近接入”,减少迁移成本。
下面示例以 Gemini API 的 gemini-embedding-2-preview 为例;如果你走 Vertex AI,模型 ID 一致,但鉴权与 endpoint 不同(以官方文档为准)。
output_dimensionalityimport os
from google import genai
from google.genai import types
MODEL = "gemini-embedding-2-preview"
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
texts = [
"向量检索的关键不在 LLM,而在 embedding 层。",
"Gemini Embedding 2 支持原生多模态向量。",
"用 1536 维通常能在效果和成本间取得平衡。",
]
result = client.models.embed_content(
model=MODEL,
contents=texts,
config=types.EmbedContentConfig(
task_type="RETRIEVAL_DOCUMENT",
output_dimensionality=1536,
),
)
vectors = [e.values for e in result.embeddings]
print("count:", len(vectors), "dim:", len(vectors[0]))如果你选择的维度不是默认的 3072(比如 768/1536),做相似度检索前建议先做一次 L2 归一化(尤其是你用 cosine similarity 的时候):
import numpy as np
def l2_normalize(vec: list[float]) -> list[float]:
v = np.asarray(vec, dtype=np.float32)
n = np.linalg.norm(v)
return (v / (n if n != 0 else 1.0)).tolist()
normed_vectors = [l2_normalize(v) for v in vectors]Part 输入import os
from pathlib import Path
from google import genai
from google.genai import types
MODEL = "gemini-embedding-2-preview"
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
image_bytes = Path("./dog.png").read_bytes()
content = types.Content(
parts=[
types.Part(text="一只狗在草地上追飞盘。"),
types.Part.from_bytes(data=image_bytes, mime_type="image/png"),
]
)
result = client.models.embed_content(
model=MODEL,
contents=[content],
config=types.EmbedContentConfig(
task_type="RETRIEVAL_DOCUMENT",
output_dimensionality=1536,
),
)
vector = result.embeddings[0].values
print("dim:", len(vector))同理,你也可以把 PDF / 音频 / 视频作为
Part(通常是from_bytes或from_uri)塞进parts里,关键是“多模态在同一个向量空间”。
outputDimensionalityimport { GoogleGenAI } from '@google/genai'
const MODEL = 'gemini-embedding-2-preview'
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! })
const texts = [
'向量检索的关键不在 LLM,而在 embedding 层。',
'Gemini Embedding 2 支持原生多模态向量。',
'用 1536 维通常能在效果和成本间取得平衡。',
]
const resp = await ai.models.embedContent({
model: MODEL,
contents: texts,
taskType: 'RETRIEVAL_DOCUMENT',
outputDimensionality: 1536,
})
const vectors = resp.embeddings.map((e) => e.values)
console.log('count:', vectors.length, 'dim:', vectors[0].length)
function l2Normalize(vec: number[]) {
const norm = Math.sqrt(vec.reduce((sum, x) => sum + x * x, 0))
return vec.map((x) => x / (norm || 1))
}
const normedVectors = vectors.map(l2Normalize)Part(图片 + 文本)输入import { readFileSync } from 'node:fs'
import { GoogleGenAI } from '@google/genai'
const MODEL = 'gemini-embedding-2-preview'
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! })
const imageBase64 = readFileSync('./dog.png').toString('base64')
const resp = await ai.models.embedContent({
model: MODEL,
// 多模态通常用 content.parts 组织(文本 + 图片等)
content: {
parts: [
{ text: '一只狗在草地上追飞盘。' },
{
inlineData: {
mimeType: 'image/png',
data: imageBase64,
},
},
],
},
taskType: 'RETRIEVAL_DOCUMENT',
outputDimensionality: 1536,
})
// 单条 content 一般返回 embedding(批量 contents 返回 embeddings)
const vector = resp.embedding.values
console.log('dim:', vector.length)如果你准备把这段代码搬进生产,我建议你顺手把这些元信息写进向量库:model_id、output_dimensionality、taskType、以及原始内容的 source/timestamp/page/clip_range 等,这会让你后面做回滚和 A/B 测试轻松很多。
us-central1,这会影响你数据合规与延迟策略(尤其是多媒体输入)。gemini-embedding-2-preview):https://ai.google.dev/gemini-api/docs/models/gemini-embedding-2-preview