Home / Articles / Practical notes: The Three Tiers of Google Cloud RAG: Vector Search, RAG Engine, and Agent Retrieval

This article is published in English.

Practical notes: The Three Tiers of Google Cloud RAG: Vector Search, RAG Engine, and Agent Retrieval

Operable walkthrough of Practical notes: The Three Tiers of Google Cloud RAG: Vector Search, RAG Engine, and Agent Retrieval: contracts, checks, and drop-in code slots for.

3958 words

Use this as an operator-facing rebuild of the ideas in “The Three Tiers of Google Cloud RAG: Vector Search, RAG Engine, and Agent Retrieval”: clear stages, ordered code slots, and recovery notes that survive a handoff. Overview works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

Architectural and Abstraction Layers

For Architectural and Abstraction Layers, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap.

1. Vertex AI Vector Search (Level 1: High-Performance Infrastructure)

For 1. Vertex AI Vector Search (Level 1: High-Performance Infrastructure), define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap.

Core Architecture and Mechanics

For Core Architecture and Mechanics, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap. For Core Architecture and Mechanics, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

The Three-Stage ScaNN Retrieval Pipeline

When working through The Three-Stage ScaNN Retrieval Pipeline, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

Distributed Infrastructure: Vertex Matching Engine Innovations

When working through Distributed Infrastructure: Vertex Matching Engine Innovations, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

Production Use Cases for Google Vector Search

When working through Production Use Cases for Google Vector Search, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface. When working through Production Use Cases for Google Vector Search, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

1. Real-Time Multimodal E-Commerce & Visual Catalog Search

  1. Real-Time Multimodal E-Commerce & Visual Catalog Search works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Separate chunking policy from retrieval policy. Changing one should not force a rewrite of the other when quality metrics move.

2. Billion-Scale Candidate Generation for Recommendation Funnels

  1. Billion-Scale Candidate Generation for Recommendation Funnels works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Separate chunking policy from retrieval policy. Changing one should not force a rewrite of the other when quality metrics move.

3. Real-Time Financial Fraud & Cyber Anomaly Clustering

  1. Real-Time Financial Fraud & Cyber Anomaly Clustering works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Separate chunking policy from retrieval policy. Changing one should not force a rewrite of the other when quality metrics move.
  2. Real-Time Financial Fraud & Cyber Anomaly Clustering works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

Code: Index Creation, Streaming Ingestion, and Querying

For Code: Index Creation, Streaming Ingestion, and Querying, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap.

package main

import (
 "context"
 "fmt"
 "log"

 aiplatform "cloud.google.com/go/aiplatform/apiv1"
 aiplatformpb "cloud.google.com/go/aiplatform/apiv1/aiplatformpb"
 "google.golang.org/api/option"
)

