ВойтиКонтактыНачать бесплатно
Reliability and Routing30 июля 2026 г.Flatkey Team

Наблюдаемость LLM API: метрики, трассировки, логи и стоимость

Практическое руководство по мониторингу LLM API с проверенными метриками успеха, распределёнными трассировками, безопасными структурированными логами, SLO, алертами и стоимостью на принятую задачу.

Наблюдаемость LLM API: метрики, трассировки, логи и стоимость

Наблюдаемость LLM API — это практика превращения каждого вызова модели в достаточно структурированные данные, чтобы ответить на четыре производственных вопроса:

  1. Успешен ли был запрос?
  2. Сколько времени ждал пользователь?
  3. Что запрос потребил и сколько это стоило?
  4. Почему система выбрала именно эту модель, повторную попытку или fallback?

Обычный HTTP-мониторинг необходим, но его недостаточно. 200 OK всё ещё может содержать невалидный JSON, пустой ответ, отказ, сломанный tool call или вывод, нарушающий контракт приложения. Запрос также может завершиться успешно после трёх попыток и незаметно стоить в четыре раза дороже, чем ожидалось.

Практическая цель — не логировать каждый prompt. Цель — создать небольшой, согласованный контракт телеметрии, который связывает результаты приложения с моделью, провайдером, маршрутом, задержкой, использованием токенов, повторными попытками и стоимостью — без утечки пользовательских данных.

Это руководство показывает, как построить такой контракт с помощью метрик, трассировок, структурированных логов, service-level objectives, дашбордов и алертов.

Что должна объяснять наблюдаемость LLM API

Полезная система наблюдаемости позволяет инженеру дежурной смены быстро перейти от симптома к причине.

Производственный вопрос Какие данные нужны
Почему резко выросла задержка? Сквозная длительность, длительность у провайдера, время ожидания в очереди, время до первого токена, модель, регион, число повторных попыток
Почему выросла стоимость? Входные токены, выходные токены, кэшированные токены при наличии, снимок цены модели, количество попыток, доля принятых задач
Почему пользователи видят плохие результаты? Результат валидатора вывода, ошибки схемы, состояние отказа, результат tool call, оценка, версия prompt
Почему трафик перешёл на другую модель? Политика маршрутизации, выбранная цель, причина fallback, состояние circuit breaker, ошибки провайдера
Инцидент связан с конкретным провайдером? Провайдер, модель, аккаунт или deployment, регион, код статуса, ID запроса провайдера
Можем ли мы воспроизвести один запрос? Внутренний ID запроса, ID трассировки, обезличенный отпечаток входных данных, версия prompt, параметры модели

Первое правило проектирования простое: измеряйте контракт приложения, а не только транспортный контракт.

Пять уровней телеметрии

Мониторинг LLM API становится проще, когда вы разделяете пять уровней вместо того, чтобы пытаться поместить все сигналы в один дашборд.

1. Метрики запросов

Метрики показывают тренды и обеспечивают работу алертов. Записывайте счётчики и гистограммы для:

  • Количество запросов
  • Сквозная задержка
  • Время до первого токена для потоковых ответов
  • Задержка у провайдера или при вызове модели
  • Успешные, неудачные, отменённые и завершившиеся по тайм-ауту запросы
  • Ответы HTTP 429 и 5xx
  • Повторные попытки и fallback
  • Входные, выходные и кэшированные токены
  • Оценочная и сверенная стоимость

У метрик должны быть ограниченные по кардинальности labels. Хорошие labels включают provider, model, route, environment, status и error_type. Избегайте labels с высокой кардинальностью, таких как ID пользователей, ID запросов, текст prompt или полные URL.

2. Распределённые трассировки

Трассировка объясняет путь одного запроса через ваш API, очередь, слой извлечения, вызовы инструментов, gateway и провайдера модели.

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

POST /support/reply
├── retrieve_customer_context
├── llm.route
│   ├── llm.attempt provider_a/model_primary
│   └── llm.attempt provider_b/model_fallback
├── validate_structured_output
└── persist_draft

