Реализовать 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) — симулируем:

  1. Установите Ollama (или аналогичный локальный сервер).
  2. Загрузите модель mistral:7b-instruct командой ollama pull mistral:7b-instruct.
  3. Используйте langchain_community.chat_models.ChatOllama для генерации.

Если нет доступа к NLI‑модели — симулируем:

  1. Используйте простую эвристику: сравнение эмбеддингов с retrieved‑чанками через cosine similarity.
  2. Если средняя косинусная близость предложения к контексту < 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 часа)

Действия

  1. Сбор базы документов

    • Найдите 10–15 текстов (например, первые главы из учебников по ML, статьи с Википедии по темам «Transformer», «RAG», «Attention»).
    • Сохраните в data/documents/ в формате .txt.
    • Разбейте на чанки (1024 символа с overlap 128). Используйте RecursiveCharacterTextSplitter.
  2. Создание векторного индекса

    • Выберите модель эмбеддингов: 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")
    
  3. Генерация тестового датасета

    • Напишите 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 часа)

Действия

  1. Выбор метода проверки фактов

    • Основной: использование NLI‑модели.
    • Запасной: косинусное сходство эмбеддингов предложения и контекста.
  2. Реализация класса 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 — кандидат на галлюцинацию.
  3. Разбивка ответа на предложения

    • Используйте nltk.sent_tokenize или регулярное выражение.
    • Для каждого предложения найдите самые похожие чанки из контекста (top‑3 по косинусному сходству).
    • Прогоните через NLI‑модель (предложение = hypothesis, чанк = premise).
    • Усредните вероятность entailment по трём чанкам — это confidence.
  4. Создание порогов принятия решений

    • high (зелёный): confidence ≥ 0.8
    • medium (жёлтый): 0.4 ≤ confidence < 0.8
    • low (красный): confidence < 0.4

Ожидаемый результат этапа

  • Модуль detector.py с классом HallucinationDetector, принимающий ответ LLM и список контекстных чанков и возвращающий список предложений с меткой уверенности.

Этап 3: Интеграция в UI и визуализация (1–1.5 часа)

Действия

  1. Создание 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)
      
  2. Добавление интерактивности

    • При нажатии на подсвеченный фрагмент (через st.button или st.expander) показывать:
      • Уровень уверенности (score).
      • Топ‑2 поддерживающих чанка (текст и similarity).
      • Кнопка «Показать источник» → открывает весь документ.
  3. Тестирование на датасете

    • Загрузите qa_dataset.json и прогоните через детектор.
    • Выведите матрицу ошибок (True/False hallucination vs predicted).
    • Подсчитайте Precision, Recall, F1 для класса «галлюцинация».

Ожидаемый результат этапа

  • Рабочий Streamlit‑демо, где пользователь вводит вопрос, видит подсвеченный ответ и может проверить источники.

Этап 4: Оценка качества и доработка (1 час)

Действия

  1. Сбор метрик детектора

    • На размеченном датасете вычислите:
      • Accuracy (доля верно классифицированных предложений).
      • Precision (доля действительно галлюцинаций среди предсказанных).
      • Recall (доля найденных галлюцинаций среди всех реальных).
      • F1‑score.
    • Пример кода:
    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))
    
  2. Анализ ошибок

    • Выпишите 3–5 случаев ложноположительных и ложноотрицательных срабатываний.
    • Попробуйте улучшить: изменить пороги, использовать усреднение по более широкому контексту, добавить эвристику на основе длины предложения.
  3. Запись в README

    • Опишите метрики, типы ошибок, возможные улучшения.

Ожидаемый результат этапа

  • Отчёт о точности детектора, исправленные пороги (опционально), обновлённый README.

Этап 5: Финализация и демонстрация (30 минут)

Действия

  1. Оформление репозитория

    • app.pyStreamlit‑демо.
    • detector.py — модуль детекции.
    • rag.py — RAG‑пайплайн.
    • requirements.txt — все зависимости.
    • README.md с описанием, примерами, графиками (см. Этап 4).
  2. Подготовка презентации (опционально)

    • Скриншот 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Реализация индикатора галлюцинаций (текущая задача)
112Confidence calibration в LLM
156Анализ ошибок LLM с помощью эмбеддингов
203Streamlit для создания ML‑демо
301Сравнение cross‑encoder vs bi‑encoder для entailment
450Обработка контекста в LangChain

10. Чек-лист самопроверки

  • Я подготовил рабочую RAG‑систему, которая возвращает ответ и список чанков.
  • Я реализовал детектор, который разбивает ответ на предложения и вычисляет confidence для каждого.
  • Я создал Streamlit‑приложение с цветовой подсветкой (зелёный/жёлтый/красный).
  • Я добавил интерактивность: клик на фрагмент показывает исходные чанки.
  • Я провёл оценку на датасете из минимум 30 примеров и получил F1 ≥ 0.7.
  • Я написал README, где объяснил архитектуру, этапы запуска и результаты.
  • Я проверил, что код запускается в чистом окружении (conda/venv) и не требует проприетарных ключей (если используется локальная LLM).