Гайд · TNWS AI
Как найти смысловые дубли вопросов через paraphrase_mining
Ищем пары похожих вопросов, читаем позиции и score, исключаем отрицания и цифры ручной проверкой до объединения записей.
Задача и применимость
Поисковый запрос: «как найти смысловые дубли FAQ paraphrase_mining sentence transformers». Ниже одна практическая задача для Python с библиотекой Sentence Transformers 6.1.0, опубликованной 18 сентября 2026 года, и checkpoint sentence-transformers/all-MiniLM-L6-v2. Пример на английских предложениях выбран потому, что поддержка русского выбранной демонстрационной моделью не должна подразумеваться автоматически. Для реального русского корпуса подберите подтверждённую карточкой языков модель и повторите оценку. Внешний поиск, генерация LLM и принятие бизнес-решения остаются отдельными этапами.
Фактическая основа: util.paraphrase_mining(model, sentences) возвращает отсортированные пары вида [score, id1, id2]; top_k и max_pairs управляют количеством кандидатов. Это поиск похожих формулировок, а не готовое решение об объединении записей. Точный прогноз значений векторных оценок без запуска весов модели не обещается. Примеры кода ниже сверены с текущей официальной документацией и проверены на синтаксис Python; в этом окружении сами веса не загружались. При обновлении модели или зависимости сначала повторите контрольный пример.
Нумерованная инструкция
- Соберите список коротких FAQ-вопросов с уникальными ID.
- Подайте тексты в paraphrase_mining с ограниченным top_k.
- Преобразуйте id1/id2 к исходным текстам без перестановки массива.
- Просмотрите пары по убыванию score и отметьте истинные смысловые дубли.
- Перед слиянием отдельно проверьте отрицания, числа и разные процедуры.
Подготовьте изолированное окружение и установите зафиксированный пакет: pip install "sentence-transformers==6.1.0". Библиотека потребует подходящих зависимостей и свободной памяти под выбранные веса; установка пакета не скачивает заранее любую модель. Перед тестом напечатайте установленную версию и зафиксируйте имя checkpoint. Не отправляйте в примеры клиентские имена, закрытые документы или ключи доступа.
Готовый шаблон
from sentence_transformers import SentenceTransformer, util
items = [("q1", "How do I return a purchase?"),
("q2", "What is the process for returning an item?"),
("q3", "Can I return an item after the deadline?"),
("q4", "Where can I track my parcel?")]
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
for score, i, j in util.paraphrase_mining(
model, [text for _, text in items], top_k=3):
print(round(score, 3), items[i][0], items[j][0])
Запускайте первый раз на очень маленьком обезличенном наборе. Для каждой строки и документа сохраняйте стабильный ID: иначе невозможно выяснить, почему нейросеть выбрала конкретную запись. Если вывод отличается от ожидаемой формы, сначала проверьте состав входа, затем конфигурацию модели и только после этого настройки ранжирования. Не маскируйте ошибки ручной подстановкой заранее «правильного» ответа.
Конкретный вход и ожидаемый результат
Вход — четыре вопроса q1–q4. q1 и q2 могут быть кандидатами на слияние; q3 отличается критическим условием «after the deadline», q4 о доставке. Ожидаемая структура ответа — оценка, две исходные позиции и IDs. Решение о дубликате принимает редактор после чтения обеих формулировок и правил возврата.
Проверяйте структуру отдельно от смысла. Массив верного размера не означает хорошего поиска, а высокий score не удостоверяет факт в документе. Сохраните реальные выводы программы и сопоставьте их с заранее размеченными эталонными ID. При переносе на другой корпус обновите проверочные данные; простая замена входного предложения в коде не доказывает обобщения метода.
Разбор метода и ограничений
Семантический дубль отличается от текстового совпадения. Два вопроса могут выглядеть одинаково, но требовать разных ответов для цифрового и физического товара. А «How do I return» и «What is the process for returning» могут вести к одной редакционной статье. Функция возвращает вероятных кандидатов, ускоряя ручной разбор, а не удаляет одну запись из базы. Сначала сохраняйте связи обеих версий и историю посещений: SEO-страницы нельзя без плана перенаправления просто стереть. Приборный score зависит от модели, поэтому порог объединения выбирайте после просмотра ложных совпадений. q3 полезен как отрицательный контроль: одно условие о сроке может полностью поменять ответ, даже если вектора близки.
Дополнительный сценарий проверки
Промаркируйте хотя бы несколько десятков пар разного типа: перефразирования, совпадения с разными датами, отрицания, уточнение товара, не связанные вопросы. Разделите ошибки «пропущен дубль» и «слиты разные условия»; последняя опаснее, когда речь о гарантиях и возвратах. Для большого корпуса лимит max_pairs ограничивает вывод, а параметры chunk_size — нагрузку; измеряйте память на фактическом наборе. Если после сортировки или фильтрации вопросов список items меняется, позиции i/j потеряют смысл. Фиксируйте snapshot входного массива. Не переносите показанный английский checkpoint на русский FAQ без языковой оценки. Слияние делайте после проверки фактических ответов и политики перенаправления URL, а не по одной числовой оценке.
Критерии принятия
- Каждый i/j восстановлен к неизменённому исходному вопросу.
- q1/q2 просмотрены вместе с ответами, а q3 не слит автоматически.
- Порог выбран по размеченной выборке, а не по чужому примеру.
Если один пункт не проходит, настройка не готова для массового применения. При перезапуске сервиса повторно прогоните контрольный запрос и сверяйте ID, а не только наличие числовой оценки. Разделяйте ошибки получения embeddings, поиска кандидатов, фильтрации доступа и формирования финального ответа; хорошая метрика одного этапа не подтверждает работу остальных.
Типичные ошибки и что не делать
- Не удалять FAQ автоматически при высоком score.
- Не игнорировать слова «после» и «не».
- Не менять порядок массива после вычисления пар.
Не обещайте точность и экономию ресурсов без измерений на своём оборудовании и корпусе. Не подменяйте документ нейросетевым выводом при объяснении решения пользователю. Помните о правах на доступ к исходным материалам: embedding не является анонимизацией приватного текста. При изменении модели, языка или способа подготовки данных повторите тесты до переключения рабочего трафика.
FAQ
Удаляет ли функция дубли сама?
Нет, возвращает список пар-кандидатов.
Что означают i и j?
Индексы предложений во входном списке.
Можно ли назначить универсальный порог?
Нет, его проверяют на своей разметке.
Официальные источники
Частые вопросы
Удаляет ли функция дубли сама?
Нет, возвращает список пар-кандидатов.
Что означают i и j?
Индексы предложений во входном списке.
Можно ли назначить универсальный порог?
Нет, его проверяют на своей разметке.
Читайте также
Как квантовать embeddings в int8 через SentenceTransformer.encode
Сравниваем тип и размер массива float32/int8, объясняем необходимость калибровки и измерения recall перед заменой хранилища.
Как найти релевантный фрагмент через semantic_search в Sentence Transformers
Кодируем вопрос и документы, связываем corpus_id с текстом, проверяем top_k и строим отказ при отсутствии подходящего источника.
Как переранжировать результаты поиска через CrossEncoder.rank
Повторно проверяем top-k кандидатов для одного вопроса, сохраняем corpus_id и не применяем дорогую парную модель ко всей коллекции.
Комментарии
Пока тихо. Скажите первое слово