Каждая попытка вызова модели должна быть отдельным span. Если используются два провайдера, трассировка должна показывать две попытки, а не скрывать их обе внутри одного непрозрачного span llm.call.

Семантические конвенции Generative AI от OpenTelemetry предоставляют полезный общий словарь для span-ов, метрик и событий в generative AI. Рассматривайте версию конвенции как часть схемы телеметрии, чтобы можно было осознанно мигрировать по мере изменения атрибутов.

3. Структурированные логи

Логи фиксируют отдельные решения и диагностический контекст, который был бы слишком дорогим или слишком детализированным для меток метрик.

Полезные события включают:

  • llm.request.started
  • llm.route.selected
  • llm.retry.scheduled
  • llm.fallback.selected
  • llm.response.validated
  • llm.request.completed
  • llm.request.failed

Каждое событие должно содержать одинаковые поля корреляции: request_id, trace_id, route, model, provider, prompt_version и attempt.

4. Сигналы качества и контракта

Качество нельзя вывести из кодов статуса. По возможности добавляйте детерминированные валидаторы:

  • JSON успешно распарсен
  • Обязательные поля схемы присутствуют
  • Имя инструмента и аргументы разрешены
  • Список ссылок на источники присутствует, когда это требуется
  • Длина вывода находится в пределах ограничений продукта
  • Распознан отказ или состояние безопасности
  • Проверки бизнес-правил пройдены

Для субъективных задач позже добавляйте результаты выборочной оценки. Связывайте онлайн-телеметрию запросов и офлайн-оценку через стабильный request ID или sample ID.

Перед заменой production-модели используйте повторяемый процесс оценки AI-модели, а не полагайтесь только на агрегированную задержку и цену токенов.

5. Стоимость и бизнес-результаты

Подсчет токенов — это сигнал использования, а не бизнес-результат. Свяжите использование модели с единицей, которая важна для вашего продукта:

  • Стоимость одного принятого ответа службы поддержки
  • Стоимость одной завершенной задачи по программированию
  • Стоимость одного сгенерированного изображения продукта, одобренного рецензентом
  • Стоимость одного обогащенного квалифицированного лида
  • Стоимость одного успешного структурированного извлечения

Наиболее полезная формула:

эффективная стоимость одной принятой задачи = общая стоимость модели / принятые задачи

Это выявляет ложную экономию. Более дешевая модель, которая приводит к большему числу повторных попыток, ошибок валидации или ручной доработке, может увеличить эффективную стоимость.

Минимальный контракт телеметрии для каждого вызова модели

Начните с версионируемой схемы событий. Точные имена полей могут соответствовать вашему стеку observability, но концепции должны оставаться стабильными.

{
  "schema_version": "llm-observability.v1",
  "timestamp": "2026-07-30T09:00:00Z",
  "request_id": "req_internal_01",
  "trace_id": "7c4b...",
  "environment": "production",
  "feature": "support_reply",
  "route": "support-default",
  "provider": "provider-a",
  "model": "model-primary",
  "prompt_version": "support-reply-v12",
  "attempt": 1,
  "stream": true,
  "status": "success",
  "http_status": 200,
  "latency_ms": 1840,
  "time_to_first_token_ms": 410,
  "input_tokens": 1640,
  "output_tokens": 284,
  "cached_input_tokens": 900,
  "estimated_cost_usd": 0.0068,
  "validator": "passed",
  "fallback_reason": null,
  "provider_request_id": "redacted-or-scoped-value"
}

Не делайте необработанные промпты и ответы обязательными полями. Сохраняйте их только тогда, когда есть определённая необходимость, утверждённая политика хранения, соответствующие механизмы контроля доступа и безопасный путь редактирования/маскирования.

Метрики, которые должны быть на первой панели мониторинга

Не начинайте с 40 панелей. Постройте одну операционную панель, которая отвечает на вопрос, получают ли пользователи корректные результаты в рамках бюджета по задержке и стоимости.

