Настроить playground для тестирования агента
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить playground для тестирования агента
1. Цель задачи
Создать интерактивный UI‑playground, позволяющий разработчикам и QA‑инженерам вручную тестировать AI‑агента без написания кода. Интерфейс должен предоставлять поле ввода запроса, визуализировать полную трассировку работы агента (мысли, действия, наблюдения) и собирать фидбек от тестировщика. Результат — рабочий веб‑интерфейс, который ускоряет итерации отладки агента до нескольких секунд.
Ключевой результат Запускаемый одной командой playground, в котором можно ввести запрос, увидеть пошаговую логику агента и оставить оценку качества ответа.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Агент (реальный или заглушка) | Собственный проект на LangChain / LlamaIndex или простая Python‑реализация ReAct |
| Требования к UI | Описаны ниже в этом ТЗ |
| Инструмент для быстрого UI | Streamlit / Gradio (установить через pip) |
| Данные для тестирования | Ручной набор тестовых запросов (3–5 штук) |
Если нет реального агента — симулируем:
- Создать файл
mock_agent.py, реализующий простой ReAct‑цикл:think— генерирует случайную "мысль" (например, "Нужно найти информацию о ...")- act — эмулирует вызов инструмента (возвращает фиктивный результат)
observe— обрабатывает результат и формирует следующий шаг- После 2–3 итераций возвращает финальный ответ
- Все шаги сохранять в список словарей с ключами: step,
type(think/act/observe),content,tool_used(если есть),duration_ms. - Экспортировать функцию run_agent(query: str) -> tuple[str, list[dict]].
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Фреймворк UI | Streamlit 1.28+ | Быстрое создание веб‑интерфейса |
| Агент (реальный или мок) | Python, LangChain / LlamaIndex / самописный | Обработка запросов и генерация трассировки |
| Логирование трассировки | JSON + st.session_state | Хранение истории шагов текущей сессии |
| Сбор фидбека | Streamlit компоненты (st.radio, st.button, st.text_area) | Оценка ответа пользователем |
| Версионирование | Git | Хранение исходного кода playground |
4. Этапы выполнения
Этап 1: Проектирование макета UI и архитектуры (30 минут)
Действия
-
Нарисовать макет интерфейса на бумаге или в Figma:
- Левая панель (или верхняя область): поле ввода запроса + кнопка «Отправить».
- Центральная область: вывод финального ответа агента.
- Ниже ответа: интерактивное дерево/список трассировки (раскрывающиеся шаги).
- Правая панель или низ: блок фидбека (оценка от 1 до 5, текстовый комментарий, кнопка «Отправить фидбек»).
- Кнопка «Очистить историю» / «Новая сессия».
-
Определить структуру данных трассировки:
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 и т.д. ] -
Выбрать подход к отображению трассировки:
Ожидаемый результат этапа Чёткий план расположения элементов и формат данных трассировки.
Этап 2: Реализация базового UI ввода и вывода ответа (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("🚀 Отправить") -
Реализовать обработку запроса:
if run_button and query: with st.spinner("Агент думает..."): answer, trace = run_agent(query) st.session_state.last_answer = answer st.session_state.trace = trace -
Вывести финальный ответ:
if st.session_state.last_answer: st.subheader("📝 Ответ агента") st.info(st.session_state.last_answer)
Ожидаемый результат этапа Рабочее поле ввода, кнопка, после нажатия отображается ответ агента (без трассировки пока).
Этап 3: Визуализация трассировки (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']} мс") -
Добавить сводную статистику:
- Общее количество шагов, общее время выполнения, список использованных инструментов.
- Вывести в виде метрик st.metric.
-
Проверить на тестовом запросе — все шаги раскрываются, информация читаема.
Ожидаемый результат этапа При нажатии «Отправить» под ответом видна полная трассировка в раскрывающихся блоках.
Этап 4: Сбор фидбека и логирование (45 минут)
Действия
-
Добавить блок фидбека после трассировки:
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("Фидбек сохранён!") -
Добавить кнопку «Новая сессия», которая очищает st.session_state.trace и
last_answer, оставляя ввод пустым. -
Улучшить UX: если трассировки нет, блок фидбека не показывается; после отправки фидбека поля сбрасываются.
Ожидаемый результат этапа Возможность оценить ответ, оставить комментарий, данные фидбека пишутся в JSONL‑файл.
Этап 5: Тестирование, полировка и упаковка (45 минут)
Действия
-
Запустить playground локально:
streamlit run playground.py -
Протестировать на наборе запросов:
- Проверить, что при пустом запросе кнопка не вызывает ошибок.
- Проверить, что трассировка корректно отображается для 1, 2, 5 шагов.
- Проверить отправку фидбека и чтение файла feedback_log.jsonl.
-
Добавить минимальную обработку ошибок:
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}] -
Создать requirements.txt:
streamlit>=1.28 # Если используется LangChain: langchain-core, openai и т.д. -
Написать короткий 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. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | ReAct паттерн: как устроен цикл агента |
| 43 | Streamlit: базовые компоненты и стейт-менеджмент |
| 87 | Визуализация шагов агента (трассировка) |
| 110 | Сбор фидбека от пользователей в AI-системах |
| 152 | Обработка ошибок в streamlit‑приложениях |
| 189 | JSONL формат для логов: структура и чтение |
| 234 | Интеграция LangChain с Streamlit |
| 310 | Потоковый вывод ответов агента (streaming) |
| 402 | Тестирование агентов: ручное vs автоматическое |
| 501 | Создание mock-объектов для юнит-тестов агента |
10. Чек-лист самопроверки
- Я создал файл playground.py и убедился, что он запускается командой streamlit run playground.py.
- Я протестировал как минимум три разных запроса (короткий, длинный, с ошибкой в агенте).
- Я проверил, что каждый шаг трассировки отображается и содержит все поля из схемы.
- Я отправил фидбек и убедился, что запись появилась в feedback_log.jsonl.
- Я написал README с точной командой запуска и примерами использования.
- Я упаковал все файлы в одну папку и проверил, что зависимости устанавливаются из requirements.txt.