LLM Observability в production: метрики, трейсы и алерты

Автор: Обновлено

Что такое LLM observability?

LLM observability — практика сквозного восстановления AI-запроса и измерения того, решил ли он задачу пользователя безопасно, быстро и в заданном бюджете. Она объединяет traces, metadata моделей и tools, версии промптов, quality scores, продуктовые outcomes и alerts.

TL;DR

  • -Model latency и HTTP status недостаточны: LLM-запрос может технически пройти и всё равно не решить задачу пользователя
  • -Один root observation должен представлять пользовательскую задачу, а дочерние — retrieval, tools, model calls, parsing и guardrails
  • -Измеряйте contract failures, качество задачи, latency, cost per successful task и продуктовый outcome, а не только токены и model IDs
  • -Привязывайте версии промпта и релиза к generation, чтобы регрессию можно было связать с точным изменением
  • -Маскируйте чувствительные данные до export, ограничивайте доступ, осознанно задавайте retention и проверяйте отказ telemetry без отказа продукта

LLM-endpoint может вернуть 200 OK, уложиться в latency target и выдать уверенный неверный ответ. В этом и состоит observability gap: инфраструктурная telemetry видит завершённый запрос, но не видит решённую задачу.

Production LLM observability связывает весь путь:

request → retrieval → tool calls → model generations → parser → guardrail → outcome

Для каждой задачи нужно уметь ответить:

  • что произошло и в каком порядке;
  • какие prompt, model, tools и retrieval release использовались;
  • где потрачены время и деньги;
  • прошёл ли output контракт и помог ли пользователю;
  • изменил ли новый release любой из этих сигналов.

Langfuse — одна из практических реализаций. Это open-source платформа с OpenTelemetry-based SDK, tracing, prompt management, evaluation и metrics. Здесь речь об эксплуатации этого контура. Установка вынесена в отдельный пошаговый гайд по Langfuse. Контракты, роутинг, отказоустойчивость и релизы вокруг этого контура разобраны в общем руководстве по production LLM stack.

Начинайте с задачи, а не с model call

Полезная граница trace — одна пользовательская задача: классифицировать тикет, ответить в support, собрать маршрут или проверить pull request. Trace одного provider call теряет retrieval и tool steps, которые часто и вызвали ошибку.

Рабочая иерархия выглядит так:

root: answer-support-question
├── span: load-account-policy
├── span: retrieve-help-center
├── generation: draft-answer
├── tool: check-subscription-status
├── generation: revise-answer
└── span: validate-citations

В Langfuse observations являются OpenTelemetry spans. Generation — специализированный observation с model, parameters, token usage, cost и timing. Tool и retrieval observations сохраняют немодельную работу в одном причинном дереве. Актуальное SDK overview описывает mapping на OpenTelemetry и context propagation.

Не создавайте плоский список generations в надежде восстановить parentage позже. Передавайте trace context через async jobs и границы сервисов с самого начала.

Минимальный trace на актуальном Python SDK

Текущий Python SDK использует OpenTelemetry-based observation API:

from langfuse import get_client

langfuse = get_client()

with langfuse.start_as_current_observation(
    as_type="span",
    name="answer-support-question",
    input={"ticket_id": ticket_id},
) as root:
    with langfuse.start_as_current_observation(
        as_type="generation",
        name="draft-answer",
        model=model_id,
        input=messages,
        prompt=prompt,
    ) as generation:
        response = call_model(model_id=model_id, messages=messages)
        generation.update(output=response)

    root.update(output={"status": "completed"})

Credentials задаются через environment variables, а не через source code. В long-running service SDK экспортирует данные асинхронно. В short-lived job вызовите flush до завершения процесса.

Связь prompt=prompt принципиальна: она прикрепляет точную managed prompt version к generation и позволяет строить prompt-level metrics и разбирать rollback. Полный release workflow описан в гайде по prompt engineering в production.

Спроектируйте telemetry contract

Instrumentation быстро расползается, если каждая команда придумывает names и metadata. До дашборда задайте небольшую общую схему.

Names

Используйте стабильные имена задач, а не route paths и model names:

support.answer
travel.itinerary.create
code_review.pull_request

Model — dimension, а не identity задачи. После смены модели time series должен продолжиться.

Dimensions

Добавляйте только dimensions, по которым будете фильтровать или группировать:

DimensionПримерНа какой вопрос отвечает
environmentproductionПроблема только в одной среде?
releaseGit SHA или app versionКакой release изменил поведение?
featureitineraryКакой product surface создаёт cost?
prompt versionсвязанный prompt objectРегрессию вызвал prompt release?
modelruntime model IDИзменился routing или provider?
session_idстабильный internal IDMulti-turn flow сломался посередине?
tagscanary, paidПроблема только у одной когорты?

