English translation is not available yet. Showing Russian content.

Протестировать multi-turn диалоги

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Протестировать multi-turn диалоги

1. Цель задачи

Разработать и выполнить автоматизированный тест, который воспроизводит реальные multi-turn диалоги из логов (production или тестового окружения) и сравнивает ответы текущей версии агента с эталонными ответами (записанными ранее). Задача позволяет выявить регрессии в качестве диалогов при изменении модели, промпта, памяти или контекста. Ключевой результат Набор метрик, показывающих процент диалогов, в которых ответы деградировали (или улучшились), и воспроизводимый pipeline для повторного прогона.


2. Исходные данные

Что нужноОткуда взять
Логи production/тестового multi-turn диалоговЭкспорт из БД (PostgreSQL, ClickHouse) или лог-файлы (JSONL)
Эталонные ответы (ground truth)Те же логи, но записанные до изменений (версия «хорошего» агента)
Агент (LLM + memory + инструменты)Существующий pet-проект (например, Pet 221) или учебный агент
Скрипт для replay диалоговНаписать самостоятельно на Python
Метрики сравнения текстовBLEU / ROUGE / METEOR / cosine similarity (sentence-transformers)

Если нет реальных production логов — симулируем:

  1. Запустить текущего агента в тестовом режиме с фиктивным пользователем — записать 10–15 multi-turn диалогов разных сценариев.
  2. Сохранить логи (входные сообщения, контекст, ответы) как эталонную выборку.
  3. Затем внести контролируемое изменение (например, изменить system prompt, уменьшить длину истории, заменить model endpoint).
  4. Повторно прогнать те же сценарии — получить новую выборку.
  5. Сравнить ответы и оценить деградацию.

3. Технологический стек

КомпонентИнструментыНазначение
ЯзыкPython 3.10+Написание тестового pipeline
Реплей диалоговpytest + asyncio / requestsЗапуск агента в заданной последовательности
Работа с текстомsentence-transformers, evaluate (HuggingFace)Расчёт семантической близости и NLP-метрик
Логированиеjson, jsonlines (JSONL)Чтение и запись диалогов
Интеграция с агентомLangChain / AutoGen / прямой APIВызов агента с историей сообщений
Отчётpandas + matplotlib (или просто JSON)Сводка метрик по каждому turn

4. Этапы выполнения

Этап 1: Подготовка данных логов (1–2 часа)

Действия

  1. Определить формат хранения диалогов Каждый диалог — это последовательность сообщений: [user_message, agent_message, user_message, ...]. Пример записи в JSONL:

    {"dialog_id": "d001", "turn_id": 1, "role": "user", "content": "Какая погода в Москве?"}
    {"dialog_id": "d001", "turn_id": 1, "role": "assistant", "content": "В Москве сейчас +5°C, облачно."}
    {"dialog_id": "d001", "turn_id": 2, "role": "user", "content": "А завтра?"}
    {"dialog_id": "d001", "turn_id": 2, "role": "assistant", "content": "Прогноз на завтра: +3°C, дождь."}
    
  2. Собрать эталонные логи (GT).

    • Если есть production — экспорт за период стабильной работы.
    • Если нет — симулировать через агента (см. п.2).
  3. Сформировать тестовые наборы

    • Разделить диалоги на train/test/validation (по дате или случайно).
    • Сохранить в отдельных файлах: gt_dialogs.jsonl, test_dialogs.jsonl.
  4. Выделить контекст для каждого turn Для корректного replay нужно подавать агенту полную историю диалога до текущего turn. Проверить, что ваш агент поддерживает передачу messages (OpenAI-style) или conversation_id с историей.

Ожидаемый результат этапа Набор файлов JSONL с корректной структурой, готовых для подачи в pipeline.


Этап 2: Разработка pipeline replay (2–3 часа)

