Как всё начиналось
Открываешь карточку клиента, звонишь, договариваешься — а через пару дней выясняется, что с ним уже полгода работает соседний отдел. Две цены, два договора, клиент в недоумении. У меня на одном внедрении в дистрибуции было именно так: 18 400 записей, после чистки осталось 11 200. Почти 40 % — дубли.
Воронка врёт, LTV завышен, отчёты в мусор. РОП каждое утро вручную склеивает карточки. Классика.
Что вообще бывает с названиями
Я разметил пару тысяч пар и увидел полный зоопарк:
- «ООО Ромашка», «Ромашка ООО», «Общество с ограниченной ответственностью Ромашка»
- ИП в трёх вариантах написания ФИО
- разные кавычки, пробелы, «Ромашко» вместо «Ромашка»
- холдинги, где «Торг» и «Логистика» — это два разных юрлица, хотя названия почти одинаковые
ИНН заполнен только у 41 %. Оставшиеся 59 % — пустые уже три года. Так что «просто сверим по ИНН» не работает.
Первая попытка — нормализация + Левенштейн
Сделал простую функцию: lower, убрал кавычки и оргформы, посчитал расстояние. На тесте получилось 71 % точности и 58 % полноты.
Левенштейн радостно склеивал «Ромашка-Торг» и «Ромашка-Логистика», но пропускал «ИП Иванов И.И.» и «ИП Иванов Иван Иванович». Потому что он смотрит на символы, а не на смысл.
Эмбеддинги: стало лучше, но появились новые проблемы
Перешёл на pgvector и русские модели эмбеддингов. Косинусная близость выше 0.92. Точность выросла до 84 %, полнота до 79 %.
Зато начал склеивать «Тёплый дом, ООО» и «Тёплый домик, ИП» — семантически близко, а юридически разные компании. Цена ошибки высокая.
Гибридный подход, который пошёл в прод
Сейчас у меня работает каскад:
- HNSW по эмбеддингам быстро отдаёт топ-10 кандидатов.
- Если ИНН совпал и валидный — дубль с уверенностью 0.99.
- Если ИНН разный — разные юрлица, точка.
- Если ИНН пустой — отдаём в небольшую LLM с жёстким промптом (400 токенов + few-shot).
Плюс добавил правило по телефону директора — сильный сигнал.
Результат на той же базе: точность 96.4 %, полнота 93.1 %. РОП тратит 40 минут в неделю вместо 6–8 часов. Две крупные сделки всплыли именно из «потерянных» дублей.
Сейчас при создании новой карточки триггер сразу ищет соседей и, если confidence > 0.85, показывает предупреждение.
Где всё ещё ломается
Холдинги с десятками однофамильных юрлиц — оставляю на ручную проверку. Иностранные контрагенты — отдельный канал. Старые CRM, где в названии лежит «Иванов И.И. (тел. +7...)» — сначала чистим регулярками.
Вывод
Одна метрика никогда не даёт больше 85 %. Нормально работает только каскад: быстрый отбор эмбеддингами, жёсткие правила по ИНН, LLM на спорных случаях и человек как арбитр. Всё остальное — либо дорого, либо опасно.