Трафик и успешность

  • Запросов в минуту
  • Коэффициент успешности передачи
  • Коэффициент валидированной успешности
  • Коэффициент отмен
  • Коэффициент тайм-аутов
  • Коэффициент усиления повторных попыток
  • Коэффициент использования fallback

Validated success rate должен быть основным сигналом доступности:

validated success rate = requests that pass the application contract / eligible requests

Это строже и полезнее, чем 2xx responses / requests.

Задержка

Отслеживайте распределения, а не средние значения:

  • Задержка end-to-end p50, p95 и p99
  • Задержка вызова провайдера p50, p95 и p99
  • Время до первого токена p50 и p95
  • Ожидание в очереди p95
  • Выполнение инструмента p95
  • Длительность валидации p95

Разделяйте стриминговые и нестриминговые маршруты. Стриминговый запрос может восприниматься как отзывчивый при хорошем времени до первого токена, даже если общее время завершения велико.

Надёжность

  • Частота 429 по провайдеру и модели
  • Частота 5xx по провайдеру и модели
  • Частота сетевых ошибок
  • Частота некорректных или не соответствующих схеме ответов
  • Частота ошибок вызова инструмента
  • Состояние open у circuit breaker
  • Частота исчерпания бюджета повторных попыток

Если ограничения по частоте являются частой причиной, используйте ограниченную стратегию повторных попыток LLM для ограничений RPM и TPM вместо нескоординированных повторов в каждом приложенческом воркере.

Использование и стоимость

  • Входные и выходные токены по feature
  • Токены на принятую задачу
  • Оценочная стоимость на запрос
  • Стоимость на принятую задачу
  • Стоимость повторных попыток
  • Разница стоимости fallback
  • Ежедневные расходы по сравнению с бюджетом
  • Оценка стоимости по сравнению со счётом провайдера или экспортом использования

Сохраняйте и estimated_cost, и reconciled_cost. Первое обеспечивает мониторинг почти в реальном времени; второе корректирует оценки после поступления авторитетных биллинговых данных.

Как отслеживать ретраи и fallback-маршрутизацию

Ретраи и fallback — это место, где базовый мониторинг обычно ломается. Если все попытки используют одно поле статуса, дорогой и деградировавший запрос может выглядеть как исправный.

Для каждой попытки фиксируйте такие поля:

Поле Почему это важно
attempt Показывает усиление нагрузки и порядок принятия решений
target_id Определяет провайдера, развертывание, регион и модель без раскрытия секретов
reason Различает таймаут, 429, 5xx, ошибку валидации и policy routing
remaining_budget_ms Подтверждает, что маршрутизатор соблюдал пользовательский дедлайн
safe_to_repeat Явно показывает решения об идемпотентности
output_started Предотвращает небезопасный fallback после того, как потоковый вывод достиг клиента
contract_compatible Подтверждает, что следующий target поддерживает требуемую схему, инструменты и модальность

Продакшен LLM API fallback routing playbook должен определять политику принятия решений. Затем наблюдаемость должна доказать, что маршрутизатор следовал ей.

Паттерн инструментирования на TypeScript

Следующий пример отделяет телеметрию от конкретного SDK модели. Он записывает один родительский span маршрута и один дочерний span для каждой попытки.

import { context, SpanStatusCode, trace } from "@opentelemetry/api";

const tracer = trace.getTracer("ai-gateway");

type ModelAttempt = {
  provider: string;
  model: string;
  reason: "primary" | "retry" | "fallback";
};

