Как вы логируете и дебажите многошаговые агенты?

Краткий тезис

Многошаговые агенты — это системы, которые выполняют последовательность вызовов LLM, инструментов и логических решений, часто с циклами и ветвлениями. Без структурированного логирования и трейсинга (tracing) отладка таких агентов превращается в «чёрный ящик»: невозможно понять, почему агент принял неверное решение или зациклился. Ключевой подход — записывать каждый шаг в формате «мысль → действие → наблюдение» (ReAct-паттерн) с помощью специализированных инструментов (LangSmith, LangFuse), которые визуализируют граф вызовов, замеряют latency и позволяют воспроизводить сессии.


1. Термины и контекст

Многошаговый агент (multi-step agent) — программа, которая в цикле вызывает LLM, интерпретирует ответ, выбирает следующее действие (вызов инструмента, запрос к БД, переход к другому агенту) и повторяет до достижения цели или лимита шагов. Примеры: ReAct-агенты, Plan-and-Execute, Agentic RAG.

Логирование (logging) — запись событий (входные/выходные данные, ошибки, метаданные) в структурированном виде (JSON, таблицы) для последующего анализа.

Дебаг (debugging) — процесс поиска и исправления ошибок в поведении агента. Включает воспроизведение сценария, анализ логов, сравнение ожидаемого и фактического поведения.

Трейсинг (tracing) — форма логирования, которая фиксирует полную цепочку вызовов (trace) — от пользовательского запроса до финального ответа, включая все вложенные вызовы LLM, инструментов и под-агентов. Позволяет видеть «граф» выполнения.

ReAct-паттерн — архитектура агента, где на каждом шаге LLM генерирует мысль (рассуждение), действие (вызов инструмента) и наблюдение (результат действия). Этот паттерн естественно ложится в структуру лога.


2. Почему отладка многошаговых агентов сложнее обычных RAG-систем?

АспектОбычная RAGМногошаговый агент
Количество вызовов LLM1 (генерация ответа)от 2 до десятков (планирование, выполнение, рефлексия)
Ветвлениянетесть (if-else, циклы, параллельные вызовы)
Зависимость от состояниянет (каждый запрос независим)есть (агент накапливает контекст, память)
Недетерминизмумеренный (разные ответы на один запрос)высокий (разные пути выполнения из-за LLM)
Источники ошибокretrieval + генерацияпланирование, выбор инструмента, выполнение, синтаксис вызова, таймауты

Без логирования каждого шага невозможно ответить на вопросы:

  • Почему агент выбрал именно этот инструмент?
  • Где произошла ошибка — в рассуждении LLM или в работе инструмента?
  • Не зациклился ли агент?
  • Сколько шагов потребовалось и сколько токенов потрачено?

3. Инструменты для трейсинга и логирования

3.1 LangSmith (от LangChain)

  • Трейсинг каждого вызова LLM, инструмента, цепочки.
  • Визуализация графа выполнения (DAG).
  • Метрики: latency, количество шагов, стоимость токенов.
  • Воспроизведение (replay) сессии с теми же параметрами.
  • Аннотации и ручная оценка.

3.2 LangFuse (open-source)

  • Аналогичный функционал: трейсинг, метрики, дашборды.
  • Поддержка не только LangChain, но и LlamaIndex, OpenAI SDK, custom агентов.
  • Сессии — группировка шагов одного диалога.
  • Prompt management — версионирование промптов.

3.3 Weights & Biases (WandB)

  • Tracing через wandb.log и wandb.trace.
  • Хорош для экспериментов и сравнения конфигураций.
  • Меньше специализирован для агентов, но гибок.

3.4 MLflow

  • MLflow Tracing (новый модуль) — захват вызовов LLM и инструментов.
  • Интеграция с OpenTelemetry.

3.5 Самописное логирование

  • JSON-логи в файл/базу данных.
  • Плюс: полный контроль.
  • Минус: нет визуализации, сложно анализировать.

4. Структура лога для многошагового агента

Рекомендуемый формат — запись каждого шага как отдельного события с полями:

