ВойтиКонтактыНачать бесплатно
Base URL and SDK Migration27 июля 2026 г.Flatkey Team

Миграция OpenAI client: сохранение RPM, TPM и поведения повторных попыток

Перенесите клиент в стиле OpenAI на единый gateway без всплесков повторных попыток, изучив RPM, TPM, таймауты, потоковую передачу, backoff, canary-релизы и откат.

Миграция OpenAI client: сохранение RPM, TPM и поведения повторных попыток

Миграция OpenAI client может выглядеть завершённой после двух изменений конфигурации: заменить API-ключ и указать для SDK новый base URL. Первый запрос проходит успешно, формат ответа выглядит привычно, и pull request кажется готовым к слиянию.

Это доказывает совместимость интерфейса. Это не доказывает поведение в production.

Более сложная часть миграции OpenAI client — сохранить то, что происходит, когда нагрузка становится неравномерной: запросы приходят всплесками, промпты становятся больше, потоки длятся дольше ожидаемого, провайдер возвращает 429, или ответ истекает по тайм-ауту уже после того, как работа могла начаться. Если SDK, ваше приложение и очередь задач повторяют попытки независимо друг от друга, один неудачный вызов может превратиться в несколько почти одновременных попыток.

В этом руководстве показано, как перенести существующую Python- или TypeScript-интеграцию в стиле OpenAI на единый gateway, сделав поведение при rate-limit и повторных попытках явным. В примерах используется совместимый с OpenAI base URL от Flatkey, но метод проверки применим к любой миграции gateway.

Быстрый ответ: что должно измениться?

Для безопасной миграции OpenAI client рассматривайте эти настройки вместе, а не считайте base URL единственным изменением.

Область миграции Что проверить Безопасное стартовое решение
API endpoint Base URL и аутентификация Менять через переменные окружения, а не разрозненные литералы
Выбор модели Точные идентификаторы моделей и поддерживаемые параметры Зафиксировать одну известную модель для canary
Повторные попытки SDK Автоматическое число повторов и коды статуса, подлежащие повтору Решить, кто отвечает за retries: SDK или ваше приложение
Повторные попытки приложения Backoff, jitter, лимит попыток и retry budget Оставить одного владельца retries и логировать каждую попытку
Управление RPM Скорость поступления запросов и размер всплеска Добавить ограничение по concurrency или очереди до cutover
Управление TPM Промпт плюс ожидаемое число выходных токенов Тестировать реалистичные большие промпты, а не только smoke test в одну строку
Тайм-ауты Connect, read и общая длительность запроса Задать явные значения для синхронных и streaming-вызовов
Наблюдаемость ID запросов, попытки, токены, задержка и итоговый результат Сравнивать логи клиента с логами использования gateway

Если сначала нужен разбор самих сокращений, прочитайте LLM rate limits explained: RPM, TPM, and retries. Это руководство начинается там, где заканчивается то объяснение: на diff миграции и плане production-тестирования.

Почему замена base URL необходима, но недостаточна

В quickstart Flatkey описано минимальное изменение клиента: сохранить шаблон запросов OpenAI SDK и указать base URL как https://router.flatkey.ai/v1. Там же рекомендуется после запроса проверить Usage Logs, чтобы убедиться в модели, числе токенов, задержке и стоимости.

Это правильный smoke test. Для production миграции OpenAI client нужны ещё четыре вопроса:

  1. Повторяет ли SDK автоматически 429, таймауты или ошибки сервера?
  2. Есть ли другой слой, который также повторяет ту же самую неудачную операцию?
  3. Ограничивается ли параллелизм по скорости запросов, скорости токенов или по обоим параметрам?
  4. Можно ли отличить одну логическую операцию от её отдельных попыток?

В официальной документации OpenAI Python и Node SDK сейчас указано, что выбранные сбои повторяются по умолчанию два раза, включая ответы 429, ошибки соединения, таймауты и некоторые ошибки сервера. Оба SDK предоставляют настройки повторных попыток и таймаута. Это значение по умолчанию удобно для прямой интеграции, но может стать незаметным усилением, когда в вашем коде уже реализован backoff.

Цель миграции — не «отключить все повторы». Цель — «знать, какой слой отвечает за повтор».

Шаг 1: инвентаризируйте каждый слой повторов до изменения кода

Начните с построения реального пути вызова.

действие пользователя или задача
  -> обёртка повторов приложения
  -> повтор доставки из очереди
  -> повтор SDK OpenAI
  -> шлюз
  -> провайдер

