Skip to content
Go back

The Insider's Guide to Building Enterprise RAG with Vertex AI RAG Engine

This guide reflects the state of Vertex AI RAG Engine as of early 2026. Google Cloud services evolve rapidly, and some features or pricing may have changed since publication. Always verify against the official documentation for the most current information.

The Uncomfortable Truth About RAG

Large language models have a fundamental problem. They don’t know your data. They hallucinate. They make things up with alarming confidence. This isn’t a bug. It’s an inherent limitation of transformer architectures that can only generate responses based on training data.

Retrieval-Augmented Generation is the fix. It grounds LLMs in your actual enterprise data, producing accurate, verifiable responses.

But here is what most teams don’t understand until it’s too late: building RAG from scratch means stitching together document parsers, chunking logic, embedding models, vector databases, and retrieval pipelines. It’s a massive engineering challenge. Most RAG implementations fail because engineers underestimate the data pipeline complexity.

Google’s Vertex AI RAG Engine industrializes what was previously a fragile, hand-stitched architecture into a managed service with production-grade guarantees. This guide covers the architectural decisions, the hidden constraints, the cost formulas, and the complete working code you need.


TL;DR — The Decision Matrices That Actually Matter

Vector Database Comparison

DatabaseManagementCMEKBest For
RagManagedDbFully managedYesMost teams should start here
RagManagedVertexVectorSearchFully managedNoLatest features, data visibility
WeaviateUser-managedNoHybrid search, open-source flexibility
PineconeUser-managedNoExisting Pinecone investments
Vertex AI Feature StoreUser-managedNoBigQuery-native workflows

Parser Comparison

ParserCostBest For
DefaultFreePlain text, simple PDFs
LLM ParserPer-tokenComplex documents with tables and charts
Document AI LayoutDocument AI pricingContext-aware chunking for structured docs

Embedding Models

ModelUse Case
text-embedding-005Default, English-only, recommended for RAG corpora
text-multilingual-embedding-002Multilingual corpora
Fine-tuned or OSS modelsLong-term projects that need deprecation protection

Cost Snapshot (Monthly PoC)

ComponentEstimated Cost
RagManagedDb BasicAround $200-250/month
Embeddings (1M tokens)$0.075
LLM Parser (5M tokens)$3.75
Vertex Ranking API (10k requests)$1
Gemini 2.0 Flash (3M output tokens)$7.5

The Limits You’ll Hit

  • 3 concurrent imports per region
  • 60 RPM for management APIs
  • 600 RPM for retrieval queries
  • 10,000 maximum files per import request
  • One corpus per generation request
  • 50 unique KMS keys per project per region for CMEK

The Architecture: Six Stages You Must Understand

RAG Pipeline Architecture The six-stage RAG pipeline implemented by Vertex AI RAG Engine.

Vertex AI RAG Engine implements a specific architecture. You need to understand each stage at a granular level:

Data Ingestion -> Transformation -> Embedding -> Indexing -> Retrieval -> Generation

Each stage has tradeoffs, failure modes, and costs. Let’s examine them.


Stage 1: Data Ingestion

Data Ingestion Sources Multiple data sources feeding into the RAG ingestion pipeline.

Supported Sources

SourceSize LimitsKey Requirements
Local file uploadUp to 25 MiB per fileSynchronous, good for demos
Cloud StorageUnlimited objects (each up to 5 TiB)Bulk import via ImportRagFiles
Google DriveStandard Drive quotasService account needs Viewer permission
SlackAPI-dependentAPI key stored in Secret Manager
JiraAPI-dependentAPI key stored in Secret Manager
SharePointAPI-dependentAzure app registration required

The Silent Failure Problem

Google Drive imports fail silently. The Vertex AI RAG Data Service Agent (service-{project_number}@gcp-sa-vertex-rag.iam.gserviceaccount.com) must have Viewer permissions on specific folders. Without this, no files import and no error message displays. This catches many teams off guard.

Data Deduplication