export async function runModelRoute(
  attempts: ModelAttempt[],
  callModel: (attempt: ModelAttempt) => Promise<{
    text: string;
    usage?: { inputTokens?: number; outputTokens?: number };
    providerRequestId?: string;
  }>,
) {
  return tracer.startActiveSpan("llm.route", async (routeSpan) => {
    routeSpan.setAttribute("app.llm.route", "support-default");
    routeSpan.setAttribute("app.llm.attempt_limit", attempts.length);

    try {
      for (const [index, attempt] of attempts.entries()) {
        const result = await tracer.startActiveSpan(
          "llm.attempt",
          { attributes: {
            "gen_ai.system": attempt.provider,
            "gen_ai.request.model": attempt.model,
            "app.llm.attempt": index + 1,
            "app.llm.reason": attempt.reason,
          } },
          context.active(),
          async (attemptSpan) => {
            const startedAt = performance.now();

            try {
              const response = await callModel(attempt);
              const valid = response.text.trim().length > 0;

              attemptSpan.setAttribute("app.llm.validated", valid);
              attemptSpan.setAttribute(
                "gen_ai.usage.input_tokens",
                response.usage?.inputTokens ?? 0,
              );
              attemptSpan.setAttribute(
                "gen_ai.usage.output_tokens",
                response.usage?.outputTokens ?? 0,
              );
              attemptSpan.setAttribute(
                "app.llm.latency_ms",
                performance.now() - startedAt,
              );

              if (!valid) {
                throw new Error("response_validation_failed");
              }

              attemptSpan.setStatus({ code: SpanStatusCode.OK });
              return response;
            } catch (error) {
              attemptSpan.recordException(error as Error);
              attemptSpan.setStatus({
                code: SpanStatusCode.ERROR,
                message: (error as Error).message,
              });
              return null;
            } finally {
              attemptSpan.end();
            }
          },
        );

        if (result) {
          routeSpan.setAttribute("app.llm.selected_attempt", index + 1);
          routeSpan.setStatus({ code: SpanStatusCode.OK });
          return result;
        }
      }

      throw new Error("llm_route_exhausted");
    } catch (error) {
      routeSpan.recordException(error as Error);
      routeSpan.setStatus({
        code: SpanStatusCode.ERROR,
        message: (error as Error).message,
      });
      throw error;
    } finally {
      routeSpan.end();
    }
  });
}

В продакшене добавляйте ваши счётчики метрик и структурированные события логов вместе со спанами. Также сохраняйте идентификаторы запросов провайдера, когда они доступны; они часто необходимы при эскалации инцидента к провайдеру модели. Не включайте эти идентификаторы в публичные сообщения об ошибках.

Логи без утечки промпта

Самый безопасный вариант по умолчанию — ведение логов с приоритетом метаданных.

Логировать по умолчанию

  • Внутренние идентификаторы запроса и трассировки
  • Идентификатор запроса у провайдера
  • Название функции и маршрута
  • Провайдер, модель и псевдоним развёртывания
  • Версия шаблона промпта
  • Параметры, такие как temperature и максимальное количество выходных токенов
  • Использование токенов
  • Задержка и время до первого токена
  • Класс ошибки и решение о повторной попытке
  • Результат валидатора
  • Очищенные имена инструментов

Не логировать по умолчанию

  • Сырые промпты или ответы
  • API-ключи или заголовки авторизации
  • Секреты клиентов
  • Извлечённые документы
  • Аргументы инструментов, содержащие персональные или регулируемые данные
  • Полные пути к файлам или записи базы данных
  • Подписанные URL

Когда захват содержимого необходим для отладки или оценки, собирайте его отдельно, перед сохранением удаляйте чувствительные данные, ограничивайте доступ, шифруйте его и задавайте короткий срок хранения. Руководство по безопасному управлению API-ключами описывает смежные меры контроля для секретов, логирования, ротации и реагирования на инциденты.

SLO для функций на базе LLM

Цель уровня сервиса для LLM должна описывать видимую пользователю функцию, а не учётную запись провайдера.

Примеры SLO для функции структурированных ответов службы поддержки:

SLO Пример целевого значения
Валидированная доступность 99,5% подходящих запросов возвращают выходные данные, соответствующие контракту
Интерактивная задержка 95% выдают первый токен менее чем за 1,5 секунды
Задержка завершения 95% завершаются менее чем за 8 секунд
Ограничение стоимости 99% остаются ниже предельной стоимости на запрос
Ограничение срабатывания fallback Менее 3% требуют fallback в течение скользящего часа

