{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "477f0fa2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd\n",
"import os \n",
"from dotenv import load_dotenv\n",
"from tqdm import tqdm\n",
"\n",
"load_dotenv()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ce00fa3f-b017-4dd9-b39b-fc106ff59c61",
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"from pathlib import Path\n",
"\n",
"SRC_ROOT = Path().resolve().parents[1]\n",
"\n",
"sys.path.insert(0, str(SRC_ROOT))\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "28a9a5e2",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/kirill/rag_tg_2025/env/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n",
"/Users/kirill/rag_tg_2025/src/config.py:41: UserWarning: Qdrant client version 1.16.2 is incompatible with server version 1.14.1. Major versions should match and minor version difference must not exceed 1. Set check_compatibility=False to skip version check.\n",
" qdrant_client = QdrantClient(url=QDRANT_URL)\n"
]
}
],
"source": [
"from src.evaluation.qa_evaluator import QAEvaluator\n",
"from src.rag.rag import RAG"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "8c548b19-ad11-4515-95dc-1ae687baaff7",
"metadata": {},
"outputs": [],
"source": [
"rag = RAG(\n",
" embed_model_name = \"Qwen/Qwen3-Embedding-0.6B\",\n",
" embed_index_name = \"recursive_Qwen3-Embedding-0.6B\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b12d7862-83e2-4fde-a322-892512303e25",
"metadata": {},
"outputs": [],
"source": [
"test_cases = pd.read_csv(r'/Users/kirill/rag_tg_2025/src/dataset/test_cases.csv')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "05fc2a82-27d4-4103-9044-a5b0298956f4",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" message_id | \n",
" original_text | \n",
" strict_question | \n",
" real_question | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 130738 | \n",
" Итальянский суд принял решение экстрадировать ... | \n",
" Какое решение приняло итальянское судопроизвод... | \n",
" Что там с Кузнецовым — его в Германию выдадут ... | \n",
"
\n",
" \n",
" | 1 | \n",
" 129361 | \n",
" Пять пассажиров автобуса №793 пострадали в ДТП... | \n",
" Сколько пассажиров автобуса №793 пострадали в ... | \n",
" Сколько человек в автобусе 793 пострадали, ког... | \n",
"
\n",
" \n",
" | 2 | \n",
" 133468 | \n",
" Владимир Путин утвердил концепцию государствен... | \n",
" Кто утвердил концепцию государственной миграци... | \n",
" Кто там утвердил новую миграционную концепцию ... | \n",
"
\n",
" \n",
" | 3 | \n",
" 123139 | \n",
" Генпрокуратура и Минюст подали в Верховный суд... | \n",
" Какое юридическое действие предприняли Генерал... | \n",
" Что Генпрокуратура и Минюст сделали с сатанист... | \n",
"
\n",
" \n",
" | 4 | \n",
" 129894 | \n",
" Обломки дрона обнаружили польские пограничники... | \n",
" Где и кем был обнаружен непилотируемый летател... | \n",
" Что там польские пограничники нашли рядом с Бе... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" message_id original_text \\\n",
"0 130738 Итальянский суд принял решение экстрадировать ... \n",
"1 129361 Пять пассажиров автобуса №793 пострадали в ДТП... \n",
"2 133468 Владимир Путин утвердил концепцию государствен... \n",
"3 123139 Генпрокуратура и Минюст подали в Верховный суд... \n",
"4 129894 Обломки дрона обнаружили польские пограничники... \n",
"\n",
" strict_question \\\n",
"0 Какое решение приняло итальянское судопроизвод... \n",
"1 Сколько пассажиров автобуса №793 пострадали в ... \n",
"2 Кто утвердил концепцию государственной миграци... \n",
"3 Какое юридическое действие предприняли Генерал... \n",
"4 Где и кем был обнаружен непилотируемый летател... \n",
"\n",
" real_question \n",
"0 Что там с Кузнецовым — его в Германию выдадут ... \n",
"1 Сколько человек в автобусе 793 пострадали, ког... \n",
"2 Кто там утвердил новую миграционную концепцию ... \n",
"3 Что Генпрокуратура и Минюст сделали с сатанист... \n",
"4 Что там польские пограничники нашли рядом с Бе... "
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_cases.head()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "93c8f6dc-b210-43b6-ba0d-f555a82e1c93",
"metadata": {},
"outputs": [],
"source": [
"evaluator = QAEvaluator(\n",
" df=test_cases,\n",
" text_column=\"original_text\",\n",
" temperature=0.0,\n",
" api_key=os.getenv(\"OPENROUTER_API_KEY\")\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "4e5b93dd-98a2-44ae-862b-41af1ed9f15d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Всего батчей: 11\n"
]
}
],
"source": [
"batch_size = 16\n",
"question_iterator = evaluator.get_questions(\n",
" question_column=\"strict_question\", # или \"real_question\"\n",
" batch_size=batch_size\n",
")\n",
"\n",
"print(f\"Всего батчей: {len(question_iterator)}\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "ffc71d69-c387-4cb4-8dc9-23c197398440",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████████████████████████████████████████████████████████████████████████████| 167/167 [09:47<00:00, 3.52s/it]\n"
]
}
],
"source": [
"generated_answers = []\n",
"\n",
"for query in tqdm(test_cases[\"real_question\"]):\n",
" results = rag.invoke(query)\n",
" generated_answers.append(\n",
" (results[\"answer\"], results[\"reason\"])\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "117fabac-a952-40f6-ad3d-0cf74994040d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" message_id | \n",
" original_text | \n",
" strict_question | \n",
" real_question | \n",
" generated_answer | \n",
" generated_reason | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 130738 | \n",
" Итальянский суд принял решение экстрадировать ... | \n",
" Какое решение приняло итальянское судопроизвод... | \n",
" Что там с Кузнецовым — его в Германию выдадут ... | \n",
" Нет, его не выдадут в Германию — решение об эк... | \n",
" Кассационный суд Италии отменил решение апелля... | \n",
"
\n",
" \n",
" | 1 | \n",
" 129361 | \n",
" Пять пассажиров автобуса №793 пострадали в ДТП... | \n",
" Сколько пассажиров автобуса №793 пострадали в ... | \n",
" Сколько человек в автобусе 793 пострадали, ког... | \n",
" Пять | \n",
" В контексте в первом пункте указано, что пять ... | \n",
"
\n",
" \n",
" | 2 | \n",
" 133468 | \n",
" Владимир Путин утвердил концепцию государствен... | \n",
" Кто утвердил концепцию государственной миграци... | \n",
" Кто там утвердил новую миграционную концепцию ... | \n",
" Владимир Путин | \n",
" В контексте в первом пункте прямо указано, что... | \n",
"
\n",
" \n",
" | 3 | \n",
" 123139 | \n",
" Генпрокуратура и Минюст подали в Верховный суд... | \n",
" Какое юридическое действие предприняли Генерал... | \n",
" Что Генпрокуратура и Минюст сделали с сатанист... | \n",
" Генпрокуратура и Минюст подали в Верховный суд... | \n",
" В контексте указано, что Генеральная прокурату... | \n",
"
\n",
" \n",
" | 4 | \n",
" 129894 | \n",
" Обломки дрона обнаружили польские пограничники... | \n",
" Где и кем был обнаружен непилотируемый летател... | \n",
" Что там польские пограничники нашли рядом с Бе... | \n",
" Да, польские пограничники нашли дрон с надпися... | \n",
" Согласно контексту (пункт 1), обломки дрона об... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" message_id original_text \\\n",
"0 130738 Итальянский суд принял решение экстрадировать ... \n",
"1 129361 Пять пассажиров автобуса №793 пострадали в ДТП... \n",
"2 133468 Владимир Путин утвердил концепцию государствен... \n",
"3 123139 Генпрокуратура и Минюст подали в Верховный суд... \n",
"4 129894 Обломки дрона обнаружили польские пограничники... \n",
"\n",
" strict_question \\\n",
"0 Какое решение приняло итальянское судопроизвод... \n",
"1 Сколько пассажиров автобуса №793 пострадали в ... \n",
"2 Кто утвердил концепцию государственной миграци... \n",
"3 Какое юридическое действие предприняли Генерал... \n",
"4 Где и кем был обнаружен непилотируемый летател... \n",
"\n",
" real_question \\\n",
"0 Что там с Кузнецовым — его в Германию выдадут ... \n",
"1 Сколько человек в автобусе 793 пострадали, ког... \n",
"2 Кто там утвердил новую миграционную концепцию ... \n",
"3 Что Генпрокуратура и Минюст сделали с сатанист... \n",
"4 Что там польские пограничники нашли рядом с Бе... \n",
"\n",
" generated_answer \\\n",
"0 Нет, его не выдадут в Германию — решение об эк... \n",
"1 Пять \n",
"2 Владимир Путин \n",
"3 Генпрокуратура и Минюст подали в Верховный суд... \n",
"4 Да, польские пограничники нашли дрон с надпися... \n",
"\n",
" generated_reason \n",
"0 Кассационный суд Италии отменил решение апелля... \n",
"1 В контексте в первом пункте указано, что пять ... \n",
"2 В контексте в первом пункте прямо указано, что... \n",
"3 В контексте указано, что Генеральная прокурату... \n",
"4 Согласно контексту (пункт 1), обломки дрона об... "
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_cases[\"generated_answer\"] = [p[0] for p in generated_answers]\n",
"test_cases[\"generated_reason\"] = [p[1] for p in generated_answers]\n",
"test_cases.head()"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "5e32d246-9a16-4ffc-95c8-542a400efe33",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Оценка ответов: 4%|██▊ | 7/167 [00:18<10:24, 3.90s/it]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ошибка при оценке ответа: Failed to parse AnswerEvaluation from completion {}. Got: 4 validation errors for AnswerEvaluation\n",
"is_valid\n",
" Field required [type=missing, input_value={}, input_type=dict]\n",
" For further information visit https://errors.pydantic.dev/2.9/v/missing\n",
"relevance_score\n",
" Field required [type=missing, input_value={}, input_type=dict]\n",
" For further information visit https://errors.pydantic.dev/2.9/v/missing\n",
"completeness_score\n",
" Field required [type=missing, input_value={}, input_type=dict]\n",
" For further information visit https://errors.pydantic.dev/2.9/v/missing\n",
"factual_accuracy_score\n",
" Field required [type=missing, input_value={}, input_type=dict]\n",
" For further information visit https://errors.pydantic.dev/2.9/v/missing\n",
"For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/OUTPUT_PARSING_FAILURE \n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Оценка ответов: 100%|█████████████████████████████████████████████████████████████████| 167/167 [03:53<00:00, 1.40s/it]\n"
]
}
],
"source": [
"answers = test_cases[\"generated_answer\"]\n",
"metrics = evaluator.evaluate_answers(answers, show_progress=True)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "342b07de-a8e5-4336-a83d-611abd192aff",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" total_questions | \n",
" valid_answers | \n",
" accuracy | \n",
" avg_relevance | \n",
" avg_completeness | \n",
" avg_factual_accuracy | \n",
" combined_score | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 167 | \n",
" 125 | \n",
" 0.748503 | \n",
" 0.879641 | \n",
" 0.697605 | \n",
" 0.805389 | \n",
" 0.794212 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" total_questions valid_answers accuracy avg_relevance avg_completeness \\\n",
"0 167 125 0.748503 0.879641 0.697605 \n",
"\n",
" avg_factual_accuracy combined_score \n",
"0 0.805389 0.794212 "
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"metrics_df = pd.DataFrame(\n",
" data=[(\n",
" metrics[\"total_questions\"], metrics[\"valid_answers\"], metrics[\"accuracy\"],\\\n",
" metrics[\"avg_relevance\"], metrics[\"avg_completeness\"], metrics[\"avg_factual_accuracy\"], \\\n",
" metrics[\"combined_score\"]\n",
" )],\n",
" columns=[\"total_questions\", \"valid_answers\", \"accuracy\", \"avg_relevance\", \"avg_completeness\", \\\n",
" \"avg_factual_accuracy\", \"combined_score\"]\n",
")\n",
"metrics_df"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "488b4f03-556a-42a5-811a-1fbe36c5f7be",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" index | \n",
" question | \n",
" answer | \n",
" is_valid | \n",
" relevance_score | \n",
" completeness_score | \n",
" factual_accuracy_score | \n",
"
\n",
" \n",
" \n",
" \n",
" | 112 | \n",
" 112 | \n",
" На каком уровне оказалась цена нефти марки Ura... | \n",
" Да, цена российской нефти марки Urals в Новоро... | \n",
" True | \n",
" 1.0 | \n",
" 0.5 | \n",
" 1.0 | \n",
"
\n",
" \n",
" | 37 | \n",
" 37 | \n",
" Согласно официальному сообщению Росавиации, ка... | \n",
" В аэропорту Ярославля введены временные ограни... | \n",
" True | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
"
\n",
" \n",
" | 140 | \n",
" 140 | \n",
" По какому инциденту Следственный комитет Росси... | \n",
" Следственный комитет завел уголовное дело по ф... | \n",
" True | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
"
\n",
" \n",
" | 0 | \n",
" 0 | \n",
" Какое решение приняло итальянское судопроизвод... | \n",
" Не знаю. | \n",
" False | \n",
" 0.5 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 98 | \n",
" 98 | \n",
" Что произошло на фестивале в Пенсильвании, США... | \n",
" На фестивале в Пенсильвании минивэн въехал в т... | \n",
" True | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" index question \\\n",
"112 112 На каком уровне оказалась цена нефти марки Ura... \n",
"37 37 Согласно официальному сообщению Росавиации, ка... \n",
"140 140 По какому инциденту Следственный комитет Росси... \n",
"0 0 Какое решение приняло итальянское судопроизвод... \n",
"98 98 Что произошло на фестивале в Пенсильвании, США... \n",
"\n",
" answer is_valid \\\n",
"112 Да, цена российской нефти марки Urals в Новоро... True \n",
"37 В аэропорту Ярославля введены временные ограни... True \n",
"140 Следственный комитет завел уголовное дело по ф... True \n",
"0 Не знаю. False \n",
"98 На фестивале в Пенсильвании минивэн въехал в т... True \n",
"\n",
" relevance_score completeness_score factual_accuracy_score \n",
"112 1.0 0.5 1.0 \n",
"37 1.0 1.0 1.0 \n",
"140 1.0 1.0 1.0 \n",
"0 0.5 0.0 0.0 \n",
"98 1.0 1.0 1.0 "
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.DataFrame(metrics[\"detailed_results\"]).sample(5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "731e781a",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "76ed2ec5",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 5
}