Files are hashed by content, path, and filename. The response.skipped_rag_files_count tells you how many were skipped because they were unchanged. A file is skipped when it has been imported before, hasn’t changed, and the chunking configuration hasn’t changed.

Service Account Prerequisites

When ingesting from Drive, Slack, or external connectors:

  1. Enable Secret Manager
  2. Store API keys as secrets
  3. Grant the RAG service account roles/secretmanager.secretAccessor
  4. Reference secrets as projects/<PROJECT>/secrets/<SECRET>/versions/latest

Stage 2: Data Transformation

Document Transformation and Chunking Document parsing and chunking with overlap visualization.

Parsing Options

ParserCostBest ForLimitations
Default ParserFreePlain text, simple PDFsLimited structure understanding
LLM ParserPer-token (Gemini pricing)Complex documents, charts, tablesGemini 2.x variants only; 3.x not yet supported
Document AI Layout ParserDocument AI pricingContext-aware chunkingMax 20 MB, 500 pages per PDF

LLM Parser Cost Formula

Cost = N_files x N_pages x (input_tokens x input_price + output_tokens x output_price)

Example: 1,000 PDFs with 50 pages each, 600 input tokens plus 100 output tokens per page, using Gemini 2.0 Flash-Lite ($0.075/M input, $0.3/M output):

Cost = 1,000 x 50 x (600 x 0.075/1M + 100 x 0.3/1M) = $3.75

LLM Parser Custom Prompts

For specialized documents (legal contracts, technical manuals, scientific papers), custom prompts help extract the right information:

llm_parser_cfg = rag.LlmParserConfig(
    model_name="projects/<PROJECT>/locations/<LOC>/publishers/google/models/gemini-2.5-pro",
    custom_parsing_prompt="""You are a factual data extractor.
Extract key data from the document.
Present each fact in a structured list.
Focus on: names, dates, numbers.
Avoid: analysis or interpretation.""",
    max_parsing_requests_per_min=900
)

Chunking Strategy

Defaults are 1,024 tokens with 256 token overlap. Smaller chunks mean more precise embeddings but more retrieval calls. Larger chunks provide more context but risk losing specific details.

Important: Document AI Layout Parser ignores overlap settings and creates layout-aware chunks that respect headings, tables, and images.

transformation_config = rag.TransformationConfig(
    chunking_config=rag.ChunkingConfig(
        chunk_size=512,
        chunk_overlap=100
    )
)

Stage 3: Embedding Models

Vector Embeddings Visualization Text being converted to numerical vectors in semantic space.

Model Options

ModelDimensionUse CaseNotes
text-embedding-005768Default, recommended for RAGNo deployment required
text-multilingual-embedding-002768Multilingual corporaSame quality, multiple languages
Fine-tuned Gecko768Specialized domainsImmune to deprecation, requires endpoint
OSS E5 models384-1024Full controlDeploy from Model Garden first

The Stickiness Problem

The embedding model is locked to the corpus at creation time. You cannot change it without recreating the corpus and re-importing all data. When publisher models are deprecated, you must migrate.

For long-term projects: Use fine-tuned or self-deployed OSS models. They survive deprecation.

Embedding Quotas

For gemini-embedding-001:

  • Maximum input texts per request: 250
  • Maximum tokens per request: 20,000
  • Maximum tokens per input text: 2,048 (only first 2,048 tokens are used)
  • Quota: 5,000,000 tokens per minute per region

Stage 4: Vector Database Choices

Vector Database Comparison Comparison of vector database options for RAG Engine.

This is the most consequential decision you’ll make.

RagManagedDb (Default, Generally Available)

What most teams should use.

Underlying technology is Google Spanner. The RAG Engine manages provisioning and scaling.

Tiers:

  • Basic: 100 processing units, fixed configuration (around $200-250/month)
  • Scaled: 1,000-10,000 processing units (1-10 nodes), autoscaling, production-grade
  • Unprovisioned: Deletes the Spanner instance, stops billing (cannot be reversed)