Эти числа — примеры, а не универсальные цели. Определяйте их на основе ожиданий пользователей, сложности задачи, поведения провайдера и юнит-экономики.

Используйте бюджет ошибок, чтобы решать, когда замедлять выпуск функций, ужесточать политику маршрута или перенаправлять трафик. Провайдер может соответствовать собственной цели доступности, а ваш продукт — не достигать своего SLO, потому что очередь, инструменты, валидация или поведение fallback добавляют сбои.

Пейте сигналы, диагностируйте по причинам

Эскалируйте оператору при пользовательском воздействии. Используйте оповещения меньшей важности или аннотации на дашборде для вероятных причин.

Симптомы, требующие эскалации

  • Валидированная доля успешных запросов нарушает SLO
  • p95 времени до первого токена превышает пользовательский порог
  • Резко растёт доля исчерпанных маршрутов
  • Стоимость на принятый запрос превышает ограничение
  • У критической функции нет здоровой целевой системы, совместимой с контрактом

Диагностические сигналы

  • У одного провайдера растёт доля 429
  • Меняется доля ошибок схемы у одной модели
  • Увеличивается усиление повторных попыток
  • Растёт ожидание в очереди
  • Открывается circuit breaker
  • После релиза промпта меняется использование токенов

Не создавайте paging на каждый 5xx у провайдера. Если fallback работает и пользователи по-прежнему получают валидные ответы в пределах бюджета задержки, событие может требовать расследования, но не пробуждения инженера дежурной смены.

Операционная модель с тремя дашбордами

Дашборд 1: Пользовательский опыт

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

Панель 2: Маршрутизация и провайдеры

Показывайте долю трафика, ошибки провайдеров, повторы, резервные переключения, срабатывания circuit breaker, исчерпание маршрутов и задержку по модели и целевому направлению.

Панель 3: Использование и экономика

Показывайте токены, оценочные расходы, сверенные расходы, стоимость на одну принятую задачу, отклонение от бюджета и основные функции по стоимости.

Сохраняйте аннотации о развертывании и версии промпта на всех трёх панелях. Иначе регрессия, которая начинается сразу после релиза, может выглядеть как случайная вариативность провайдера.

Контрольный список внедрения

  1. Определите одну версионируемую схему событий.
  2. Генерируйте внутренний ID запроса на границе продукта.
  3. Передавайте контекст трассировки через очереди, инструменты и вызовы модели.
  4. Создавайте дочерний span для каждой попытки обращения к модели.
  5. Записывайте ID запросов провайдера, когда они возвращаются.
  6. Добавьте детерминированную проверку валидности вывода.
  7. Явно отслеживайте причины повторов и резервных переключений.
  8. Рассчитывайте оценочную стоимость на основе версионируемой таблицы цен.
  9. Сверяйте оценки с официальными экспортами usage или billing.
  10. Постройте одну панель пользовательских результатов до панелей провайдеров.
  11. Установите SLO для валидированного успеха и задержки.
  12. Редактируйте или исключайте промпты, ответы, секреты и чувствительные данные инструментов.
  13. Проводите тесты отказов для timeout, 429, 5xx, некорректного вывода и исчерпания маршрутов.
  14. Проверьте кардинальность меток перед включением метрик в production.
  15. Сэмплируйте трассировки по риску: сохраняйте ошибки и медленные запросы чаще, чем обычные успешные.

Типичные ошибки наблюдаемости

Считать каждый 200 успехом

Добавьте валидаторы контрактов и отдельно отчитайтесь о валидированном успехе.

Логировать сырые промпты для каждого запроса

Это создаёт проблемы с конфиденциальностью, безопасностью, сроками хранения и стоимостью. Предпочитайте метаданные и контролируемое сэмплирование.

Скрывать повторы внутри одной длительности

Создавайте один span и одно событие на каждую попытку, чтобы операторы могли видеть усиление нагрузки.

Использовать имена моделей как единственный идентификатор маршрута

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

Настраивать оповещения по средней задержке

