Гайд · TNWS AI
Как переранжировать результаты поиска через CrossEncoder.rank
Повторно проверяем top-k кандидатов для одного вопроса, сохраняем corpus_id и не применяем дорогую парную модель ко всей коллекции.
Задача и применимость
Поисковый запрос: «как переранжировать найденные документы CrossEncoder rank». Ниже одна практическая задача для Python с библиотекой Sentence Transformers 6.1.0, опубликованной 18 сентября 2026 года, и checkpoint cross-encoder/stsb-distilroberta-base. Пример на английских предложениях выбран потому, что поддержка русского выбранной демонстрационной моделью не должна подразумеваться автоматически. Для реального русского корпуса подберите подтверждённую карточкой языков модель и повторите оценку. Внешний поиск, генерация LLM и принятие бизнес-решения остаются отдельными этапами.
Фактическая основа: CrossEncoder вычисляет оценку для пары запрос-документ; rank(query, documents) сортирует кандидатов и возвращает corpus_id и score. В отличие от bi-encoder, его нельзя использовать для предварительного независимого вычисления и кеширования одного вектора каждого документа. Quickstart использует stsb-distilroberta-base. Точный прогноз значений векторных оценок без запуска весов модели не обещается. Примеры кода ниже сверены с текущей официальной документацией и проверены на синтаксис Python; в этом окружении сами веса не загружались. При обновлении модели или зависимости сначала повторите контрольный пример.
Нумерованная инструкция
- Получите ограниченный список кандидатов от первого этапа поиска и сохраните их IDs.
- Создайте CrossEncoder с моделью из официального примера.
- Передайте одинаковый исходный вопрос и тексты кандидатов в rank.
- Верните corpus_id к ID документа, а не к позиции всего индекса.
- Сравните top-1 до и после rerank на размеченных вопросах.
Подготовьте изолированное окружение и установите зафиксированный пакет: pip install "sentence-transformers==6.1.0". Библиотека потребует подходящих зависимостей и свободной памяти под выбранные веса; установка пакета не скачивает заранее любую модель. Перед тестом напечатайте установленную версию и зафиксируйте имя checkpoint. Не отправляйте в примеры клиентские имена, закрытые документы или ключи доступа.
Готовый шаблон
from sentence_transformers import CrossEncoder
query = "A man is eating pasta."
docs = [("d1", "A man is eating food."),
("d2", "A man is riding a horse."),
("d3", "A man is eating a piece of bread.")]
model = CrossEncoder("cross-encoder/stsb-distilroberta-base")
for hit in model.rank(query, [text for _, text in docs]):
doc_id, text = docs[hit["corpus_id"]]
print(doc_id, float(hit["score"]), text)
Запускайте первый раз на очень маленьком обезличенном наборе. Для каждой строки и документа сохраняйте стабильный ID: иначе невозможно выяснить, почему нейросеть выбрала конкретную запись. Если вывод отличается от ожидаемой формы, сначала проверьте состав входа, затем конфигурацию модели и только после этого настройки ранжирования. Не маскируйте ошибки ручной подстановкой заранее «правильного» ответа.
Конкретный вход и ожидаемый результат
Вход — вопрос о человеке, который ест пасту, и три англоязычных кандидата о еде, лошади и хлебе. Ожидается ранжированный список из трёх doc_id; d1 или d3 должны быть проверены выше нерелевантного d2 на реальном запуске. Конкретный порядок двух похожих записей и численные scores не фиксируются.
Проверяйте структуру отдельно от смысла. Массив верного размера не означает хорошего поиска, а высокий score не удостоверяет факт в документе. Сохраните реальные выводы программы и сопоставьте их с заранее размеченными эталонными ID. При переносе на другой корпус обновите проверочные данные; простая замена входного предложения в коде не доказывает обобщения метода.
Разбор метода и ограничений
Cross-encoder рассматривает вопрос и документ совместно. Это делает второй этап полезным для неоднозначных кандидатов, но стоимость работы растёт с количеством пар. Схема «всё заново прогнать через CrossEncoder» для большого архива обычно непропорциональна: сначала дешёвый retrieval, затем ограниченный rerank. Замерьте задержку при 10 и 50 кандидатах и выберите бюджет по p95 своего сервиса. Примерные scores модели STS описывают похожесть англоязычных фраз, а не право на доступ к документу. Если кандидат из другого tenant попал в набор, reranker может поставить его первым; контроль доступа должен сработать раньше. Сохраните ID кандидата отдельно от его временной позиции внутри списка.
Дополнительный сценарий проверки
Создайте вопросы с похожими словами, но разными условиями: «returns within 14 days» и «returns after 14 days». Если первый этап не нашёл корректный документ, rerank не сможет изобрести его из пустоты. Поэтому отдельно измеряйте recall кандидатов и accuracy после перестановки. Проверяйте два сценария: top-10 содержит нужный текст, top-10 его не содержит. Во втором повышение score нерелевантного отрывка не является улучшением. Для русскоязычных договоров выберите reranker с подтверждённой поддержкой русского, иначе англоязычная демонстрационная модель может выдать цифры без качества. После перехода на новую модель не сравнивайте абсолютные scores со старой без калибровки. Ответ LLM формируйте только из фактически разрешённых и проверенных источников.
Критерии принятия
- Каждый corpus_id относится к локальному списку кандидатов.
- Релевантный документ входит в первый этап поиска.
- Прирост top-1 проверен на размеченной выборке и измерена p95 задержка.
Если один пункт не проходит, настройка не готова для массового применения. При перезапуске сервиса повторно прогоните контрольный запрос и сверяйте ID, а не только наличие числовой оценки. Разделяйте ошибки получения embeddings, поиска кандидатов, фильтрации доступа и формирования финального ответа; хорошая метрика одного этапа не подтверждает работу остальных.
Типичные ошибки и что не делать
- Не отправлять всю коллекцию прямо в CrossEncoder.rank.
- Не считать reranker заменой фильтра прав доступа.
- Не трактовать score как вероятность истинности ответа.
Не обещайте точность и экономию ресурсов без измерений на своём оборудовании и корпусе. Не подменяйте документ нейросетевым выводом при объяснении решения пользователю. Помните о правах на доступ к исходным материалам: embedding не является анонимизацией приватного текста. При изменении модели, языка или способа подготовки данных повторите тесты до переключения рабочего трафика.
FAQ
Может ли reranker добавить потерянный документ?
Нет, он только переставляет переданные кандидаты.
Что обозначает corpus_id?
Позицию во входном списке rank.
Нужно ли кодировать документы заранее?
Для CrossEncoder пары оцениваются совместно при вызове.
Официальные источники
Частые вопросы
Может ли reranker добавить потерянный документ?
Нет, он только переставляет переданные кандидаты.
Что обозначает corpus_id?
Позицию во входном списке rank.
Нужно ли кодировать документы заранее?
Для CrossEncoder пары оцениваются совместно при вызове.
Читайте также
Как квантовать embeddings в int8 через SentenceTransformer.encode
Сравниваем тип и размер массива float32/int8, объясняем необходимость калибровки и измерения recall перед заменой хранилища.
Как найти релевантный фрагмент через semantic_search в Sentence Transformers
Кодируем вопрос и документы, связываем corpus_id с текстом, проверяем top_k и строим отказ при отсутствии подходящего источника.
Как найти смысловые дубли вопросов через paraphrase_mining
Ищем пары похожих вопросов, читаем позиции и score, исключаем отрицания и цифры ручной проверкой до объединения записей.
Комментарии
Пока тихо. Скажите первое слово