Retrieval strategies:

  • KNN (Default): Exact nearest neighbors, perfect recall, latency increases with corpus size. Good for corpora under 10,000 files.
  • ANN (Preview): Approximate nearest neighbors, lower latency for large corpora. Requires index rebuilding.

ANN Configuration:

  • tree_depth: 2 for around 10K files, 3 for larger corpora
  • leaf_count: Recommended 10 x sqrt(number_of_files), default is 500
  • You must rebuild after significant data changes: rebuild_ann_index: true

RagManagedVertexVectorSearch (Preview)

Uses Vertex AI Vector Search 2.0. RAG Engine manages the Vector Search 2.0 collections, and you have full access to them in your project.

Availability: Only in us-central1 and requires allowlisting.

vector_db = rag.RagManagedVertexVectorSearch()
rag_corpus = rag.create_corpus(
    display_name="my_corpus",
    backend_config=rag.RagVectorDbConfig(vector_db=vector_db)
)

Weaviate (Preview)

For teams that need hybrid search.

Weaviate supports hybrid search (dense + sparse vectors). This combines semantic and keyword searches to improve relevance.

  • Requires provisioning and managing your Weaviate instance
  • API key stored in Google Cloud Secret Manager
  • One-to-one mapping between RAG corpus and Weaviate collection
  • Collection name is immutable once set
  • First letter of collection name must be capitalized

Required schema fields:

fileId (text)
corpusId (text)
chunkId (text)
chunkDataType (text)
chunkData (text)
fileOriginalUri (text)

Pinecone (Generally Available)

For teams already invested in Pinecone.

  • Requires index creation before corpus creation
  • Dimension must match embedding model (768 for Gecko models)
  • Supported distance metrics: cosine, dotproduct, euclidean
  • API key stored in Secret Manager
  • For pod-based indexes: specify file_id in pod.metadata_config.indexed field

Vertex Vector Search 1.0 (Generally Available)

If you want to bring your own Vector Search instance:

  • IndexUpdateMethod must be STREAM_UPDATE
  • Distance measure: DOT_PRODUCT_DISTANCE or COSINE_DISTANCE
  • Use numeric IDs for index and index_endpoint resource names

Vertex AI Feature Store (Preview)

For BigQuery-native workflows.

  • Uses BigQuery table as data source
  • Requires FeatureOnlineStore instance with optimized online serving
  • Supports vector similarity search (approximate nearest neighbors)
  • Default distance metric: DOT_PRODUCT_DISTANCE

Required BigQuery table schema:

corpus_id (STRING, required)
file_id (STRING, required)
chunk_id (STRING, required)
chunk_data_type (STRING, nullable)
chunk_data (STRING, nullable)
file_original_uri (STRING, nullable)
embeddings (FLOAT, repeated)

The Immutability Warning

The vector database choice is immutable after corpus creation. Choose based on your cost structure, scalability needs, and maintenance preferences.


Stage 5: Retrieval

Retrieval and Reranking Process Two-stage retrieval with optional reranking for improved relevance.

Basic Retrieval

retrieval_cfg = rag.RagRetrievalConfig(
    top_k=10,
    filter=rag.Filter(vector_distance_threshold=0.5)
)
response = rag.retrieval_query(
    rag_resources=[rag.RagResource(rag_corpus=corpus_name)],
    text="Your query",
    rag_retrieval_config=retrieval_cfg
)

Parameters:

  • top_k: Number of results (default 10)
  • vector_distance_threshold: Only return results below this threshold (lower means stricter similarity)
  • rag_file_ids: Optional filter to specific files within corpus

Rate limit: Retrieval requests are limited to 600 RPM per region.

Hybrid Search (Weaviate Only)

Weaviate automatically enables hybrid search. No additional configuration needed. Just use Weaviate as your vector database.

Hybrid search cannot be used with Vertex Vector Search 1.0, 2.0, or RagManagedDb.

Reranking

RerankerLatencyAccuracyCost
Vertex AI Ranking APIUnder 100msState-of-the-artPer-request pricing
LLM Reranker1-2 secondsModel-dependentLLM token pricing

