Настроить playground для тестирования агента

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить playground для тестирования агента

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

Создать интерактивный UI‑playground, позволяющий разработчикам и QA‑инженерам вручную тестировать AI‑агента без написания кода. Интерфейс должен предоставлять поле ввода запроса, визуализировать полную трассировку работы агента (мысли, действия, наблюдения) и собирать фидбек от тестировщика. Результат — рабочий веб‑интерфейс, который ускоряет итерации отладки агента до нескольких секунд.

Ключевой результат Запускаемый одной командой playground, в котором можно ввести запрос, увидеть пошаговую логику агента и оставить оценку качества ответа.


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

Что нужноОткуда взять
Агент (реальный или заглушка)Собственный проект на LangChain / LlamaIndex или простая Python‑реализация ReAct
Требования к UIОписаны ниже в этом ТЗ
Инструмент для быстрого UIStreamlit / Gradio (установить через pip)
Данные для тестированияРучной набор тестовых запросов (3–5 штук)

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

  1. Создать файл mock_agent.py, реализующий простой ReAct‑цикл:
    • think — генерирует случайную "мысль" (например, "Нужно найти информацию о ...")
    • act — эмулирует вызов инструмента (возвращает фиктивный результат)
    • observe — обрабатывает результат и формирует следующий шаг
    • После 2–3 итераций возвращает финальный ответ
  2. Все шаги сохранять в список словарей с ключами: step, type (think/act/observe), content, tool_used (если есть), duration_ms.
  3. Экспортировать функцию run_agent(query: str) -> tuple[str, list[dict]].

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

КомпонентИнструментыНазначение
Фреймворк UIStreamlit 1.28+Быстрое создание веб‑интерфейса
Агент (реальный или мок)Python, LangChain / LlamaIndex / самописныйОбработка запросов и генерация трассировки
Логирование трассировкиJSON + st.session_stateХранение истории шагов текущей сессии
Сбор фидбекаStreamlit компоненты (st.radio, st.button, st.text_area)Оценка ответа пользователем
ВерсионированиеGitХранение исходного кода playground

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

Этап 1: Проектирование макета UI и архитектуры (30 минут)

Действия

  1. Нарисовать макет интерфейса на бумаге или в Figma:

    • Левая панель (или верхняя область): поле ввода запроса + кнопка «Отправить».
    • Центральная область: вывод финального ответа агента.
    • Ниже ответа: интерактивное дерево/список трассировки (раскрывающиеся шаги).
    • Правая панель или низ: блок фидбека (оценка от 1 до 5, текстовый комментарий, кнопка «Отправить фидбек»).
    • Кнопка «Очистить историю» / «Новая сессия».
  2. Определить структуру данных трассировки:

    trace_schema = [
        {
            "step": 1,
            "type": "think",
            "content": "Пользователь спрашивает о погоде...",
            "tool_used": None,
            "duration_ms": 120,
            "timestamp": "2025-03-19T12:00:01"
        },
        {
            "step": 2,
            "type": "act",
            "content": "Вызов get_weather(location='Moscow')",
            "tool_used": "get_weather",
            "duration_ms": 340,
            "timestamp": "2025-03-19T12:00:02"
        },
        # ... observe и т.д.
    ]
    
  3. Выбрать подход к отображению трассировки:

    • Использовать st.expander для каждого шага.
    • Внутри expander выводить тип шага эмодзи (💭 think, ⚡ act, 👀 observe), содержимое, использованный инструмент, длительность.
    • Для act-шагов дополнительно показывать результат инструмента под спойлером.

Ожидаемый результат этапа Чёткий план расположения элементов и формат данных трассировки.


Этап 2: Реализация базового UI ввода и вывода ответа (1 час)