func main() {
 ctx := context.Background()
 projectID := "my-enterprise-gcp-project"
 location := "us-central1"

 // 1. Initialize Vertex AI Match Client (Vector Search Query Service)
 matchClient, err := aiplatform.NewMatchClient(ctx)
 if err != nil {
  log.Fatalf("failed to create vertex match client: %v", err)
 }
 defer matchClient.Close()

 indexEndpointPath := fmt.Sprintf(
  "projects/%s/locations/%s/indexEndpoints/product_catalog_endpoint_id",
  projectID, location,
 )
 deployedIndexID := "product_catalog_deployed_v1"

 // 2. Construct 768-dimensional Query Embedding Vector
 queryVector := make([]float32, 768)
 queryVector[0] = 0.032
 queryVector[1] = -0.108
 queryVector[2] = 0.449

 // 3. Build Nearest Neighbor Request with Boolean & Numeric Restricts
 req := &aiplatformpb.FindNeighborsRequest{
  IndexEndpoint:   indexEndpointPath,
  DeployedIndexId: deployedIndexID,
  Queries: []*aiplatformpb.FindNeighborsRequest_Query{
   {
    Datapoint: &aiplatformpb.IndexDatapoint{
     DatapointId:   "query_req_001",
     FeatureVector: queryVector,
     Restricts: []*aiplatformpb.IndexDatapoint_Restriction{
      {
       Namespace: "category",
       AllowList: []string{"electronics", "audio"},
      },
      {
       Namespace: "brand",
       AllowList: []string{"sony", "bose"},
      },
     },
     NumericRestricts: []*aiplatformpb.IndexDatapoint_NumericRestriction{
      {
       Namespace: "price",
       Value: &aiplatformpb.IndexDatapoint_NumericRestriction_ValueFloat{
        ValueFloat: 350.0,
       },
       Op: aiplatformpb.IndexDatapoint_NumericRestriction_LESS_EQUAL,
      },
      {
       Namespace: "in_stock",
       Value: &aiplatformpb.IndexDatapoint_NumericRestriction_ValueInt{
        ValueInt: 1,
       },
       Op: aiplatformpb.IndexDatapoint_NumericRestriction_EQUAL,
      },
     },
    },
    NeighborCount: 5,
   },
  },
  ReturnFullDatapoint: false,
 }

 // 4. Execute Sub-Millisecond Vector Similarity Search
 resp, err := matchClient.FindNeighbors(ctx, req)
 if err != nil {
  log.Fatalf("failed to execute find neighbors: %v", err)
 }

 if len(resp.NearestNeighbors) > 0 {
  fmt.Printf("Retrieved %d nearest neighbors:\n", len(resp.NearestNeighbors[0].Neighbors))
  for _, neighbor := range resp.NearestNeighbors[0].Neighbors {
   fmt.Printf("Datapoint ID: %s | Distance: %.4f\n", neighbor.Datapoint.DatapointId, neighbor.Distance)
  }
 }
}

2. Vertex AI RAG Engine (Level 2: Managed Middleware)

For 2. Vertex AI RAG Engine (Level 2: Managed Middleware), define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap.

Core Architecture and Mechanics

For Core Architecture and Mechanics, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap. For Core Architecture and Mechanics, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

Another Architectural Advantage: Pluggable Vector Database Backends

When working through Another Architectural Advantage: Pluggable Vector Database Backends, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

Why This Decoupled Architecture is a Game-Changer

When working through Why This Decoupled Architecture is a Game-Changer, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

Production Use Case: Enterprise HR Policy and Regulatory Compliance Assistant

When working through Production Use Case: Enterprise HR Policy and Regulatory Compliance Assistant, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface. When working through Production Use Case: Enterprise HR Policy and Regulatory Compliance Assistant, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

Code: Grounded Generation with Vertex RAG Store

Code: Grounded Generation with Vertex RAG Store works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Separate chunking policy from retrieval policy. Changing one should not force a rewrite of the other when quality metrics move.

package main

import (
 "context"
 "fmt"
 "log"

 "google.golang.org/genai"
)

func main() {
 ctx := context.Background()
 projectID := "my-enterprise-gcp-project"
 location := "us-central1"

 // 1. Initialize Google GenAI Client with Vertex AI Backend
 client, err := genai.NewClient(ctx, &genai.ClientConfig{
  Project:  projectID,
  Location: location,
  Backend:  genai.BackendVertexAI,
 })
 if err != nil {
  log.Fatalf("failed to initialize genai client: %v", err)
 }

 // 2. Reference the Managed RAG Corpus Resource
 // (Corpus can be backed by RagManagedDb, Vertex Vector Search, Weaviate, or Pinecone)
 ragCorpusResource := fmt.Sprintf(
  "projects/%s/locations/%s/ragCorpora/enterprise_hr_policies_corpus",
  projectID, location,
 )

 // 3. Configure Grounding Tool with Vertex RAG Store and Semantic Reranking
 config := &genai.GenerateContentConfig{
  Tools: []*genai.Tool{
   {
    Retrieval: &genai.Retrieval{
     VertexRagStore: &genai.VertexRagStore{
      RagResources: []*genai.VertexRagStoreRagResource{
       {RagCorpus: ragCorpusResource},
      },
      SimilarityTopK:          genai.Ptr(int64(3)),
      VectorDistanceThreshold: genai.Ptr(0.5),
     },
    },
   },
  },
 }

 // 4. Generate Grounded Response with Gemini 3.5 Flash
 prompt := "Summarize our international meal reimbursement policy and specify receipt requirements."
 result, err := client.Models.GenerateContent(ctx, "gemini-3.5-flash", genai.Text(prompt), config)
 if err != nil {
  log.Fatalf("failed to generate grounded content: %v", err)
 }

 // 5. Output Synthesized Text and Inspect Verifiable Grounding Supports
 fmt.Println("--- Grounded Answer from Gemini ---")
 fmt.Println(result.Text())

 if len(result.Candidates) > 0 && result.Candidates[0].GroundingMetadata != nil {
  meta := result.Candidates[0].GroundingMetadata
  fmt.Printf("\nGrounding supports detected: %d\n", len(meta.GroundingSupports))
  for _, support := range meta.GroundingSupports {
   if support.Segment != nil {
    fmt.Printf("Segment: %q (Grounded by chunks: %v)\n", support.Segment.Text, support.GroundingChunkIndices)
   }
  }
 }
}

