Embeddings and Vertex AI Search (Gemini)
Google’s embeddings story in 2026 splits between gemini-embedding-2 (the current multimodal embedding model — text, image, video, audio, documents all mapped into a single unified embedding space for cross-modal search) and gemini-embedding-001 (text-only legacy, still supported but on a deprecation glide-path). Both support Matryoshka representations via the output_dimensionality parameter — you can ask for 128, 256, 768, 1536, or 3072 dimensions and the model returns the appropriately-truncated head of the full vector, which means you can store cheap 128-dim vectors for first-pass retrieval and re-rank with the full 3072-dim later. For managed RAG infrastructure, Vertex AI Search (formerly Discovery Engine) is Google’s hosted product — upload docs, get an indexed semantic search endpoint without running your own vector DB.
See also
- vision-and-long-context-gemini — alternative to RAG: just put everything in context
- context-caching-gemini — another alternative: cache the long doc
- vertex-ai-enterprise-gemini — Vertex AI in detail
- rag-embeddings-vector-search — vendor-neutral RAG patterns
- citations-and-grounding — sister doc for Claude (citations API; no embeddings)
1. Model catalog
Per ai.google.dev/gemini-api/docs/embeddings 2026-05.
| Model | Modalities | Max input tokens | Output dims (Matryoshka) | Status |
|---|---|---|---|---|
gemini-embedding-2 | Text, image, video, audio, documents | 8,192 (per item) | 128 / 256 / 768 / 1536 / 3072 | Stable / GA |
gemini-embedding-001 | Text only | 2,048 | 128 / 256 / 768 / 1536 / 3072 | Stable, deprecating |
text-embedding-004 | Text only | 2,048 | 768 (fixed) | Legacy |
Embedding spaces are incompatible between models. Upgrading from gemini-embedding-001 to gemini-embedding-2 requires re-embedding all existing data. There’s no projection between them. Plan migrations as a re-index.
Why gemini-embedding-2 is a big deal
Cross-modal search in a single index: you can query “show me clips where someone laughs” and match against an embedding index that mixes text descriptions, image frames, and audio clips. Before gemini-embedding-2, this required separate per-modality indexes + a reranking layer.
2. Basic embedding call
Python (unified SDK)
from google import genai
from google.genai import types
client = genai.Client(api_key="...")
result = client.models.embed_content(
model="gemini-embedding-2",
contents=[
"First chunk of text to embed.",
"Second chunk.",
"Third chunk.",
],
config=types.EmbedContentConfig(
output_dimensionality=768,
),
)
for emb in result.embeddings:
print(len(emb.values)) # 768
print(emb.values[:5]) # first 5 floatsMultimodal
result = client.models.embed_content(
model="gemini-embedding-2",
contents=[
"A photo of a cat sleeping in a sunbeam.", # text
types.Part.from_bytes(data=img_bytes, mime_type="image/jpeg"), # image
client.files.upload(file="clip.mp4"), # video via Files API
],
config=types.EmbedContentConfig(output_dimensionality=1536),
)All three embeddings sit in the same vector space — cosine similarity is meaningful across modalities.
REST
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": {"parts": [{"text": "Hello world"}]},
"outputDimensionality": 768
}'For batches, use :batchEmbedContents:
POST .../models/gemini-embedding-2:batchEmbedContents
{
"requests": [
{"content": {"parts": [{"text": "First"}]}, "outputDimensionality": 768},
{"content": {"parts": [{"text": "Second"}]}, "outputDimensionality": 768}
]
}3. Matryoshka dimensions
The output is truncatable: a 3072-dim vector contains the same information as a 1536-dim vector in its first 1536 components. The model is trained so that the truncated vectors are still useful (not random subsets).
Allowed values
128, 256, 768, 1536, 3072. Not arbitrary — these are the supported truncation points.
Tradeoffs
| Dim | Quality | Storage / index size | Search speed |
|---|---|---|---|
| 128 | Lossy — first-pass coarse | 8× smaller than 1024 | 8× faster |
| 256 | Good for high-recall first pass | 4× smaller | 4× faster |
| 768 | Strong default — most RAG | Baseline | Baseline |
| 1536 | Higher precision | 2× larger | 2× slower |
| 3072 | Best quality, near-saturation | 4× larger | 4× slower |
Two-stage retrieval pattern
# Index: store both 128-dim (cheap) and 3072-dim (precise)
emb_full = embed(text, dim=3072)
emb_short = emb_full[:128] # truncation works in NumPy too if normalized
# Search:
# Stage 1: ANN search on 128-dim index, k=200 candidates
# Stage 2: rerank top 200 with 3072-dim cosineSaves 96 % of search compute with minimal quality loss. Standard pattern for high-QPS retrieval at scale.
4. Task type (legacy on 001, replaced on 2)
gemini-embedding-001 accepts a task_type parameter that biases the embedding:
config=types.EmbedContentConfig(
output_dimensionality=768,
task_type="RETRIEVAL_DOCUMENT", # for documents being indexed
# or "RETRIEVAL_QUERY" for queries
# or "SEMANTIC_SIMILARITY", "CLASSIFICATION", "CLUSTERING", "QUESTION_ANSWERING", "FACT_VERIFICATION"
)Important asymmetry: documents indexed with RETRIEVAL_DOCUMENT should be queried with RETRIEVAL_QUERY (and vice versa). Mixing causes ~10-20 % retrieval-quality loss in observed benchmarks. The two task types produce embeddings biased for their role in retrieval, even though they share the same vector space.
On gemini-embedding-2
Per ai.google.dev/gemini-api/docs/embeddings 2026-05: “include task instructions directly in the prompt for text-only tasks” rather than via a task_type parameter. The newer model handles task biasing via natural-language instruction embedded in the input.
result = client.models.embed_content(
model="gemini-embedding-2",
contents=["Retrieve documents matching: What is photosynthesis?"],
)For document indexing, just embed the document text without instruction prefixes. For querying, prefix the query with intent: “Retrieve documents matching:
5. Normalization
Embeddings are L2-normalized by default — cosine_similarity and dot_product give equivalent results. Most vector DBs (Pinecone, Qdrant, pgvector, Weaviate) expect normalized inputs; just use them directly.
If you truncate a Matryoshka vector below the model’s output, re-normalize:
import numpy as np
v = np.array(emb.values)
v_short = v[:128]
v_short = v_short / np.linalg.norm(v_short)6. Pricing
Per ai.google.dev/gemini-api/docs/pricing:
| Model | Cost per 1M input tokens |
|---|---|
gemini-embedding-2 | (check pricing page — typically $0.15-$0.30) |
gemini-embedding-001 | Lower legacy rate |
Free tier: limited daily quota, suitable for prototyping.
Batch embeddings: 50 % discount via client.batches.create_embeddings(...).
7. Token counting + cost estimation
count = client.models.count_tokens(
model="gemini-embedding-2",
contents=texts,
)
print(f"{count.total_tokens} tokens × \$0.15/MTok = \${count.total_tokens / 1_000_000 * 0.15:.4f}")For 1M chunks of average 500 tokens each = 500M tokens = $75 to embed. Compare to OpenAI text-embedding-3-large at $0.13 / MTok for same workload.
8. Vertex AI Search (managed RAG)
Per cloud.google.com/vertex-ai-search 2026-05. Google’s hosted RAG product (formerly Discovery Engine).
What it is
- Upload documents (PDF, text, structured records) to a “datastore”
- Vertex AI Search indexes them automatically (embedding + keyword)
- Query endpoint returns ranked results + LLM-synthesized answer (powered by Gemini)
- No code to run embeddings, no vector DB to operate
When to use
- Production RAG without infra work
- Multi-source search (mix docs + structured data + cloud storage)
- Compliance requirements (HIPAA / PCI / GDPR — Google manages security boundary)
- Customer-facing search UIs (Vertex provides ready widgets)
When to skip
- Highly custom retrieval (BM25 + rerank pipelines, hybrid sparse-dense, etc.) — run your own
- Tight cost control on a known workload — managed services charge premiums
- Need cross-modal embedding flexibility — use
gemini-embedding-2directly
Tiers
- Search — basic semantic + keyword search
- Search + Generative AI — adds LLM answer synthesis
- Vertex AI Agent Builder — adds full conversational agent on top
Per-tier pricing varies; see Vertex pricing page.
9. Vector DB choices (when running your own)
Common pairings with Gemini embeddings:
| DB | Strengths | Notes |
|---|---|---|
| pgvector (Postgres) | Cheap, transactional, joins with relational data | Strong for hybrid (semantic + filter) queries |
| Pinecone | Managed, fast ANN, simple API | Per-vector pricing; check at scale |
| Qdrant | Self-hosted or cloud, rich filters, Rust speed | Strong open-source choice |
| Weaviate | Multi-modal native, hybrid search built-in | Good fit for gemini-embedding-2 multimodal |
| Milvus | Scales to billions of vectors | Heavier ops |
| Vertex AI Vector Search | Native GCP, scales to billions, low-latency | Best for GCP-resident workloads |
For multimodal indexes with gemini-embedding-2, Weaviate and Qdrant have first-class multimodal support; pgvector treats all vectors as opaque (works fine, just not optimized).
10. Worked RAG example
from google import genai
from google.genai import types
client = genai.Client(api_key="...")
# Index docs
docs = ["Document chunk 1...", "Document chunk 2...", ...]
result = client.models.embed_content(
model="gemini-embedding-2",
contents=docs,
config=types.EmbedContentConfig(output_dimensionality=768),
)
vectors = [e.values for e in result.embeddings]
# Store (doc, vector) pairs in your vector DB...
# Query
query = "What is the company's retention policy?"
q_result = client.models.embed_content(
model="gemini-embedding-2",
contents=[f"Retrieve documents matching: {query}"],
config=types.EmbedContentConfig(output_dimensionality=768),
)
q_vec = q_result.embeddings[0].values
# (In your vector DB) cosine-similarity top-k
top_chunks = vector_db.search(q_vec, k=5)
# Synthesize
resp = client.models.generate_content(
model="gemini-3.5-flash",
contents=[
"Answer the question using only the provided context. Cite chunk numbers.",
*[f"[Chunk {i+1}] {c.text}" for i, c in enumerate(top_chunks)],
f"Question: {query}",
],
)
print(resp.text)11. Embedding for non-RAG use cases
- Classification — embed examples + query, k-NN to class
- Clustering — embed corpus, k-means / HDBSCAN over vectors
- Semantic deduplication — embed records, find near-duplicates by cosine threshold
- Recommendation — embed items + user history, find nearest items
- Cross-lingual search —
gemini-embedding-2is multilingual; English query can match Japanese documents
12. Common pitfalls
- Mixing task types — indexing with
RETRIEVAL_DOCUMENTthen querying with the default mode loses 10-20 % retrieval quality. Be consistent. - Re-indexing on model upgrade —
gemini-embedding-001 → gemini-embedding-2requires re-embedding all data. Plan the migration cost. - Truncation without normalization — Matryoshka truncation produces an unnormalized vector; re-normalize before similarity ops.
- 3072 dim for everything — wastes storage + search time. 768 is enough for most RAG; 1536 / 3072 for marginal precision gains.
- Embedding long documents whole —
gemini-embedding-2max input is 8,192 tokens (down from full-doc fantasies); chunk first. - Forgetting batch endpoint —
batchEmbedContentsis rate-limit-friendly and 50 % cheaper. Use it. - Using sparse embeddings as cosine inputs — embeddings are dense L2-normalized floats. Don’t binarize or sparsify without a re-training step.
- Skipping the query intent prefix on
gemini-embedding-2— embeddings are quality-sensitive to task framing. “Retrieve documents matching:” + query is meaningfully better than raw query.
13. Comparison to other vendors
| Aspect | Gemini | OpenAI | Claude |
|---|---|---|---|
| Current model | gemini-embedding-2 (multimodal) | text-embedding-3-large (text-only) | n/a — Anthropic doesn’t ship embedding models |
| Multimodal | Yes | No (text only) | n/a |
| Matryoshka | Yes (5 dim options) | Yes (dimensions param, truncatable) | n/a |
| Max input tokens | 8,192 | 8,191 | n/a |
| Cross-modal queries | Yes (text↔image↔audio↔video) | No | n/a |
| Task-type biasing | gemini-embedding-001 only; embed-2 uses prompt instructions | None (single embedding) | n/a |
| Managed RAG service | Vertex AI Search | OpenAI File Search (Assistants/Responses) | Claude has no equivalent |
14. Further reading
- Embeddings — canonical reference
- Vertex AI Search — managed RAG service
- Matryoshka representations — the original paper
- google-gemini/cookbook embeddings notebooks — RAG worked examples
- Vertex AI Vector Search — GCP vector DB