Действия

  1. Создать файл playground.py:

    import streamlit as st
    from mock_agent import run_agent   # или реальный импорт
    
    st.set_page_config(page_title="Agent Playground", layout="wide")
    st.title("🤖 Agent Playground")
    
    # Состояние сессии
    if "trace" not in st.session_state:
        st.session_state.trace = []
    if "last_answer" not in st.session_state:
        st.session_state.last_answer = ""
    
    # Ввод запроса
    col1, col2 = st.columns([4, 1])
    with col1:
        query = st.text_input("Введите запрос к агенту:", key="query_input")
    with col2:
        run_button = st.button("🚀 Отправить")
    
  2. Реализовать обработку запроса:

    if run_button and query:
        with st.spinner("Агент думает..."):
            answer, trace = run_agent(query)
        st.session_state.last_answer = answer
        st.session_state.trace = trace
    
  3. Вывести финальный ответ:

    if st.session_state.last_answer:
        st.subheader("📝 Ответ агента")
        st.info(st.session_state.last_answer)
    

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


Этап 3: Визуализация трассировки (1 час)

Действия

  1. Добавить отображение трассировки под ответом:

    if st.session_state.trace:
        st.subheader("🔍 Трассировка шагов")
        for step_data in st.session_state.trace:
            emoji_map = {"think": "💭", "act": "⚡", "observe": "👀"}
            with st.expander(f"Шаг {step_data['step {emoji_map[step_data['type']]} {step_data['type'].upper()}"):
                st.write(f"Содержание {step_data['content']}")
                if step_data.get("tool_used"):
                    st.write(f"**Инструмент:** `{step_data['tool_used']}`")
                st.caption(f"Длительность: {step_data['duration_ms']} мс")
    
  2. Добавить сводную статистику:

    • Общее количество шагов, общее время выполнения, список использованных инструментов.
    • Вывести в виде метрик st.metric.
  3. Проверить на тестовом запросе — все шаги раскрываются, информация читаема.

Ожидаемый результат этапа При нажатии «Отправить» под ответом видна полная трассировка в раскрывающихся блоках.


Этап 4: Сбор фидбека и логирование (45 минут)

Действия

  1. Добавить блок фидбека после трассировки:

    st.subheader("📊 Фидбек")
    feedback_rating = st.slider("Оцените ответ от 1 до 5", 1, 5, 3, key="rating")
    feedback_comment = st.text_area("Комментарий (необязательно)", key="comment")
    if st.button("💾 Отправить фидбек", key="submit_feedback"):
        feedback_data = {
            "query": query,
            "answer": st.session_state.last_answer,
            "trace": st.session_state.trace,
            "rating": feedback_rating,
            "comment": feedback_comment,
            "timestamp": datetime.now().isoformat()
        }
        # Сохранить в файл feedback_log.jsonl
        import json
        with open("feedback_log.jsonl", "a") as f:
            f.write(json.dumps(feedback_data) + "\n")
        st.success("Фидбек сохранён!")
    
  2. Добавить кнопку «Новая сессия», которая очищает st.session_state.trace и last_answer, оставляя ввод пустым.

  3. Улучшить UX: если трассировки нет, блок фидбека не показывается; после отправки фидбека поля сбрасываются.

Ожидаемый результат этапа Возможность оценить ответ, оставить комментарий, данные фидбека пишутся в JSONL‑файл.


Этап 5: Тестирование, полировка и упаковка (45 минут)