Не используйте email и внешние account IDs в tags. High-cardinality dimensions полезны для debugging, но неудобны и дороги в dashboards. Стабильные внутренние ID нужны там, где требуется восстановление сессии или deletion workflow.

Inputs и outputs

«Логировать всё» не должно быть default. Отдельно решите, сохранять ли:

  • production input и output;
  • retrieved documents;
  • tool arguments и results;
  • model configuration;
  • error bodies;
  • evaluation reasoning.

Operational metrics можно сохранить без исходного content. Относитесь к traces как к production dataset с теми же правилами доступа и retention, что у исходных данных.

Измеряйте пять слоёв, а не один dashboard

1. Contract correctness

Эти сигналы детерминированы и должны быть дешёвыми:

  • ошибки JSON или schema validation;
  • отсутствие обязательных fields;
  • невалидные или неразрешённые tool calls;
  • ссылки на несуществующие citations;
  • retry exhaustion и включение fallback;
  • пустой или обрезанный output.

Contract error — не «низкое качество», а поломанный интерфейс. Обычно он должен останавливать rollout раньше субъективного score.

2. Качество задачи

Langfuse хранит результаты evaluation как scores. Score может прийти из user feedback, human annotation, deterministic code, LLM judge или experiment. Актуальная модель scores поддерживает numeric, categorical, boolean и text values.

Выбирайте score под задачу:

ЗадачаСигнал лучше абстрактного «helpfulness»
Classificationкорректность label по class и failure slice
Extractionschema validity и field-level precision/recall
RAG answercitation validity, groundedness, полнота ответа
Agent workflowtask completion, tool errors, лишние steps
Customer supportaccepted answer, correction, reopen, escalation

Для output, который нельзя оценить детерминированно, используйте LLM-as-a-Judge, но калибруйте judge по решениям людей. Judge — измерительный инструмент, а не ground truth.

3. Operations

Измеряйте end-to-end и per-observation значения:

  • request volume и error rate;
  • p50, p95 и p99 task latency;
  • provider latency и time to first token, если доступен;
  • retries, rate limits, timeouts и fallback usage;
  • queue delay и evaluator lag.

Медленный tool call и медленный model call требуют разных владельцев. Для этого и нужно дерево trace.

4. Economics

Tokens — вход для расчёта стоимости, но не продуктовая метрика. Считайте:

  • cost per task;
  • cost per successful task;
  • cost по feature, release, prompt version и model route;
  • retry и fallback cost;
  • стоимость evaluators отдельно.

Дешёвый ответ, после которого растут reopens и ручные исправления, может оказаться дороже на уровне workflow.

5. Product outcome

Свяжите trace ID с downstream event, который означает успех: accepted suggestion, completed booking, resolved ticket, merged pull request или retained user. Без этой связи observability оптимизирует proxy, пока продукт становится хуже.

Sampling: сохраняйте редкие failures, семплируйте обычный success

Одинаковое сохранение 10% всех traces просто, но часто неверно. Сохраняйте:

  • каждый contract failure и provider error;
  • весь canary traffic на маленьком rollout;
  • sessions с явным negative feedback;
  • high-cost и high-latency outliers;
  • репрезентативный sample обычного success.

Дорогие evaluators запускайте на контролируемой выборке. Langfuse использует детерминированный evaluator sampling: evaluators с одинаковыми filters и rate могут получить один и тот же subset. Сравнение scores будет чище, чем на независимых random samples.

Запишите sampling policy рядом с dashboard. Quality rate по flagged failures нельзя сравнивать с rate по случайному трафику.

Alerts: связывайте симптом с действием

Не алертите по каждой raw metric. У alert должны быть owner, comparison window, minimum sample и понятная реакция.

AlertС чем сравниватьПервое действие
Contract failuresтекущий release против recent baselineостановить rollout; проверить parser/tool schema
Quality regressionprompt/model version и failure sliceпоставить canary на паузу; открыть scored examples
Cost per successfeature и model routeпроверить retries, context size, routing
p95 task latencytrace и child observationнайти slow span до настройки модели
Provider errorsprovider, region, error classвключить или проверить fallback policy
Telemetry delayingestion timestamp против event timeпроверить exporter, queue, worker, storage

Thresholds задаются по наблюдаемой дисперсии и business impact. Универсальное правило «10% regression» шумит на низком трафике и пропускает абсолютные ошибки в high-risk workflow.

Dashboard должен показывать моменты смены версий. Alert без application release, prompt version, model route и environment отправляет on-call инженера в ручные раскопки.

Privacy и retention — часть instrumentation

Промпты и tool results часто содержат персональные или конфиденциальные данные. Маскируйте их до выхода trace из процесса: post-ingestion cleanup слишком поздний для строгих data boundaries. Для новых Python SDK setup Langfuse рекомендует mask_otel_spans в masking guide.

Минимум:

  1. классифицируйте fields, которые разрешено экспортировать;
  2. маскируйте secrets, tokens, email, телефоны и document content по требованиям;
  3. разделите production и non-production projects и keys;
  4. ограничьте project access и export permissions;
  5. задайте deletion и retention procedure;
  6. тестируйте observability на репрезентативных redacted fixtures.

Self-hosted Langfuse по умолчанию не удаляет event data автоматически. Retention — осознанная настройка продукта или инфраструктуры. В retention documentation описаны доступность по планам, nightly deletion и влияние blob storage.

Cloud или self-hosted: решайте по стоимости эксплуатации

Self-hosted Langfuse больше не является двухконтейнерным PostgreSQL stack. Актуальный Langfuse v4 использует web и worker services, Postgres, ClickHouse, Redis или Valkey и S3-compatible blob storage. Docker Compose поддерживается для local и low-scale развёртывания; официальный self-hosting guide рекомендует managed или orchestrated варианты для production scale и high availability.

Self-hosting оправдан, когда организации нужны data locality, network isolation или контроль инфраструктуры и она готова отвечать за:

  • backups и restore drills;
  • schema и version upgrades;
  • ClickHouse capacity и retention;
  • queue и worker health;
  • object storage lifecycle;
  • authentication, TLS и secrets;
  • alerting самой observability-системы.

Cloud выбирайте, когда managed operations ценнее самостоятельной эксплуатации этого stack. Не называйте self-hosting более дешёвым, пока не посчитано инженерное время и восстановление после сбоев.

Миграция старой Langfuse instrumentation

Если код всё ещё использует langfuse.trace(...), trace.generation(...) или legacy batch ingestion, не копируйте старые примеры в новые сервисы. Langfuse v4 работает по observations-first модели на OpenTelemetry. Python SDK v4 и JS/TS SDK v5 по умолчанию используют актуальные data APIs.

Compatibility guide перечисляет требования к server и SDK, deprecated endpoints и migration deadlines. Там же указано, что старые SDK или OTLP exporter без актуального ingestion header могут показывать данные в v2 API с задержкой. Проверяйте freshness, прежде чем считать пустой dashboard признаком спокойной системы.

Практический rollout

День 1: одна задача. Проследите один пользовательский path целиком: retrieval, tools, model calls, parsing и финальный status.

День 2: contract signals. Добавьте schema failures, retries, fallback usage, latency и cost. Проверьте, что отказ telemetry не ломает запрос пользователя.

День 3: один quality score. Выберите сигнал, связанный с задачей, прикрепите его к тому же trace и посмотрите примеры с обоих концов distribution.

День 4: versions и privacy. Добавьте release и prompt versions. Настройте masking, access и retention до расширения coverage.

День 5: один actionable alert. Начните с failure, у которого понятны owner и response. В безопасной среде намеренно создайте условие и проверьте alert.

Затем повторите для следующего важного workflow. Цель — не максимальное количество traces. Цель — минимальный путь от «пользователи говорят, что AI стал хуже» до точного release, prompt, model route, tool call и failed example, которые объясняют почему.

Часто задаваемые вопросы

Чем LLM observability отличается от обычного APM?
APM по-прежнему отвечает за инфраструктуру, ошибки и latency. LLM observability добавляет model input и output, токены и стоимость, версии промптов и моделей, tool trajectory, retrieval context и quality scores: успешный HTTP-ответ не доказывает полезность результата.
Что должен представлять один trace в Langfuse?
Один trace — одна пользовательская задача или транзакция. Retrieval, tool calls, model generations, parsing и validation идут дочерними observations. Тогда end-to-end latency, стоимость и успех относятся к одной и той же задаче.
Обязательно ли хранить исходные промпты и ответы?
Нет. Храните только то, что требуется для debugging и evaluation. Маскируйте или пропускайте чувствительные input, output и metadata до export; используйте стабильные внутренние ID для агрегации и удаления; отдельно задавайте доступ и retention.
Стоит ли self-host Langfuse?
Self-host оправдан, когда data residency, network isolation или контроль инфраструктуры важнее стоимости эксплуатации Postgres, ClickHouse, Redis или Valkey, blob storage, web и worker services. Для managed path используйте Langfuse Cloud. Docker Compose подходит для локального и low-scale запуска, но не является готовой high-availability архитектурой.