Агент с наблюдаемостью (OpenTelemetry)

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Агент с наблюдаемостью (OpenTelemetry)

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

Создать production-подобного агента (LLM-агент, RAG-агент или API-бот), интегрировать систему наблюдаемости через OpenTelemetry. Реализовать traces (распределённую трассировку) для всех ключевых вызовов агента, экспортировать их в Jaeger; добавить метрики (latency, request count, errors, cache hit rate), экспортируемые в Prometheus; построить в Grafana дашборд, объединяющий traces и метрики.
Ключевой результат Рабочий дашборд, на котором видны задержки по шагам агента, частота ошибок и тренд latency.

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

Что нужноОткуда взять
Работающий агент (LLM, RAG или простой API-агент)Pet-проект №221, 222 или созданный в рамках этого ТЗ
OpenTelemetry Collector (opentelemetry-collector)docker-compose образ otel/opentelemetry-collector:latest
Jaeger (все‑в‑одном)jaegertracing/all-in-one:latest
Prometheusprom/prometheus:latest
Grafanagrafana/grafana:latest
Python 3.10+ с библиотекамиpip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc opentelemetry-instrumentation-requests prometheus-client

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

  1. Напишите простой LLM-агент на Python, который принимает запрос, вызывает requests к локальному эндпоинту (или эмулирует LLM вызов через time.sleep(0.3)) и возвращает ответ.
  2. Добавьте кеширование (например, functools.lru_cache или простой dict).
  3. Этот агент будет инструментироваться в рамках задачи.

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

КомпонентИнструментыНазначение
ИнструментированиеOpenTelemetry SDK + auto‑instrumentation (requests)Сбор traces и метрик
ТрассировкаJaeger (all‑in‑one)Визуализация и анализ трейсов
МетрикиPrometheus + prometheus‑clientСбор latency, request count, error rate
ДашбордыGrafanaОбъединённая панель трасс и метрик
КонтейнеризацияDocker / docker‑composeЛокальный запуск стека
АгентPython (fastapi / flask)Приложение для наблюдения
Протокол экспортаOTLP (gRPC) для traces, /metrics endpoint для Prometheus

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

Этап 1: Настройка инфраструктуры наблюдаемости (40–60 мин)

Действия

  1. Создать docker-compose.yml со следующими сервисами:
    • jaeger (на портах 16686, 14250, 6831/udp)
    • prometheus (порт 9090, конфигурация prometheus.yml с target на otel-collector:8889 и на агента)
    • otel-collector (порт 4317 для OTLP, 8889 для метрик Prometheus)
    • Ваш агент (порт 8000 / 5000)
  2. Настроить OpenTelemetry Collector (otel-collector-config.yaml):
    receivers:
      otlp:
        protocols:
          grpc:
    processors:
      batch:
    exporters:
      jaeger:
        endpoint: jaeger:14250
        tls:
          insecure: true
      prometheus:
        endpoint: "0.0.0.0:8889"
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch]
          exporters: [jaeger]
        metrics:
          receivers: [otlp]
          processors: [batch]
          exporters: [prometheus]
    
  3. Запустить docker-compose up -d и проверить доступность сервисов:

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

Этап 2: Инструментирование агента (60–90 мин)

Действия

  1. Установить зависимости
    pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc prometheus-client
    
  2. Создать instrumentation.py с инициализацией трассировщика и метрик:
    from opentelemetry import trace
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.instrumentation.requests import RequestsInstrumentor
    
    trace.set_tracer_provider(
        TracerProvider(resource=Resource.create({"service.name": "ai-agent"}))
    )
    span_exporter = OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True)
    trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(span_exporter))
    RequestsInstrumentor().instrument()
    
  3. Добавить метрики (Prometheus):
    • request_latency_seconds (Histogram) – латентность вызова агента
    • request_count_total (Counter) – общее количество запросов
    • request_errors_total (Counter) – количество ошибок
    • cache_hit_total (Counter) – попадания в кеш
    • Экспозиция метрик через prometheus_client.start_http_server(8001).
  4. Инструментировать ключевые функции агента
    • В каждом обработчике создать span: with tracer.start_as_current_span("call_llm") as span и установить атрибуты (query, model, tokens).
    • В функции кеша добавить атрибут cache.hit = True/False.
  5. Проверить, что после запуска агента в Jaeger появляются spans, а в http://localhost:8001/metrics видны метрики.

Ожидаемый результат этапа При каждом запросе к агенту создаётся трейс в Jaeger; метрики доступны по HTTP.

Этап 3: Настройка сбора и отображения метрик в Prometheus и Grafana (40–60 мин)

Действия

  1. Добавить в prometheus.yml цель для метрик агента:
    scrape_configs:
      - job_name: 'ai-agent'
        static_configs:
          - targets: ['agent:8001']   # в docker-compose имя сервиса
    
  2. Перезапустить Prometheus, убедиться в http://localhost:9090/targets, что цель UP.
  3. Настроить Grafana
  4. Создать собственный дашборд с панелями:
    • Panel 1 Request Latency (Histogram quantiles: p50, p90, p99)
    • Panel 2 Request Rate (rate(request_count_total[1m]))
    • Panel 3 Error Rate (rate(request_errors_total[1m]))
    • Panel 4 Cache Hit Rate (rate(cache_hit_total[1m]) / rate(request_count_total[1m]))
    • Panel 5 Span Duration (Jaeger) – используя Grafana Explore → Jaeger data source (не обязательно)
  5. Проверить, что все панели отображают реальные данные при выполнении запросов к агенту.

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

