Реализовать hallucination indicator (индикатор галлюцинаций)
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать hallucination indicator (индикатор галлюцинаций)
1. Цель задачи
Разработать прототип индикатора галлюцинаций для ответов LLM в RAG‑системе. Индикатор должен автоматически выделять фрагменты ответа, которые с высокой вероятностью не подтверждаются извлечёнными документами (retrieved context). Пользователь видит отметку уверенности и может нажать на подсвеченный фрагмент, чтобы увидеть исходные источники. Это повышает доверие к системе и даёт пользователю инструмент для критической проверки.
Ключевой результат Рабочая демо‑страница (Streamlit/Gradio), где для произвольного вопроса и ответа LLM подсвечиваются потенциальные галлюцинации, а рядом отображается уровень уверенности (low/medium/high) и ссылки на релевантные чанки.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| База документов (10–50 текстов на русском) | Собрать самостоятельно: статьи,wiki, документация (например, открытые статьи по машинному обучению) |
| RAG‑система (базовый retrieve + generate) | Написать самостоятельно или использовать пет‑проект; можно симулировать через LangChain + Chroma |
| LLM для генерации ответов (бесплатная/локальная) | OpenAI API (gpt‑4o‑mini) или локальная через Ollama (Mistral 7B, Qwen 2.5) |
| Датасет вопросов (20–30) с известными правильными ответами | Сгенерировать самостоятельно на основе базы документов (вопросы, на которые ответ есть в базе, и вопросы, вызывающие галлюцинации) |
| NLI‑модель или кросс‑энкодер для проверки фактов | cross‑encoder/nli‑deberta‑v3‑large (HuggingFace) или аналог на русском (RuBERT для NLI) |
| Предобученная модель для эмбеддингов | intfloat/multilingual‑e5‑large или sentence‑transformers/all‑MiniLM‑L6‑v2 |
Если нет реального инструмента (например, LLM через API) — симулируем:
- Установите Ollama (или аналогичный локальный сервер).
- Загрузите модель mistral:7b-instruct командой ollama pull mistral:7b-instruct.
- Используйте langchain_community.chat_models.ChatOllama для генерации.
Если нет доступа к NLI‑модели — симулируем:
- Используйте простую эвристику: сравнение эмбеддингов с retrieved‑чанками через cosine similarity.
- Если средняя косинусная близость предложения к контексту < 0.5 — считаем потенциальной галлюцинацией.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык программирования | Python 3.10+ | Основной |
| RAG‑фреймворк | LangChain (или LlamaIndex) | Сборка pipeline retrieve → generate |
| Векторное хранилище | Chroma (in‑memory) или FAISS | Хранение и поиск чанков |
| LLM (генерация) | OpenAI API / Ollama (Mistral, Qwen) | Генерация ответов |
| NLI / проверка фактов | HuggingFace Transformers (cross‑encoder) | Оценка entailment между claim и контекстом |
| UI / прототип | Streamlit или Gradio | Демонстрация индикатора |
| Дополнительно | sentence‑transformers (эмбеддинги) | Сравнение предложений |
| Метрики | scikit‑learn, numpy | Оценка точности детектора |
| Логирование | loguru | Отладка и анализ |
4. Этапы выполнения
Этап 1: Подготовка RAG‑системы и датасета (1.5–2 часа)
Действия
-
Сбор базы документов
- Найдите 10–15 текстов (например, первые главы из учебников по ML, статьи с Википедии по темам «Transformer», «RAG», «Attention»).
- Сохраните в
data/documents/в формате.txt. - Разбейте на чанки (1024 символа с overlap 128). Используйте RecursiveCharacterTextSplitter.
-
Создание векторного индекса
- Выберите модель эмбеддингов: sentence‑transformers/all‑MiniLM‑L6‑v2 (английский) или русскоязычную
intfloat/multilingual‑e5‑large. - Закодируйте чанки и поместите в Chroma:
from langchain_community.vectorstores import Chroma from langchain.embeddings import SentenceTransformerEmbeddings embeddings = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2") vectordb = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db") - Выберите модель эмбеддингов: sentence‑transformers/all‑MiniLM‑L6‑v2 (английский) или русскоязычную
-
Генерация тестового датасета
- Напишите 15 вопросов, на которые в базе есть точный ответ (закрытые вопросы).
- Напишите 15 вопросов, по которым база не содержит информации (открытые, обобщающие, провоцирующие галлюцинации).
- Для каждого вопроса запросите ответ у LLM через RAG (retrieve + generate).
- Разметьте вручную: какие предложения в ответе являются галлюцинациями (не подтверждаются чанками). Сохраните в data/qa_dataset.json в формате: [{ "question": "...", "answer": "...", "sentences": [{"text": "...", "hallucination": true/false, "supporting_chunks": [...]}] }].
Ожидаемый результат этапа
- Рабочий RAG (retrieve + generate)
- Файл qa_dataset.json с 30 примерами, размеченными по предложениям.
Этап 2: Разработка модуля детекции галлюцинаций (2–3 часа)
Действия
-
Выбор метода проверки фактов
- Основной: использование NLI‑модели.
- Запасной: косинусное сходство эмбеддингов предложения и контекста.
-
Реализация класса
HallucinationDetector- Метод
score_sentence(sentence: str, context_chunks: list[str]) -> dict:- Возвращает {"score": float (0–1), "label": "hallucination"/"fact", "evidence": str}.
- Пример с NLI:
import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification model_name = "cross-encoder/nli-deberta-v3-large" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained(model_name) def nli_entailment(premise, hypothesis): inputs = tokenizer(premise, hypothesis, return_tensors="pt", truncation=True) with torch.no_grad(): logits = model(**inputs).logits # 0: contradiction, 1: neutral, 2: entailment probs = torch.softmax(logits, dim=1) return probs[0][2].item() # вероятность entailment- Если вероятность entailment < 0.3 — кандидат на галлюцинацию.
- Метод
-
Разбивка ответа на предложения
- Используйте nltk.sent_tokenize или регулярное выражение.
- Для каждого предложения найдите самые похожие чанки из контекста (top‑3 по косинусному сходству).
- Прогоните через NLI‑модель (предложение = hypothesis, чанк = premise).
- Усредните вероятность entailment по трём чанкам — это confidence.
-
Создание порогов принятия решений
high(зелёный): confidence ≥ 0.8medium(жёлтый): 0.4 ≤ confidence < 0.8low(красный): confidence < 0.4
Ожидаемый результат этапа
- Модуль
detector.pyс классомHallucinationDetector, принимающий ответ LLM и список контекстных чанков и возвращающий список предложений с меткой уверенности.
Этап 3: Интеграция в UI и визуализация (1–1.5 часа)
Действия
-
Создание Streamlit‑приложения (
app.py)- Поле ввода вопроса → вызов RAG (retrieve + generate).
- После получения ответа — вызов
detector.score_answer(answer, chunks). - Отображение ответа с подсветкой:
import streamlit as st import markdown def highlight_sentence(text, label): colors = {"high": "lightgreen", "medium": "khaki", "low": "lightcoral"} color = colors.get(label, "white") return f'<span style="background-color: {color};">{text}</span>' html_parts = [highlight_sentence(sent["text"], sent["confidence_label"]) for sent in detected_sentences] st.markdown(" ".join(html_parts), unsafe_allow_html=True)
-
Добавление интерактивности
- При нажатии на подсвеченный фрагмент (через
st.buttonилиst.expander) показывать:- Уровень уверенности (score).
- Топ‑2 поддерживающих чанка (текст и similarity).
- Кнопка «Показать источник» → открывает весь документ.
- При нажатии на подсвеченный фрагмент (через
-
Тестирование на датасете
- Загрузите
qa_dataset.jsonи прогоните через детектор. - Выведите матрицу ошибок (True/False hallucination vs predicted).
- Подсчитайте Precision, Recall, F1 для класса «галлюцинация».
- Загрузите
Ожидаемый результат этапа
- Рабочий Streamlit‑демо, где пользователь вводит вопрос, видит подсвеченный ответ и может проверить источники.
Этап 4: Оценка качества и доработка (1 час)
Действия
-
Сбор метрик детектора
- На размеченном датасете вычислите:
- Пример кода:
from sklearn.metrics import classification_report y_true = [sent["hallucination"] for example in dataset for sent in example["sentences"]] y_pred = [1 if sent["confidence_label"] in ["low", "medium"] else 0 ...] print(classification_report(y_true, y_pred)) -
Анализ ошибок
- Выпишите 3–5 случаев ложноположительных и ложноотрицательных срабатываний.
- Попробуйте улучшить: изменить пороги, использовать усреднение по более широкому контексту, добавить эвристику на основе длины предложения.
-
Запись в README
- Опишите метрики, типы ошибок, возможные улучшения.
Ожидаемый результат этапа
- Отчёт о точности детектора, исправленные пороги (опционально), обновлённый README.
Этап 5: Финализация и демонстрация (30 минут)
Действия
-
Оформление репозитория
app.py— Streamlit‑демо.detector.py— модуль детекции.rag.py— RAG‑пайплайн.requirements.txt— все зависимости.README.mdс описанием, примерами, графиками (см. Этап 4).
-
Подготовка презентации (опционально)
- Скриншот UI с подсветкой.
- Табличка с метриками.
Ожидаемый результат этапа
- Завершённый проект, готовый к демонстрации и ревью.
5. Критерии приемки (Definition of Done)
- RAG‑система возвращает ответ на любой вопрос из датасета менее чем за 5 секунд (при локальной LLM).
- Детектор разбивает ответ на предложения и для каждого определяет confidence (high/medium/low).
- В UI текст ответа отображается с цветовой подсветкой в зависимости от уверенности.
- При клике на подсвеченный фрагмент раскрываются поддерживающие чанки.
- На датасете из 30 примеров F1‑score по классу «галлюцинация» ≥ 0.7.
- Код залит в Git‑репозиторий с README, requirements.txt и инструкцией по запуску.
- Проведён анализ ошибок: выявлены 2–3 слабых места с описанием в README.
6. Ожидаемый результат
Основной артефакт
- Репозиторий с кодом, содержащий:
app.py— интерактивное Streamlit‑приложение с индикатором галлюцинаций.detector.py— классы и функции детекции.rag.py— сборка RAG‑пайплайна (retrieve + generate).data/qa_dataset.json— размеченный датасет.evaluation/— скрипты расчёта метрик и анализа ошибок.requirements.txt.
Опциональные дополнительные результаты
- Ноутбук Jupyter с визуализацией распределения confidence.
- График confusion matrix.
- Запись демонстрации (скринкаст).
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| NLI‑модель слишком медленная (5+ секунд на предложение) | Использовать модель поменьше (например, cross‑encoder/nli‑deberta‑v3‑xsmall); кэшировать результаты для одинаковых пар. |
| LLM‑генерация через API дорогая | Перейти на локальную LLM (Ollama с Mistral 7B) или использовать небольшую модель (Qwen 2.5 1.5B). |
| Низкое качество разбивки на предложения (не делится на русском) | Подключить razdel (библиотека сегментации для русского) или nltk с русским токенизатором. |
| Высокий процент ложноположительных срабатываний (красные подсветки почти всего) | Увеличить порог low до 0.5; добавить эвристику: если предложение содержит факт из документа, а не перефразирование, считать его зелёным. |
| RAG иногда возвращает пустой контекст | Обрабатывать случай отсутствия чанков: помечать весь ответ как low с сообщением «Нет релевантных документов». |
| Отсутствие GPU для NLI‑модели | Использовать CPU‑версию (работает медленнее, но 1–2 предложения в секунду приемлемо для демо). |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| Этап 1: Подготовка RAG и датасета | 1.5–2 |
| Этап 2: Разработка детектора | 2–3 |
| Этап 3: UI и визуализация | 1–1.5 |
| Этап 4: Оценка и доработка | 1 |
| Этап 5: Финализация | 0.5 |
| Итого | 6–8 часов |
Примечание Для первого раза заложите +2 часа на отладку и подбор NLI‑модели. Если используются платные API — время на регистрацию и настройку не учтено.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Что такое галлюцинации LLM и как их классифицировать? |
| 34 | Как измерить фактуальную корректность ответов RAG? |
| 45 | Метрики для оценки качества retrieval (hit rate, MRR) |
| 67 | Использование NLI для верификации фактов |
| 88 | Реализация индикатора галлюцинаций (текущая задача) |
| 112 | Confidence calibration в LLM |
| 156 | Анализ ошибок LLM с помощью эмбеддингов |
| 203 | Streamlit для создания ML‑демо |
| 301 | Сравнение cross‑encoder vs bi‑encoder для entailment |
| 450 | Обработка контекста в LangChain |
10. Чек-лист самопроверки
- Я подготовил рабочую RAG‑систему, которая возвращает ответ и список чанков.
- Я реализовал детектор, который разбивает ответ на предложения и вычисляет confidence для каждого.
- Я создал Streamlit‑приложение с цветовой подсветкой (зелёный/жёлтый/красный).
- Я добавил интерактивность: клик на фрагмент показывает исходные чанки.
- Я провёл оценку на датасете из минимум 30 примеров и получил F1 ≥ 0.7.
- Я написал README, где объяснил архитектуру, этапы запуска и результаты.
- Я проверил, что код запускается в чистом окружении (conda/venv) и не требует проприетарных ключей (если используется локальная LLM).