File size: 13,991 Bytes
f9c215a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# Architecture Overview

This document explains the architecture of the RAG (Retrieval-Augmented Generation) chatbot for the Agentic AI eBook.

## System Overview

The system follows a standard RAG pattern: documents are chunked and embedded into a vector database during ingestion, then at query time, relevant chunks are retrieved and used to generate grounded answers.

### Key Components

1. **Ingestion Pipeline** (`app/ingest.py`) - Processes the PDF, creates chunks, generates embeddings, and stores in Pinecone
2. **Vector Store** (`app/vectorstore.py`) - Wrapper around Pinecone for storing and retrieving vectors
3. **RAG Pipeline** (`app/rag_pipeline.py`) - LangGraph-based pipeline for query processing
4. **Streamlit UI** (`streamlit_app/app.py`) - Web interface for user interactions

---

## Architecture Diagram

```
                              INGESTION FLOW
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                                                             β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚    β”‚   PDF    │───▢│  Extract │───▢│  Clean   │───▢│     Chunk        β”‚   β”‚
β”‚    β”‚  File    β”‚    β”‚   Text   β”‚    β”‚   Text   β”‚    β”‚  (500 tokens,    β”‚   β”‚
β”‚    β”‚          β”‚    β”‚ by Page  β”‚    β”‚          β”‚    β”‚   50 overlap)    β”‚   β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                              β”‚             β”‚
β”‚                                                              β–Ό             β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚    β”‚     Pinecone     │◀───│     Upsert       │◀───│   Embeddings     β”‚   β”‚
β”‚    β”‚   Vector Store   β”‚    β”‚    Vectors       β”‚    β”‚  (MiniLM-L6-v2)  β”‚   β”‚
β”‚    β”‚                  β”‚    β”‚                  β”‚    β”‚   384 dims       β”‚   β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜


                               QUERY FLOW
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                                                             β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                             β”‚
β”‚    β”‚   User   β”‚                                                             β”‚
β”‚    β”‚  Query   β”‚                                                             β”‚
β”‚    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                                                             β”‚
β”‚         β”‚                                                                   β”‚
β”‚         β–Ό                                                                   β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚    β”‚                    LANGGRAPH PIPELINE                             β”‚    β”‚
β”‚    β”‚                                                                   β”‚    β”‚
β”‚    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚    β”‚
β”‚    β”‚  β”‚   Embed     │──▢│  Retrieve   │──▢│  Calculate  β”‚            β”‚    β”‚
β”‚    β”‚  β”‚   Query     β”‚   β”‚   Top-K     β”‚   β”‚ Confidence  β”‚            β”‚    β”‚
β”‚    β”‚  β”‚             β”‚   β”‚  Chunks     β”‚   β”‚             β”‚            β”‚    β”‚
β”‚    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜            β”‚    β”‚
β”‚    β”‚                           β”‚                 β”‚                    β”‚    β”‚
β”‚    β”‚                           β–Ό                 β–Ό                    β”‚    β”‚
β”‚    β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚    β”‚
β”‚    β”‚                    β”‚     Generate Answer         β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚                             β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”‚ If OpenAI Key:      β”‚   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”‚  β†’ LLM Generation   β”‚   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”‚  (grounded prompt)  β”‚   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”‚ Else:               β”‚   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”‚  β†’ Extractive Mode  β”‚   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β”‚  (return chunks)    β”‚   β”‚               β”‚    β”‚
β”‚    β”‚                    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚               β”‚    β”‚
β”‚    β”‚                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚    β”‚
β”‚    β”‚                                  β”‚                               β”‚    β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                       β”‚                                     β”‚
β”‚                                       β–Ό                                     β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚    β”‚                         RESPONSE                                  β”‚    β”‚
β”‚    β”‚  {                                                                β”‚    β”‚
β”‚    β”‚    "final_answer": "...",                                        β”‚    β”‚
β”‚    β”‚    "retrieved_chunks": [...],                                    β”‚    β”‚
β”‚    β”‚    "confidence": 0.92                                            β”‚    β”‚
β”‚    β”‚  }                                                                β”‚    β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                       β”‚                                     β”‚
β”‚                                       β–Ό                                     β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚    β”‚                      STREAMLIT UI                                 β”‚    β”‚
β”‚    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚    β”‚
β”‚    β”‚  β”‚  Chat Interface  β”‚  β”‚  Retrieved Chunks Panel           β”‚    β”‚    β”‚
β”‚    β”‚  β”‚  - Question box  β”‚  β”‚  - Chunk text                     β”‚    β”‚    β”‚
β”‚    β”‚  β”‚  - Answer card   β”‚  β”‚  - Page numbers                   β”‚    β”‚    β”‚
β”‚    β”‚  β”‚  - Confidence    β”‚  β”‚  - Relevance scores               β”‚    β”‚    β”‚
β”‚    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚    β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

---

## Design Decisions

### 1. Chunking Strategy

We use **500 tokens** as the target chunk size with **50-100 token overlap**. This provides:
- Enough context for meaningful retrieval
- Overlap ensures important information spanning chunk boundaries isn't lost
- Token counting via tiktoken ensures consistent chunk sizes across different text densities

**Chunk ID Format**: `pdfpage_{page}_chunk_{index}` - This makes it easy to trace retrieved content back to the source PDF page for verification.

### 2. Embedding Model Choice

We use **sentence-transformers/all-MiniLM-L6-v2**:
- Open source and free (no API costs)
- Small model (384 dimensions) = fast inference and lower storage costs
- Good quality for semantic similarity tasks
- Can run entirely on CPU

Trade-off: Larger models like OpenAI's ada-002 (1536 dims) may provide better retrieval quality, but MiniLM offers excellent cost/performance ratio for this use case.

### 3. LangGraph Pipeline

The RAG pipeline uses LangGraph for orchestration because:
- Clear separation of pipeline stages (embed β†’ retrieve β†’ generate)
- Easy to add/modify nodes (e.g., reranking, query expansion)
- Built-in state management
- Aligns with modern LLM application patterns

### 4. Dual-Mode Answer Generation

The system supports two modes:

**LLM Generation Mode** (with OpenAI key):
- Uses GPT-3.5-turbo for natural language generation
- System prompt strictly instructs the model to only use provided chunks
- Produces more readable, synthesized answers

**Extractive Fallback Mode** (no API key):
- Returns relevant chunks directly with minimal formatting
- Always works, even offline
- Ensures the app is functional without paid APIs

This design choice ensures the application is **always functional** regardless of API availability.

### 5. Confidence Score Computation

Confidence is computed from retrieval similarity scores:

```python
# Normalize cosine similarity from [-1, 1] to [0, 1]
normalized = (score + 1) / 2

# Use maximum normalized score as confidence
confidence = max(normalized_scores)
```

This gives users an intuitive sense of how well the retrieved chunks match their query.

---

## File Structure

```
rag-eAgenticAI/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py          # Package exports
β”‚   β”œβ”€β”€ ingest.py            # PDF β†’ chunks β†’ embeddings β†’ Pinecone
β”‚   β”œβ”€β”€ vectorstore.py       # Pinecone wrapper (create, upsert, query)
β”‚   β”œβ”€β”€ rag_pipeline.py      # LangGraph pipeline + answer generation
β”‚   └── utils.py             # Chunking, cleaning, confidence calculation
β”‚
β”œβ”€β”€ streamlit_app/
β”‚   β”œβ”€β”€ app.py               # Main Streamlit application
β”‚   └── assets/              # Static assets (images, CSS)
β”‚
β”œβ”€β”€ samples/
β”‚   β”œβ”€β”€ sample_queries.txt   # Example questions to test
β”‚   └── expected_responses.md # Expected JSON response format
β”‚
β”œβ”€β”€ infra/
β”‚   └── hf_space_readme_template.md  # Hugging Face Spaces config
β”‚
β”œβ”€β”€ data/                    # PDF files and generated chunks (gitignored)
β”‚
β”œβ”€β”€ README.md                # Main documentation
β”œβ”€β”€ architecture.md          # This file
β”œβ”€β”€ requirements.txt         # Python dependencies
β”œβ”€β”€ LICENSE                  # MIT License
└── .gitignore              # Git ignore rules
```

---

## Data Flow Summary

1. **Ingestion** (run once):
   - PDF β†’ pdfplumber β†’ raw text by page
   - Text β†’ clean_text() β†’ cleaned text
   - Cleaned text β†’ chunk_text() β†’ chunks with metadata
   - Chunks β†’ SentenceTransformer β†’ embeddings
   - Embeddings β†’ Pinecone upsert β†’ stored vectors

2. **Query** (each user question):
   - Question β†’ SentenceTransformer β†’ query embedding
   - Query embedding β†’ Pinecone query β†’ top-k chunks
   - Chunks + scores β†’ compute_confidence() β†’ confidence score
   - Chunks + question β†’ LLM/extractive β†’ final answer
   - Answer + chunks + confidence β†’ JSON response β†’ Streamlit UI