3. Vertex AI Agent Retrieval (Level 3: Autonomous Reasoning)

  1. Vertex AI Agent Retrieval (Level 3: Autonomous Reasoning) works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Budget tokens per turn and per session. Agentic tools expand context aggressively; hard caps keep demos from becoming surprise invoices.

Core Architecture and Key Attributes

Core Architecture and Key Attributes works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Separate chunking policy from retrieval policy. Changing one should not force a rewrite of the other when quality metrics move. Core Architecture and Key Attributes works best when treated as a measurable surface. Capture one golden transcript, one failure case, and the rollback note before expanding scope. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

Key Attributes of Vertex AI Agent Retrieval

For Key Attributes of Vertex AI Agent Retrieval, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap.

Production Use Case: Autonomous SRE DevOps Incident Resolution Agent

For Production Use Case: Autonomous SRE DevOps Incident Resolution Agent, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap.

Code: Building an Autonomous Agent with Google ADK

For Code: Building an Autonomous Agent with Google ADK, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Cite the passages that actually grounded the answer. Without citations, operators cannot tell hallucination from an indexing gap. For Code: Building an Autonomous Agent with Google ADK, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

package main

import (
 "context"
 "fmt"
 "log"

 "google.golang.org/adk/agent"
 "google.golang.org/adk/model"
 "google.golang.org/adk/runner"
 "google.golang.org/adk/tool"
 "google.golang.org/adk/tool/vertexsearch"
)

// TelemetryQueryParams defines input arguments for the structured telemetry tool.
type TelemetryQueryParams struct {
 ServiceName       string `json:"service_name" jsonschema:"description=The target microservice name (e.g. payment-gateway)"`
 TimeWindowMinutes int    `json:"time_window_minutes" jsonschema:"description=The lookback window in minutes"`
}

// TelemetryReport defines the structured metrics returned to the agent.
type TelemetryReport struct {
 Service          string  `json:"service"`
 TimeWindow       string  `json:"time_window"`
 ErrorRate        float64 `json:"error_rate_percentage"`
 DominantStatus   string  `json:"dominant_http_status"`
 RootDependency   string  `json:"root_downstream_dependency"`
 ActiveRestarts   int     `json:"active_pod_restarts"`
 Region           string  `json:"region"`
}

// QuerySystemTelemetry is a custom tool function registered with the ADK agent.
func QuerySystemTelemetry(ctx context.Context, params TelemetryQueryParams) (TelemetryReport, error) {
 // Simulated query against Cloud Spanner and BigQuery live telemetry
 return TelemetryReport{
  Service:        params.ServiceName,
  TimeWindow:     fmt.Sprintf("%dm", params.TimeWindowMinutes),
  ErrorRate:      14.8,
  DominantStatus: "504 Gateway Timeout",
  RootDependency: "auth-token-validator-v2",
  ActiveRestarts: 12,
  Region:         "us-central1",
 }, nil
}