Действия

  1. Запустить playground локально:

    streamlit run playground.py
    
  2. Протестировать на наборе запросов:

    • Проверить, что при пустом запросе кнопка не вызывает ошибок.
    • Проверить, что трассировка корректно отображается для 1, 2, 5 шагов.
    • Проверить отправку фидбека и чтение файла feedback_log.jsonl.
  3. Добавить минимальную обработку ошибок:

    try:
        answer, trace = run_agent(query)
    except Exception as e:
        st.error(f"Ошибка агента: {e}")
        answer = "Ошибка выполнения"
        trace = [{"step": 0, "type": "think", "content": str(e), "duration_ms": 0}]
    
  4. Создать requirements.txt:

    streamlit>=1.28
    # Если используется LangChain: langchain-core, openai и т.д.
    
  5. Написать короткий README.md с инструкцией по запуску.

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


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

  • Playground запускается одной командой streamlit run playground.py.
  • Поле ввода запроса и кнопка «Отправить» отображаются при запуске.
  • После отправки запроса в течение 5 секунд появляется ответ агента.
  • Под ответом отображается полная трассировка шагов (think/act/observe) в раскрывающихся блоках.
  • Каждый шаг содержит тип, содержание, использованный инструмент (если есть) и длительность.
  • Блок фидбека появляется только после получения ответа.
  • Фидбек (оценка + комментарий) сохраняется в файл feedback_log.jsonl.
  • Кнопка «Новая сессия» очищает историю и позволяет ввести новый запрос.
  • Интерфейс не ломается при пустом запросе или при ошибке агента (показывается сообщение).
  • В репозитории лежат playground.py, requirements.txt, README.md и файл агента (или заглушки).

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

Основной артефакт Папка agent_playground/ со следующими файлами:

ФайлСодержание
playground.pyОсновной скрипт Streamlit с полным UI
mock_agent.pyЗаглушка агента (если нет реального)
requirements.txtЗависимости
README.mdИнструкция по запуску и использованию
feedback_log.jsonlФайл с логами фидбека (создаётся после первого фидбека)

Дополнительные результаты

  • Возможность легко адаптировать под реального агента (достаточно заменить импорт mock_agent на реальный).
  • JSON-формат трассировки, пригодный для последующего анализа в дашбордах.

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

СложностьРешение
Агент работает асинхронно и долго (блокирует UI)Использовать threading или запускать агента в отдельном треде; показывать спиннер и прогресс по шагам через st.empty
Трассировка не помещается на экран (много шагов)Использовать st.expander с дефолтным закрытым состоянием для старых шагов; добавить кнопку «Свернуть все»
Потеря состояния при повторном запускеВсё хранить в st.session_state (трассировка, ответ, флаги). Не использовать глобальные переменные
Фидбек случайно теряется при обновлении страницыСохранять фидбек сразу в файл (через st.button), а не только в session_state
Неудобно тестировать без реального агентаСоздать mock_agent.py с управляемыми задержками и детерминированной трассировкой

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

ЭтапВремя
Этап 1: Проектирование макета0.5 ч
Этап 2: Базовый UI (ввод + ответ)1 ч
Этап 3: Визуализация трассировки1 ч
Этап 4: Фидбек и логирование0.75 ч
Этап 5: Тестирование и упаковка0.75 ч
Итого4 ч

При первом выполнении (одновременное изучение Streamlit и создание заглушки агента) заложите дополнительно 1–2 часа.


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

ВопросТема
12ReAct паттерн: как устроен цикл агента
43Streamlit: базовые компоненты и стейт-менеджмент
87Визуализация шагов агента (трассировка)
110Сбор фидбека от пользователей в AI-системах
152Обработка ошибок в streamlit‑приложениях
189JSONL формат для логов: структура и чтение
234Интеграция LangChain с Streamlit
310Потоковый вывод ответов агента (streaming)
402Тестирование агентов: ручное vs автоматическое
501Создание mock-объектов для юнит-тестов агента

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

  • Я создал файл playground.py и убедился, что он запускается командой streamlit run playground.py.
  • Я протестировал как минимум три разных запроса (короткий, длинный, с ошибкой в агенте).
  • Я проверил, что каждый шаг трассировки отображается и содержит все поля из схемы.
  • Я отправил фидбек и убедился, что запись появилась в feedback_log.jsonl.
  • Я написал README с точной командой запуска и примерами использования.
  • Я упаковал все файлы в одну папку и проверил, что зависимости устанавливаются из requirements.txt.