{
  "session_id": "abc123",
  "step": 1,
  "timestamp": "2025-03-20T10:00:00Z",
  "type": "thought",
  "content": "Пользователь спрашивает про погоду. Нужно вызвать инструмент get_weather.",
  "llm_call_id": "call_001"
}

Далее:

{
  "session_id": "abc123",
  "step": 2,
  "timestamp": "2025-03-20T10:00:01Z",
  "type": "action",
  "tool": "get_weather",
  "arguments": {"city": "Москва"},
  "llm_call_id": "call_001"
}

Затем:

{
  "session_id": "abc123",
  "step": 3,
  "timestamp": "2025-03-20T10:00:02Z",
  "type": "observation",
  "result": {"temperature": 5, "condition": "облачно"},
  "tool_call_id": "tool_001"
}

И так далее. В конце — финальный ответ агента.

Важные поля

  • session_id — идентификатор диалога.
  • parent_id — для вложенных вызовов (если агент вызывает под-агента).
  • duration_ms — время выполнения шага.
  • error — если шаг завершился ошибкой.
  • token_usage — количество токенов (prompt + completion).

5. Пример интеграции трейсинга (LangChain + LangSmith)

import os
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.callbacks.tracers import LangChainTracer

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your_key"
os.environ["LANGCHAIN_PROJECT"] = "agent_debug"

tracer = LangChainTracer()

@tool
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    # имитация вызова API
    return f"Погода в {city}: 5°C, облачно"

llm = ChatOpenAI(model="gpt-4", temperature=0)
tools = [get_weather]

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, callbacks=[tracer])

response = agent_executor.invoke({"input": "Какая погода в Москве?"})

В LangSmith появится trace с шагами: вызов LLM → мысль → вызов инструмента → наблюдение → финальный ответ. Можно кликнуть на каждый шаг и увидеть входные/выходные данные, длительность, стоимость.


6. Метрики для оценки работы агента

МетрикаОписаниеКак считать
Success rateДоля сессий, где агент достиг цели(успешные сессии) / (все сессии)
Average stepsСреднее количество шагов до завершениясумма шагов / количество сессий
Max stepsМаксимальное количество шагов (показатель зацикливания)максимум по сессиям
Average latencyСреднее время выполнения сессиисумма duration / количество сессий
Token costСтоимость токенов на сессиюсумма prompt_tokens + completion_tokens по всем вызовам LLM
Tool error rateДоля вызовов инструментов, завершившихся ошибкой(ошибки инструментов) / (все вызовы инструментов)
Hallucination rateДоля ответов, содержащих фактические ошибки (требует ручной проверки)(галлюцинации) / (все ответы)

Эти метрики можно собирать автоматически из трейсов и выводить в дашборд.


7. Стратегии дебага

7.1 Воспроизведение сессии

  • Используйте session_id для повторного запуска агента с теми же входными данными.
  • В LangSmith есть кнопка «Replay» — он запускает агента с тем же seed (если задан) и показывает отличия.

7.2 Логирование промежуточных состояний

  • Сохраняйте состояние памяти агента (историю сообщений) на каждом шаге.
  • При ошибке можно восстановить контекст и понять, на каком шаге произошёл сбой.

7.3 A/B тестирование

  • Сравнивайте две версии агента (разные промпты, модели, наборы инструментов) на одном наборе тестовых запросов.
  • Используйте метрики из раздела 6 для объективного сравнения.

7.4 Визуализация графа

  • Инструменты (LangSmith, LangFuse) показывают дерево вызовов. Ищите узлы с большим временем выполнения или ошибками.
  • Если агент зациклился, на графе будет видна повторяющаяся последовательность шагов.

7.5 Логирование не только успехов, но и ошибок

  • Фиксируйте все исключения (timeout, rate limit, некорректный ответ инструмента).
  • Добавляйте в лог stack trace и входные данные, которые привели к ошибке.

8. Продвинутые техники