func main() {
 ctx := context.Background()
 projectID := "my-enterprise-gcp-project"

 // 1. Create Structured Telemetry Function Tool using Google ADK
 telemetryTool, err := tool.NewFunction(
  "query_system_telemetry",
  "Queries Cloud Spanner and BigQuery for live microservice error rates and container health.",
  QuerySystemTelemetry,
 )
 if err != nil {
  log.Fatalf("failed to create telemetry tool: %v", err)
 }

 // 2. Configure Vertex AI Search Datastore Retrieval Tool in Google ADK
 datastoreResource := fmt.Sprintf(
  "projects/%s/locations/global/collections/default_collection/dataStores/sre-runbooks-datastore",
  projectID,
 )
 runbookTool, err := vertexsearch.NewDatastoreTool(vertexsearch.DatastoreConfig{
  Name:        "sre_runbook_search",
  Description: "Searches authoritative SRE incident runbooks, architecture specs, and standard operating procedures (SOPs).",
  DatastoreID: datastoreResource,
 })
 if err != nil {
  log.Fatalf("failed to create vertex search tool: %v", err)
 }

 // 3. Define Autonomous SRE Agent using Google ADK
 systemInstruction := `You are an expert Autonomous Site Reliability Engineering (SRE) Incident Agent.
When investigating production alerts:
1. Use query_system_telemetry to inspect live metrics and isolate the failing component.
2. Formulate a targeted search query with sre_runbook_search to find the exact recovery SOP.
3. Synthesize a comprehensive Incident Diagnosis Report containing:
   - Root cause analysis with telemetry evidence
   - Step-by-step remediation commands cited directly from the runbook
   - Actionable rollback or mitigation steps.`

 sreIncidentAgent, err := agent.New(agent.Config{
  Name:        "sre_incident_investigator",
  Model:       model.Gemini("gemini-3.5-flash"),
  Description: "Autonomous SRE agent that investigates telemetry, retrieves runbooks, and drafts mitigation plans.",
  Instruction: systemInstruction,
  Tools:       []tool.Tool{telemetryTool, runbookTool},
 })
 if err != nil {
  log.Fatalf("failed to initialize ADK agent: %v", err)
 }

 // 4. Execute Multi-Turn Autonomous Workflow with Google ADK Runner
 r := runner.NewInMemoryRunner(sreIncidentAgent)

 userIncidentPrompt := "CRITICAL ALERT: Payment service checkout latency spiked to 4500ms in us-central1. " +
  "Investigate the payment-gateway service, locate the relevant runbook, and recommend immediate remediation."

 response, err := r.Run(ctx, userIncidentPrompt)
 if err != nil {
  log.Fatalf("agent execution failed: %v", err)
 }

 fmt.Println("--- Agentic Incident Resolution Plan ---")
 fmt.Println(response.Text())
}

4. Decision Framework: Choosing the Right Google RAG Service

When working through 4. Decision Framework: Choosing the Right Google RAG Service, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

Comparison Matrix

When working through Comparison Matrix, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Record timings and token or query cost next to functional results. Cost visibility early prevents surprise bills when the path moves from demo to shared environments. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

5. Summary and Architectural Takeaways

When working through 5. Summary and Architectural Takeaways, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface. When working through 5. Summary and Architectural Takeaways, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest. Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.

Operational checklist

When working through Operational checklist, write down the contract first: required inputs, success signal, and what happens on partial failure. That checklist keeps later code changes honest.

Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish.

Measure recall on a fixed question set before tuning prompts. Prompt churn rarely fixes a weak retrieval surface.

Keep graph state flat and typed. Nested blobs hide which node wrote which field and break resume after interrupts.

Score single-turn answers and multi-turn trajectories separately. Aggregate chat scores bury tool-loop failures.

Write a short runbook: how to rotate keys, how to drain the queue, how to roll back the last ingest.

Before promoting the stack, freeze versions, capture a golden transcript for the critical path, and confirm rollback steps. Shared environments need rate limits, tenancy checks, and a clear owner for secret rotation. Prefer boring reliability over clever one-off demos.

Batch note for 331adf7ac401: keep provider keys out of the repo, set a per-session token ceiling, and store transcripts next to the eval fixtures so later model swaps stay comparable.