Для каждого слоя зафиксируйте:

  • Какие ошибки запускают новую попытку.
  • Максимальное число попыток.
  • Используется ли фиксированная задержка, экспоненциальный backoff или jitter.
  • Учитывается ли значение Retry-After, предоставленное сервером.
  • Сохраняется ли один и тот же идентификатор операции между попытками.
  • Предполагается ли, что запрос с таймаутом не был выполнен до начала какой-либо работы.

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

Оцените максимальное усиление

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

3 доставки из очереди × 3 попытки приложения × 3 попытки SDK = 27 HTTP-попыток

Вы можете никогда не достичь полного числа, но это умножение объясняет, почему краткий 429 может превратиться в шторм повторов. Запишите это число в обзор миграции. Так скрытые значения по умолчанию становятся видимыми.

Шаг 2: перенесите настройки endpoint в конфигурацию

Сделайте diff миграции обратимым. Не заменяйте строки endpoint по всей кодовой базе.

Python до и после

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LLM_API_KEY"],
    base_url=os.environ.get("LLM_BASE_URL", "https://api.openai.com/v1"),
    max_retries=0,
    timeout=45.0,
)

Для canary Flatkey настройте:

export LLM_API_KEY="$FLATKEY_API_KEY"
export LLM_BASE_URL="https://router.flatkey.ai/v1"

TypeScript до и после

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.LLM_API_KEY,
  baseURL: process.env.LLM_BASE_URL ?? "https://api.openai.com/v1",
  maxRetries: 0,
  timeout: 45_000,
});

В этих примерах SDK-повторы установлены в ноль, потому что следующий раздел явно передает ответственность за повторные попытки приложению. Если в вашем приложении нет слоя повторов, вы можете вместо этого оставить ограниченные повторы SDK. Не оставляйте оба варианта одновременно по ошибке.

Для более широкого контрольного списка совместимости см. OpenAI Compatible API Gateway: Migration Checklist for Minimal Code Changes.

Шаг 3: передайте ответственность за повторные попытки одному слою

Политика повторов, которая действительно полезна, состоит из пяти частей:

  1. Короткий список ошибок, для которых допустим повтор.
  2. Строгий лимит на число попыток.
  3. Максимальное общее время на повторы.
  4. Экспоненциальная задержка с jitter.
  5. Структурированные логи для каждой попытки.

Вот небольшой Python-обертка для синхронного вызова chat:

import random
import time
from openai import APITimeoutError, APIConnectionError, APIStatusError, RateLimitError

RETRYABLE_STATUS_CODES = {408, 409, 429, 500, 502, 503, 504}


def create_chat_with_retry(client, *, model, messages, max_attempts=4):
    started_at = time.monotonic()

    for attempt in range(1, max_attempts + 1):
        try:
            return client.chat.completions.create(
                model=model,
                messages=messages,
            )
        except (RateLimitError, APITimeoutError, APIConnectionError) as error:
            retryable = True
            caught_error = error
        except APIStatusError as error:
            retryable = error.status_code in RETRYABLE_STATUS_CODES
            caught_error = error

        if not retryable or attempt == max_attempts:
            raise caught_error

        exponential_delay = min(2 ** (attempt - 1), 16)
        jitter = random.uniform(0, 0.5 * exponential_delay)
        sleep_seconds = exponential_delay + jitter

        print({
            "event": "llm_retry",
            "attempt": attempt,
            "next_delay_seconds": round(sleep_seconds, 2),
            "elapsed_seconds": round(time.monotonic() - started_at, 2),
            "error_type": type(caught_error).__name__,
        })
        time.sleep(sleep_seconds)

    raise RuntimeError("unreachable")

Рассматривайте это как отправную точку для проверки и доработки, а не как универсальную политику. В production сначала разбирайте и учитывайте корректный заголовок ответа Retry-After, а уже затем переходите к локально вычисленной задержке. Добавьте ограничение на общее прошедшее время, чтобы повторы не превышали задержку, допустимую для вашего продукта.

Не повторяйте каждую ошибку

Сбой Действие по умолчанию Почему
400 неверный запрос Не повторять без изменений Нужно изменить payload
401 аутентификация Не повторять без изменений Нужно изменить ключ или заголовок
404 модель не найдена Не повторять без изменений Нужно изменить идентификатор модели или доступ
429 ограничение по rate limit Повторить с задержкой и jitter Может освободиться емкость
500 или 503 Повторить в рамках небольшого бюджета Сбой может быть временным
Таймаут клиента Повторять осторожно Запрос на upstream, возможно, уже был выполнен

Краткое руководство Flatkey даёт те же общие рекомендации для 429: повторяйте запрос с экспоненциальной задержкой и jitter. Специфичное для миграции дополнение — убедиться, что эту политику выполняет только один уровень.

Шаг 4: подберите параллелизм с учётом и RPM, и TPM

