Вступление. На пути к продакшену API-прокси — этап, который большинство разработчиков обойти не могут. Сайт прокси может обещать «99,9% скорости и стабильности» и «выделенный канал для высокой нагрузки». Но стоит подключиться, и подводных камней оказывается куда больше, чем обещает слоган. Здесь мы рассказываем, как наша команда перешла от покупки наугад к автоматизированным проверкам, и делимся схемой тестирования, которую применяем до оплаты и интеграции.

1. Сбои, которые заставили нас выработать методику

Многомерная система метрик, описанная ниже, появилась не потому, что мы были такими уж умными. Мы заплатили за неё деньгами, инцидентами в продакшене и жалобами пользователей.

1. Ложный 200 OK и тихий обрыв

Первые автоматические проверки были простыми. Скрипт на Python каждые 5 минут отправлял POST-запрос на прокси. HTTP 200 с каким-нибудь текстом считался признаком исправной работы.

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

Логи оказались хуже обращений. Некоторые прокси всё равно возвращали 200 OK, когда пул аккаунтов у вышестоящего поставщика был исчерпан (ограничение частоты запросов 429 или ошибка авторизации 401), когда шлюз уходил в таймаут (504) или когда падал узел. Посреди SSE-потока они могли тихо вставить data: [DONE] и оборвать ответ либо поместить в JSON {"error": "rate limit exceeded"} и выдать это за ответ модели. Мониторинг, который смотрел только на код статуса, такой ложный 200 обманывал полностью.

2. Ночные зависания и первый токен, который так и не пришёл

После этого мы добавили круглосуточные проверочные запросы. Днём среднее время ответа держалось около 2 секунд, и дашборд выглядел прилично. А в ночной пик росли таймауты и доля пользователей, которые не дожидались ответа.

Большинство этих прокси не были прямым официальным каналом. Они смешивали пулы американских аккаунтов и прокси-узлы в нескольких регионах. Когда начинался рабочий день в Северной Америке или наступал ночной пик в Китае, параллельная нагрузка обрушивала маршрут. В худшем случае полный ответ всё равно укладывался примерно в 4 секунды, но первый токен (TTFT) приходил через целых 12 секунд. Пользователи смотрели на пустое поле и уходили.

После этих двух инцидентов мы пересмотрели правило: один ping или пара случайных запросов — это не проверка ИИ-протокола и не проверка потока.

2. Три версии системы тестирования

1.0 Слепые пробы и интуиция

  • Что мы делали: отправляли несколько промптов в веб-интерфейсе или писали скрипт на 10 запросов и на глаз оценивали скорость и качество ответов.
  • Ограничение: выборка крошечная и шумная. Высокая параллельная нагрузка или редкий обрыв соединения проявляются только в продакшене.

2.0 Параллельная нагрузка и коды статуса HTTP

  • Что мы делали: запускали Postman и Locust с параллельной нагрузкой и следили за распределением кодов статуса, средней задержкой и долей успешных запросов.
  • Ограничение: так виден только внешний шлюз. Обрыв потока, поддельная ошибка и зависание между токенами остаются незамеченными.

3.0 Конечный автомат для потока и опыт других отраслей

Когда наши собственные метрики упёрлись в потолок, мы поговорили с Чжоу-гэ, который работает в высокочастотной торговле и эксплуатации CDN.

Его мысль была прямой: API-прокси для ИИ — это не обычный веб-эндпоинт, а сетевой промежуточный узел с долгоживущими соединениями и высокой параллельной нагрузкой.

Он сравнил SSE-потоки ИИ — по топологии и чувствительности к потерям — с передачей аудио и видео в реальном времени (WebRTC/RTMP) и с потоками биржевых котировок. Привычная схема замеров для веб-запросов здесь не подходит. Полезные аналогии — задержка tick-to-trade в высокочастотной торговле и время до первого кадра в CDN.

После этого разговора мы отказались от старого мониторинга. Мы развернули проверочные узлы в нескольких регионах, разделили установку соединения, TLS-рукопожатие, приход первого токена, пропускную способность по токенам и разбор SSE-пакетов, а затем сгладили временные ряды. Это и есть автоматизированный стандарт, которым мы пользуемся сейчас.

3. Три параметра, которые определяют работу в продакшене

                         ┌── TTFT (время до первого токена) -> сколько ждёт пользователь
            ┌── Задержка ┼── TPS (скорость генерации) -> плавность «печатной машинки»
            │            └── Задержка P95/P99 -> худший случай и пик нагрузки
            │
Метрики ────┼── Надёжность ┬── Успешный разбор -> отсев ложных 200 и некорректных ответов
            │              └── Retry-to-success -> устойчивость при экспоненциальных повторах
            │
            └── Качество потока ┬── Обрывы потока -> ответ обрывается на полуслове
                                └── Джиттер токенов -> вывод подвисает

