Skip to content

Commit 60cc097

Browse files
authored
Feat/improve rag quickstart (#2501)
Added improve_rag with MLFlow to quickstart ```sh ragas quickstart improve_rag ``` To use with output path: ```sh ragas quickstart improve_rag -o /your_path ```
1 parent 51b989d commit 60cc097

9 files changed

Lines changed: 897 additions & 48 deletions

File tree

docs/howtos/cli/improve_rag.md

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
# Improve RAG Quickstart
2+
3+
The `improve_rag` template demonstrates how to compare different RAG approaches using real-world evaluation data. It includes naive (single retrieval) and agentic (multi-step retrieval) RAG modes.
4+
5+
## Create the Project
6+
7+
```sh
8+
# Using uvx (no installation required)
9+
uvx ragas quickstart improve_rag
10+
cd improve_rag
11+
12+
# Or with ragas installed
13+
ragas quickstart improve_rag
14+
cd improve_rag
15+
```
16+
17+
## Install Dependencies
18+
19+
```sh
20+
uv sync
21+
```
22+
23+
Or with pip:
24+
25+
```sh
26+
pip install -e .
27+
```
28+
29+
## Set Your API Key
30+
31+
```sh
32+
export OPENAI_API_KEY="your-openai-key"
33+
```
34+
35+
## Run the Evaluation
36+
37+
### Naive RAG Mode (Default)
38+
39+
```sh
40+
uv run python evals.py
41+
```
42+
43+
### Agentic RAG Mode
44+
45+
```sh
46+
uv run python evals.py --agentic
47+
```
48+
49+
!!! note "Agentic Mode Requirements"
50+
Agentic mode requires the `openai-agents` package. Install it with:
51+
```sh
52+
pip install openai-agents
53+
```
54+
55+
## Optional: MLflow Tracing
56+
57+
For detailed tracing of LLM calls, start MLflow before running:
58+
59+
```sh
60+
mlflow ui --port 5000
61+
```
62+
63+
Then run your evaluation. Traces will be automatically sent to MLflow if the server is running.
64+
65+
## Project Structure
66+
67+
```
68+
improve_rag/
69+
├── README.md # Project documentation
70+
├── pyproject.toml # Project configuration
71+
├── rag.py # RAG implementation (naive & agentic)
72+
├── evals.py # Evaluation workflow
73+
├── __init__.py # Python package marker
74+
└── evals/
75+
├── datasets/ # Test datasets (hf_doc_qa_eval.csv)
76+
├── experiments/ # Evaluation results
77+
└── logs/ # Evaluation logs
78+
```
79+
80+
## Understanding the RAG Modes
81+
82+
### Naive RAG
83+
84+
The naive approach performs a single retrieval step:
85+
86+
1. **Query** → BM25 retrieves top-k documents
87+
2. **Context** → Retrieved documents form the context
88+
3. **Generate** → LLM generates response from context
89+
90+
```python
91+
rag = RAG(llm_client=client, retriever=retriever, mode="naive")
92+
result = await rag.query("What is the Diffusers library?")
93+
```
94+
95+
**Pros:**
96+
97+
- Simple and fast
98+
- Predictable latency
99+
- Lower cost (single LLM call)
100+
101+
**Cons:**
102+
103+
- May miss relevant documents with different terminology
104+
- No query refinement
105+
- Limited to single retrieval strategy
106+
107+
### Agentic RAG
108+
109+
The agentic approach lets an agent control the retrieval:
110+
111+
1. **Query** → Agent analyzes the question
112+
2. **Search** → Agent decides what to search for (multiple searches possible)
113+
3. **Refine** → Agent can refine searches based on results
114+
4. **Generate** → Agent synthesizes final answer
115+
116+
```python
117+
rag = RAG(llm_client=client, retriever=retriever, mode="agentic")
118+
result = await rag.query("What command uploads an ESPnet model?")
119+
```
120+
121+
**Pros:**
122+
123+
- Can try multiple search strategies
124+
- Better at finding specific technical information
125+
- Adapts search based on initial results
126+
127+
**Cons:**
128+
129+
- Higher latency (multiple LLM calls)
130+
- Higher cost
131+
- Less predictable behavior
132+
133+
## The Evaluation Dataset
134+
135+
The template includes `hf_doc_qa_eval.csv` with questions about HuggingFace documentation:
136+
137+
| Field | Description |
138+
|-------|-------------|
139+
| `question` | Technical question about HuggingFace tools |
140+
| `expected_answer` | Ground truth answer |
141+
142+
Example questions:
143+
144+
- "What is the default checkpoint used by the sentiment analysis pipeline?"
145+
- "What command is used to upload an ESPnet model?"
146+
- "What is the purpose of the Diffusers library?"
147+
148+
## Understanding the Code
149+
150+
### The RAG Implementation (`rag.py`)
151+
152+
#### BM25Retriever
153+
154+
Uses BM25 (Best Matching 25) algorithm for document retrieval:
155+
156+
```python
157+
class BM25Retriever:
158+
def __init__(self, dataset_name="m-ric/huggingface_doc"):
159+
# Loads HuggingFace documentation
160+
# Splits into chunks for better retrieval
161+
# Creates BM25 index
162+
163+
def retrieve(self, query: str, top_k: int = 3):
164+
# Returns top-k most relevant documents
165+
```
166+
167+
#### RAG Class
168+
169+
Unified interface for both modes:
170+
171+
```python
172+
class RAG:
173+
def __init__(self, llm_client, retriever, mode="naive"):
174+
self.mode = mode
175+
if mode == "agentic":
176+
self._setup_agent()
177+
178+
async def query(self, question: str, top_k: int = 3):
179+
if self.mode == "naive":
180+
return await self._naive_query(question, top_k)
181+
else:
182+
return await self._agentic_query(question, top_k)
183+
```
184+
185+
### The Evaluation Script (`evals.py`)
186+
187+
The correctness metric compares model responses to expected answers:
188+
189+
```python
190+
correctness_metric = DiscreteMetric(
191+
name="correctness",
192+
prompt="""Compare the model response to the expected answer...
193+
Return 'pass' if correct, 'fail' if incorrect.""",
194+
allowed_values=["pass", "fail"],
195+
)
196+
```
197+
198+
## Customization
199+
200+
### Change the Knowledge Base
201+
202+
Replace HuggingFace docs with your own documents:
203+
204+
```python
205+
class CustomRetriever:
206+
def __init__(self, documents: list[str]):
207+
from langchain_community.retrievers import BM25Retriever
208+
self.retriever = BM25Retriever.from_texts(documents)
209+
210+
def retrieve(self, query: str, top_k: int = 3):
211+
self.retriever.k = top_k
212+
return self.retriever.invoke(query)
213+
```
214+
215+
### Use a Different Model
216+
217+
Change the model in `evals.py`:
218+
219+
```python
220+
# Use GPT-4 for better accuracy
221+
rag = RAG(llm_client=client, retriever=retriever, model="gpt-4o")
222+
223+
# Or use a different provider
224+
from anthropic import Anthropic
225+
client = Anthropic()
226+
# Note: Would need to modify rag.py for non-OpenAI clients
227+
```
228+
229+
### Add Custom Metrics
230+
231+
Evaluate additional aspects:
232+
233+
```python
234+
from ragas.metrics import NumericalMetric
235+
236+
completeness = NumericalMetric(
237+
name="completeness",
238+
prompt="""How complete is the response (1-5)?
239+
Question: {question}
240+
Expected: {expected_answer}
241+
Response: {response}
242+
Score:""",
243+
allowed_values=(1, 5),
244+
)
245+
246+
# Add to experiment
247+
result = {
248+
**row,
249+
"correctness": correctness_score.value,
250+
"completeness": completeness.score(...).value,
251+
}
252+
```
253+
254+
### Modify the Agent Behavior
255+
256+
Customize the agentic search strategy in `rag.py`:
257+
258+
```python
259+
def _setup_agent(self):
260+
@function_tool
261+
def retrieve(query: str) -> str:
262+
"""Custom tool description..."""
263+
docs = self.retriever.retrieve(query, self.default_k)
264+
return "\n\n".join([doc.page_content for doc in docs])
265+
266+
self._agent = Agent(
267+
name="Custom RAG Assistant",
268+
instructions="Your custom instructions...",
269+
tools=[retrieve]
270+
)
271+
```
272+
273+
## Comparing Results
274+
275+
Run both modes and compare:
276+
277+
```sh
278+
# Run naive mode
279+
uv run python evals.py
280+
# Results saved to experiments/YYYYMMDD-HHMMSS_naiverag.csv
281+
282+
# Run agentic mode
283+
uv run python evals.py --agentic
284+
# Results saved to experiments/YYYYMMDD-HHMMSS_agenticrag.csv
285+
```
286+
287+
Analyze the results:
288+
289+
```python
290+
import pandas as pd
291+
292+
naive = pd.read_csv("evals/experiments/..._naiverag.csv")
293+
agentic = pd.read_csv("evals/experiments/..._agenticrag.csv")
294+
295+
print(f"Naive pass rate: {(naive['correctness_score'] == 'pass').mean():.1%}")
296+
print(f"Agentic pass rate: {(agentic['correctness_score'] == 'pass').mean():.1%}")
297+
```
298+
299+
## Troubleshooting
300+
301+
### MLflow Warnings
302+
303+
If you see MLflow warnings about failed traces, either:
304+
305+
1. Start MLflow: `mlflow ui --port 5000`
306+
2. Or ignore them - the evaluation still works without tracing
307+
308+
### Agentic Mode Not Working
309+
310+
Ensure you have the agents package:
311+
312+
```sh
313+
pip install openai-agents
314+
```
315+
316+
### Slow First Run
317+
318+
The first run downloads the HuggingFace documentation dataset (~300MB). Subsequent runs use the cached data.
319+
320+
## Next Steps
321+
322+
- [RAG Evaluation Guide](rag_eval.md) - Simpler evaluation setup
323+
- [Custom Metrics](../customizations/metrics/_write_your_own_metric.md) - Write your own metrics
324+
- [Evaluate and Improve RAG](../applications/evaluate-and-improve-rag.md) - Production RAG evaluation

0 commit comments

Comments
 (0)