File size: 7,726 Bytes
a7cba55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# Production-Grade Advanced RAG β€” LangGraph Β· GCP Β· Groq

An enterprise-grade, cyclic Retrieval-Augmented Generation system that tells the
difference between real technical "true data" and irrelevant "noisy data" using
history-aware planning, semantic re-ranking, and a self-critique/refine loop β€”
wrapped in an LLM gateway, guardrails, and a full RAGAS evaluation suite.

This matches the two reference architecture diagrams:
1. **Cyclic RAG Workflow (LangGraph)** β€” Query Understanding β†’ Retrieve β†’ Generate
   β†’ Critique & Evaluate β†’ (loop: Refine Query / Retrieve Again) β†’ Final Answer.
2. **System Architecture** β€” Interface layer, API + Safety layer, LangGraph
   agentic core, Retrieval layer, LLM gateway, Ingestion pipeline, Observability,
   RAGAS evaluation suite, GCP infrastructure, Terraform IaC.

---

## 1. High-level architecture

```
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚   Streamlit Chat UI / Eval  β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚ FastAPI /query  + Guardrails β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                    LangGraph Agentic Core                     β”‚
        β”‚  Query Understanding β†’ Retrieve β†’ Generate β†’ Critique/Eval    β”‚
        β”‚              β–²                                   β”‚ not good  β”‚
        β”‚              └───────────── Refine Query β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
        β”‚                              β”‚ good enough                    β”‚
        β”‚                         Final Answer                          β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚  Retrieval layer: Vector DB (Qdrant/Vertex AI Vector Search)   β”‚
        β”‚  + FlashRank local re-ranker for true-data vs noisy-data       β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚   LLM Gateway: Groq (Llama 3.3 70B primary, 3.1 8B fallback)   β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

## 2. Repo layout

```
production-rag-langgraph/
β”œβ”€β”€ ingestion/          # Document loading, chunking, embedding, ingestion pipeline
β”œβ”€β”€ core/               # LangGraph nodes + graph definition (the agentic core)
β”œβ”€β”€ gateway/            # Unified LLM gateway with primary/fallback + retries
β”œβ”€β”€ guardrails/         # Input/output guardrails (PII, prompt-injection, topical)
β”œβ”€β”€ evaluation/         # RAGAS golden dataset + evaluation harness
β”œβ”€β”€ api/                # FastAPI service (REST entrypoint)
β”œβ”€β”€ frontend/           # Streamlit chat UI + evaluation dashboard
β”œβ”€β”€ observability/      # Structured logging / tracing configuration
β”œβ”€β”€ terraform/          # GCP infrastructure as code
β”œβ”€β”€ tests/              # Unit + integration tests
β”œβ”€β”€ Dockerfile.api
β”œβ”€β”€ Dockerfile.frontend
β”œβ”€β”€ docker-compose.yml  # Local dev: Qdrant + API + Streamlit
β”œβ”€β”€ cloudbuild.yaml     # CI/CD pipeline definition for Cloud Build
└── requirements.txt
```

## 3. Quick start (local)

```bash
cp .env.example .env          # fill in GROQ_API_KEY etc.
docker compose up --build     # starts Qdrant, API (localhost:8000), UI (localhost:8501)
```

Or run natively:

```bash
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# 1. Start local Qdrant (or point QDRANT_URL at Qdrant Cloud)
docker run -p 6333:6333 qdrant/qdrant

# 2. Ingest documents
python -m ingestion.pipeline --source ./data/docs

# 3. Run the API
uvicorn api.main:app --reload --port 8000

# 4. Run the chat UI
streamlit run frontend/streamlit_app.py

# 5. Run evaluations
python -m evaluation.ragas_eval
```

## 4. Cloud deployment (GCP)

```bash
cd terraform
terraform init
terraform apply -var="project_id=YOUR_GCP_PROJECT" -var="groq_api_key=YOUR_KEY"
```

This provisions: VPC + connector, GCS buckets (raw + processed), Artifact
Registry, Cloud Run services (API + Streamlit), and IAM bindings. Vertex AI
Vector Search (the production vector store) is provisioned via the
`vertex_vector_search` module β€” swap this in for local Qdrant once you move
past prototyping.

CI/CD: `cloudbuild.yaml` builds container images, pushes to Artifact Registry,
and deploys to Cloud Run on every push to `main`.

## 5. Why "true data" vs "noisy data"

Real corpora mix authoritative technical content with boilerplate, marketing
copy, changelogs, or irrelevant tangents. Two mechanisms handle this:

- **Semantic re-ranking** (`core/retriever.py`): FlashRank cross-encoder scores
  each retrieved chunk against the *reformulated* query, not the raw one, and
  chunks below a relevance threshold are dropped before generation.
- **Critique & Evaluate node** (`core/critique.py`): after generation, a
  lightweight LLM judge checks whether the answer is actually grounded in the
  retrieved "true data" chunks. If not, the graph loops back, rewrites the
  query (`core/planner.py`'s `refine_query`), and retrieves again β€” up to
  `MAX_REFINE_ITERATIONS`.

## 6. Key design decisions

| Concern | Choice | Rationale |
|---|---|---|
| Orchestration | LangGraph `StateGraph` w/ `MemorySaver` checkpointer | native cycles + conversation memory |
| Vector store | Qdrant (local/dev) β†’ Vertex AI Vector Search (prod) | swappable via `VECTOR_BACKEND` env var |
| Re-ranker | FlashRank (local, no extra API cost) | fast cross-encoder re-ranking |
| LLM inference | Groq (Llama 3.3 70B primary / Llama 3.1 8B fallback) | ultra-low latency + high throughput |
| Gateway | Custom unified gateway (Portkey-compatible interface) | retries, fallback, cost/latency logging |
| Guardrails | NeMo-Guardrails-style config + custom filters | topical rails, PII redaction, jailbreak defense |
| Evaluation | RAGAS (faithfulness, answer relevancy, context precision/recall) | industry-standard RAG metrics |
| IaC | Terraform, modularized | reusable, reviewable, environment-parameterized |

## 7. Environment variables

See `.env.example` for the full list. Minimum to run locally: `GROQ_API_KEY`,
`QDRANT_URL`, `QDRANT_API_KEY` (if using Qdrant Cloud).