1. Задержка: отделяем ожидание от генерации

  • TTFT (время до первого токена): миллисекунды от HTTP-запроса до первого SSE-пакета. Это и есть «первый кадр». Наша планка для продакшена — TTFT < 1,5 секунды.
  • TPS (токенов в секунду): скорость генерации после первого токена, то есть число сгенерированных токенов, делённое на длительность. При низком TPS «печатная машинка» в интерфейсе начинает заикаться.
  • Задержка P95 / P99: не верьте лестному среднему. 95-й и 99-й процентили показывают пик нагрузки, длинный контекст и перегруженный канал.

2. Надёжность: видеть сквозь ложный успех

  • Успешный разбор (parse success): одного 200 недостаточно. Официальный SDK должен разобрать ответ, JSON должен быть полным, а ошибка, вставленная прокси, не должна подмешиваться в ответ.
  • Retry-to-success: имитируйте экспоненциальную задержку повторов, как в продакшене, и проверьте, восстанавливается ли запрос после 429 или 5xx через резервный канал не более чем за 3 повторные попытки.

3. Качество потока: ловим тихие сбои

  • Обрывы потока (stream interruption): доля вызовов, у которых TCP-соединение рвётся или замолкает до согласованного маркера data: [DONE].
  • Джиттер между токенами (inter-token jitter): стандартное отклонение интервала между соседними SSE-пакетами; понятие заимствовано из передачи аудио и видео. Высокий джиттер означает, что маршрут на стороне бэкенда нестабилен или что в нём наслоено несколько прокси-буферов.

4. Ориентиры: велосипед мы не изобретали

1. Четыре золотых сигнала Google SRE

В книге Google SRE названы четыре золотых сигнала: задержка, трафик, ошибки и насыщение. Наши проверочные узлы считают прокси недоверенным внешним сервисом, а оповещения строятся на этих четырёх сигналах.

2. OpenTelemetry и правила W3C для SSE

Для потоков мы взяли точки трассировки долгоживущих соединений из OpenTelemetry и протокол Server-Sent Events от W3C. Проверочный узел фиксирует TCP-рукопожатие, согласование TLS, заголовки, первый фрагмент данных и сигнал [DONE].

3. Доверительный интервал Уилсона

Ранжировать прокси по формуле «успехи / попытки» несправедливо. Сервис, который справился 10 раз из 10 (100%), не обязательно надёжнее того, что справился 9900 раз из 10 000 (99%).

Мы используем нижнюю границу доверительного интервала Уилсона:

Score = (p̂ + z²/(2n) - z × √(p̂(1-p̂)/n + z²/(4n²))) / (1 + z²/n)

p̂ — наблюдаемая доля успешных запросов, n — размер выборки, z — квантиль нормального распределения для уровня доверия 95%. Малая выборка или короткий период тестирования снижают оценку.

5. Как устроен проверочный узел

[Региональные узлы (AWS US West / GCP East Asia / Европа)]
       │
       ├──> [Плановый и пиковый трафик] ──> [Прокси-слой API] ──> [Вышестоящий API / пул аккаунтов]
       │                                            │
       └──< [Парсер SSE и конечный автомат] <───────┘
               │
               ├──> [TimescaleDB / Prometheus (метрики с микросекундной точностью)]
               └──> [Оценка по доверительному интервалу и автоматическая атрибуция]

1. Проверочные узлы в нескольких регионах

Лёгкие проверочные узлы работают в AWS US West, GCP East Asia (Гонконг / Токио) и в Европе. Параллельные запросы из этих регионов позволяют отличить зависший прокси-узел самого сервиса от колебаний в работе OpenAI или Anthropic.

2. Конечный автомат на уровне сокета

  • CONNECTING: фиксируем время отправки t0.
  • FIRST_BYTE: пришёл первый SSE-фрагмент; TTFT = t1 - t0.
  • STREAMING: интервалы между фрагментами, TPS и джиттер.
  • COMPLETED: ответ завершился, маркер [DONE] на месте, JSON корректен.

3. Автоматическая атрибуция

  • Шлюз упал: 502 Bad Gateway или 504 Gateway Timeout означают, что отказал собственный узел Nginx или Envoy прокси-сервиса.
  • Пул аккаунтов пуст: 429 Too Many Requests или 401 Unauthorized означают, что не справился контроль параллельной нагрузки на стороне прокси или у вышестоящего ключа закончился баланс.
  • Промежуточное ПО: 200 OK с обрывом посреди потока или ошибкой разбора означает, что переполнилось собственное промежуточное ПО прокси — биллинговое или фильтрующее промпты.

6. Три правила, прежде чем выбрать прокси

  1. Не доверяйте одному тесту. Собирайте выборку днём и ночью не менее 3–7 дней подряд. Следите за задержкой P95 и долей успешных запросов в ночной пик, с 21:00 до 01:00.
  2. Тест должен быть потоковым. Непотоковый запрос скрывает задержку первого токена, буферизацию в промежуточном ПО и поток, который обрывается на середине.
  3. Подозрительно низкая цена — не подарок. Обычно за ней стоят общий пул аккаунтов, некачественный прокси-узел или дешёвая открытая модель, выданная за Opus или GPT-4o.