Nick Duong · Architecture notes
← All projects

Knowledge graphs on GCP · AWS & OCI equivalents

GraphRAG vs Vector RAG

Two retrieval systems on one corpus, deployed on Cloud Run at near-zero idle cost, with the same architecture mapped to AWS and OCI.

43source docs
1,943graph nodes
4,081relationships
~98%hosting cost cut

Overview

The Data Science group at CVS Health / Aetna wanted to know whether a knowledge graph beats plain vector search for questions about its data assets: file layouts, field definitions and production schedules. A question like "which feeds carry the claim-status field, and who owns them?" needs relationships, not just similar text.

I built both systems on the same corpus of 43 internal reference documents: 17 XLS, 15 DOC, 9 PDF, 1 DOCX and 1 XLSX. The corpus contained no member or PHI data.


System

Cypher

graph facts + question

43 docs
XLS · DOC · PDF

Gemini extracts
entities + relationships
(schema-constrained)

Neo4j Aura
knowledge graph

Analyst

Flask app
Cloud Run (scale to zero)

Vertex AI Gemini

LLMOps
prompts · evals · metrics


GraphRAG or vector RAG?

Decision guide

'What does field X mean?'
local, single-passage

'Which feeds carry X, who owns them,
what breaks if it changes?'
multi-hop, relational

both

What does the question need?

Vector RAG
cheap · fast · good recall on prose

GraphRAG
explicit edges · explainable path

Hybrid
vector to find entry nodes →
graph expansion 1–2 hops → LLM

Vector RAG GraphRAG
Best for Local, single-passage questions over prose Multi-hop, relational questions
Ingest cost One embedding call per chunk LLM extraction per chunk (51 calls, about 10 min for 43 docs)
Sensitivity Chunking and embedding model Schema allowlist: a bad schema gives a bad graph
Explainability Shows the retrieved passages Shows the path of nodes and edges behind the answer

GCP deployment

git push main

GitHub Actions
build linux/amd64

Artifact Registry

Cloud Run
min 0 → scale to zero

Secret Manager
Neo4j creds

Neo4j Aura

Vertex AI Gemini

The cost story: about 98% lower

Before → after

After ≈ $0.15/mo

Before ≈ $7.38/mo

delete VM

prune

scale to zero

Self-hosted Neo4j on
Compute Engine n1-standard-2
always on

Artifact Registry
~41 GB of old images

Cloud Run

Neo4j Aura (managed)

Registry: keep last 2 images

Cloud Run min-instances 0
lazy init on first request

Lesson: scale-to-zero compute buys you nothing if the database is always on. The VM was the cost, not Cloud Run. Put state on a managed tier that also scales down, prune the registry, and initialize lazily.

Model A/B results

The A/B harness compared Gemini models on the GraphRAG service, measuring success rate and latency:

Model Success Median latency
gemini-2.0-flash-001 100% 12.2 s
gemini-2.0-flash-exp 96% 13.8 s
gemini-2.5-flash-preview 75% 28.3 s
gemini-2.5-pro-preview 32% 47.2 s

Every failure was a client read timeout (30/60 s), not a model error. For interactive use, the "smarter" model lost, so 2.0 Flash stayed in production.

Engineering lessons

  1. Aura → self-hosted VM → back to Aura. Self-hosting looked cheaper and wasn't. Deleting the VM required repointing the Cloud Run secrets and env vars to Aura. State placement drives cost.
  2. Model and region availability. Gemini 2.5 wasn't available in us-east1, which led to a model fallback chain (a 404 falls back to 2.0 Flash).
  3. ChromaDB on Cloud Run:
    • The collection's default embedding function didn't match the Vertex vectors, so queries pass precomputed 768-d query_embeddings.
    • Chroma rejects list metadata, so lists are JSON-serialized.
    • The DB is baked into the image, so the container is immutable and needs no volume.
  4. LLM-as-judge pitfall. The evaluator kept returning the example scores from its own prompt. An LLM judge needs calibration against human-labeled examples, and an alarm when its scores show zero variance.

From pilot to production


The same system on AWS

git push

GitHub Actions
OIDC → IAM role (keyless)

ECR

ECS Fargate (or App Runner)
or Lambda container + Web Adapter for true scale-to-zero

Secrets Manager

Amazon Neptune
(or Neo4j Aura on AWS)

Bedrock
Claude / Titan embeddings

Service map: GCP → AWS → OCI

Component GCP (built) AWS OCI
Serverless container Cloud Run (min 0) ECS Fargate / App Runner. True scale-to-zero needs Lambda (container image) + Lambda Web Adapter. OCI Functions (scale-to-zero) · Container Instances · OKE + KEDA / Knative
Registry Artifact Registry ECR OCIR
CI auth Workload Identity Federation GitHub OIDC → IAM role OCI DevOps, or Identity Domains token exchange
Secrets Secret Manager Secrets Manager OCI Vault
LLM Vertex AI Gemini Bedrock (Claude, Llama, Titan) OCI Generative AI / self-hosted on GPU shapes
Embeddings text-embedding-005 (768-d) Titan Text Embeddings v2 / Cohere Embed OCI GenAI Cohere Embed
Graph DB Neo4j Aura Neptune (openCypher / Gremlin) / Neo4j Aura on AWS Oracle Database 23ai property graphs (SQL/PGQ) / Neo4j on OCI Compute
Vector store ChromaDB (embedded) OpenSearch Serverless · Aurora pgvector · Bedrock KB Oracle 23ai AI Vector Search · OCI Database with PostgreSQL (pgvector) · OCI Search with OpenSearch
Object storage GCS S3 Object Storage (S3-compatible API)
Edge auth IAP / Cloud Run IAM ALB OIDC / Cognito / API Gateway OCI API Gateway + Identity Domains, OCI WAF
Logs / metrics Cloud Logging / Monitoring CloudWatch / X-Ray OCI Logging / Monitoring / APM
Region gotcha Gemini 2.5 not in us-east1 Bedrock model availability by region (cross-region inference profiles) GenAI models by region; private hosting avoids it