Этап 4: Тестирование и демонстрация (30–45 мин)

Действия

  1. Запустить нагрузочный тест (например, 100 запросов ab -n 100 http://localhost:8000/query?text=test или скриптом Python).
  2. В Jaeger:
    • Отфильтровать трейсы по service.name = ai-agent
    • Выбрать самый медленный трейс, проанализировать, какой span занял больше всего времени.
  3. В Grafana:
    • Посмотреть, как менялся latency во время нагрузки.
    • Убедиться, что error rate не превышает допустимого порога.
  4. Проверка аварийного сценария временно отключите LLM (заставьте агент выбрасывать исключение), убедитесь, что request_errors_total увеличивается, а в Jaeger появляются spans с ошибкой.

Ожидаемый результат этапа Полноценная демонстрация наблюдаемости: трейсы в Jaeger, метрики в Prometheus, дашборд в Grafana.

Этап 5: Документирование (20–30 мин)

Действия

  1. Написать краткую документацию в README.md:
    • Архитектура (схема: агент → OTLP → Collector → Jaeger / PrometheusGrafana)
    • Инструкция по запуску docker-compose up
    • Как посмотреть трейсы и дашборд
  2. Включить скриншоты дашборда и пример трейса.

Ожидаемый результат этапа Документированный проект с инструкцией по развёртыванию.

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

  • OpenTelemetry SDK установлен и корректно экспортирует трейсы в Jaeger.
  • В Jaeger UI видны трейсы с минимум 4 spans (вход агента, вызов LLM, кеш-чек, ответ).
  • Prometheus успешно собирает метрики с агента (endpoint /metrics).
  • В Prometheus присутствуют как минимум метрики: request_latency_seconds, request_count_total, request_errors_total.
  • Grafana подключена к Prometheus и Jaeger (опционально).
  • Дашборд в Grafana содержит не менее 4 панелей (latency, request rate, error rate, cache hit rate).
  • Нагрузочный тест (100 запросов) явно изменяет значения на дашборде.
  • README.md с описанием архитектуры и инструкцией по запуску.
  • Все сервисы запускаются одной командой docker-compose up.

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

АртефактСодержание
РепозиторийКод агента, конфигурация OpenTelemetry, docker-compose.yml, README.md
Jaeger UI (скриншот)Трейс с детальными spans и атрибутами (query, model, cache.hit)
Grafana дашборд (экспорт JSON или ссылка)4+ панели метрик, обновляющиеся в реальном времени

Дополнительно (опционально):

  • Настройка алертов в Grafana (например, при latency > 5s).
  • Добавление метрик по использованию памяти/CPU агента (через OpenTelemetry или node_exporter).

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

СложностьРешение
Не удаётся подключиться к OpenTelemetry CollectorПроверить, что otel-collector работает, порт 4317 доступен. Использовать docker network ls и проверить, что агент в той же сети compose.
Метрики не попадают в PrometheusУбедиться, что /metrics агента возвращает данные (curl localhost:8001/metrics). Проверить scrape_configs и перезапустить Prometheus.
Трейсы не видны в JaegerПроверить exporter в collector (jaeger endpoint). В агенте использовать правильный endpoint http://otel-collector:4317.
Grafana не может подключиться к PrometheusВ data source указать имя сервиса (prometheus) или IP, не localhost.
Auto‑instrumentation requests не работаетВручную создать span для вызовов requests.get или добавить instrumentor() после импортов.

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

ЭтапВремя (минут)
Этап 1: Настройка инфраструктуры50
Этап 2: Инструментирование агента75
Этап 3: Настройка Prometheus + Grafana50
Этап 4: Тестирование и демонстрация40
Этап 5: Документирование25
Итого240 минут (4 часа)

Примечание для первого раза: Время может увеличиться на 30–60 минут из-за отладки соединений между контейнерами.

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

ВопросТема
1Что такое OpenTelemetry и зачем он нужен?
12Как настроить Jaeger для сбора трейсов?
15Как экспортировать метрики Prometheus из Python?
23Архитектура OpenTelemetry Collector
48Инструментирование FastAPI/Flask с OpenTelemetry
55Создание дашбордов в Grafana
89Best practices для именования spans
124Мониторинг LLM-агентов: ключевые метрики
201Развертывание стека наблюдаемости через docker-compose
317Обработка ошибок и метрики error rate

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

  • Я убедился, что все сервисы из docker-compose.yml запускаются без ошибок.
  • Я протестировал, что при запросе к агенту в Jaeger появляется трейс с ожидаемыми spans.
  • Я проверил, что Prometheus собирает метрики с агента (цель UP).
  • Я создал дашборд в Grafana, отображающий минимум 4 панели с реальными данными.
  • Я написал README, в котором новичок сможет за 5 минут запустить проект.