Действия

  1. Написать функцию replay_dialog(dialog: list[dict], agent_endpoint)

    • Принимает список сообщений (user + assistant) из лога.
    • Воспроизводит диалог пошагово: для каждого user message отправляет историю агенту и получает ответ.
    • Сохраняет полученные ответы в структуру actual_responses.
    • Логирует ошибки и время выполнения.
  2. Добавить механизм «заморозки» недетерминированных ответов Если агент использует случайный seed, установить temperature=0 или фиксированный seed.

  3. Обработать краевые случаи

    • Агент может вернуть ошибку (retry + логирование).
    • Агент может использовать инструменты (функции) — проверить, что ответы соответствуют ожидаемому формату.
    • Если агент возвращает финальный ответ с размышлениями (CoT) — сравнивать только итоговый ответ.
  4. Создание пакета с тестами Использовать pytest с фикстурой, загружающей диалоги:

    @pytest.mark.parametrize("dialog", load_dialogs("gt_dialogs.jsonl"))
    def test_single_dialog(dialog):
        actual = replay_dialog(dialog)
        expected = extract_expected(dialog)
        metrics = compare_turns(actual, expected)
        assert metrics["avg_semantic_similarity"] > 0.85
    

Ожидаемый результат этапа Рабочий скрипт/проверка, который по заданному набору диалогов воспроизводит ответы агента и возвращает их для сравнения.


Этап 3: Реализация сравнения и метрик (1.5–2 часа)

Действия

  1. Для каждой пары (expected, actual) вычислить метрики:

    • ROUGE-L (ROUGE-1/2/L) — n-gram overlap.
    • BLEU — точность n-gram с учётом brevity penalty.
    • METEOR — более гибкая метрика с учётом синонимов.
    • Семантическое сходство через cosine distance между эмбеддингами (sentence-transformers: all-MiniLM-L6-v2).
  2. Написать функцию compare_turns(expected: str, actual: str) -> dict:

    from evaluate import load
    import numpy as np
    from sentence_transformers import SentenceTransformer
    
    bleu_scorer = load("bleu")
    rouge_scorer = load("rouge")
    meteor_scorer = load("meteor")
    model = SentenceTransformer("all-MiniLM-L6-v2")
    
    def compare_turns(exp, act):
        bleu = bleu_scorer.compute(predictions=[act], references=[exp])
        rouge = rouge_scorer.compute(predictions=[act], references=[exp])
        meteor = meteor_scorer.compute(predictions=[act], references=[exp])
        emb_exp = model.encode(exp)
        emb_act = model.encode(act)
        sim = np.dot(emb_exp, emb_act) / (np.linalg.norm(emb_exp)*np.linalg.norm(emb_act))
        return {"bleu": bleu["bleu"], "rouge-l": rouge["rouge-l"], "meteor": meteor["meteor"], "semantic_similarity": sim}
    
  3. Агрегировать метрики по диалогу

    • Среднее, медиана, минимальное/максимальное для каждого turn.
    • Процент turns, где семантическое сходство <0.8 (считать деградацией).
  4. Сравнить с порогом Определить acceptable thresholds на основе ручной оценки 5–10 диалогов (например, average semantic similarity >= 0.85).

Ожидаемый результат этапа Функция сравнения, выдающая метрики на уровне turn и диалога.


Этап 4: Запуск и анализ результатов (1–2 часа)

Действия

  1. Запустить replay на двух версиях агента:

    • Версия V1 (эталон, если есть) — для валидации reproducibility.
    • Версия V2 (текущая с изменениями) — целевая.
  2. Собрать отчёт в JSON

    {
      "dialog_id": "d001",
      "turns": [
        {"turn": 1, "bleu": 0.45, "rouge-l": 0.5, "meteor": 0.6, "sem_sim": 0.92}
      ],
      "averages": {...},
      "degraded_turns": 0,
      "total_turns": 5
    }
    
  3. Построить гистограмму распределения semantic similarity для быстрой визуальной оценки.

  4. Проверить consistency

    • Запустить replay дважды (с той же seed) — метрики должны совпадать (кроме возможных вариаций из-за floating point).
    • Если агент недетерминирован даже при temperature=0 — принять допуск ±0.05 для similarity.

Ожидаемый результат этапа Финальный отчёт с метриками и выводами (регрессия, улучшение, без изменений).


Этап 5: Оформление документации и автоматизация (0.5–1 час)

