Обычный запрос к API либо отработал, либо вернул ошибку, и для отладки этого почти хватает. С LLM сложнее: ответ может быть корректным JSON и совершенно неверным по смыслу, а счёт растёт и на удачных вызовах. Без специального лога ничего из этого не поймать.
Почему нужен отдельный слой логов
Обычные логи приложения фиксируют сам вызов и код ответа. Для LLM этого мало: привычный API либо упал, либо отработал, а модель способна тихо ошибиться внутри вполне успешного ответа.
Отдельный лог вокруг каждого вызова решает две задачи сразу. Он позволяет воспроизвести конкретный случай при отладке и показывает, куда уходят деньги, без ручной сверки таблиц в конце месяца.
Request id на каждый вызов
Первым пишите уникальный идентификатор запроса. Когда запросов тысячи в день, без него не связать жалобу пользователя, строку в логе приложения и конкретный вызов к модели.
Лучше всего сгенерировать id на входе в систему и протащить его через весь путь: от действия пользователя до вызова API и обратно. Тогда одно обращение в поддержку разворачивается в цепочку событий, а не в «где-то что-то пошло не так».
Токены и латентность по каждому вызову
Входные и выходные токены записывайте всегда и отдельно друг от друга. Это нужно и для счёта, и для диагностики. Резкий рост входных токенов часто означает, что в промпт случайно попал лишний контекст. Рост выходных обычно говорит о том, что модель стала отвечать длиннее обычного, иногда из-за изменённого промпта или системной инструкции.
Латентность тоже фиксируйте отдельно от общего времени ответа приложения. У медленного ответа несколько возможных причин: сама модель, сеть, очередь перед вызовом. Раздельный замер сразу показывает, где именно тормозит.
Привязка к ключу и пользователю
Самое полезное и чаще всего пропускаемое: связать каждый вызов с тем, кто его сделал. Какой ключ API, какая команда, какой пользователь или фича внутри продукта. Месячный итог отвечает на вопрос «сколько потратили», но не на вопрос «кто и на что».
Без привязки расследование скачка расходов превращается в перебор гипотез. С ней хватает разбивки: сразу виден ключ или фича, которая вдруг стала делать в разы больше вызовов или выдавать заметно более длинные ответы.
В codexkey статистика уже разложена по ключам. Если выдать отдельный ключ на каждую фичу или команду, привязка получается даром, без дополнительного кода на стороне продукта. Суб-организации с собственными бюджетами и порогами нужны именно для этого: видно, какая команда или продукт подходит к лимиту, пока расход не стал проблемой.
Что из содержимого логировать, а что нет
Полный текст промпта и ответа полезен при отладке, но хранить его как есть не всегда безопасно, особенно если в диалоге может оказаться персональная информация пользователя. Разумный компромисс: полное содержимое писать в отдельное хранилище с ограниченным доступом и коротким сроком хранения, а в основные логи и метрики класть только хеш или короткую выжимку.
Метаданные вызова (модель, версия промпта, название инструмента в агентном сценарии) стоит логировать всегда и без ограничений. Персональных данных в них нет, а для отладки они дают почти всё нужное и без самого диалога.
Как превратить логи в бюджет и алерты
Сырые логи сами ничего не решают, важно, что с ними делать. Регулярно считайте на их основе три вещи: суммарный расход за период по каждому ключу, долю запросов с аномально большим числом токенов и долю неудачных вызовов, которые пришлось повторить.
Дальше эти числа становятся порогами: уведомление при подходе к месячному лимиту, алерт при резком скачке латентности, флаг на ключ, у которого число токенов на вызов вдруг выросло в разы. codexkey уже показывает часть этой картины на уровне ключей и суб-организаций, а публичная статус-страница снимает вопрос «это у нас или у провайдера» без внутреннего расследования.
Пример из практики: ключ, выданный фиче с рассылками, после чьей-то правки системного промпта начинает выдавать письма втрое длиннее обычных. Без разбивки по ключам это всплывёт только в конце месяца, в общем счёте. С разбивкой алерт на аномальный рост токенов сработает в течение дня.
Коротко
Минимум для лога вокруг LLM-вызова: id запроса, входные и выходные токены отдельно, латентность, привязка к ключу и пользователю. Содержимое диалога храните отдельно и с ограничениями, метаданные пишите свободно. На такой основе деньги считаются, а баги находятся, и не приходится гадать по общему счёту в конце месяца.