Агент с наблюдаемостью (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 |
| Prometheus | prom/prometheus:latest |
| Grafana | grafana/grafana:latest |
| Python 3.10+ с библиотеками | pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc opentelemetry-instrumentation-requests prometheus-client |
Если нет реального агента — симулируем:
- Напишите простой LLM-агент на Python, который принимает запрос, вызывает requests к локальному эндпоинту (или эмулирует LLM вызов через time.sleep(0.3)) и возвращает ответ.
- Добавьте кеширование (например, functools.lru_cache или простой dict).
- Этот агент будет инструментироваться в рамках задачи.
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 мин)
Действия
- Создать docker-compose.yml со следующими сервисами:
- jaeger (на портах 16686, 14250, 6831/udp)
- prometheus (порт 9090, конфигурация prometheus.yml с target на otel-collector:8889 и на агента)
- otel-collector (порт 4317 для OTLP, 8889 для метрик Prometheus)
- Ваш агент (порт 8000 / 5000)
- Настроить 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] - Запустить docker-compose up -d и проверить доступность сервисов:
- Jaeger UI: http://localhost:16686
- Prometheus: http://localhost:9090
- Агент: http://localhost:8000/health
Ожидаемый результат этапа Все сервисы запущены и готовы к приёму данных.
Этап 2: Инструментирование агента (60–90 мин)
Действия
- Установить зависимости
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc prometheus-client - Создать 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() - Добавить метрики (Prometheus):
request_latency_seconds(Histogram) – латентность вызова агента- request_count_total (Counter) – общее количество запросов
- request_errors_total (Counter) – количество ошибок
- cache_hit_total (Counter) – попадания в кеш
- Экспозиция метрик через prometheus_client.start_http_server(8001).
- Инструментировать ключевые функции агента
- Проверить, что после запуска агента в Jaeger появляются spans, а в
http://localhost:8001/metricsвидны метрики.
Ожидаемый результат этапа При каждом запросе к агенту создаётся трейс в Jaeger; метрики доступны по HTTP.
Этап 3: Настройка сбора и отображения метрик в Prometheus и Grafana (40–60 мин)
Действия
- Добавить в
prometheus.ymlцель для метрик агента:scrape_configs: - job_name: 'ai-agent' static_configs: - targets: ['agent:8001'] # в docker-compose имя сервиса - Перезапустить Prometheus, убедиться в
http://localhost:9090/targets, что цельUP. - Настроить Grafana
- Добавить Data Source: Prometheus (URL:
http://prometheus:9090) - Импортировать дашборд
13658(OpenTelemetry Collector Dashboard) или создать свой.
- Добавить Data Source: Prometheus (URL:
- Создать собственный дашборд с панелями:
- 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 (не обязательно)
- Проверить, что все панели отображают реальные данные при выполнении запросов к агенту.
Ожидаемый результат этапа Рабочий дашборд в Grafana с метриками агента.
Этап 4: Тестирование и демонстрация (30–45 мин)
Действия
- Запустить нагрузочный тест (например, 100 запросов
ab -n 100 http://localhost:8000/query?text=testили скриптом Python). - В Jaeger:
- Отфильтровать трейсы по
service.name = ai-agent - Выбрать самый медленный трейс, проанализировать, какой span занял больше всего времени.
- Отфильтровать трейсы по
- В Grafana:
- Проверка аварийного сценария временно отключите LLM (заставьте агент выбрасывать исключение), убедитесь, что
request_errors_totalувеличивается, а в Jaeger появляются spans с ошибкой.
Ожидаемый результат этапа Полноценная демонстрация наблюдаемости: трейсы в Jaeger, метрики в Prometheus, дашборд в Grafana.
Этап 5: Документирование (20–30 мин)
Действия
- Написать краткую документацию в
README.md:- Архитектура (схема: агент → OTLP → Collector → Jaeger / Prometheus → Grafana)
- Инструкция по запуску
docker-compose up - Как посмотреть трейсы и дашборд
- Включить скриншоты дашборда и пример трейса.
Ожидаемый результат этапа Документированный проект с инструкцией по развёртыванию.
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 + Grafana | 50 |
| Этап 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 |
| 89 | Best practices для именования spans |
| 124 | Мониторинг LLM-агентов: ключевые метрики |
| 201 | Развертывание стека наблюдаемости через docker-compose |
| 317 | Обработка ошибок и метрики error rate |
10. Чек-лист самопроверки
- Я убедился, что все сервисы из
docker-compose.ymlзапускаются без ошибок. - Я протестировал, что при запросе к агенту в Jaeger появляется трейс с ожидаемыми spans.
- Я проверил, что Prometheus собирает метрики с агента (цель
UP). - Я создал дашборд в Grafana, отображающий минимум 4 панели с реальными данными.
- Я написал README, в котором новичок сможет за 5 минут запустить проект.