Наблюдаемость: метрики, логи, трейсы
Три столпа, стек Prometheus + Loki + Grafana, что мерить в AI-продукте и как связать три источника
Наблюдаемость: метрики, логи, трейсы
Мониторинг отвечает на вопрос «работает ли?», наблюдаемость — на вопрос «почему сломалось?», причём для поломки, которую вы не предвидели. Разница практическая: первое — это график с зелёной галочкой, второе — возможность за десять минут дойти от «пользователь жалуется» до конкретной строчки и конкретного запроса.
Три столпа и вопросы, на которые они отвечают
| Столп | Что это | Вопрос | Инструмент |
|---|---|---|---|
| Метрики | Числа во времени, дёшево хранить | Что и когда пошло не так? | Prometheus |
| Логи | События с контекстом, дороже | Что именно произошло в этот момент? | Loki |
| Трейсы | Путь одного запроса по системе | Где потерялось время и на каком шаге упало? | Tempo, Langfuse |
Порядок расследования всегда один: метрика показывает аномалию, трейс находит шаг, лог объясняет причину. Стек нужен целиком именно потому, что каждый следующий шаг без предыдущего означает «искать вручную».
- Prometheus ходит по
/metricsваших сервисов и складывает ряды. Формат простой текстовый, клиентские библиотеки есть везде. - Loki хранит логи не как полнотекстовый индекс, а по меткам (
service,env,level) — поэтому дёшево и хорошо ложится на один сервер. - Grafana — одно окно: дашборды поверх обеих баз и алерты.
Что мерить в AI-продукте
Обычные четыре сигнала (нагрузка, задержка, ошибки, насыщение) остаются, но добавляются свои — иначе продукт «работает», а денег нет:
- Стоимость. Токены и рубли на запрос, на пользователя, в сутки. Метрика, которая раньше всех показывает, что промпт распух.
- Задержка отдельно для вызовов модели. Общий p95 API маскирует то, что модель отвечает по восемь секунд.
- Доля деградаций. Как часто сработал фолбэк, ретрай, кэш вместо живого ответа — это альтернативы из ваших UC, ставшие метрикой.
- Качество. Доля ответов, не прошедших проверку формата или валидацию; оценки из evals по свежему трафику.
Полезное правило: если в UC написано «система деградирует на архив» — это счётчик. Не измеряете деградации — не узнаете, что продукт наполовину живёт на фолбэках.
Связка: один запрос — одна история
Три столпа сходятся только при общем идентификаторе. trace_id
рождается на входе в систему, кладётся в лог каждой записи, в спан
трейса и в атрибуты трейса LLM. Тогда из графика в Grafana можно
провалиться в конкретный запрос, а из него — в логи именно этого
запроса.
Без этого получается три отдельных инструмента и ручное сопоставление по времени — то, ради чего наблюдаемость и заводили, не работает.
Минимум для лабы 3–4:
# compose.yml — стек рядом с продуктом
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
loki:
image: grafana/loki:latest
grafana:
image: grafana/grafana:latest
ports:
- "3001:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
volumes:
- grafana:/var/lib/grafana
volumes:
grafana:Дашборды и источники данных тоже as-code:
JSON дашборда и provisioning-файлы лежат в monitoring/ в репозитории.
Дашборд, собранный кликами и живущий только в одном браузере, — это не
артефакт, его нельзя ни сдать, ни восстановить.
Алерты
Алерт имеет смысл, только если на него кто-то реагирует ночью или его не должно быть. Для проекта курса хватает трёх:
- Сервис не отвечает (health-чек падает N минут).
- Доля ошибок выше порога за окно.
- Стоимость за сутки превысила бюджет.
Всё остальное смотрится глазами на дашборде: когда алертов много, команда перестаёт на них реагировать.
Дальше — Langfuse: третий столп для той части системы, где обычные трейсы бесполезны.