8.1 Семантическое логирование

  • Вместо сырых JSON-логов используйте векторные эмбеддинги для поиска похожих сессий.
  • Например, если агент часто ошибается на запросах про «погоду», можно найти все такие сессии по эмбеддингу запроса.

8.2 Автоматическая детекция аномалий

  • Настройте алерты на метрики: если success rate упал ниже 80% за последний час, или среднее количество шагов превысило 10.
  • Используйте ML для классификации «хороших» и «плохих» трейсов.

8.3 Интеграция с OpenTelemetry

  • Для production-систем можно экспортировать трейсы в Jaeger или Grafana Tempo.
  • Это позволит объединить логи агента с логированием инфраструктуры (базы данных, API).

9. Сравнение инструментов трейсинга

ИнструментБесплатный tierВизуализация графаReplay сессийИнтеграция с LangChainИнтеграция с LlamaIndexOpen-source
LangSmith5000 шагов/месДаДаНативнаяЧерез callbackНет
LangFuse50 000 шагов/месДаДаНативнаяНативнаяДа
WandBОграниченныйЧастично (таблицы)НетЧерез callbackЧерез callbackНет
MLflowНеограниченноДа (экспериментально)НетЧерез callbackЧерез callbackДа
СамописныйНеограниченноНетНетЛюбаяЛюбаяДа

Рекомендация для разработки и отладки — LangSmith или LangFuse (выбор зависит от бюджета и требований к open-source). Для production с большим объёмом — LangFuse self-hosted или комбинация самописного логирования + OpenTelemetry.


10. Best practices

  1. Логируйте всё, что может пригодиться — входные данные, выходные, метаданные, время, ошибки. Лучше потом отфильтровать лишнее, чем не иметь нужного.
  2. Используйте структурированные форматы (JSON, Protobuf) — это упрощает парсинг и анализ.
  3. Добавляйте идентификаторы сессии и родительского вызова — для построения дерева.
  4. Не логируйте чувствительные данные (пароли, персональные данные) — маскируйте или исключайте.
  5. Настройте алерты на критические метрики (success rate, количество шагов).
  6. Регулярно просматривайте случайные трейсы — это помогает заметить паттерны ошибок.
  7. Версионируйте промпты и конфигурации агента — чтобы можно было сопоставить поведение с версией.
  8. Используйте seed для LLM (если модель поддерживает) — для воспроизводимости.

Пет-проект для закрепления

Задача Создать простого ReAct-агента, который отвечает на вопросы о погоде и времени, и подключить к нему трейсинг через LangFuse (self-hosted или cloud). Затем намеренно внести ошибку (например, неправильное имя инструмента) и отладить её с помощью визуализации.

Инструменты

  • Python, LangChain, LangFuse SDK.
  • OpenAI API (или любая другая LLM).
  • LangFuse (регистрация на cloud.langfuse.com или локальный запуск через Docker).

Шаги:

  1. Установить langchain, langchain-openai, langfuse.
  2. Создать два инструмента: get_weather(city) и get_time(timezone).
  3. Создать ReAct-агента с промптом, который заставляет LLM сначала думать, потом действовать.
  4. Подключить LangFuseCallbackHandler к AgentExecutor.
  5. Запустить несколько запросов (например, «Какая погода в Лондоне?», «Сколько времени в Нью-Йорке?»).
  6. Зайти в дашборд LangFuse, найти трейсы, изучить каждый шаг.
  7. Намеренно изменить имя инструмента в коде (например, get_weathr вместо get_weather) и запустить снова. Посмотреть, как ошибка отобразится в трейсе (вызов инструмента с ошибкой, LLM попытается исправить или зациклится).
  8. Добавить метрику success_rate через API LangFuse и вывести в дашборд.

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


Связь с другими вопросами

ВопросТема
146Как проектировать многошаговых агентов?
148Как обеспечить воспроизводимость агентов?
149Какие метрики использовать для оценки агентов?
150Как тестировать агентов в production?
145Что такое Agentic RAG и чем отличается от обычного RAG?
144Как управлять памятью агента?

Навигация