Отметим: когда AI-платформа начинает обслуживать тысячи запросов в секунду, биллинг превращается в узкое место. Токены LLM тарифицируются по модели input/output, GPU-время — посекундно с минимальным порогом, API-запросы — с rate limiting. Ошибка в конфигурации — и платформа теряет до 10% выручки. Мы строим биллинг-системы, которые синхронизируют эти разнородные ресурсы в единую модель учета. Наши инженеры имеют 5+ лет опыта в разработке биллинга для высоконагруженных AI-сервисов.
Как обеспечить точный учёт токенов и GPU-часов?
Основная сложность — комбинирование нескольких единиц тарификации в единую систему. LLM токены (input/output) обычно тарифицируются отдельно, с прогрессивной шкалой скидок при больших объёмах. GPU-часы считаются посекундно, с минимальным временем списания — типично 10 секунд, чтобы избежать микротранзакций. API-запросы часто лимитируются по rate с burst-квотой. Всё это нужно объединить в согласованный инвойс, понятный клиенту. Для каждого ресурса мы проектируем отдельную модель данных с поддержкой tiered-цен, кредитов и минимальных списаний. Итоговая система поддерживает PostgreSQL для OLTP-операций и ClickHouse для аналитических агрегаций за произвольный период. Гарантируем прозрачный учёт с детальной разбивкой по модели, эндпоинту и временному слоту.
from dataclasses import dataclass from enum import Enum from decimal import Decimal class BillingUnit(Enum): TOKEN = "token" # 1M токенов GPU_SECOND = "gpu_second" # GPU-время REQUEST = "request" # Запрос GB_MONTH = "gb_month" # Хранилище @dataclass class PricingRule: resource: BillingUnit unit_price: Decimal tier_breaks: list # [(volume_threshold, discounted_price)] minimum_charge: Decimal = Decimal('0') PRICING = { "llm_input_token": PricingRule( resource=BillingUnit.TOKEN, unit_price=Decimal('0.000005'), # $5 per 1M tokens tier_breaks=[ (10_000_000, Decimal('0.000004')), # >10M → $4/1M (100_000_000, Decimal('0.000003')), # >100M → $3/1M ] ), "gpu_a100_second": PricingRule( resource=BillingUnit.GPU_SECOND, unit_price=Decimal('0.00089'), # ~$3.20/hour per A100 tier_breaks=[], minimum_charge=Decimal('0.01') # Минимум 10 секунд биллинга ), } | Ресурс | Единица измерения | Особенности учёта |
|---|---|---|
| LLM токены | 1M токенов | Input vs output, tiered pricing |
| GPU-часы | Секунда (минимум 10) | Округление вверх, типы GPU |
| API запросы | Штука | Rate limiting, burst |
| Хранилище | GB в месяц | С учётом репликации |
Сравнение: real-time метринг vs batch-биллинг
Вместо того чтобы полагаться на ежечасный batch, real-time метринг с Redis и Kafka снижает задержки списания до 10 мс. Это в 50 раз быстрее традиционных подходов, что особенно важно при high-load, где каждый запрос стоит денег. Такая архитектура позволяет сократить потери выручки до 10% и повысить точность бюджетирования.
Почему real-time метринг критичен для AI-биллинга?
Без real-time метринга клиенты могут превысить бюджет, а платформа — потерять деньги из-за задержек в списании. Мы используем Redis для быстрых счётчиков (актуальный баланс, rate limiting) и Kafka для аудита. P99 задержки записи события — менее 10 мс. Сертифицированные инженеры гарантируют отказоустойчивость системы.
Реализация метринга включает два параллельных потока: оперативные счётчики в Redis для мгновенного контроля лимитов и очередь событий в Kafka для дальнейшей агрегации. Это обеспечивает баланс между скоростью и надёжностью.
class UsageMeter: def __init__(self, redis_client, kafka_producer): self.redis = redis_client self.kafka = kafka_producer async def record_llm_usage(self, customer_id: str, model_id: str, input_tokens: int, output_tokens: int, request_id: str): # 1. Real-time счётчики в Redis (для rate limiting и balance checks) pipe = self.redis.pipeline() month_key = f"usage:{customer_id}:{self.current_month()}" pipe.hincrby(month_key, f"{model_id}:input_tokens", input_tokens) pipe.hincrby(month_key, f"{model_id}:output_tokens", output_tokens) pipe.expire(month_key, 60 * 60 * 24 * 40) # 40 дней await pipe.execute() # 2. Детальные события в Kafka для аудита и биллинга await self.kafka.send("usage_events", { "event_type": "llm_inference", "customer_id": customer_id, "model_id": model_id, "request_id": request_id, "input_tokens": input_tokens, "output_tokens": output_tokens, "timestamp": datetime.utcnow().isoformat() }) async def record_gpu_job(self, customer_id: str, job_id: str, gpu_type: str, duration_seconds: float): # GPU биллинг с округлением вверх до секунды billable_seconds = max(ceil(duration_seconds), 10) # Минимум 10 сек await self.kafka.send("usage_events", { "event_type": "gpu_training", "customer_id": customer_id, "job_id": job_id, "gpu_type": gpu_type, "duration_seconds": billable_seconds, "timestamp": datetime.utcnow().isoformat() }) Apache Kafka используется как надёжный брокер событий, а Redis — для низколатентных счётчиков. Такая связка проверена в production с нагрузкой более 10 тыс. событий в секунду.
Как генерировать инвойсы и контролировать бюджет?
Инвойсы строятся на агрегации событий из ClickHouse. Мы поддерживаем tiered-цены, кредиты и скидки. Контроль бюджета — с алертами по порогам и автоблокировкой.
class InvoiceGenerator: async def generate_monthly_invoice(self, customer_id: str, billing_period: str) -> Invoice: # Агрегация usage событий из ClickHouse usage = await self.clickhouse.query(""" SELECT model_id, sum(input_tokens) as total_input, sum(output_tokens) as total_output, sum(gpu_seconds) as total_gpu, count() as total_requests FROM usage_events WHERE customer_id = %(customer_id)s AND toYYYYMM(timestamp) = %(period)s GROUP BY model_id """, {"customer_id": customer_id, "period": billing_period}) line_items = [] total = Decimal('0') for row in usage: input_cost = self.compute_tiered_price( row['total_input'], PRICING['llm_input_token'] ) output_cost = self.compute_tiered_price( row['total_output'], PRICING['llm_output_token'] ) line_items.append({ 'description': f"{row['model_id']} - Input tokens", 'quantity': row['total_input'], 'unit': "1M tokens", 'unit_price': float(PRICING['llm_input_token'].unit_price * 1_000_000), 'amount': float(input_cost) }) total += input_cost + output_cost # Применение кредитов и скидок credits = await self.get_customer_credits(customer_id) final_amount = max(total - credits, Decimal('0')) invoice = Invoice( customer_id=customer_id, period=billing_period, line_items=line_items, subtotal=float(total), credits_applied=float(min(credits, total)), total=float(final_amount) ) # Отправка через Stripe if final_amount > 0: await self.stripe.create_invoice(customer_id, invoice) return invoice async def check_budget_alerts(customer_id: str): customer = await db.get_customer(customer_id) current_spend = await usage_meter.get_current_month_spend(customer_id) thresholds = [0.5, 0.8, 0.9, 1.0] # % от месячного бюджета for threshold in thresholds: alert_amount = customer.monthly_budget * threshold if current_spend >= alert_amount: alert_key = f"budget_alert:{customer_id}:{threshold}:{current_month()}" if not await redis.exists(alert_key): await send_budget_alert(customer, threshold, current_spend) await redis.setex(alert_key, 86400 * 31, "1") Пример конфигурации тарифов
Тарифы задаются в YAML-файле: ресурсы, tiered-цены, минимальные списания. Изменение тарифов занимает минуты без передеплоя.Процесс разработки биллинг-системы
| Этап | Длительность | Результат |
|---|---|---|
| Аналитика тарифов и метрик | 2–3 дня | Модель данных и спецификация |
| Проектирование микросервисов | 3–5 дней | Архитектура на диаграммах |
| Реализация метринга и биллинга | 1–3 недели | Работающий MVP |
| Интеграция с платёжным шлюзом | 3–5 дней | Тестовые транзакции |
| Тестирование (unit, load) | 5–7 дней | Отчёт о покрытии и P99 |
| Деплой и документация | 2–3 дня | Инструкция по эксплуатации |
Входит: полная документация API, доступ к исходным кодам, обучение команды заказчика (2 часа), поддержка в течение месяца после релиза.
Наш опыт — более 50 реализованных проектов в области AI-биллинга. Наиболее распространённая причина потерь на практике — некорректная настройка tiered-цен при переходе между ценовыми порогами: без правильного расчёта платформа начисляет меньше, чем должна. Ещё одна частая проблема — отсутствие обработки edge cases: отменённые запросы после начала инференса, прерванные GPU-джобы, retry-запросы после таймаута. Каждый из этих сценариев требует явного решения в биллинговой логике. Мы верифицируем тарифную модель на синтетических данных с граничными случаями до запуска. Получите консультацию: свяжитесь с нами для предварительного аудита. Мы оценим сложность ваших тарифов и предложим сроки.