Vertex Ranking API:

Requires enabling the Discovery Engine API.

ranking_cfg = rag.Ranking(
    rank_service=rag.RankService(model_name="semantic-ranker-default@latest")
)
retrieval_cfg = rag.RagRetrievalConfig(top_k=10, ranking=ranking_cfg)

LLM Reranker:

ranking_cfg = rag.Ranking(
    llm_ranker=rag.LlmRanker(model_name="gemini-2.5-pro")
)
retrieval_cfg = rag.RagRetrievalConfig(top_k=10, ranking=ranking_cfg)

Only one ranking layer allowed per config. Supplying both produces a 400 error.


Stage 6: Generation

Grounded Generation with Gemini LLM generating grounded responses with retrieved context and citations.

Direct Retrieval Tool Integration

retrieval_tool = Tool.from_retrieval(
    retrieval=rag.Retrieval(
        source=rag.VertexRagStore(
            rag_resources=[rag.RagResource(rag_corpus=corpus_name)],
            rag_retrieval_config=rag.RagRetrievalConfig(top_k=10)
        )
    )
)

model = GenerativeModel(
    model_name="gemini-2.0-flash-001",
    tools=[retrieval_tool]
)

response = model.generate_content("Your question")
print(response.text)  # Grounded answer with citations

Supported Models

  • Gemini 2.5 Pro, Flash, Flash-Lite
  • Gemini 3.1 Pro, Flash-Lite (preview)
  • Gemini 3 Flash, 3 Pro (preview)
  • Self-deployed models from Model Garden
  • Managed APIs: Mistral on Vertex AI, Llama 3.1/3.2

Important: Fine-tuned Gemini models are not supported with RAG Engine.

Limitation: At most one corpus per generation request.

Vertex AI Search as Retrieval Backend

You can also use Vertex AI Search as the retrieval backend instead of a vector database. This is useful if you already have search applications built on Vertex AI Search.

vertex_ai_search_config = rag.VertexAiSearchConfig(
    serving_config=f"{vertex_ai_search_engine_name}/servingConfigs/default_search"
)

corpus = rag.create_corpus(
    display_name="search_backed_corpus",
    vertex_ai_search_config=vertex_ai_search_config
)

Quick Start: Complete Working Example

import vertexai
from vertexai import rag
from vertexai.generative_models import GenerativeModel, Tool

PROJECT_ID = "your-project-id"
LOCATION = "us-central1"

# Initialize
vertexai.init(project=PROJECT_ID, location=LOCATION)

# Create corpus with defaults
rag_corpus = rag.create_corpus(
    display_name="my_corpus",
    backend_config=rag.RagVectorDbConfig(
        rag_embedding_model_config=rag.RagEmbeddingModelConfig(
            vertex_prediction_endpoint=rag.VertexPredictionEndpoint(
                publisher_model="publishers/google/models/text-embedding-005"
            )
        )
    )
)

# Import files
rag.import_files(
    rag_corpus.name,
    ["gs://my-bucket/documents/"],
    transformation_config=rag.TransformationConfig(
        chunking_config=rag.ChunkingConfig(chunk_size=512, chunk_overlap=100)
    )
)

# Create retrieval tool
rag_retrieval_tool = Tool.from_retrieval(
    retrieval=rag.Retrieval(
        source=rag.VertexRagStore(
            rag_resources=[rag.RagResource(rag_corpus=rag_corpus.name)]
        )
    )
)

# Generate
model = GenerativeModel("gemini-2.0-flash-001", tools=[rag_retrieval_tool])
response = model.generate_content("What are the key points?")
print(response.text)

Enterprise Production Setup

Enterprise Security Features Security controls including CMEK, VPC-SC, and IAM permissions.

Security: CMEK Implementation

Requirements:

  1. Cloud KMS API enabled
  2. Key ring in same region as RAG Engine endpoint
  3. Purpose: Symmetric encrypt/decrypt
  4. Grant RAG service account roles/cloudkms.cryptoKeyEncrypterDecrypter
