ГлавнаяБлогКак перенести навыки бэкенда в AI: шлюз для LLM
Python

Как перенести навыки бэкенда в AI: шлюз для LLM

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

Al
Редакция Algolitalgolit.ru
12 мин чтения13 июня 2026 г.

Почему бэкендеры уже готовы к AI-инфраструктуре

Представьте: вы отправляете один и тот же промпт в Claude Haiku и Gemini 2.5 Flash. Flash дешевле за токен, но тратит 28 токенов на рассуждения, а Haiku — всего 4. В результате Flash обходится в 8.6 раза дороже за запрос. Я заметил это только потому, что инструментировал каждый вызов: токены, стоимость, задержка — всё в Postgres. Этот инстинкт — ключевой. За два с половиной года создания кросс-граничных платежей в реальном времени в NPCI я привык, что округление — это инцидент, а падение смежника — испорченная суббота. В этом году я строил шлюз для LLM — и использовал те же инструменты. Это не совпадение.

AI-инфраструктура выглядит новой областью. На деле это та же системная работа, которую бэкенд-инженеры делали всегда. Модельный API — это внешняя зависимость: медленная, иногда недоступная, с лимитами и оплатой за вызов. Вы уже интегрировали такую зависимость — платежный процессор, KYC-провайдер, банк-партнер. Модель — не магия. Это дорогой и нестабильный внешний сервис, а сложные части — надежность, контроль затрат, отказоустойчивость — мы уже решили.

Circuit Breaker для LLM: как мы делали в платежах

Шлюзу нужен circuit breaker для каждого провайдера. В NPCI я строил именно это — на платежной платформе, где каждый партнер был внешним сервисом в другой стране, со своим SLA и определением «доступен». Мои отказоустойчивые процессоры на Go оборачивали партнеров в circuit breaker и rate limiter по одной причине: когда партнер начинал падать, худшее — продолжать долбить его, пока пулы воркеров забиваются зависшими вызовами. Поэтому вы отключаетесь, быстро падаете и пускаете тонкий поток трафика для проверки восстановления. CLOSED, OPEN, HALF_OPEN. Те же три состояния для Anthropic и Gemini — изменилось только имя: «банк-партнер» стал «провайдером модели».

import time
import threading
from enum import Enum

class CircuitState(Enum):
    CLOSED = 'closed'       # Нормальная работа
    OPEN = 'open'           # Провайдер недоступен
    HALF_OPEN = 'half_open' # Проверка восстановления

class CircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=30):
        self.state = CircuitState.CLOSED
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.last_failure_time = None
        self.lock = threading.Lock()

    def call(self, func, *args, **kwargs):
        with self.lock:
            if self.state == CircuitState.OPEN:
                # Проверяем, не прошло ли время для восстановления
                if time.time() - self.last_failure_time >= self.recovery_timeout:
                    self.state = CircuitState.HALF_OPEN
                else:
                    raise Exception("Circuit breaker OPEN — запрос отклонён")

        try:
            result = func(*args, **kwargs)
            with self.lock:
                # Успешный вызов в HALF_OPEN восстанавливает цепь
                if self.state == CircuitState.HALF_OPEN:
                    self.state = CircuitState.CLOSED
                    self.failure_count = 0
                return result
        except Exception as e:
            with self.lock:
                self.failure_count += 1
                self.last_failure_time = time.time()
                if self.failure_count >= self.failure_threshold:
                    self.state = CircuitState.OPEN
            raise e

Метрики и аудит: Postgres как основа

Шлюз должен учитывать каждый вызов в Postgres. Это журнал аудита, а платежи работают на журналах. В 20+ сервисах на Go я завязал всё на идемпотентность, чтобы повторный запрос не удваивал счёт. Лог стоимости ключится по request_id по той же причине. Деньги всегда фиксированной точности, никогда не float — поэтому cost_usd — NUMERIC, а не float. Вы не аппроксимируете деньги, и не аппроксимируете затраты.

import psycopg2
from datetime import datetime

class CostLogger:
    def __init__(self, dsn):
        self.conn = psycopg2.connect(dsn)
        self.cur = self.conn.cursor()
        self.cur.execute("""
            CREATE TABLE IF NOT EXISTS llm_calls (
                request_id TEXT PRIMARY KEY,
                model TEXT NOT NULL,
                prompt_tokens INTEGER,
                completion_tokens INTEGER,
                cost_usd NUMERIC(10, 6) NOT NULL,  -- Фиксированная точность
                created_at TIMESTAMP DEFAULT NOW()
            )
        """)
        self.conn.commit()

    def log_call(self, request_id, model, prompt_tokens, completion_tokens, cost_usd):
        # Идемпотентная вставка: повторный вызов не дублирует запись
        self.cur.execute("""
            INSERT INTO llm_calls (request_id, model, prompt_tokens, completion_tokens, cost_usd)
            VALUES (%s, %s, %s, %s, %s)
            ON CONFLICT (request_id) DO NOTHING
        """, (request_id, model, prompt_tokens, completion_tokens, cost_usd))
        self.conn.commit()

Повторные попытки и circuit breaker: транзиентные vs устойчивые сбои

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

import time
import random
from enum import Enum

class RetryStrategy:
    def __init__(self, max_retries=3, base_delay=1.0, max_delay=10.0):
        self.max_retries = max_retries
        self.base_delay = base_delay
        self.max_delay = max_delay

    def execute(self, func, *args, **kwargs):
        last_exception = None
        for attempt in range(self.max_retries):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                last_exception = e
                # Транзиентные ошибки: таймаут, 429, 503
                if self._is_transient(e):
                    delay = min(self.base_delay * (2 ** attempt) + random.uniform(0, 1), self.max_delay)
                    time.sleep(delay)
                else:
                    # Устойчивая ошибка: не повторяем
                    raise e
        raise last_exception

    def _is_transient(self, e):
        # Пример: проверка по коду ошибки
        return hasattr(e, 'status_code') and e.status_code in (429, 503, 504)

Новое в AI: токен-экономика и недетерминированность

Не буду притворяться, что всё было знакомо. Несколько вещей действительно новы, и все они связаны с самой моделью. Токен-экономика — реальная дисциплина: сюрприз с 8.6× не существует ни в одной базе данных, за которую я когда-либо выставлял счёт. Модель недетерминирована так, как недетерминировано хранилище: один и тот же вход может дать разный выход, поэтому вы не можете проверять точные строки, и «тестирование» становится оценками и распределениями вместо равенства. И модель, тихо тратящая ваш бюджет на собственные рассуждения, не имеет аналога в платежном коммутаторе. Это новая поверхность — но это несколько недель нового на годах фундамента, а не новая карьера.

Практический вывод: что делать прямо сейчас

Если вы бэкенд-инженер и сомневаетесь, переносится ли ваш опыт распределённых систем на AI: он не просто переносится — он дефицитен. Любой может вызвать LLM API за полдня. Гораздо меньше людей могут сделать этот вызов надёжным, когда провайдер деградирует, дешёвым, когда математика токенов идёт против вас, и наблюдаемым, когда кто-то просит объяснить счёт. Это не AI-экспертиза. Это работа, которую вы уже делали, только с моделью на конце.

Шлюз доступен по адресу https://llm-gateway-python.onrender.com, а код на GitHub: https://github.com/Yogesh23012001/llm-gateway-python. Скопируйте circuit breaker и cost logger в свой проект — и вы уже на шаг впереди.

#LLM#бэкенд-разработка#circuit breaker#метрики#Postgres
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →
Как перенести навыки бэкенда в AI: шлюз для LLM | Algolit