Действия

  1. Написать README с инструкцией по запуску: как указать пути к логам, как запустить тест с помощью одной команды.
  2. Упаковать pipeline в скрипт запуска (например, python run_test.py --gt gt.jsonl --agent-endpoint http://...).
  3. Добавить финальные чек-листы в раздел Criteria below.

Ожидаемый результат этапа Воспроизводимый git-репозиторий с кодом, отчётом и документацией.


5. Критерии приемки (Definition of Done)

  • Pipeline replay работает без ошибок на всех диалогах тестового набора (минимум 10 диалогов по 3–7 turns).
  • Для каждого turn вычислены метрики BLEU, ROUGE-L, METEOR, semantic similarity.
  • Порог деградации (средний semantic similarity < 0.85) обнаруживает изменения в ответах.
  • При повторном прогоне с теми же параметрами результаты идентичны (допуск ±0.01 для метрик).
  • Скрипт корректно обрабатывает ошибки агента (timeout, пустой ответ) и логирует их.
  • Финальный отчёт сгруппирован по диалогам и содержит средние метрики по всем turns.
  • README содержит команду запуска и описание формата входных логов.
  • Тест может быть запущен на CI (например, GitHub Actions) с установкой зависимостей.

6. Ожидаемый результат

Основной артефакт Папка проекта multi-turn-test с содержимым:

  • gt_dialogs.jsonl — эталонные диалоги.
  • test_dialogs.jsonl — те же диалоги (дубль, или новая версия).
  • replay.py — реализация replay.
  • compare.py — метрики сравнения.
  • run_test.py — точка входа.
  • report.json — результаты прогона.
  • report.html (опционально) — визуализация гистограмм.
  • README.md — инструкция.

Содержание report.json

{
  "configuration": {"temperature": 0, "model": "gpt-4o-mini"},
  "overall": {
    "num_dialogs": 10,
    "num_turns": 45,
    "avg_bleu": 0.52,
    "avg_rouge-l": 0.61,
    "avg_meteor": 0.68,
    "avg_semantic_similarity": 0.88
  },
  "degraded_dialogs": ["d005", "d008"],
  "degraded_turns_percent": 13.3
}

Опциональные дополнительные результаты

  • График распределения semantic_similarity.
  • Таблица с детальными метриками по каждому turn (CSV).

7. Возможные сложности и их решение

СложностьРешение
Агент требует сессии/контекст через conversation_id, а не список сообщенийИзменить replay на создание новой сессии для каждого диалога и отправку по rest API
Логи хранятся в нестандартном формате (например, в базе данных)Написать скрипт-экспортёр в JSONL; в ТЗ принять, что логи уже экспортированы
Агент использует внешние инструменты (поиск, календарь) и ответы недетерминированыУстановить фиксированные моки для инструментов (mock API) или зафиксировать ответы на уровне записей лога
Метрики BLEU/ROUGE дают низкие значения из-за вариативности языкаОсновной упор на semantic similarity; порог деградации устанавливать на основе 95-процентного перцентиля эталонных ответов
Агент слишком медленный (долгие ответы)Использовать asyncio для параллельного запуска диалогов; ограничить количество попыток
Отсутствие эталонных ответов (логов старой версии)Использовать ту же самую версию агента как baseline, прогоняя дважды: первый прогон — эталон, второй — с изменениями

8. Бюджет времени (оценка)

ЭтапВремя
1. Подготовка данных1–2 ч
2. Pipeline replay2–3 ч
3. Сравнение и метрики1.5–2 ч
4. Запуск и анализ1–2 ч
5. Документирование0.5–1 ч
Итого6–10 ч

Примечание: для первого выполнения задачи рекомендуем заложить 10 часов, включая настройку окружения и отладку интеграции с агентом.


9. Связанные вопросы из базы знаний

ВопросТема
45Метрики качества диалоговых систем
102A/B тестирование агентов
131Сбор логов и телеметрия для AI
218Регрессионное тестирование LLM
304Multi-turn conversation memory
405Evaluation pipelines для RAG
512Семантическое сходство эмбеддингов
619LangChain / AutoGen тестирование
700Production-мониторинг агентов
888Чек-листы QA для AI продуктов

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

  • Я создал JSONL-файл с тестовыми диалогами, где корректно указаны все turns.
  • Я написал replay-функцию, которая получает ответы агента на каждый turn.
  • Я реализовал вычисление минимум трёх метрик (BLEU, ROUGE, semantic similarity).
  • Я проверил, что при повторном прогоне с одинаковыми параметрами метрики совпадают.
  • Я подготовил README с командой запуска одной строкой.
  • Я убедился, что порог деградации настроен так, что он срабатывает при небольших изменениях (temperature > 0).
  • Я включил в отчёт список диалогов с деградацией и процент таких turns.