Add Jupyter Notebook for Fine Tuning Dataset with Question Generation
Browse files- Created a new notebook `07_Fine_Tuning_Dataset.ipynb` for fine-tuning tasks.
- Implemented code to load blog posts, update metadata, and split documents.
- Integrated LangChain's ChatOpenAI for generating questions based on document context.
- Added functions for extracting questions from the generated responses.
- Included asynchronous processing for creating questions from multiple documents.
- Handled potential kernel crashes during execution.
py-src/lets_talk/utils/blog.py
CHANGED
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
12 |
from typing import List, Dict, Any, Optional
|
13 |
from datetime import datetime
|
14 |
|
|
|
15 |
from langchain_community.document_loaders import DirectoryLoader
|
16 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
17 |
from langchain.schema.document import Document
|
@@ -48,7 +49,9 @@ def load_blog_posts(data_dir: str = DATA_DIR,
|
|
48 |
data_dir,
|
49 |
glob=glob_pattern,
|
50 |
show_progress=show_progress,
|
51 |
-
recursive=recursive
|
|
|
|
|
52 |
)
|
53 |
|
54 |
documents = text_loader.load()
|
@@ -85,8 +88,12 @@ def update_document_metadata(documents: List[Document],
|
|
85 |
if len(path_parts) > 1:
|
86 |
# Use the directory name as post_slug
|
87 |
doc.metadata["post_slug"] = path_parts[-2]
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
90 |
# Add document length as metadata
|
91 |
doc.metadata["content_length"] = len(doc.page_content)
|
92 |
|
@@ -249,7 +256,9 @@ def load_vector_store(storage_path: str = VECTOR_STORAGE_PATH,
|
|
249 |
def process_blog_posts(data_dir: str = DATA_DIR,
|
250 |
create_embeddings: bool = True,
|
251 |
force_recreate_embeddings: bool = False,
|
252 |
-
storage_path: str = VECTOR_STORAGE_PATH
|
|
|
|
|
253 |
"""
|
254 |
Complete pipeline to process blog posts and optionally create vector embeddings.
|
255 |
|
@@ -267,11 +276,17 @@ def process_blog_posts(data_dir: str = DATA_DIR,
|
|
267 |
|
268 |
# Update metadata
|
269 |
documents = update_document_metadata(documents)
|
|
|
|
|
|
|
|
|
270 |
|
271 |
|
272 |
# Get and display stats
|
273 |
stats = get_document_stats(documents)
|
274 |
-
|
|
|
|
|
275 |
|
276 |
result = {
|
277 |
"documents": documents,
|
@@ -284,7 +299,8 @@ def process_blog_posts(data_dir: str = DATA_DIR,
|
|
284 |
# Using in-memory vector store to avoid pickling issues
|
285 |
vector_store = create_vector_store(
|
286 |
documents,
|
287 |
-
force_recreate=force_recreate_embeddings
|
|
|
288 |
)
|
289 |
result["vector_store"] = vector_store
|
290 |
|
|
|
12 |
from typing import List, Dict, Any, Optional
|
13 |
from datetime import datetime
|
14 |
|
15 |
+
from langchain_community.document_loaders.text import TextLoader
|
16 |
from langchain_community.document_loaders import DirectoryLoader
|
17 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
18 |
from langchain.schema.document import Document
|
|
|
49 |
data_dir,
|
50 |
glob=glob_pattern,
|
51 |
show_progress=show_progress,
|
52 |
+
recursive=recursive,
|
53 |
+
loader_cls=TextLoader
|
54 |
+
|
55 |
)
|
56 |
|
57 |
documents = text_loader.load()
|
|
|
88 |
if len(path_parts) > 1:
|
89 |
# Use the directory name as post_slug
|
90 |
doc.metadata["post_slug"] = path_parts[-2]
|
91 |
+
try:
|
92 |
+
#extract title from `doc.page_content`'s front matter like `title:`
|
93 |
+
doc.metadata["post_title"] = doc.page_content.split("title:")[1].split("\n")[0].strip()
|
94 |
+
except Exception as e:
|
95 |
+
doc.metadata["post_title"] = path_parts[-2].replace("-", " ").title()
|
96 |
+
|
97 |
# Add document length as metadata
|
98 |
doc.metadata["content_length"] = len(doc.page_content)
|
99 |
|
|
|
256 |
def process_blog_posts(data_dir: str = DATA_DIR,
|
257 |
create_embeddings: bool = True,
|
258 |
force_recreate_embeddings: bool = False,
|
259 |
+
storage_path: str = VECTOR_STORAGE_PATH,
|
260 |
+
split_docs: bool = True,
|
261 |
+
display_stats:bool = False) -> Dict[str, Any]:
|
262 |
"""
|
263 |
Complete pipeline to process blog posts and optionally create vector embeddings.
|
264 |
|
|
|
276 |
|
277 |
# Update metadata
|
278 |
documents = update_document_metadata(documents)
|
279 |
+
|
280 |
+
if split_docs:
|
281 |
+
# Split documents into smaller chunks
|
282 |
+
documents = split_documents(documents)
|
283 |
|
284 |
|
285 |
# Get and display stats
|
286 |
stats = get_document_stats(documents)
|
287 |
+
|
288 |
+
if display_stats:
|
289 |
+
display_document_stats(stats)
|
290 |
|
291 |
result = {
|
292 |
"documents": documents,
|
|
|
299 |
# Using in-memory vector store to avoid pickling issues
|
300 |
vector_store = create_vector_store(
|
301 |
documents,
|
302 |
+
force_recreate=force_recreate_embeddings,
|
303 |
+
storage_path=storage_path
|
304 |
)
|
305 |
result["vector_store"] = vector_store
|
306 |
|
py-src/notebooks/{05_SGD_Eval.ipynb β 05_SDG_Eval.ipynb}
RENAMED
@@ -2,7 +2,7 @@
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
-
"execution_count":
|
6 |
"id": "ca8bd0e4",
|
7 |
"metadata": {},
|
8 |
"outputs": [
|
@@ -10,7 +10,9 @@
|
|
10 |
"name": "stdout",
|
11 |
"output_type": "stream",
|
12 |
"text": [
|
13 |
-
"Adding
|
|
|
|
|
14 |
]
|
15 |
}
|
16 |
],
|
@@ -20,14 +22,21 @@
|
|
20 |
"\n",
|
21 |
"# Add the project root to the Python path\n",
|
22 |
"package_root = os.path.abspath(os.path.join(os.getcwd(), \"../\"))\n",
|
23 |
-
"print(f\"Adding
|
24 |
"if package_root not in sys.path:\n",
|
25 |
-
"\tsys.path.append(package_root)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
]
|
27 |
},
|
28 |
{
|
29 |
"cell_type": "code",
|
30 |
-
"execution_count":
|
31 |
"id": "b48fa7d4",
|
32 |
"metadata": {},
|
33 |
"outputs": [],
|
@@ -38,7 +47,7 @@
|
|
38 |
},
|
39 |
{
|
40 |
"cell_type": "code",
|
41 |
-
"execution_count":
|
42 |
"id": "cd3c7329",
|
43 |
"metadata": {},
|
44 |
"outputs": [],
|
@@ -50,48 +59,47 @@
|
|
50 |
},
|
51 |
{
|
52 |
"cell_type": "code",
|
53 |
-
"execution_count":
|
54 |
-
"id": "
|
55 |
"metadata": {},
|
56 |
"outputs": [
|
57 |
{
|
58 |
-
"
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
|
|
|
|
64 |
}
|
65 |
],
|
66 |
"source": [
|
67 |
-
"#
|
68 |
-
"
|
69 |
-
"
|
70 |
-
"
|
71 |
-
"# change to the directory to the root of the project\n",
|
72 |
-
"project_root = os.path.abspath(os.path.join(os.getcwd(), \"../../\"))\n",
|
73 |
-
"print(f\"Project root: {project_root}\")\n",
|
74 |
-
"os.chdir(project_root)"
|
75 |
]
|
76 |
},
|
77 |
{
|
78 |
"cell_type": "code",
|
79 |
-
"execution_count":
|
80 |
-
"id": "
|
81 |
"metadata": {},
|
82 |
"outputs": [
|
83 |
{
|
84 |
"name": "stderr",
|
85 |
"output_type": "stream",
|
86 |
"text": [
|
87 |
-
"100%|ββββββββββ| 14/14 [00:00<00:00,
|
88 |
]
|
89 |
},
|
90 |
{
|
91 |
"name": "stdout",
|
92 |
"output_type": "stream",
|
93 |
"text": [
|
94 |
-
"Loaded 14 documents from data/\n"
|
|
|
95 |
]
|
96 |
},
|
97 |
{
|
@@ -103,75 +111,67 @@
|
|
103 |
}
|
104 |
],
|
105 |
"source": [
|
106 |
-
"docs = blog.load_blog_posts()\n",
|
107 |
-
"docs = blog.update_document_metadata(docs)"
|
|
|
|
|
108 |
]
|
109 |
},
|
110 |
{
|
111 |
"cell_type": "code",
|
112 |
-
"execution_count":
|
113 |
-
"id": "
|
114 |
"metadata": {},
|
115 |
"outputs": [
|
116 |
{
|
117 |
-
"
|
118 |
-
|
119 |
-
|
120 |
-
]
|
121 |
-
|
122 |
-
"execution_count": 22,
|
123 |
-
"metadata": {},
|
124 |
-
"output_type": "execute_result"
|
125 |
}
|
126 |
],
|
127 |
"source": [
|
128 |
-
"
|
129 |
]
|
130 |
},
|
131 |
{
|
132 |
"cell_type": "code",
|
133 |
-
"execution_count":
|
134 |
-
"id": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
"metadata": {},
|
136 |
"outputs": [
|
137 |
{
|
138 |
"data": {
|
139 |
"text/plain": [
|
140 |
-
"
|
141 |
]
|
142 |
},
|
143 |
-
"execution_count":
|
144 |
"metadata": {},
|
145 |
"output_type": "execute_result"
|
146 |
}
|
147 |
],
|
148 |
"source": [
|
149 |
-
"
|
150 |
-
"import importlib\n",
|
151 |
-
"importlib.reload(eval)"
|
152 |
]
|
153 |
},
|
154 |
{
|
155 |
"cell_type": "code",
|
156 |
-
"execution_count":
|
157 |
"id": "03663a91",
|
158 |
"metadata": {},
|
159 |
-
"outputs": [
|
160 |
-
{
|
161 |
-
"name": "stderr",
|
162 |
-
"output_type": "stream",
|
163 |
-
"text": [
|
164 |
-
"Applying HeadlineSplitter: 0%| | 0/14 [00:00<?, ?it/s] unable to apply transformation: 'headlines' property not found in this node\n",
|
165 |
-
"Applying SummaryExtractor: 20%|ββ | 3/15 [00:02<00:09, 1.20it/s]Property 'summary' already exists in node 'ed7c49'. Skipping!\n",
|
166 |
-
"Applying SummaryExtractor: 33%|ββββ | 5/15 [00:06<00:15, 1.58s/it]Property 'summary' already exists in node 'f14d00'. Skipping!\n",
|
167 |
-
"Applying [EmbeddingExtractor, ThemesExtractor, NERExtractor]: 0%| | 0/71 [00:00<?, ?it/s]Property 'summary_embedding' already exists in node 'ed7c49'. Skipping!\n",
|
168 |
-
"Property 'summary_embedding' already exists in node 'f14d00'. Skipping!\n",
|
169 |
-
"Generating personas: 100%|ββββββββββ| 3/3 [00:00<00:00, 3.11it/s] \n",
|
170 |
-
"Generating Scenarios: 100%|ββββββββββ| 3/3 [00:13<00:00, 4.46s/it]\n",
|
171 |
-
"Generating Samples: 100%|ββββββββββ| 12/12 [00:53<00:00, 4.50s/it]\n"
|
172 |
-
]
|
173 |
-
}
|
174 |
-
],
|
175 |
"source": [
|
176 |
"from lets_talk.config import EMBEDDING_MODEL,SDG_LLM_MODLEL,EVAL_LLM_MODEL\n",
|
177 |
"testset = eval.generate_testset(docs=docs,llm_model = SDG_LLM_MODLEL, embedding_model = EMBEDDING_MODEL,testset_size=10)"
|
@@ -490,12 +490,12 @@
|
|
490 |
},
|
491 |
{
|
492 |
"cell_type": "code",
|
493 |
-
"execution_count":
|
494 |
"id": "4ae903d8",
|
495 |
"metadata": {},
|
496 |
"outputs": [],
|
497 |
"source": [
|
498 |
-
"df.to_csv(\"evals/
|
499 |
]
|
500 |
},
|
501 |
{
|
@@ -918,12 +918,12 @@
|
|
918 |
},
|
919 |
{
|
920 |
"cell_type": "code",
|
921 |
-
"execution_count":
|
922 |
"id": "f5d50d7b",
|
923 |
"metadata": {},
|
924 |
"outputs": [],
|
925 |
"source": [
|
926 |
-
"eval_df.to_csv(\"evals/
|
927 |
]
|
928 |
},
|
929 |
{
|
@@ -1003,12 +1003,12 @@
|
|
1003 |
},
|
1004 |
{
|
1005 |
"cell_type": "code",
|
1006 |
-
"execution_count":
|
1007 |
"id": "49fa29f2",
|
1008 |
"metadata": {},
|
1009 |
"outputs": [],
|
1010 |
"source": [
|
1011 |
-
"result.to_pandas().to_csv(\"evals/
|
1012 |
]
|
1013 |
}
|
1014 |
],
|
|
|
2 |
"cells": [
|
3 |
{
|
4 |
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
"id": "ca8bd0e4",
|
7 |
"metadata": {},
|
8 |
"outputs": [
|
|
|
10 |
"name": "stdout",
|
11 |
"output_type": "stream",
|
12 |
"text": [
|
13 |
+
"Adding package root to sys.path: /home/mafzaal/source/lets-talk/py-src\n",
|
14 |
+
"Current notebook directory: /home/mafzaal/source/lets-talk/py-src/notebooks\n",
|
15 |
+
"Project root: /home/mafzaal/source/lets-talk\n"
|
16 |
]
|
17 |
}
|
18 |
],
|
|
|
22 |
"\n",
|
23 |
"# Add the project root to the Python path\n",
|
24 |
"package_root = os.path.abspath(os.path.join(os.getcwd(), \"../\"))\n",
|
25 |
+
"print(f\"Adding package root to sys.path: {package_root}\")\n",
|
26 |
"if package_root not in sys.path:\n",
|
27 |
+
"\tsys.path.append(package_root)\n",
|
28 |
+
"\n",
|
29 |
+
"notebook_dir = os.getcwd()\n",
|
30 |
+
"print(f\"Current notebook directory: {notebook_dir}\")\n",
|
31 |
+
"# change to the directory to the root of the project\n",
|
32 |
+
"project_root = os.path.abspath(os.path.join(os.getcwd(), \"../../\"))\n",
|
33 |
+
"print(f\"Project root: {project_root}\")\n",
|
34 |
+
"os.chdir(project_root)"
|
35 |
]
|
36 |
},
|
37 |
{
|
38 |
"cell_type": "code",
|
39 |
+
"execution_count": 3,
|
40 |
"id": "b48fa7d4",
|
41 |
"metadata": {},
|
42 |
"outputs": [],
|
|
|
47 |
},
|
48 |
{
|
49 |
"cell_type": "code",
|
50 |
+
"execution_count": 2,
|
51 |
"id": "cd3c7329",
|
52 |
"metadata": {},
|
53 |
"outputs": [],
|
|
|
59 |
},
|
60 |
{
|
61 |
"cell_type": "code",
|
62 |
+
"execution_count": 5,
|
63 |
+
"id": "1f9f2076",
|
64 |
"metadata": {},
|
65 |
"outputs": [
|
66 |
{
|
67 |
+
"data": {
|
68 |
+
"text/plain": [
|
69 |
+
"<module 'lets_talk.utils.blog' from '/home/mafzaal/source/lets-talk/py-src/lets_talk/utils/blog.py'>"
|
70 |
+
]
|
71 |
+
},
|
72 |
+
"execution_count": 5,
|
73 |
+
"metadata": {},
|
74 |
+
"output_type": "execute_result"
|
75 |
}
|
76 |
],
|
77 |
"source": [
|
78 |
+
"# hot reload the module\n",
|
79 |
+
"import importlib\n",
|
80 |
+
"importlib.reload(eval)\n",
|
81 |
+
"importlib.reload(blog)"
|
|
|
|
|
|
|
|
|
82 |
]
|
83 |
},
|
84 |
{
|
85 |
"cell_type": "code",
|
86 |
+
"execution_count": 3,
|
87 |
+
"id": "cc282d9c",
|
88 |
"metadata": {},
|
89 |
"outputs": [
|
90 |
{
|
91 |
"name": "stderr",
|
92 |
"output_type": "stream",
|
93 |
"text": [
|
94 |
+
"100%|ββββββββββ| 14/14 [00:00<00:00, 3266.23it/s]"
|
95 |
]
|
96 |
},
|
97 |
{
|
98 |
"name": "stdout",
|
99 |
"output_type": "stream",
|
100 |
"text": [
|
101 |
+
"Loaded 14 documents from data/\n",
|
102 |
+
"Split 14 documents into 162 chunks\n"
|
103 |
]
|
104 |
},
|
105 |
{
|
|
|
111 |
}
|
112 |
],
|
113 |
"source": [
|
114 |
+
"#docs = blog.load_blog_posts()\n",
|
115 |
+
"#docs = blog.update_document_metadata(docs)\n",
|
116 |
+
"\n",
|
117 |
+
"blog_posts = blog.process_blog_posts(create_embeddings=False)"
|
118 |
]
|
119 |
},
|
120 |
{
|
121 |
"cell_type": "code",
|
122 |
+
"execution_count": 7,
|
123 |
+
"id": "e768b97b",
|
124 |
"metadata": {},
|
125 |
"outputs": [
|
126 |
{
|
127 |
+
"name": "stdout",
|
128 |
+
"output_type": "stream",
|
129 |
+
"text": [
|
130 |
+
"{'total_documents': 162, 'total_characters': 127917, 'min_length': 172, 'max_length': 998, 'avg_length': 789.6111111111111, 'documents': [{'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'source': 'data/introduction-to-ragas/index.md', 'title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'text_length': 6994}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/generating-test-data-with-ragas/', 'source': 'data/generating-test-data-with-ragas/index.md', 'title': '\"Part 4: Generating Test Data with Ragas\"', 'text_length': 14680}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/', 'source': 'data/advanced-metrics-and-customization-with-ragas/index.md', 'title': '\"Part 5: Advanced Metrics and Customization with Ragas\"', 'text_length': 11530}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/building-research-agent/', 'source': 'data/building-research-agent/index.md', 'title': 'Building a Research Agent with RSS Feed Support', 'text_length': 7320}, {'url': 'https://thedataguy.pro/blog/rss-feed-announcement/', 'source': 'data/rss-feed-announcement/index.md', 'title': '\"Subscribe to Our Blog via RSS\"', 'text_length': 2139}, {'url': 'https://thedataguy.pro/blog/rss-feed-announcement/', 'source': 'data/rss-feed-announcement/index.md', 'title': '\"Subscribe to Our Blog via RSS\"', 'text_length': 2139}, {'url': 'https://thedataguy.pro/blog/rss-feed-announcement/', 'source': 'data/rss-feed-announcement/index.md', 'title': '\"Subscribe to Our Blog via RSS\"', 'text_length': 2139}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/metric-driven-development/', 'source': 'data/metric-driven-development/index.md', 'title': '\"Metric-Driven Development: Make Smarter Decisions, Faster\"', 'text_length': 12450}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/', 'source': 'data/basic-evaluation-workflow-with-ragas/index.md', 'title': '\"Part 2: Basic Evaluation Workflow with Ragas\"', 'text_length': 11222}, {'url': 'https://thedataguy.pro/blog/langchain-experience-csharp-perspective/', 'source': 'data/langchain-experience-csharp-perspective/index.md', 'title': \"A C# Programmer's Perspective on LangChain Expression Language\", 'text_length': 3361}, {'url': 'https://thedataguy.pro/blog/langchain-experience-csharp-perspective/', 'source': 'data/langchain-experience-csharp-perspective/index.md', 'title': \"A C# Programmer's Perspective on LangChain Expression Language\", 'text_length': 3361}, {'url': 'https://thedataguy.pro/blog/langchain-experience-csharp-perspective/', 'source': 'data/langchain-experience-csharp-perspective/index.md', 'title': \"A C# Programmer's Perspective on LangChain Expression Language\", 'text_length': 3361}, {'url': 'https://thedataguy.pro/blog/langchain-experience-csharp-perspective/', 'source': 'data/langchain-experience-csharp-perspective/index.md', 'title': \"A C# Programmer's Perspective on LangChain Expression Language\", 'text_length': 3361}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/', 'source': 'data/evaluating-ai-agents-with-ragas/index.md', 'title': '\"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\"', 'text_length': 9821}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/integrations-and-observability-with-ragas/', 'source': 'data/integrations-and-observability-with-ragas/index.md', 'title': '\"Part 7: Integrations and Observability with Ragas\"', 'text_length': 9098}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/building-feedback-loops-with-ragas/', 'source': 'data/building-feedback-loops-with-ragas/index.md', 'title': '\"Part 8: Building Feedback Loops with Ragas\"', 'text_length': 8160}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/coming-back-to-ai-roots/', 'source': 'data/coming-back-to-ai-roots/index.md', 'title': 'Coming Back to AI Roots - My Professional Journey', 'text_length': 5827}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/data-is-king/', 'source': 'data/data-is-king/index.md', 'title': '\"Data is King: Why Your Data Strategy IS Your Business Strategy\"', 'text_length': 6197}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}, {'url': 'https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/', 'source': 'data/evaluating-rag-systems-with-ragas/index.md', 'title': '\"Part 3: Evaluating RAG Systems with Ragas\"', 'text_length': 8811}]}\n"
|
131 |
+
]
|
|
|
|
|
|
|
132 |
}
|
133 |
],
|
134 |
"source": [
|
135 |
+
"print(blog_posts[\"stats\"])"
|
136 |
]
|
137 |
},
|
138 |
{
|
139 |
"cell_type": "code",
|
140 |
+
"execution_count": 4,
|
141 |
+
"id": "21d9a2df",
|
142 |
+
"metadata": {},
|
143 |
+
"outputs": [],
|
144 |
+
"source": [
|
145 |
+
"docs = blog_posts[\"documents\"]"
|
146 |
+
]
|
147 |
+
},
|
148 |
+
{
|
149 |
+
"cell_type": "code",
|
150 |
+
"execution_count": 5,
|
151 |
+
"id": "33949cc9",
|
152 |
"metadata": {},
|
153 |
"outputs": [
|
154 |
{
|
155 |
"data": {
|
156 |
"text/plain": [
|
157 |
+
"Document(metadata={'source': 'data/introduction-to-ragas/index.md', 'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'post_slug': 'introduction-to-ragas', 'post_title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'content_length': 6994}, page_content='---\\ntitle: \"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"\\ndate: 2025-04-26T18:00:00-06:00\\nlayout: blog\\ndescription: \"Explore the essential evaluation framework for LLM applications with Ragas. Learn how to assess performance, ensure accuracy, and improve reliability in Retrieval-Augmented Generation systems.\"\\ncategories: [\"AI\", \"RAG\", \"Evaluation\",\"Ragas\"]\\ncoverImage: \"https://images.unsplash.com/photo-1593642634367-d91a135587b5?q=80&w=1770&auto=format&fit=crop&ixlib=rb-4.0.3\"\\nreadingTime: 7\\npublished: true\\n---\\n\\nAs Large Language Models (LLMs) become fundamental components of modern applications, effectively evaluating their performance becomes increasingly critical. Whether you\\'re building a question-answering system, a document retrieval tool, or a conversational agent, you need reliable metrics to assess how well your application performs. This is where Ragas steps in.\\n\\n## What is Ragas?')"
|
158 |
]
|
159 |
},
|
160 |
+
"execution_count": 5,
|
161 |
"metadata": {},
|
162 |
"output_type": "execute_result"
|
163 |
}
|
164 |
],
|
165 |
"source": [
|
166 |
+
"docs[0]"
|
|
|
|
|
167 |
]
|
168 |
},
|
169 |
{
|
170 |
"cell_type": "code",
|
171 |
+
"execution_count": null,
|
172 |
"id": "03663a91",
|
173 |
"metadata": {},
|
174 |
+
"outputs": [],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
"source": [
|
176 |
"from lets_talk.config import EMBEDDING_MODEL,SDG_LLM_MODLEL,EVAL_LLM_MODEL\n",
|
177 |
"testset = eval.generate_testset(docs=docs,llm_model = SDG_LLM_MODLEL, embedding_model = EMBEDDING_MODEL,testset_size=10)"
|
|
|
490 |
},
|
491 |
{
|
492 |
"cell_type": "code",
|
493 |
+
"execution_count": null,
|
494 |
"id": "4ae903d8",
|
495 |
"metadata": {},
|
496 |
"outputs": [],
|
497 |
"source": [
|
498 |
+
"df.to_csv(\"evals/testset_2.csv\",index=False)"
|
499 |
]
|
500 |
},
|
501 |
{
|
|
|
918 |
},
|
919 |
{
|
920 |
"cell_type": "code",
|
921 |
+
"execution_count": null,
|
922 |
"id": "f5d50d7b",
|
923 |
"metadata": {},
|
924 |
"outputs": [],
|
925 |
"source": [
|
926 |
+
"eval_df.to_csv(\"evals/rag_eval_2.csv\",index=False)"
|
927 |
]
|
928 |
},
|
929 |
{
|
|
|
1003 |
},
|
1004 |
{
|
1005 |
"cell_type": "code",
|
1006 |
+
"execution_count": null,
|
1007 |
"id": "49fa29f2",
|
1008 |
"metadata": {},
|
1009 |
"outputs": [],
|
1010 |
"source": [
|
1011 |
+
"result.to_pandas().to_csv(\"evals/rag_eval_result_2.csv\",index=False)"
|
1012 |
]
|
1013 |
}
|
1014 |
],
|
py-src/notebooks/07_Fine_Tuning_Dataset.ipynb
ADDED
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
+
"id": "c95ab233",
|
7 |
+
"metadata": {},
|
8 |
+
"outputs": [
|
9 |
+
{
|
10 |
+
"name": "stdout",
|
11 |
+
"output_type": "stream",
|
12 |
+
"text": [
|
13 |
+
"Adding package root to sys.path: /home/mafzaal/source/lets-talk/py-src\n",
|
14 |
+
"Current notebook directory: /home/mafzaal/source/lets-talk/py-src/notebooks\n",
|
15 |
+
"Project root: /home/mafzaal/source/lets-talk\n"
|
16 |
+
]
|
17 |
+
}
|
18 |
+
],
|
19 |
+
"source": [
|
20 |
+
"import sys\n",
|
21 |
+
"import os\n",
|
22 |
+
"\n",
|
23 |
+
"# Add the project root to the Python path\n",
|
24 |
+
"package_root = os.path.abspath(os.path.join(os.getcwd(), \"../\"))\n",
|
25 |
+
"print(f\"Adding package root to sys.path: {package_root}\")\n",
|
26 |
+
"if package_root not in sys.path:\n",
|
27 |
+
"\tsys.path.append(package_root)\n",
|
28 |
+
"\n",
|
29 |
+
"\n",
|
30 |
+
"notebook_dir = os.getcwd()\n",
|
31 |
+
"print(f\"Current notebook directory: {notebook_dir}\")\n",
|
32 |
+
"# change to the directory to the root of the project\n",
|
33 |
+
"project_root = os.path.abspath(os.path.join(os.getcwd(), \"../../\"))\n",
|
34 |
+
"print(f\"Project root: {project_root}\")\n",
|
35 |
+
"os.chdir(project_root)"
|
36 |
+
]
|
37 |
+
},
|
38 |
+
{
|
39 |
+
"cell_type": "code",
|
40 |
+
"execution_count": 4,
|
41 |
+
"id": "15e97530",
|
42 |
+
"metadata": {},
|
43 |
+
"outputs": [],
|
44 |
+
"source": [
|
45 |
+
"import nest_asyncio\n",
|
46 |
+
"\n",
|
47 |
+
"nest_asyncio.apply()"
|
48 |
+
]
|
49 |
+
},
|
50 |
+
{
|
51 |
+
"cell_type": "code",
|
52 |
+
"execution_count": 2,
|
53 |
+
"id": "b4f2ddc0",
|
54 |
+
"metadata": {},
|
55 |
+
"outputs": [],
|
56 |
+
"source": [
|
57 |
+
"import lets_talk.utils.blog as blog\n",
|
58 |
+
"import lets_talk.utils.eval as eval"
|
59 |
+
]
|
60 |
+
},
|
61 |
+
{
|
62 |
+
"cell_type": "code",
|
63 |
+
"execution_count": 3,
|
64 |
+
"id": "123779af",
|
65 |
+
"metadata": {},
|
66 |
+
"outputs": [
|
67 |
+
{
|
68 |
+
"name": "stderr",
|
69 |
+
"output_type": "stream",
|
70 |
+
"text": [
|
71 |
+
"100%|ββββββββββ| 14/14 [00:00<00:00, 16100.98it/s]"
|
72 |
+
]
|
73 |
+
},
|
74 |
+
{
|
75 |
+
"name": "stdout",
|
76 |
+
"output_type": "stream",
|
77 |
+
"text": [
|
78 |
+
"Loaded 14 documents from data/\n",
|
79 |
+
"Split 14 documents into 162 chunks\n"
|
80 |
+
]
|
81 |
+
},
|
82 |
+
{
|
83 |
+
"name": "stderr",
|
84 |
+
"output_type": "stream",
|
85 |
+
"text": [
|
86 |
+
"\n"
|
87 |
+
]
|
88 |
+
}
|
89 |
+
],
|
90 |
+
"source": [
|
91 |
+
"docs = blog.load_blog_posts()\n",
|
92 |
+
"docs = blog.update_document_metadata(docs)\n",
|
93 |
+
"split_docs = blog.split_documents(docs)"
|
94 |
+
]
|
95 |
+
},
|
96 |
+
{
|
97 |
+
"cell_type": "code",
|
98 |
+
"execution_count": null,
|
99 |
+
"id": "b0f749db",
|
100 |
+
"metadata": {},
|
101 |
+
"outputs": [],
|
102 |
+
"source": [
|
103 |
+
"from langchain_core.prompts import ChatPromptTemplate\n",
|
104 |
+
"from langchain_openai import ChatOpenAI\n",
|
105 |
+
"\n",
|
106 |
+
"qa_chat_model = ChatOpenAI(\n",
|
107 |
+
" model=\"gpt-4.1-mini\",\n",
|
108 |
+
" temperature=0,\n",
|
109 |
+
")\n",
|
110 |
+
"\n",
|
111 |
+
"qa_prompt = \"\"\"\\\n",
|
112 |
+
"Given the following context, you must generate questions based on only the provided context.\n",
|
113 |
+
"You are to generate {n_questions} questions which should be provided in the following format:\n",
|
114 |
+
"\n",
|
115 |
+
"1. QUESTION #1\n",
|
116 |
+
"2. QUESTION #2\n",
|
117 |
+
"...\n",
|
118 |
+
"\n",
|
119 |
+
"Context:\n",
|
120 |
+
"{context}\n",
|
121 |
+
"\"\"\"\n",
|
122 |
+
"\n",
|
123 |
+
"qa_prompt_template = ChatPromptTemplate.from_template(qa_prompt)\n",
|
124 |
+
"question_generation_chain = qa_prompt_template | qa_chat_model"
|
125 |
+
]
|
126 |
+
},
|
127 |
+
{
|
128 |
+
"cell_type": "code",
|
129 |
+
"execution_count": 10,
|
130 |
+
"id": "adb3ae7b",
|
131 |
+
"metadata": {},
|
132 |
+
"outputs": [],
|
133 |
+
"source": [
|
134 |
+
"context = split_docs[0].page_content\n",
|
135 |
+
"n_questions = 3\n",
|
136 |
+
"response = question_generation_chain.invoke({\"context\": context, \"n_questions\": n_questions})\n"
|
137 |
+
]
|
138 |
+
},
|
139 |
+
{
|
140 |
+
"cell_type": "code",
|
141 |
+
"execution_count": 12,
|
142 |
+
"id": "6df35cfd",
|
143 |
+
"metadata": {},
|
144 |
+
"outputs": [
|
145 |
+
{
|
146 |
+
"data": {
|
147 |
+
"text/plain": [
|
148 |
+
"'1. What is the primary purpose of the Ragas evaluation framework in LLM applications? \\n2. Why is it important to have reliable metrics when assessing the performance of LLM-based systems? \\n3. In what types of applications can Ragas be used to evaluate performance?'"
|
149 |
+
]
|
150 |
+
},
|
151 |
+
"execution_count": 12,
|
152 |
+
"metadata": {},
|
153 |
+
"output_type": "execute_result"
|
154 |
+
}
|
155 |
+
],
|
156 |
+
"source": [
|
157 |
+
"response.content"
|
158 |
+
]
|
159 |
+
},
|
160 |
+
{
|
161 |
+
"cell_type": "code",
|
162 |
+
"execution_count": null,
|
163 |
+
"id": "dcd0bf6d",
|
164 |
+
"metadata": {},
|
165 |
+
"outputs": [
|
166 |
+
{
|
167 |
+
"name": "stdout",
|
168 |
+
"output_type": "stream",
|
169 |
+
"text": [
|
170 |
+
"Extracted questions:\n",
|
171 |
+
"1 - What is the primary purpose of the Ragas evaluation framework in LLM applications?\n",
|
172 |
+
"2 - Why is it important to have reliable metrics when assessing the performance of LLM-based systems?\n",
|
173 |
+
"3 - In what types of applications can Ragas be used to evaluate performance?\n"
|
174 |
+
]
|
175 |
+
}
|
176 |
+
],
|
177 |
+
"source": [
|
178 |
+
"questions = extract_questions(response.content)\n",
|
179 |
+
"print(\"Extracted questions:\")\n",
|
180 |
+
"for i, question in enumerate(questions):\n",
|
181 |
+
" print(f\"{i + 1}. {question}\")"
|
182 |
+
]
|
183 |
+
},
|
184 |
+
{
|
185 |
+
"cell_type": "code",
|
186 |
+
"execution_count": 19,
|
187 |
+
"id": "e78f93b8",
|
188 |
+
"metadata": {},
|
189 |
+
"outputs": [],
|
190 |
+
"source": [
|
191 |
+
"import tqdm\n",
|
192 |
+
"import asyncio\n",
|
193 |
+
"\n",
|
194 |
+
"\n",
|
195 |
+
"def extract_questions(response_text):\n",
|
196 |
+
" # Split the response text into lines\n",
|
197 |
+
" lines = response_text.strip().split('\\n')\n",
|
198 |
+
"\n",
|
199 |
+
" # Extract questions (format: \"1. QUESTION\")\n",
|
200 |
+
" extracted_questions = []\n",
|
201 |
+
" for line in lines:\n",
|
202 |
+
" line = line.strip()\n",
|
203 |
+
" if line and any(line.startswith(f\"{i}.\") for i in range(1, n_questions+1)):\n",
|
204 |
+
" # Remove the number prefix and get just the question\n",
|
205 |
+
" question = line.split('.', 1)[1].strip()\n",
|
206 |
+
" extracted_questions.append(question)\n",
|
207 |
+
"\n",
|
208 |
+
" return extracted_questions\n",
|
209 |
+
"\n",
|
210 |
+
"\n",
|
211 |
+
"\n",
|
212 |
+
"\n",
|
213 |
+
"\n",
|
214 |
+
"async def create_questions(documents, n_questions):\n",
|
215 |
+
" question_set = []\n",
|
216 |
+
" \n",
|
217 |
+
"\n",
|
218 |
+
" for doc in tqdm.tqdm(documents):\n",
|
219 |
+
" \n",
|
220 |
+
" context = doc.page_content\n",
|
221 |
+
"\n",
|
222 |
+
" # Generate questions using the question generation chain\n",
|
223 |
+
" response = await question_generation_chain.ainvoke({\n",
|
224 |
+
" \"context\": context,\n",
|
225 |
+
" \"n_questions\": n_questions\n",
|
226 |
+
" })\n",
|
227 |
+
"\n",
|
228 |
+
" questions = extract_questions(response.content)\n",
|
229 |
+
" \n",
|
230 |
+
" for i, question in enumerate(questions):\n",
|
231 |
+
" questions.append({\"question\":question, \"context\": context})\n",
|
232 |
+
" \n",
|
233 |
+
"\n",
|
234 |
+
" \n",
|
235 |
+
"\n",
|
236 |
+
" return question_set"
|
237 |
+
]
|
238 |
+
},
|
239 |
+
{
|
240 |
+
"cell_type": "code",
|
241 |
+
"execution_count": null,
|
242 |
+
"id": "b1ece53b",
|
243 |
+
"metadata": {},
|
244 |
+
"outputs": [],
|
245 |
+
"source": [
|
246 |
+
"ds = await create_questions(split_docs[:2], 3)"
|
247 |
+
]
|
248 |
+
},
|
249 |
+
{
|
250 |
+
"cell_type": "code",
|
251 |
+
"execution_count": null,
|
252 |
+
"id": "aa92dd7d",
|
253 |
+
"metadata": {},
|
254 |
+
"outputs": [
|
255 |
+
{
|
256 |
+
"name": "stderr",
|
257 |
+
"output_type": "stream",
|
258 |
+
"text": [
|
259 |
+
" 0%| | 0/2 [00:00<?, ?it/s]"
|
260 |
+
]
|
261 |
+
},
|
262 |
+
{
|
263 |
+
"ename": "",
|
264 |
+
"evalue": "",
|
265 |
+
"output_type": "error",
|
266 |
+
"traceback": [
|
267 |
+
"\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n",
|
268 |
+
"\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n",
|
269 |
+
"\u001b[1;31mClick <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. \n",
|
270 |
+
"\u001b[1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
|
271 |
+
]
|
272 |
+
}
|
273 |
+
],
|
274 |
+
"source": []
|
275 |
+
}
|
276 |
+
],
|
277 |
+
"metadata": {
|
278 |
+
"kernelspec": {
|
279 |
+
"display_name": ".venv",
|
280 |
+
"language": "python",
|
281 |
+
"name": "python3"
|
282 |
+
},
|
283 |
+
"language_info": {
|
284 |
+
"codemirror_mode": {
|
285 |
+
"name": "ipython",
|
286 |
+
"version": 3
|
287 |
+
},
|
288 |
+
"file_extension": ".py",
|
289 |
+
"mimetype": "text/x-python",
|
290 |
+
"name": "python",
|
291 |
+
"nbconvert_exporter": "python",
|
292 |
+
"pygments_lexer": "ipython3",
|
293 |
+
"version": "3.13.2"
|
294 |
+
}
|
295 |
+
},
|
296 |
+
"nbformat": 4,
|
297 |
+
"nbformat_minor": 5
|
298 |
+
}
|
py-src/notebooks/update_blog_data.ipynb
CHANGED
@@ -12,25 +12,57 @@
|
|
12 |
},
|
13 |
{
|
14 |
"cell_type": "code",
|
15 |
-
"execution_count":
|
16 |
"id": "6ec048b4",
|
17 |
"metadata": {},
|
18 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
"source": [
|
20 |
"import sys\n",
|
21 |
"import os\n",
|
22 |
"from pathlib import Path\n",
|
23 |
"from dotenv import load_dotenv\n",
|
24 |
-
"
|
25 |
"\n",
|
26 |
"import sys\n",
|
27 |
"import os\n",
|
28 |
"\n",
|
29 |
"# Add the project root to the Python path\n",
|
30 |
-
"
|
31 |
-
"print(f\"Adding
|
32 |
-
"if
|
33 |
-
"\tsys.path.append(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
]
|
35 |
},
|
36 |
{
|
@@ -56,7 +88,7 @@
|
|
56 |
"name": "stderr",
|
57 |
"output_type": "stream",
|
58 |
"text": [
|
59 |
-
"100%|ββββββββββ| 14/14 [00:00<00:00,
|
60 |
]
|
61 |
},
|
62 |
{
|
@@ -76,11 +108,8 @@
|
|
76 |
],
|
77 |
"source": [
|
78 |
"import lets_talk.utils.blog as blog_utils\n",
|
79 |
-
"\n",
|
80 |
"docs = blog_utils.load_blog_posts()\n",
|
81 |
-
"docs = blog_utils.update_document_metadata(docs)\n"
|
82 |
-
"\n",
|
83 |
-
"\n"
|
84 |
]
|
85 |
},
|
86 |
{
|
@@ -88,11 +117,29 @@
|
|
88 |
"execution_count": null,
|
89 |
"id": "a14c70dc",
|
90 |
"metadata": {},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
"outputs": [
|
92 |
{
|
93 |
"data": {
|
94 |
"text/plain": [
|
95 |
-
"Document(metadata={'source': 'data/introduction-to-ragas/index.md', 'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'post_slug': 'introduction-to-ragas', 'post_title': 'Introduction
|
96 |
]
|
97 |
},
|
98 |
"execution_count": 8,
|
@@ -101,17 +148,17 @@
|
|
101 |
}
|
102 |
],
|
103 |
"source": [
|
104 |
-
"
|
105 |
]
|
106 |
},
|
107 |
{
|
108 |
"cell_type": "code",
|
109 |
-
"execution_count":
|
110 |
"id": "72dd14b5",
|
111 |
"metadata": {},
|
112 |
"outputs": [],
|
113 |
"source": [
|
114 |
-
"vector_store = blog_utils = blog_utils.create_vector_store(
|
115 |
]
|
116 |
},
|
117 |
{
|
@@ -126,7 +173,7 @@
|
|
126 |
},
|
127 |
{
|
128 |
"cell_type": "code",
|
129 |
-
"execution_count":
|
130 |
"id": "8b552e6b",
|
131 |
"metadata": {},
|
132 |
"outputs": [
|
@@ -137,27 +184,27 @@
|
|
137 |
"\n",
|
138 |
"Query: What is RAGAS?\n",
|
139 |
"Retrieved 3 documents:\n",
|
140 |
-
"1.
|
141 |
-
"2.
|
142 |
-
"3.
|
143 |
"\n",
|
144 |
"Query: How to build research agents?\n",
|
145 |
"Retrieved 3 documents:\n",
|
146 |
-
"1. Building Research Agent (https://thedataguy.pro/blog/building-research-agent/)\n",
|
147 |
-
"2.
|
148 |
-
"3.
|
149 |
"\n",
|
150 |
"Query: What is metric driven development?\n",
|
151 |
"Retrieved 3 documents:\n",
|
152 |
-
"1. Metric
|
153 |
-
"2.
|
154 |
-
"3.
|
155 |
"\n",
|
156 |
"Query: Who is TheDataGuy?\n",
|
157 |
"Retrieved 3 documents:\n",
|
158 |
-
"1.
|
159 |
-
"2.
|
160 |
-
"3. Evaluating
|
161 |
]
|
162 |
}
|
163 |
],
|
@@ -185,7 +232,7 @@
|
|
185 |
},
|
186 |
{
|
187 |
"cell_type": "code",
|
188 |
-
"execution_count":
|
189 |
"id": "4cdd6899",
|
190 |
"metadata": {},
|
191 |
"outputs": [],
|
|
|
12 |
},
|
13 |
{
|
14 |
"cell_type": "code",
|
15 |
+
"execution_count": 3,
|
16 |
"id": "6ec048b4",
|
17 |
"metadata": {},
|
18 |
+
"outputs": [
|
19 |
+
{
|
20 |
+
"name": "stdout",
|
21 |
+
"output_type": "stream",
|
22 |
+
"text": [
|
23 |
+
"Adding package root to sys.path: /home/mafzaal/source/lets-talk/py-src\n"
|
24 |
+
]
|
25 |
+
}
|
26 |
+
],
|
27 |
"source": [
|
28 |
"import sys\n",
|
29 |
"import os\n",
|
30 |
"from pathlib import Path\n",
|
31 |
"from dotenv import load_dotenv\n",
|
32 |
+
"\n",
|
33 |
"\n",
|
34 |
"import sys\n",
|
35 |
"import os\n",
|
36 |
"\n",
|
37 |
"# Add the project root to the Python path\n",
|
38 |
+
"package_root = os.path.abspath(os.path.join(os.getcwd(), \"../\"))\n",
|
39 |
+
"print(f\"Adding package root to sys.path: {package_root}\")\n",
|
40 |
+
"if package_root not in sys.path:\n",
|
41 |
+
"\tsys.path.append(package_root)\n"
|
42 |
+
]
|
43 |
+
},
|
44 |
+
{
|
45 |
+
"cell_type": "code",
|
46 |
+
"execution_count": 4,
|
47 |
+
"id": "7a7a9f3f",
|
48 |
+
"metadata": {},
|
49 |
+
"outputs": [
|
50 |
+
{
|
51 |
+
"name": "stdout",
|
52 |
+
"output_type": "stream",
|
53 |
+
"text": [
|
54 |
+
"Current notebook directory: /home/mafzaal/source/lets-talk/py-src/notebooks\n",
|
55 |
+
"Project root: /home/mafzaal/source/lets-talk\n"
|
56 |
+
]
|
57 |
+
}
|
58 |
+
],
|
59 |
+
"source": [
|
60 |
+
"notebook_dir = os.getcwd()\n",
|
61 |
+
"print(f\"Current notebook directory: {notebook_dir}\")\n",
|
62 |
+
"# change to the directory to the root of the project\n",
|
63 |
+
"project_root = os.path.abspath(os.path.join(os.getcwd(), \"../../\"))\n",
|
64 |
+
"print(f\"Project root: {project_root}\")\n",
|
65 |
+
"os.chdir(project_root)"
|
66 |
]
|
67 |
},
|
68 |
{
|
|
|
88 |
"name": "stderr",
|
89 |
"output_type": "stream",
|
90 |
"text": [
|
91 |
+
"100%|ββββββββββ| 14/14 [00:00<00:00, 4617.46it/s]"
|
92 |
]
|
93 |
},
|
94 |
{
|
|
|
108 |
],
|
109 |
"source": [
|
110 |
"import lets_talk.utils.blog as blog_utils\n",
|
|
|
111 |
"docs = blog_utils.load_blog_posts()\n",
|
112 |
+
"docs = blog_utils.update_document_metadata(docs)\n"
|
|
|
|
|
113 |
]
|
114 |
},
|
115 |
{
|
|
|
117 |
"execution_count": null,
|
118 |
"id": "a14c70dc",
|
119 |
"metadata": {},
|
120 |
+
"outputs": [
|
121 |
+
{
|
122 |
+
"name": "stdout",
|
123 |
+
"output_type": "stream",
|
124 |
+
"text": [
|
125 |
+
"Split 14 documents into 162 chunks\n"
|
126 |
+
]
|
127 |
+
}
|
128 |
+
],
|
129 |
+
"source": [
|
130 |
+
"split_docs = blog_utils.split_documents(docs)"
|
131 |
+
]
|
132 |
+
},
|
133 |
+
{
|
134 |
+
"cell_type": "code",
|
135 |
+
"execution_count": 8,
|
136 |
+
"id": "1c40c587",
|
137 |
+
"metadata": {},
|
138 |
"outputs": [
|
139 |
{
|
140 |
"data": {
|
141 |
"text/plain": [
|
142 |
+
"Document(metadata={'source': 'data/introduction-to-ragas/index.md', 'url': 'https://thedataguy.pro/blog/introduction-to-ragas/', 'post_slug': 'introduction-to-ragas', 'post_title': '\"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"', 'content_length': 6994}, page_content='---\\ntitle: \"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\"\\ndate: 2025-04-26T18:00:00-06:00\\nlayout: blog\\ndescription: \"Explore the essential evaluation framework for LLM applications with Ragas. Learn how to assess performance, ensure accuracy, and improve reliability in Retrieval-Augmented Generation systems.\"\\ncategories: [\"AI\", \"RAG\", \"Evaluation\",\"Ragas\"]\\ncoverImage: \"https://images.unsplash.com/photo-1593642634367-d91a135587b5?q=80&w=1770&auto=format&fit=crop&ixlib=rb-4.0.3\"\\nreadingTime: 7\\npublished: true\\n---\\n\\nAs Large Language Models (LLMs) become fundamental components of modern applications, effectively evaluating their performance becomes increasingly critical. Whether you\\'re building a question-answering system, a document retrieval tool, or a conversational agent, you need reliable metrics to assess how well your application performs. This is where Ragas steps in.\\n\\n## What is Ragas?')"
|
143 |
]
|
144 |
},
|
145 |
"execution_count": 8,
|
|
|
148 |
}
|
149 |
],
|
150 |
"source": [
|
151 |
+
"split_docs[0]"
|
152 |
]
|
153 |
},
|
154 |
{
|
155 |
"cell_type": "code",
|
156 |
+
"execution_count": 10,
|
157 |
"id": "72dd14b5",
|
158 |
"metadata": {},
|
159 |
"outputs": [],
|
160 |
"source": [
|
161 |
+
"vector_store = blog_utils = blog_utils.create_vector_store(split_docs,'./db/vector_store_5')"
|
162 |
]
|
163 |
},
|
164 |
{
|
|
|
173 |
},
|
174 |
{
|
175 |
"cell_type": "code",
|
176 |
+
"execution_count": 11,
|
177 |
"id": "8b552e6b",
|
178 |
"metadata": {},
|
179 |
"outputs": [
|
|
|
184 |
"\n",
|
185 |
"Query: What is RAGAS?\n",
|
186 |
"Retrieved 3 documents:\n",
|
187 |
+
"1. \"Part 3: Evaluating RAG Systems with Ragas\" (https://thedataguy.pro/blog/evaluating-rag-systems-with-ragas/)\n",
|
188 |
+
"2. \"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\" (https://thedataguy.pro/blog/introduction-to-ragas/)\n",
|
189 |
+
"3. \"Part 4: Generating Test Data with Ragas\" (https://thedataguy.pro/blog/generating-test-data-with-ragas/)\n",
|
190 |
"\n",
|
191 |
"Query: How to build research agents?\n",
|
192 |
"Retrieved 3 documents:\n",
|
193 |
+
"1. Building a Research Agent with RSS Feed Support (https://thedataguy.pro/blog/building-research-agent/)\n",
|
194 |
+
"2. \"Part 1: Introduction to Ragas: The Essential Evaluation Framework for LLM Applications\" (https://thedataguy.pro/blog/introduction-to-ragas/)\n",
|
195 |
+
"3. Building a Research Agent with RSS Feed Support (https://thedataguy.pro/blog/building-research-agent/)\n",
|
196 |
"\n",
|
197 |
"Query: What is metric driven development?\n",
|
198 |
"Retrieved 3 documents:\n",
|
199 |
+
"1. \"Metric-Driven Development: Make Smarter Decisions, Faster\" (https://thedataguy.pro/blog/metric-driven-development/)\n",
|
200 |
+
"2. \"Metric-Driven Development: Make Smarter Decisions, Faster\" (https://thedataguy.pro/blog/metric-driven-development/)\n",
|
201 |
+
"3. \"Part 5: Advanced Metrics and Customization with Ragas\" (https://thedataguy.pro/blog/advanced-metrics-and-customization-with-ragas/)\n",
|
202 |
"\n",
|
203 |
"Query: Who is TheDataGuy?\n",
|
204 |
"Retrieved 3 documents:\n",
|
205 |
+
"1. \"Part 2: Basic Evaluation Workflow with Ragas\" (https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/)\n",
|
206 |
+
"2. \"Part 2: Basic Evaluation Workflow with Ragas\" (https://thedataguy.pro/blog/basic-evaluation-workflow-with-ragas/)\n",
|
207 |
+
"3. \"Part 6: Evaluating AI Agents: Beyond Simple Answers with Ragas\" (https://thedataguy.pro/blog/evaluating-ai-agents-with-ragas/)\n"
|
208 |
]
|
209 |
}
|
210 |
],
|
|
|
232 |
},
|
233 |
{
|
234 |
"cell_type": "code",
|
235 |
+
"execution_count": 12,
|
236 |
"id": "4cdd6899",
|
237 |
"metadata": {},
|
238 |
"outputs": [],
|
scripts/build-vector-db.sh
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
#!/bin/bash
|
2 |
-
|
3 |
-
|
4 |
-
uv run python ./utils/pipeline.py
|
5 |
-
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|