from google.cloud.aiplatform_v1.types.encryption_spec import EncryptionSpec

corpus = rag.create_corpus(
    display_name="secure_corpus",
    encryption_spec=EncryptionSpec(
        kms_key_name="projects/<PROJECT>/locations/us-central1/keyRings/kr/cryptoKeys/key"
    )
)

Limitations:

  • CMEK is immutable after corpus creation
  • Maximum 50 unique KMS keys per project per region
  • Only supported on RagManagedDb

VPC-SC Security Controls

Supported. When you enable a perimeter, add the service account to the “Include Google-provided role grants” list.

Data Residency and AXT Security

Not supported.

Production Pattern with CMEK and Scaled Tier

# Create corpus with CMEK
rag_corpus = rag.create_corpus(
    display_name="enterprise_corpus",
    encryption_spec=EncryptionSpec(kms_key_name=KMS_KEY_NAME)
)

# Import with LLM parser for quality
rag.import_files(
    rag_corpus.name,
    ["gs://enterprise-bucket/documents/"],
    transformation_config=rag.TransformationConfig(
        rag.ChunkingConfig(chunk_size=1024, chunk_overlap=256)
    ),
    llm_parser=rag.LlmParserConfig(
        model_name=f"projects/{PROJECT_ID}/locations/us-central1/publishers/google/models/gemini-2.5-flash"
    )
)

Advanced Features

Gemini Live API Integration

Build real-time voice or multimodal assistants with RAG grounding:

TOOLS = {
  "retrieval": {
    "vertex_rag_store": {
      "rag_resources": {
        "rag_corpus": f"projects/{PROJECT_ID}/locations/{LOCATION}/ragCorpora/{RAG_CORPUS_ID}"
      }
    }
  }
}

async with client.aio.live.connect(
  model="gemini-2.0-flash-exp",
  config=LiveConnectConfig(
    response_modalities=[Modality.TEXT],
    tools=TOOLS
  )
) as session:
  await session.send_client_content(
    turns=Content(role="user", parts=[Part(text="Your question")])
  )
  async for message in session.receive():
    if message.text:
      print(message.text)

Memory Corpus for Persistent Context

Store and index conversation context across Live API sessions. This enables sharing contexts across different sessions and retrieving past contexts related to your conversation.

memory_corpus = rag.create_corpus(
   display_name="conversation_memory",
   corpus_type_config=rag.RagCorpusTypeConfig(
       corpus_type_config=rag.MemoryCorpus(
           llm_parser=rag.LlmParserConfig(
               model_name="projects/<PROJECT>/locations/<LOC>/publishers/google/models/gemini-2.5-pro"
           )
       )
   ),
   backend_config=rag.RagVectorDbConfig(
       rag_embedding_model_config=rag.RagEmbeddingModelConfig(
           vertex_prediction_endpoint=rag.VertexPredictionEndpoint(
               publisher_model="publishers/google/models/text-embedding-005"
           )
       )
   )
)

Memory corpora support storing and indexing text and audio speech from session contexts.


Performance and Scaling

Quotas

ResourceLimitMetric
Data management APIs60 RPMVertexRagDataService requests per minute per region
RetrievalContexts API600 RPMVertexRagService retrieve requests per minute per region
Embedding token quota5M tokens/minPer region
Concurrent ImportRagFiles3Per region
Max files per import10,000Per request

Supported Regions

RegionLocationStatus
us-central1IowaAllowlist, GA
us-east4VirginiaAllowlist, GA
us-east1Moncks Corner, SCAllowlist, Preview
europe-west3FrankfurtGA
europe-west4EemshavenGA
asia-east1TaiwanPreview
asia-northeast1TokyoPreview
asia-northeast3SeoulPreview
asia-south1MumbaiPreview
asia-southeast1SingaporePreview
europe-central2WarsawPreview
europe-north1FinlandPreview
europe-southwest1MadridPreview
europe-west1BelgiumPreview
europe-west2LondonPreview
europe-west6ZurichPreview
europe-west8MilanPreview
europe-west9ParisPreview
us-east5Columbus, OHPreview
us-south1Dallas, TXPreview
us-west1OregonPreview
us-west4Las Vegas, NVPreview

