1. Правильно выстройте архитектуру: двухэтапный retrieval
Reranking — это не самостоятельный метод retrieval. Это второй этап pipeline.1
Извлечение
Используйте векторный поиск или BM25, чтобы извлечь набор кандидатов из всего корпуса. Этот этап должен
быть быстрым и должен выбирать с запасом: цель — «ответ где-то здесь», а не
«ответ должен быть первым».
2
Реранжирование
Передайте набор кандидатов вместе с запросом в
bge-reranker-v2-m3, чтобы оценить и переупорядочить их.
Этот этап должен быть точным: цель — поднять правильный ответ на первое место.3
Обрежьте и передайте в LLM
Возьмите переупорядоченные top 3–5 в свой prompt. Чем точнее это сделано, тем меньше модель
галлюцинирует и тем меньше контекста вы оплачиваете.
Почему нельзя пропустить recall и реранжировать все подряд: cross-encoder нужен запрос,
прежде чем он сможет что-либо вычислить, поэтому ничего нельзя предварительно вычислить офлайн.
Оценивать миллионы документов по одному слишком дорого и по стоимости, и по задержке. Recall
сокращает их с миллионов до сотен; reranking правильно сортирует эти сотни.
Полный рабочий пример
Это минимальный, но полный двухэтапный retriever —text-embedding-3-small для recall, bge-reranker-v2-m3 для reranking, оба через один и тот же APIYI token:
2. Сколько кандидатов следует извлекать?
Измеренная задержка (короткие документы, P50 по 5 прогонам на ступень):
Важнее всего здесь фиксированные накладные расходы ~2 секунды: даже один документ стоит 2 секунды. Переход от 1 до 100 кандидатов добавляет всего 1.8 секунды, а выигрыш в качестве извлечения стоит гораздо больше.
На задержку на самом деле влияет общее число token, а не количество документов. Для тех же 50 кандидатов:
То же количество, но задержка выше в 4.7 раза. Именно поэтому chunking в следующем разделе не замедляет извлечение — chunking увеличивает количество документов, не увеличивая общее число token.
Если Вам действительно нужно ранжировать много документов (например, для офлайн-пакетной обработки), разделите задачу на несколько запросов по ≤100 документов и ограничьте concurrency значением 4. Учтите, что разбиение не уменьшает общее число token — TPM 20,000 по-прежнему остается общим ограничением, поэтому пакетные задания нужно ограничивать по скорости в расчете на минуту. Эта квота расширяется; для больших пакетных нагрузок сначала проверьте текущий доступный запас с помощью поддержки APIYI.
3. Разбивайте длинные документы на чанки
Это самый эффективный шаг предварительной обработки. Причину объясняют два измерения. Во-первых, нерелевантный контент размывает релевантность. Одно и то же совпадающее предложение с разным количеством добавленной воды:
Во-вторых, длина повышает шумовые оценки. Один и тот же нерелевантный документ получил 0.029 при короткой длине и 0.121 после 450 символов воды — в 4 раза выше.
Вместе это означает: длинный документ с ответом в конце проигрывает длинному документу, который вообще не по теме.
4. Настройка порогов (не просто выбирайте 0.5)
relevance_score отображается функцией sigmoid в диапазон 0–1, из-за чего он выглядит как значение уверенности. Это не так.
Измеренное распределение по всем тестовым случаям оценки качества:
Фиксированный порог 0.5 отбросил бы все корректные межъязыковые результаты и большинство результатов, занявших второе место в не-китайских языках, при этом пропустил бы отвлекающий документ с сильным совпадением по ключевым словам (для запроса «Apple Inc. FY2024 revenue,» документ о ценах на выращивание яблок получил 0.945 и занял третье место).
Обратите внимание на последнюю строку: нерелевантный документ с наивысшей оценкой (0.945) опережает релевантный документ с наименьшей оценкой (0.289). Эти два распределения перекрываются — именно поэтому не существует «безопасного» абсолютного порога.
5. Отрицание требует подстраховки
Это явная слабость модели. Для запроса “Какие достопримечательности стоит посетить зимой?” два документа, которые прямо говорят, что это не так, заняли 2-е и 3-е места, сдвинув действительно релевантные результаты на 4-е и 5-е. nDCG@3 оказался на уровне 0.47. Модель сопоставила тему “winter + attractions + travel” и так и не обработала отрицание. Исправление: добавьте легковесный проход проверки с помощью LLM после reranking. Достаточно недорогой небольшой модели:6. Мультиязычное и кросс-лингвальное использование
Китайский, английский, японский, корейский, русский, французский и арабский — а также кросс-лингвальный поиск ZH↔EN — все корректно упорядочены при тестировании. Одна модель покрывает мультиязычную базу знаний; вам не нужны отдельные развертывания для каждого языка. Но следите за величинами оценок:
Правильные кросс-лингвальные ответы получают оценки на 1–2 порядка ниже — но порядок при этом сохраняется.
7. Параллельные запросы, кэширование и идемпотентность
Сначала заложите квоту в расчет, потом говорите о параллельных запросах
Upstream (Huawei Cloud MaaS) допускает TPM 20,000 / RPM 120 для этой модели. Это ограничение чаще всего недооценивают — у модели эмбеддингов BGE-M3 на той же платформе 1,200,000 TPM, в 60 раз больше. Тестирование (с 70-секундной паузой перед каждым случаем, чтобы окно квоты успевало сброситься) позволило разделить две независимые механики:
Вывод 1: примерно 4–5 одновременных in-flight слотов. R1/R2 расходуют лишь 3–4% TPM, но массово дают сбои, а повышение параллельности с 10 до 20 все равно ограничивает число успешных запросов 4–5 — тогда как все 20 последовательных запросов в R5 проходят. Запросы сверх лимита слотов отклоняются сразу, а не ставятся в очередь.
Вывод 2: TPM 20,000 применяется независимо от параллельных запросов. R4 полностью последовательный, и 8-й запрос получает 429 при 16,093 накопленных tokens, причем до сдвига окна идет 9 подряд неудач:
Сколько поисков в минуту
Используя измеренный≈26.9 tokens/document:
Количество кандидатов — это решение по capacity не меньше, чем по качеству: удвоение числа кандидатов дает ограниченный прирост качества, но вдвое снижает пропускную способность.
Это также объясняет, почему один запрос не может содержать слишком много кандидатов — 1000 кандидатов это 26,867 tokens, 134% от всего минутного бюджета в одном вызове, так что 429 гарантирован. При 2000 — уже 269%.
Расширение квоты уже в процессе. Указанный выше TPM 20,000 — это первоначальное выделение upstream, и
APIYI уже подала заявку на его повышение. Если ваша нагрузка превышает то, что допускает таблица,
обратитесь в поддержку APIYI, чтобы пересмотрели upstream-квоту, а не снижайте масштаб проекта
под текущее значение.
Кэширование
Повторение идентичного запроса 10 раз дает побитово идентичный результат (нулевой drift). Drift около ~3.7e-4 появляется только когда порядок кандидатов перемешан (jitter пакетирования bf16), а порядок не меняется. Значит, результаты можно безопасно кэшировать:- Используйте в качестве ключа
normalised query + ordered hash of document contents - Не используйте сам
relevance_scoreв качестве ключа идемпотентности или дедупликации — поменяйте порядок кандидатов, и его последние цифры изменятся - Повторяющиеся запросы (FAQ, популярные поисковые запросы) обычно хорошо кэшируются, экономя и задержку, и нагрузку на upstream
8. Интеграция с существующими фреймворками
Имена параметров соответствуют Cohere Rerank v1 (query / documents / top_n / return_documents), но documents принимает только массив строк — [{"text": "..."}] возвращает 400 — и в ответе нет полей id / meta.
9. Контрольный список перед запуском
Корректность
Корректность
- Обратное сопоставление через
results[].index, а не по совпадению текста - Длинные документы разбиваются на фрагменты (200–500 символов) и агрегируются по лучшему score фрагмента
- Ни одна пара запрос-документ не превышает 8192 token
- Для запросов с отрицанием или исключением выполняется дополнительная проверка через LLM
Надежность
Надежность
- Наборы кандидатов ограничены 100
- Параллельные запросы ограничены 4 (измерено: upstream допускает примерно 4–5 одновременных запросов, лишние отклоняются сразу, а не ставятся в очередь)
- Пиковая пропускная способность проверена относительно TPM 20,000 (~15 поисков/мин при 100 кандидатах) и подтверждено, что ее достаточно
- Для 429 реализован backoff-retry (перегрузка upstream носит временный характер)
- Timeout установлен на 60 с или больше (100 коротких документов — это около 4.3 с на P95, но длинные документы или большие наборы доходят до десятков секунд)
- Путь запроса подтвержден как
/v1/rerank— неверный путь возвращает 200 + HTML, а не 404 - Имя модели указано правильно и в нижнем регистре — опечатка возвращает 503, что легко принять за сбой
Качество
Качество
- Фильтрация использует Top-N или относительный порог, а не угаданное фиксированное значение
- Проверены величины scores для многоязычных и межъязыковых сценариев, чтобы низкие scores не отфильтровывались
- Небольшой размеченный набор запросов был A/B-тестирован (rerank включен/выключен), чтобы подтвердить, что метрики действительно изменились
Стоимость и кэширование
Стоимость и кэширование
- Учитывается, что
usage.input_tokens/output_tokensвсегда равны 0 — см.prompt_tokens/total_tokens - Учитывается, что ни
top_n, ниreturn_documentsне снижает расход — оценивается каждый кандидат - Учет затрат основан на счете из консоли (
prompt_tokensиtotal_tokensотличаются примерно на 45% при 100 кандидатах, и в этой проверке не удалось подтвердить, какой из них выставляется к оплате) - Настроено кэширование результатов для часто повторяющихся запросов