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

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

Наблюдаемость — способность по логам и метрикам понимать, что и как делает ваша LLM-функция в проде: что запросили, что ответили, сколько это стоило и не сломалось ли.

Что логировать по каждому запросу

ПолеЗачем
модель и версия промптапонять, какой конфиг отвечал
входные сообщения (или их хеш/сводка)воспроизвести и отладить
ответ моделипроверить качество, разобрать жалобы
usage (токены)учёт стоимости
латентностьследить за скоростью
stop_reason и ошибкиловить обрывы и сбои
request idобращаться в поддержку провайдера

Метрики, за которыми следят

  • Латентность (p50/p95): не деградирует ли скорость.
  • Токены и стоимость: суммарно и на запрос; тренды по дням.
  • Доля ошибок: 429, 5xx, таймауты, обрывы по max_tokens.
  • Качество: доля ответов, прошедших валидацию формата; обратная связь пользователей.

Осторожно с приватностью

В логи попадают тексты пользователей — это персональные данные. Не логируйте лишнее, маскируйте чувствительное (почты, телефоны), соблюдайте сроки хранения и требования регуляторов (GDPR и аналоги). Никогда не логируйте ключи API.

Зачем это на практике

Без логов вы узнаёте о проблеме от пользователя, а не от системы, и не можете её воспроизвести. С логами вы видите: вот этот запрос дал плохой ответ — какой был промпт, какая версия, сколько токенов, не оборвался ли он по лимиту. Метрики по токенам ловят дрейф расходов раньше, чем придёт большой счёт. Метрики латентности показывают, когда провайдер «тормозит» и пора включать фолбэк. А request_id из ответа — это то, что просит поддержка провайдера, когда вы сообщаете о сбое.

Практика: единая точка логирования

Раз вызовы LLM собраны в один слой (урок про архитектуру), там же удобно логировать: каждый вызов оборачивается записью запроса/ответа/метрик. Это даёт сквозную картину без дублирования.

def call_llm_logged(messages, prompt_version):
    t0 = time.monotonic()
    resp = client.messages.create(model=MODEL, max_tokens=512, messages=messages)
    log.info({
        "prompt_version": prompt_version,
        "model": MODEL,
        "input_tokens": resp.usage.input_tokens,
        "output_tokens": resp.usage.output_tokens,
        "latency_ms": int((time.monotonic() - t0) * 1000),
        "stop_reason": resp.stop_reason,
        "request_id": resp._request_id,
    })
    return resp

Итог

  • Логируйте модель, промпт-версию, ввод/вывод, токены, латентность, причину остановки и ошибки.
  • Следите за метриками: латентность, стоимость, доля ошибок, качество.
  • Уважайте приватность: маскируйте ПДн, не логируйте ключи.
Проверьте себя
1. Какие данные особенно важно логировать для учёта стоимости?
AТолько текст ответа
BБлок usage с числом входных и выходных токенов
CТолько латентность
DIP-адрес пользователя
2. Что нельзя помещать в логи LLM-приложения?
AЛатентность запроса
BКлючи API
CЧисло выходных токенов
DВерсию промпта
3. Почему наблюдаемость удобно реализовать в едином LLM-слое?
AЭто требование SDK
BВсе вызовы проходят через одно место, поэтому логирование запросов, ответов и метрик не дублируется
CТак ответы становятся точнее
DЭто снижает стоимость токенов
Поддержать проект