What's the AWS equivalent of Cloud Run? There's no exact twin.

  • Fargate is the workhorse, but it doesn't scale to zero on requests.
  • App Runner is the closest developer experience.
  • Lambda with a container image and the Web Adapter gives true scale-to-zero, with a 15-minute limit.
  • On OCI, use Functions for scale-to-zero, or OKE with KEDA for Cloud Run-style semantics on Kubernetes.

Acronyms

Underlined acronyms show these definitions on hover or tap. Full glossary →

ALB
Application Load Balancer AWS's HTTP load balancer. It can enforce OIDC login itself.
API
Application Programming Interface How programs call each other, such as a REST endpoint.
APM
Application Performance Monitoring Request tracing and latency monitoring.
AWS
Amazon Web Services Amazon's cloud. GitHubScanner's CI/CD pipeline runs in AWS.
BAA
Business Associate Agreement The HIPAA contract a vendor (for example, a model endpoint) must sign before it can process PHI.
CI
Continuous Integration Building and testing every change automatically.
CI/CD
Continuous Integration / Continuous Delivery The automated build, test, scan and deploy pipeline.
CMEK
Customer-Managed Encryption Keys You hold the keys that encrypt your cloud data, and can revoke them.
CORS
Cross-Origin Resource Sharing The browser rule for which other websites may call your API.
DLP
Data Loss Prevention Finding and redacting sensitive data, for example before documents are ingested.
ECR
Elastic Container Registry AWS's container image registry.
ECS
Elastic Container Service AWS's container service. Fargate is its serverless mode.
GCP
Google Cloud Platform Google's cloud. GitHubScanner and GraphRAG run on it.
GCS
Google Cloud Storage GCP's object storage (buckets).
GenAI
Generative AI Models that generate text, code or images. "OCI GenAI" is Oracle's managed LLM service.
GPU
Graphics Processing Unit The accelerator used to host models. OCI "GPU shapes" are GPU-equipped VM sizes.
GraphRAG
Graph Retrieval-Augmented Generation RAG that retrieves facts from a knowledge graph (entities and their relationships) instead of text chunks.
HNSW
Hierarchical Navigable Small World A graph-based approximate nearest-neighbour index for fast vector search. ChromaDB uses it.
IAM
Identity and Access Management Who can do what. "Cloud Run IAM" means only authenticated callers can reach the service.
IAP
Identity-Aware Proxy Google's SSO gate in front of a web app.
IdP
Identity Provider The service behind SSO, such as Okta or Microsoft Entra ID.
KB
Knowledge Base "Bedrock KB" is Amazon Bedrock Knowledge Bases, a managed RAG service.
KEDA
Kubernetes Event-Driven Autoscaling Scales Kubernetes workloads on events, including down to zero.
KMS
Key Management Service Managed encryption keys (AWS KMS, Cloud KMS).
LLM
Large Language Model A model such as Gemini or Claude that reads and writes text. Every agent here is an LLM plus tools.
LLMOps
LLM Operations Running LLM apps in production: prompt versioning, evaluation, latency and success-rate monitoring.
MD5
Message Digest 5 A fast hash. Used here only to detect which files changed, not for security.
NLTK
Natural Language Toolkit A Python NLP library. Its data files are baked into the container image to cut cold-start time.
OCI
Oracle Cloud Infrastructure Oracle's cloud. The service maps show the OCI equivalent of each component.
OCIR
OCI Registry OCI's container image registry.
OIDC
OpenID Connect An identity layer on OAuth 2.0. It lets a CI job prove who it is and get short-lived cloud credentials without stored keys.
OKE
Oracle Kubernetes Engine OCI's managed Kubernetes (formerly Container Engine for Kubernetes).
PHI
Protected Health Information Health data covered by the US HIPAA rules. None was in the GraphRAG corpus.
PII
Personally Identifiable Information Data that identifies a person, such as a name, email or SSN.
RAG
Retrieval-Augmented Generation Look up relevant documents first, then have the LLM answer from them instead of from memory.
S3
Simple Storage Service AWS's object storage.
SHA
Secure Hash Algorithm A "git SHA" is the hash that uniquely identifies a commit.
SLA
Service-Level Agreement A promised target, such as a 12 s latency budget at 99% success.
SQL/PGQ
SQL Property Graph Queries The ISO SQL extension for graph queries. Oracle Database 23ai uses it for property graphs.
SSO
Single Sign-On One corporate login for many apps.
TLS
Transport Layer Security Encryption in transit: https://, neo4j+s://.
vCPU
Virtual CPU One virtual processor core allotted to a container or VM.
VM
Virtual Machine A rented server. GraphRAG's always-on Neo4j VM was most of its cost.
VPC
Virtual Private Cloud A private network in the cloud. VPC Service Controls put a perimeter around GCP APIs to stop data exfiltration.
WAF
Web Application Firewall Filters malicious HTTP traffic before it reaches the app.

More architecture notes