Миграция OpenAI client может сохранить синтаксис запросов, одновременно изменив рамки ёмкости. RPM и TPM ограничивают разные нагрузки:

  • RPM становится узким местом, когда вы отправляете много небольших запросов.
  • TPM становится узким местом, когда промпты, ответы или параллельные оценки велики.

Используйте наблюдаемый трафик, а не одно среднее значение. Соберите как минимум:

  • Количество запросов в минуту на медиане и пике.
  • Входные токены на p50, p95 и максимум.
  • Выходные токены на p50 и p95.
  • Медианная длительность запроса и p95.
  • Количество одновременных потоков.

Примерный верхний предел параллелизма можно оценить по каждому лимиту:

Параллелизм на основе RPM ≈ (RPM / 60) × средняя длительность запроса в секундах

Параллелизм на основе TPM ≈ (TPM / среднее число токенов на запрос / 60)
                        × средняя длительность запроса в секундах

Возьмите меньшее значение как начальный предел, затем оставьте запас для всплесков и повторных попыток.

Пример: предположим, маршрут допускает 600 RPM и 300 000 TPM, в среднем запрос использует 1500 токенов суммарно, а средняя длительность составляет 3 секунды.

Предел по RPM: (600 / 60) × 3 = 30 одновременных запросов
Предел по TPM: (300,000 / 1,500 / 60) × 3 = 10 одновременных запросов

В этом примере более жёстким ограничением является TPM. Если начать с 30 одновременных запросов только потому, что RPM выглядит щедрым, это приведёт к избежимым ответам 429.

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

Шаг 5: отдельно протестируйте потоковую передачу и поведение таймаутов

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

Для потоковых запросов протестируйте:

  • Время до первого токена.
  • Максимальный тихий интервал между фрагментами.
  • Таймаут чтения клиента.
  • Поведение при отключении потребителя.
  • Может ли ваш обёрточный механизм повторных попыток случайно запустить второй поток.
  • Сохраняется ли частичный вывод, отбрасывается или показывается пользователю.

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

Также помните, что таймауты SDK и инфраструктуры могут отличаться. Обратный прокси, serverless-платформа, worker задания или подключение браузера могут завершиться раньше, чем библиотека клиента достигнет собственного таймаута. Во время миграции OpenAI client зафиксируйте самый маленький таймаут во всей цепочке обработки запроса.

Шаг 6: перед широким трафиком запустите матрицу canary

Используйте одну закреплённую модель и небольшой процент трафика. Первый canary должен отвечать на вопрос, сохраняет ли новый маршрут поведение, а не на вопрос, работают ли все модели.

Тестовый случай Входные данные Ожидаемое подтверждение
Аутентификация Действительные и недействительные ключи Успех плюс не повторяемый 401
Проверка модели Действительные и с ошибкой написания идентификаторы моделей Успех плюс не повторяемая ошибка модели
Небольшой всплеск запросов Много коротких промптов Контролируемая постановка в очередь без всплеска повторных попыток
Большой всплеск промптов Меньше промптов с большим числом токенов Нагрузка на TPM видна и ограничена
Принудительный 429 Временно превысить лимит canary Один владелец повторной попытки, задержки с джиттером, ограниченное число попыток
Принудительный тайм-аут Задать намеренно короткий тайм-аут клиента Зарегистрированный тайм-аут без неограниченного повторного воспроизведения
Прерывание потоковой передачи Отключение во время потока Явное поведение при частичном выводе
Ошибка сервера Внедрить или смоделировать 503 Ограниченные повторные попытки и итоговый отчет об ошибке
Откат Восстановить предыдущий base URL Откат только конфигурации выполняется успешно

Для каждой логической операции записывайте:

operation_id
attempt_number
base_url_name
model_requested
http_status
input_tokens
output_tokens
latency_ms
retry_delay_ms
final_outcome

Затем сравните журналы приложения с Flatkey Usage Logs. Подсчеты должны согласовываться. Если одной операции приложения соответствует несколько запросов gateway, ваша instrumentation повторных попыток должна объяснять почему.

Шаг 7: определите пороги rollout и rollback

Миграция OpenAI client должна иметь числовые условия остановки до запуска первого canary.

Пример порогов:

  • Откатить, если итоговая частота ошибок вырастет более чем на согласованный процентный пункт.
  • Приостановить, если число попыток на операцию превышает ожидаемый бюджет повторных попыток.
  • Приостановить, если p95 latency превышает бюджет тайм-аута продукта.
  • Приостановить, если использование токенов на успешную операцию неожиданно изменится.
  • Расширять трафик только после прохождения и потоковых, и непотоковых путей.