Important: For us-central1, us-east1, and us-east4, new projects must be allowlisted. Contact [email protected].


Common Pitfalls

PitfallSymptomFix
Drive permissionsImport silently failsGrant service account Viewer on Drive folder
Embedding model deprecationCorpus becomes unusableUse fine-tuned or self-deployed models
ANN not rebuiltRetrieval quality degradesSet rebuild_ann_index: true after imports
Vector DB region mismatchHigh latencyDeploy DB in same region as RAG Engine
CMEK key region mismatchCorpus creation failsCreate key ring in same region
Exceeding import concurrencyRequests queued indefinitelyMax 3 concurrent imports per region
File size on Layout ParserImport failsMax 20 MB, 500 pages/PDF
Non-numeric Vector Search IDs400 errorUse numeric IDs, not display names
Wrong secret version404 errorUse versions/latest, not versions/1
Multiple ranking layers400 errorOnly one ranking config allowed
Lowercase Weaviate collectionCollection not foundCapitalize first letter

Cost Management

Billing Breakdown

ComponentPricing ModelTypical Monthly Cost (PoC)
RagManagedDb Basic (100 PU)Spanner pricingAround $200-250
Embedding (text-embedding-005)$0.075/M input tokens1M tokens costs about $0.075
LLM Parser (Gemini 2.5 Flash)Per-token pricing5M tokens costs about $3.75
Vertex Ranking APIPer-request pricing10k requests costs about $1
Gemini Generation (2.0 Flash)Per-token pricing3M output tokens costs about $7.5

Cost Optimization Tips

  • Use Unprovisioned tier for development (eliminates Spanner bill)
  • Default parser is free. Only use LLM or Layout parser when needed
  • Smaller chunks reduce embedding costs but increase retrieval calls
  • Batch imports to stay within quotas and avoid retries

Clean-Up Procedure

Important: This permanently deletes all data and stops billing.

curl -X PATCH \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"https://LOCATION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/ragEngineConfig?update_mask=rag_tier" \
-d '{"rag_tier": "UNPROVISIONED"}'

Warning: Data cannot be recovered after deletion.


Best Practices Checklist

Do ThisDon’t Do This
Enable Secret Manager and grant Secret Accessor to RAG service accountStore API keys in plain environment variables
Use latest secret version in all referencesReference specific versions like versions/1
Call rebuild_ann_index=true at least once for ANN backendsExpect immediate ANN updates after import
Set tree_depth and leaf_count for ANN with over 10K filesOmit them and suffer degraded recall
Use numeric IDs for Vector Search index and endpointPass display names
Verify model supports grounding before adding retrieval toolUse models without grounding capability
Keep vector_distance_threshold above 0Set to 0 expecting all results
Remember one-corpus-per-generation-tool restrictionPass multiple corpora in single tool
Capitalize Weaviate collection namesUse lowercase

Key Takeaways

The Vertex AI RAG Engine industrializes a pattern that used to require stitching together multiple services. It works. It scales. It has production-grade guarantees.

What actually matters:

  • Vector database choice determines cost structure, scalability, and feature availability. Start with RagManagedDb Basic, move to Scaled when you hit limits.

  • Parser choice determines quality. Default is free but limited. LLM parser costs money but understands complex documents.

  • Embedding models are sticky. Choose wisely based on language requirements and deprecation risk.

  • Reranking is the hidden quality booster. Use it for any user-facing application.

  • Service account permissions are the number one source of silent failures.

  • Quotas are tighter than you think. Plan for 3 concurrent imports, 60 RPM management operations, 600 RPM retrieval.

  • Region selection has consequences. Some features require allowlisting.


Sources and Further Reading


Questions? Contact [email protected]

This is the technical foundation. The rest is execution. Go build something that works.


Tags

Related Posts

Share this post on: