У интерфейса Rerank нет единого стандарта, как у Chat Completions, поэтому один и тот же код у разных поставщиков может вернуть 404 или 422. При диагностике сначала разделяйте ошибки по HTTP-статусу, затем разбирайте «мягкие» случаи, когда приходит 200, но результат неверен. Ниже пять категорий: аутентификация, набор кандидатов, ограничение скорости, тайм-ауты и пустой результат; в конце — готовый код повторов и чек-лист журналов. Модели и цены — на странице тарифов.

Примечание: Cohere, Jina, Voyage и другие названия — товарные знаки их правообладателей; статья носит технический характер. Пути интерфейсов, лимиты и коды ошибок могут меняться от версии к версии — сверяйтесь с документацией соответствующего поставщика.

1. Сначала различите пять категорий

Симптом Частый статус Типичная причина Порядок действий
Ошибка аутентификации 401, 403 Неверный ключ, нет заголовка, модель не активирована Сначала учётные данные и права
Запрос отклонён 400, 422 Слишком большой набор, несовпадение полей, пустой документ Проверить тело запроса и лимиты
Неверный путь 404 Ошибка в endpoint, старое имя модели, неверная сборка Base URL Сверить с официальной документацией
Лимит или квота 429 Резкий рост параллелизма, общий ключ, шторм повторов Backoff, снижение параллелизма
Тайм-аут или ошибка upstream 504, 5xx Много кандидатов, длинные документы, перегрузка upstream Уменьшить запрос, ограниченные повторы
Пустой результат 200 Некорректный top_n, неверное поле, документы отфильтрованы Добавить проверки и оповещения

В журнале фиксируйте как минимум время, endpoint, модель, число документов, общее число символов, top_n, статус, длительность, число повторов и request ID. Не записывайте полный ключ и не печатайте целиком пользовательские документы.

2. 401 и 403: сначала аутентификация, затем права

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

  1. Используется ли в заголовке Authorization: Bearer с ключом; некоторые шлюзы требуют x-api-key.
  2. Нет ли вокруг ключа пробелов, переводов строк или лишних кавычек. При копировании из чата они появляются чаще всего.
  3. Не переопределены ли переменные окружения локальной конфигурацией или платформой развёртывания; совпадают ли ключи в локальной и онлайн-среде.
  4. Открыт ли ключу именно интерфейс реранкинга. У некоторых аккаунтов есть только права на чат, без Rerank.
  5. Правильно ли указан endpoint. Форматы /v1/rerank и /v2/rerank могут различаться; если просто добавить /rerank к Base URL чат-интерфейса, легко получить 404 или 401.

403 — личность валидна, но прав недостаточно. Смотрите, активирована ли модель, входит ли IP в белый список, есть ли права проекта и нет ли задолженности. 401 не повторяйте: повторы только раздуют журнал ошибок и могут запустить защиту от злоупотреблений. Сначала выполните минимальный curl, затем возвращайтесь к бизнес-коду.

3. 400 и 422: слишком большой набор и несовпадение полей

Слишком большой набор кандидатов — самая частая причина 400. У хостинговых интерфейсов обычно есть лимиты на число документов за вызов, токены одного документа и размер тела запроса. У Cohere, например, официально рекомендуется не более тысячи документов за вызов, а один документ по умолчанию усекается до 4096 токенов; у других поставщиков значения иные и меняются с версией модели, поэтому перед подключением проверяйте документацию. При превышении лимита правильная реакция — не слепой повтор, а:

  • разбить набор на части, переранжировать каждую отдельно и объединить по оценкам;
  • ограничить число кандидатов уже на этапе поиска, например пятьюдесятью–двумястами;
  • длинные документы сначала нарезать или усечь, не отправляя целый PDF в documents;
  • удалить пустые строки, null, пробельные и повторяющиеся документы.

Несовпадение полей тоже даёт 400 или 422: top_n записан как top_k или наоборот; Jina и Cohere чаще используют top_n, Voyage — top_k. В documents передан массив объектов вместо массива строк, либо id и text лежат на неверном уровне. Если top_n больше числа документов, одни интерфейсы возвращают ошибку, другие автоматически усекают. Параметры return_documents, truncation, max_tokens_per_doc могут не поддерживаться текущим поставщиком. NaN, Infinity и неэкранированные переводы строк в JSON также ломают разбор.

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

4. 429: лимиты, квоты и шторм повторов

429 означает, что запрос ограничен по скорости или квота исчерпана. Частые причины: превышение запросов в секунду или параллелизма тарифа, исчерпание токеновой квоты в пик, использование одного ключа несколькими сервисами, повторы без задержки. Сначала посмотрите Retry-After и поля квоты в заголовках ответа, затем решайте, ждать или снижать параллелизм.

Порядок обработки:

  1. Определите, это лимит одного ключа или квота всего аккаунта.
  2. Переведите повторы на экспоненциальную задержку со случайным разбросом и учитывайте Retry-After.
  3. Ограничьте параллелизм и сглаживайте пики очередью, а не бесконечными повторами.
  4. Перенесите пакетные задачи на часы низкой нагрузки, разделите офлайн-оценку и онлайн-трафик.
  5. Для критичных сервисов предусмотрите деградацию: пропуск реранкинга с сохранением порядка поиска.

Не повторяйте с фиксированной секундой до отказа. Несколько экземпляров, повторяющих одновременно, создают шторм повторов и превращают небольшой лимит в длительный сбой.

5. Тайм-ауты, 504 и 5xx

Тайм-аут делится на соединение и чтение. Тайм-аут соединения обычно связан с сетью, DNS, прокси или TLS; тайм-аут чтения — с большим набором кандидатов, длинными документами, очередью upstream или холодным стартом модели. 504 обычно означает, что шлюз не дождался upstream; это не то же самое, что тайм-аут клиента.