Не сравнивайте только необработанные counts 429. Хорошая очередь может уменьшить итоговые ошибки, временно увеличив число отложенных запросов. Отслеживайте как результаты на уровне попыток, так и на уровне операций.

Чек-лист pull request для миграции

Скопируйте этот чек-лист в PR реализации.

  • Base URL и ключ берутся из переменных окружения.
  • Canary использует точный, проверенный идентификатор модели.
  • Один слой владеет повторными попытками.
  • Значения по умолчанию повторных попыток SDK документированы в PR.
  • Поведение для 429, тайм-аута и 5xx имеет ограниченное число попыток.
  • Backoff включает jitter и учитывает Retry-After, когда он присутствует.
  • Пределы RPM и TPM оценены на основе наблюдаемого трафика.
  • Для потоковой передачи есть отдельный тест на сбой.
  • Каждая попытка использует один логический operation_id.
  • Журналы использования и журналы приложения сравниваются.
  • Пороги rollout и rollback записаны до запуска.
  • Предыдущую конечную точку можно восстановить без еще одного изменения кода.

Распространенные ошибки при миграции

Сохранение повторных попыток SDK и повторных попыток приложения без расчета итогового числа

Это самое важное замечание проверки. Значения по умолчанию — это тоже поведение, даже если оно не видно в локальной функции.

Проверка только крошечного промпта

Однострочный запрос подтверждает учетные данные и совместимость ответов. Он почти ничего не говорит о давлении TPM, ограничениях вывода, длинных потоках или задержке p95.

Повторные попытки при ошибках аутентификации и валидации

Backoff не может исправить неверный ключ, неподдерживаемый параметр или неправильно написанную модель. Повторные попытки с неизменной нагрузкой тратят ресурсы и скрывают реальный дефект.

Считать тайм-аут доказательством того, что запрос не выполнялся

Клиент может перестать ждать после того, как upstream уже принял вызов. Проектируйте повторные попытки и учет с учетом этой неопределенности.

Менять endpoint, модели, промпты и политику повторных попыток в одном релизе

Это затрудняет определение причины сбоев. Сначала перенесите один известный шаблон запроса, а затем расширяйте выбор модели после того, как маршрут станет наблюдаемым.

Более безопасное определение “OpenAI-compatible”

Для планирования миграции “OpenAI-compatible” должно означать, что паттерн взаимодействия достаточно знаком, чтобы уменьшить объем изменений в коде. Это не следует интерпретировать как обещание, что каждый провайдер разделяет одинаковые квоты, подсчет токенов, семантику ошибок, задержку, поведение потоковой передачи или поддержку параметров.

Это различие делает миграцию OpenAI client проще для проверки. Сохраняйте стабильный интерфейс там, где это помогает, но проверяйте операционный контракт там, где провайдеры и маршруты могут отличаться.

Flatkey централизует доступ и биллинг за одним OpenAI-compatible base URL, что может упростить diff клиента и последующее расширение моделей. Однако инженерная работа все равно состоит в том, чтобы явно определить повторные попытки, пропускную способность и наблюдаемость до переноса производственного трафика.

Это стандарт, которому должна соответствовать production миграция OpenAI client: небольшое изменение интерфейса, подкрепленное явными операционными доказательствами.

Ознакомьтесь со страницей цен Flatkey при выборе моделей для canary, а затем утверждайте миграцию только после того, как контрольный список пройдет code review, а поведение маршрута станет видно в логах.

Часто задаваемые вопросы

Следует ли отключать повторные попытки OpenAI SDK во время миграции?

Отключите их, если ваше приложение или очередь уже отвечает за повторные попытки. Если ни один другой уровень не выполняет retry, ограниченные повторные попытки SDK могут быть разумными. Важное правило — не допускать нескольких независимых владельцев повторных попыток.

В чем разница между RPM и TPM во время миграции?

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

Следует ли всегда повторно отправлять 429?

Только в пределах ограниченного бюджета повторных попыток и задержки. Учитывайте Retry-After, когда он доступен, иначе используйте exponential backoff с jitter. Останавливайтесь, если операция больше не может уложиться в целевую задержку продукта.

Можно ли безопасно повторить генерацию, завершившуюся по тайм-ауту?

Не с уверенностью. Upstream-запрос мог выполниться, даже если клиент дождался тайм-аута. Рассматривайте повтор как возможный дубликат запроса и логируйте связь между попытками.

Какой минимальный безопасный canary?

Используйте одну закреплённую модель, один формат запроса, явное владение повторными попытками, ограничение на параллелизм и тесты для 429, тайм-аута, прерывания потоковой передачи и отката. Сравните клиентские попытки с журналами использования шлюза, прежде чем увеличивать трафик.

Источники