Средние значения скрывают проблемы хвоста распределения. Используйте p95 и p99, а также разделяйте время до первого токена и общее время завершения.

Навсегда доверять оценочной стоимости

Таблицы цен, обработка кэша и учёт провайдера могут меняться. Сверяйте оценки с данными биллинга и фиксируйте версию таблицы цен.

Позволять меткам телеметрии бесконтрольно разрастаться

ID запросов и идентификаторы клиентов должны находиться в трассировках или логах, а не в метках метрик.

Где помогает шлюз AI API

Много-провайдерным приложениям иначе нужны отдельные адаптеры для аутентификации, именования моделей, повторов, полей usage, ошибок и экспортов биллинга. Шлюз может сократить эту область интеграции, предоставляя приложению одну стабильную API-границу и при этом сохраняя сведения о провайдере и модели во внутренней телеметрии.

Flatkey предоставляет один API-ключ, один endpoint, совместимый с OpenAI, и доступ к моделям основных провайдеров. Это позволяет централизовать контракт телеметрии на стороне приложения, даже когда рабочие нагрузки используют разные текстовые, графические или видеомодели. Шлюз не заменяет наблюдаемость на уровне продукта: ваше приложение по-прежнему должно записывать функцию, версию промпта, результат валидации, пользовательскую задержку и итог принятой задачи.

Если ваша команда консолидирует поставщиков, начните с руководства по архитектуре AI API gateway, а затем добавьте контракт телеметрии из этой статьи, прежде чем переводить на продуктивный трафик.

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

Что такое наблюдаемость LLM API?

Наблюдаемость LLM API — это сбор и корреляция метрик, трассировок, логов, проверок качества, данных об использовании и стоимости для функций, работающих на базе моделей. Она объясняет как поведение провайдера, так и то, вернуло ли приложение корректный пользовательский результат.

Что следует мониторить для LLM API?

Мониторьте подтвержденную успешность, сквозную задержку, время до первого токена, задержку провайдера, показатели 429 и 5xx, повторные попытки, fallback-сценарии, использование токенов, оценочную стоимость, стоимость за принятую задачу и сбои в контракте вывода.

Следует ли хранить промпты и ответы в трассировках?

По умолчанию — нет. Сначала храните метаданные. Захватывайте содержимое только для определенной цели отладки или оценки, с редактированием, контролем доступа, шифрованием, выборкой и политикой хранения.

В чем разница между мониторингом LLM и наблюдаемостью LLM?

Мониторинг сообщает, что известная метрика пересекла порог. Наблюдаемость дает достаточно взаимосвязанных данных, чтобы расследовать новые режимы отказа на уровне приложения, маршрута, провайдера, модели, инструментов и контракта вывода.

Как рассчитать стоимость LLM на запрос?

Умножьте оплачиваемые единицы входа, выхода, кэшированного входа, медиа или другие единицы использования на версионную таблицу цен, затем добавьте стоимость повторных попыток и попыток fallback. Сверьте оценку с данными биллинга провайдера или gateway.

Какой request ID следует хранить?

Создайте собственный внутренний request ID и trace ID, а также храните request ID провайдера, если API его возвращает. Внутренние ID связывают ваши системы; ID провайдера помогает при обращении в поддержку и эскалации инцидентов.

Создайте контракт телеметрии до инцидента

Лучшее время решить, что должен фиксировать вызов модели, — до появления продуктивного трафика. Начните с подтвержденной успешности, распределений задержки, одного span на каждую попытку, ограниченных меток метрик, логов с приоритетом метаданных и стоимости за принятую задачу. Затем протестируйте систему, принудительно вызвав сбои, которые, как вы ожидаете, должен обрабатывать маршрутизатор.

Эта основа превращает расплывчатый отчет — «функция ИИ работает медленно и дорого» — в отслеживаемое решение: какая функция, какой маршрут, какая модель, какая попытка, какой сбой, какая задержка и какая стоимость.

Изучите тарифы Flatkey, если готовы сравнить мультимодельные маршруты через один API, совместимый с OpenAI.