Порядок диагностики:

  1. Проверьте минимальный запрос: один query и пять коротких документов, чтобы исключить полную недоступность сети.
  2. Постепенно увеличивайте число документов и найдите точку роста времени.
  3. Проверьте длину одного документа и общее число токенов, при необходимости усеките.
  4. Убедитесь, что клиентский тайм-аут не короче времени обработки на сервере.
  5. Для 5xx и тайм-аутов делайте ограниченное число повторов, после порога — деградация.
  6. Записывайте request ID и trace id upstream для сверки с поставщиком.

Rerank обычно не потоковый интерфейс, поэтому скрыть долгую обработку потоковым выводом нельзя. Для чувствительных к задержке сервисов реранкинг стоит вынести в асинхронную цепочку или применять только к первым десяткам кандидатов.

6. Приходит 200, но результат пустой или неверный

Такие мягкие ошибки коварнее: documents — пустой массив, и интерфейс возвращает пустой результат; top_n равен нулю или отрицательному числу; все документы исключены бизнес-фильтрами; прочитано неверное поле ответа — где-то results, где-то data; index — позиция в исходном массиве, но после разбиения на части забыли добавить смещение; семантика оценок различается — одни нормализуют к нулю–единице, другие отдают logits, направление сортировки тоже может отличаться; возвращается текст документа вместо index, и при дедупликации одинаковые тексты склеиваются.

Добавьте на клиенте проверки: число результатов не больше top_n, каждый index в допустимом диапазоне, оценки монотонны в соответствии с семантикой поставщика. При аномалии сохраняйте краткую сводку исходного ответа, а не молча возвращайте пустой список.

7. Готовый код повторов

Пример делит ошибки на три класса: аутентификация и параметры не повторяются, 429 и 5xx повторяются с задержкой, тайм-ауты — ограниченно; после исчерпания повторов происходит деградация к исходному порядку поиска.

import random
import time
import requests

def rerank(query, documents, top_n=10, model="<rerank-model>",
           url="<base-url>/v1/rerank", api_key="<key>"):
    payload = {"model": model, "query": query,
               "documents": documents, "top_n": top_n}
    headers = {"Authorization": f"Bearer {api_key}"}
    last_error = None
    for attempt in range(5):
        try:
            resp = requests.post(url, json=payload, headers=headers,
                                 timeout=(3.05, 30))
        except requests.Timeout as exc:
            last_error = exc
            time.sleep(min(2 ** attempt + random.random(), 20))
            continue

        if resp.status_code in (400, 401, 403, 404, 422):
            raise RuntimeError(f"Без повтора {resp.status_code}: {resp.text[:300]}")
        if resp.status_code == 429 or resp.status_code >= 500:
            retry_after = resp.headers.get("Retry-After")
            wait = float(retry_after) if retry_after else min(
                2 ** attempt + random.random(), 20)
            time.sleep(wait)
            last_error = RuntimeError(f"Повтор {resp.status_code}")
            continue

        data = resp.json()
        results = data.get("results") or data.get("data") or []
        if not results:
            return list(range(min(top_n, len(documents))))
        return [item["index"] for item in results[:top_n]]

    raise RuntimeError(f"Повторы исчерпаны: {last_error}")

# Вызывающая сторона всё равно адаптирует поля под поставщика:
# например, Voyage использует data и top_k.

Если документы переранжируются частями, при объединении прибавляйте к index смещение части, затем сортируйте единый список.

8. Чек-лист журналов и мониторинга

На каждый вызов записывайте: время, endpoint, модель, число документов, общее число символов или оценку токенов, top_n, статус, тип ошибки, длительность, число повторов, request ID. Не записывайте полный ключ и не сохраняйте пользовательские документы целиком; для диагностики достаточно хеша, длины и обезличенных первых символов.

Мониторинг должен покрывать четыре показателя: долю 429, долю тайм-аутов и 5xx, долю пустых результатов и задержку p95. Разбивайте их по бизнес-линиям, чтобы высокочастотная низкоценная задача не съедала квоту и не маскировала сбой основного сервиса.

Частые вопросы

Чем 401 отличается от 403?

401 — личность не прошла проверку, обычно из-за отсутствующего, неверно оформленного или просроченного ключа. 403 — личность валидна, но прав недостаточно: модель не активирована, IP не в белом списке, ограничен проект или баланс. Сначала исправляйте аутентификацию, затем права.

Что делать, если набор кандидатов превышает лимит интерфейса?

Разбейте его на клиенте, переранжируйте части отдельно и объедините по оценкам, добавив смещение к index. Более правильное решение — ограничивать число уже на этапе поиска: обычно достаточно десятков или сотен документов, не отправляйте тысячи в реранкинг.

Сколько раз повторять 429?

Единого ответа нет. Рекомендуется ограниченное число повторов, например три–пять, с экспоненциальной задержкой и случайным разбросом, с учётом Retry-After; параллелизм тоже нужно ограничить. После исчерпания — деградация, а не бесконечное накопление запросов.

Можно ли использовать потоковый режим при тайм-ауте Rerank, как в чате?

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

Приходит 200, но результатов нет — почему?

Проверьте, не пуст ли documents, корректен ли top_n, не исключили ли документы бизнес-фильтры; затем проверьте, не перепутано ли поле ответа и не выходит ли index за границы при объединении частей. Проверки и оповещение о пустом результате эффективнее разбора постфактум.

Что дальше

После диагностики зафиксируйте минимальный воспроизводимый пример и набор регрессионных случаев, затем создайте тестовый ключ в ZSQH AI Gateway и проверьте всю цепочку вызова; тарификация и лимиты — на странице тарифов.

Связанные статьи: