Автоматическое объединение дублирующихся записей в CRM с помощью AI

Разработка AI-системы дедупликации контактов и компаний в CRM

Направления AI-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1440
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    997
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1264
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    712
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1002

Разработка AI-системы дедупликации контактов и компаний в CRM

В CRM с 100 000 контактов каждый пятый — дубль. Один и тот же клиент заведён трижды: как «Иванов Иван», «Иван Иванов» и «[email protected]». Результат: аналитика врёт, письма уходят в спам, менеджеры тратят часы на «новые» лиды, которые уже являются клиентами. Мы решаем эту проблему комбинацией трёх методов: rule-based, ML и embedding. После внедрения база становится чистой, процент дублей падает с 20% до 2-5%, а точность email-маркетинга растёт (unsubscribe rate снижается на 30%). За 5 лет мы провели дедупликацию на 50+ проектах с общим объёмом данных более 50 миллионов записей.

Entity Resolution — классическая задача, но в CRM есть своя специфика: поля заполнены нерегулярно, транслитерация, опечатки. Простые точные совпадения покрывают лишь 40% дублей. Поэтому мы строим многослойную систему.

Какие проблемы решаем?

  • Раздутая база: дубли занимают место и искажают аналитику. Типичная CRM с 100 000 контактов содержит 10-25% дублей. Сокращение базы на 8-15% даёт экономию на хранении и рассылках — до $2.7k–3.9k в год для среднего бизнеса.
  • Провалы в коммуникации: клиент получает три одинаковых письма — уходит в спам, отписывается. После дедупликации unsubscribe rate падает на 30%, что сохраняет до 15% маркетингового бюджета.
  • Ошибки в продажах: менеджер тратит время на «новый» лид, который уже является существующим клиентом. Потери времени — до 20 часов в месяц на отдел из 10 человек.

Как AI находит дубликаты контактов?

Используем три слоя детекции:

  1. Rule-based (быстрый отсев): точное совпадение email или телефона — уверенный дубль. Точность 99%, но низкий recall (около 40%).
  2. ML-модель (entity resolution): библиотека dedupe — учится на размеченных парах. Учитывает опечатки, транслитерацию, пропущенные поля. Точность 92-95%, полнота 80-85%.
  3. Embedding-based (масштабирование): превращаем каждый контакт в вектор (all-MiniLM-L6-v2, 384-мерные эмбеддинги) и ищем ближайших соседей через faiss. Обрабатывает миллионы записей за секунды, точность 88%, полнота 85%.

Сравнение методов:

Метод Точность Полнота Скорость Когда применять
Rule-based 99% 40% мгновенно email/телефон точные поля
ML (dedupe) 92% 80% минуты база 10k-500k записей
Embedding 88% 85% секунды база >1M записей, нечёткие имена

ML-модель в 1.5 раза точнее rule-based подхода и в 2 раза быстрее embedding-only подхода при размере базы до 500k записей.

ML-модель дедупликации (код)

import pandas as pd import dedupe from dedupe import Dedupe class ContactDeduplicator: def __init__(self): self.deduper = None def setup_fields(self): """Описание полей для dedupe""" fields = [ dedupe.variables.String('first_name'), dedupe.variables.String('last_name'), dedupe.variables.String('email', has_missing=True), dedupe.variables.String('phone', has_missing=True), dedupe.variables.String('company'), dedupe.variables.String('job_title', has_missing=True), ] return dedupe.Dedupe(fields) def train(self, records: dict, training_file: str = None): """Обучение на помеченных парах (match/not-match)""" self.deduper = self.setup_fields() if training_file and os.path.exists(training_file): with open(training_file) as f: self.deduper.prepare_training(records, f) else: self.deduper.prepare_training(records) # Активное обучение: разметка примерных пар dedupe.console_label(self.deduper) with open(training_file, 'w') as f: self.deduper.write_training(f) self.deduper.train() def find_duplicates(self, records: dict, threshold: float = 0.5) -> list[tuple]: """Поиск дублей с вероятностями""" clustered_dupes = self.deduper.partition(records, threshold) duplicate_groups = [] for (cluster_id, record_ids, scores) in clustered_dupes: if len(record_ids) > 1: duplicate_groups.append({ 'records': list(record_ids), 'scores': list(scores), 'max_score': max(scores) }) return sorted(duplicate_groups, key=lambda x: x['max_score'], reverse=True) 

Нечёткое сравнение строк

from rapidfuzz import fuzz, process def compute_similarity(record1: dict, record2: dict) -> float: scores = [] # Email: точное или domain совпадение if record1.get('email') and record2.get('email'): if record1['email'].lower() == record2['email'].lower(): return 1.0 # Точное совпадение email — определённо дубль email1_domain = record1['email'].split('@')[1] email2_domain = record2['email'].split('@')[1] if email1_domain == email2_domain: scores.append(0.5) # Один домен — похожи # Имя: нечёткое совпадение name1 = f"{record1.get('first_name', '')} {record1.get('last_name', '')}" name2 = f"{record2.get('first_name', '')} {record2.get('last_name', '')}" name_score = fuzz.token_sort_ratio(name1, name2) / 100 scores.append(name_score * 0.4) # Телефон: нормализация и сравнение phone1 = re.sub(r'\D', '', record1.get('phone', '')) phone2 = re.sub(r'\D', '', record2.get('phone', '')) if phone1 and phone2: if phone1[-10:] == phone2[-10:]: # Последние 10 цифр scores.append(0.9) # Компания if record1.get('company') and record2.get('company'): company_score = fuzz.token_set_ratio( record1['company'], record2['company'] ) / 100 scores.append(company_score * 0.2) return sum(scores) / len(scores) if scores else 0.0 

Стратегия слияния записей

def merge_duplicates(records: list[dict]) -> dict: """Слияние группы дублей в одну запись""" merged = {} field_priority = ['email', 'phone', 'first_name', 'last_name', 'company'] for field in field_priority: values = [r.get(field) for r in records if r.get(field)] if not values: continue # Берём наиболее часто встречающееся значение merged[field] = max(set(values), key=values.count) # Для created_at берём самую раннюю дату dates = [r.get('created_at') for r in records if r.get('created_at')] if dates: merged['created_at'] = min(dates) # Объединяем теги и метки all_tags = [] for r in records: all_tags.extend(r.get('tags', [])) merged['tags'] = list(set(all_tags)) merged['merged_from'] = [r['id'] for r in records] return merged 

Почему стоит внедрять дедупликацию на базе ML?

Rule-based пропускает опечатки и транслитерацию. Embedding-based без дообучения даёт ложные срабатывания. ML-модель на dedupe — золотая середина: обучается на ваших данных за пару часов активной разметки, точность 92-95%, полнота 80-85%. Гарантируем снижение процента дублей в базе минимум на 10% — опыт внедрения на 50+ проектах. Стоимость проекта рассчитывается индивидуально в зависимости от объёма данных и сложности интеграции.

Процесс работы

  1. Аудит базы — выгружаем контакты, оцениваем текущий процент дублей.
  2. Выбор стратегии — rule-based + ML или embedding для больших объёмов.
  3. Разметка и обучение — подготавливаем тренировочный набор, обучаем модель.
  4. Интеграция — API или прямой доступ к CRM (Bitrix24, AmoCRM, Salesforce).
  5. Тестирование — A/B сравнение: автоматическое слияние vs ручной аудит.
  6. Деплой и мониторинг — пайплайн периодической дедупликации, алерты по аномалиям.

Сравнение времени для разных объёмов данных:

Объём базы Длительность проекта
до 100 000 записей 7-14 дней
100k-1M 14-30 дней
>1M записей индивидуально

Что входит в работу

  • Документация: описание модели, настройки порогов, инструкция по дообучению.
  • Доступы: к исходному коду (GitLab), к обученной модели (MLflow), к дашборду метрик.
  • Обучение: сессия для аналитиков (как размечать новые данные).
  • Поддержка: 1 месяц — исправление ошибок, донастройка порогов.

Закажите бесплатный аудит вашей CRM — мы оценим процент дублей и экономический эффект. Свяжитесь с нами через форму на сайте или по телефону.