Перейти к содержимому

Как работает учёт стоимости

Проблема: юнит-экономика LLM-платформы живёт или умирает на одном числе — сколько на самом деле стоит одна опубликованная статья? — и это число на удивление трудно получить. Плоские оценки за вызов расходятся с реальностью (здесь плоская константа однажды недосчитывала доминирующий драйвер расходов примерно в 6 раз); дашборды провайдеров агрегируют по аккаунту, а не по статье.

Прогон эмитит неизменяемое usage-событие с вектором атрибуции: тенант, контракт, запись, пайплайн, модель, счётчики токенов, время. Не строка лога — строка запрашиваемого леджера. Стоимость в момент вызова не вычисляется: события хранят факты (токены, модель), деньги считаются позже — прайсбук меняется, и сохранённая цена заморозила бы устаревшую.

Гранулярность, честно: usage_event — одна строка на прогон, а не на вызов, и разложена она по модели. Ось шага живёт рядом, в pipeline_run.metrics.llm_usage.by_step: рантайм снимает её той же дельтой до/после, которой уже считает вызовы для run_step. Разделение не косметическое — до 2026-07-23 оси шага не было вовсе, и вопрос «какой шаг здесь дорогой» не имел числового ответа. Первый же замер после её появления показал, что 60% стоимости Generate даёт один шаг (make_article_structure).

Pipeline runusage_eventtokens · model · contract ·pipeline · timepipeline_run.metricsllm_usage.by_step ·external.by_stepVersioned pricebookCost queriesCost per articleCost per step / contract /dayReconciliation vs providerinvoice

Платные не-LLM вызовы (Brave Search) считаются там же и по всем шагам: metrics.external.brave_calls. Отдельный ключ нужен потому, что метрика маховика research.brave_calls намеренно узкая — она отвечает «сколько потратил ресёрч», а не «сколько стоил прогон». Пока их путали, расход доминирующего шага был невиден целиком (T#78).

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

Слой 3 — стоимость одной статьи, честно амортизированная

Заголовок раздела «Слой 3 — стоимость одной статьи, честно амортизированная»

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

Слой 4 — бюджеты (спроектированы, ещё не заряжены)

Заголовок раздела «Слой 4 — бюджеты (спроектированы, ещё не заряжены)»

Метеринг задуман кормить принуждение: бюджеты на прогон со сторожем через канал управления прогонами. Состояние на 2026-07-23: таблица budget пуста, поэтому сторож охраняет пустоту и всегда отвечает «в пределах». Это не описка в доке, а открытая дыра SPEC-124 (WS-3) — здесь она названа вслух, потому что дока, обещающая несуществующую защиту, опаснее её отсутствия.

Что действительно работает сегодня: дневной сигнал аномалии расхода в ночном отчёте. 🔴 Автоматического killswitch не будет и по замыслу — урок инцидента GCP 2026-06-24, где автоотключение биллинга уронило прод: сигнал уведомляет владельца, решение принимает человек.

Метеринг каждого вызова стоит записи на вызов и дисциплины: любой новый путь LLM-вызова обязан эмитить событие, и сверка со счётом существует ровно для того, чтобы ловить забывшие пути. Правила амортизации — выбор модели; платформа хранит сырые векторы, поэтому модель можно поменять ретроактивно без потери данных.

Домен metering в list_domains открывает read-поверхность; стоимость по прогонам видна в отчётах прогонов.

Спеки: SPEC-107 (usage_event + прайсбук), SPEC-022/023 (бюджеты + kill-switch), SPEC-124 (сверка со счётом).