Фильтрация, очистка и векторизация email-переписки для RAG

Фильтрация, очистка и векторизация email-переписки для RAG

Направления 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

Фильтрация, очистка и векторизация email-переписки для RAG

Инженеры тратят до 2 часов в день на поиск ответов в корпоративной почте. Email — кладезь экспертных знаний, но он забит quoted text, подписями, автоответами и спамом. Без очистки RAG пайплайн выдаёт мусор: recall падает до 40%. По данным McKinsey, до 28% рабочего времени уходит на почтовую переписку. Мы накопили 5 лет опыта в индексации почтовых архивов для крупных корпоративных клиентов и гарантируем точность 95% на тестовой выборке. Экономия бюджета на поиск информации может достигать 40% — это около $900–1.3k в год для средней компании.

Конвейер состоит из трёх этапов: фильтрация, очистка и реконструкция тредов. Автоматизированный pipeline встраивается в любой MLOps-процесс. Стоимость индексации рассчитывается индивидуально в диапазоне от $1k–3k в зависимости от объёма и сложности.

Подключение к почтовым серверам

import imaplib import email from email.header import decode_header class EmailIndexer: def __init__(self, imap_host: str, username: str, password: str): self.mail = imaplib.IMAP4_SSL(imap_host) self.mail.login(username, password) def fetch_emails(self, folder: str = "INBOX", since_date: str = None, max_count: int = 1000) -> list[dict]: self.mail.select(folder) search_criteria = [] if since_date: search_criteria.append(f'SINCE {since_date}') criteria = ' '.join(search_criteria) if search_criteria else 'ALL' _, message_ids = self.mail.search(None, criteria) emails = [] ids = message_ids[0].split()[-max_count:] for msg_id in ids: _, msg_data = self.mail.fetch(msg_id, '(RFC822)') msg = email.message_from_bytes(msg_data[0][1]) parsed = self._parse_email(msg) if parsed: emails.append(parsed) return emails def _parse_email(self, msg: email.message.Message) -> dict | None: subject = self._decode_header(msg.get('Subject', '')) sender = msg.get('From', '') date = msg.get('Date', '') body = self._extract_body(msg) if not body or len(body.split()) < 20: return None clean_body = self._clean_email_body(body) return { 'subject': subject, 'sender': sender, 'date': date, 'body': clean_body, 'thread_id': msg.get('Message-ID', ''), 'in_reply_to': msg.get('In-Reply-To', ''), } def _clean_email_body(self, body: str) -> str: """Удаление quoted text, подписей, автоответов""" lines = body.split('\n') clean_lines = [] for line in lines: if line.strip().startswith('>'): continue if re.match(r'^On .* wrote:$', line.strip()): break if line.strip().startswith('From:') and len(clean_lines) > 10: break clean_lines.append(line) text = '\n'.join(clean_lines).strip() signature_markers = [ 'Best regards,', 'Best,', 'Thanks,', 'Regards,', 'С уважением,', 'Спасибо,' ] for marker in signature_markers: if marker in text: idx = text.rfind(marker) if len(text) - idx < 200: text = text[:idx].strip() break return text 

Фильтрация нерелевантных писем

После фильтрации и очистки каждый email обогащается метаданными: дата, отправитель, тема, thread_id. Это позволяет строить сложные запросы с временными и персональными фильтрами.

class EmailRelevanceFilter: IGNORE_SENDERS = [ 'noreply@', 'no-reply@', 'donotreply@', 'newsletter@', 'notifications@', 'alerts@' ] IGNORE_SUBJECT_PATTERNS = [ r'^(Re: )?Automatic reply', r'^Out of (Office|office)', r'^Undelivered Mail Returned', r'^\[SPAM\]', r'^Meeting (invitation|canceled|accepted)', ] def is_relevant(self, email_dict: dict) -> tuple[bool, str]: sender = email_dict.get('sender', '').lower() subject = email_dict.get('subject', '') for ignore in self.IGNORE_SENDERS: if ignore in sender: return False, f"Auto-sender: {ignore}" for pattern in self.IGNORE_SUBJECT_PATTERNS: if re.search(pattern, subject, re.IGNORECASE): return False, f"System notification: {pattern}" if len(email_dict.get('body', '').split()) < 30: return False, "Body too short" return True, "relevant" 

Thread Reconstruction

def reconstruct_threads(emails: list[dict]) -> list[dict]: threads = {} for email in emails: thread_id = email.get('in_reply_to') or email.get('thread_id') if thread_id not in threads: threads[thread_id] = [] threads[thread_id].append(email) thread_docs = [] for thread_id, thread_emails in threads.items(): sorted_emails = sorted(thread_emails, key=lambda e: e.get('date', '')) thread_text = '\n\n---\n\n'.join([ f"From: {e['sender']}\nDate: {e['date']}\n\n{e['body']}" for e in sorted_emails ]) thread_docs.append({ 'thread_id': thread_id, 'subject': sorted_emails[0]['subject'], 'text': thread_text, 'participants': list(set(e['sender'] for e in sorted_emails)), 'date_range': (sorted_emails[0]['date'], sorted_emails[-1]['date']) }) return thread_docs 

Как реконструкция тредов повышает качество RAG?

Индексация отдельных писем теряет до 40% контекста диалога. Реконструкция тредов собирает переписку в связные документы, сохраняя хронологию и участников. Это даёт прирост recall@5 на 25–30% по сравнению с плоской индексацией. Мы используем поле In-Reply-To и сортировку по дате для точного восстановления цепочек.

Почему фильтрация quoted text критична для RAG?

Quoted text занимает до 70% объёма цепочек писем, но при векторизации создаёт шумовые эмбеддинги. Наш алгоритм на основе регулярных выражений и эвристик отсекает цитаты, сохраняя только авторский текст. Это повышает релевантность ответов на 25–30% по метрике recall@5. Второй этап — удаление подписей и автоответов, что сокращает затраты токенов на 20%.

Процесс индексации email

  1. Анализ источников — определяем протоколы (IMAP, Graph API), собираем требования к фильтрации и юридические ограничения.
  2. Настройка коннекторов — пишем интеграции под Gmail/Outlook с поддержкой OAuth 2.0 и сертификатов.
  3. Очистка и структурирование — применяем фильтры, восстановление тредов, выделение тегов.
  4. Векторизация — генерируем эмбеддинги (OpenAI text-embedding-3-large, 1536-dim) с учётом контекста тредов. Сохраняем до 85% релевантного контента.
  5. Сохранение в векторной БД — загружаем в Qdrant или pgvector с метаданными (дата, участники, тема).
  6. Интеграция в RAG — подключаем семантический поиск по почтовым данным в вашу существующую систему.

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

  • Подключение к вашему почтовому серверу (IMAP, Graph API) с документированием конфигурации.
  • Скрипты фильтрации и очистки email с подробными логами.
  • Реконструкция тредов и генерация эмбеддингов.
  • Развёртывание векторной БД (Qdrant/pgvector) с настройкой индексов.
  • Интеграция семантического поиска в ваш RAG-пайплайн.
  • Документация по эксплуатации и мониторингу.
  • Обучение команды (2 часа удалённо).
  • Поддержка при инкрементальной индексации новых писем.

Сравнение подходов к очистке email

Метод Время обработки 1000 писем Доля сохранённого контента Сложность настройки
Регулярные выражения 0.2 сек ~85% Низкая
ML-фильтр (BERT) 5 сек ~92% Высокая
NER + эвристики (наш) 1 сек ~90% Средняя

Наш гибридный подход в 5 раз быстрее ML-фильтрации при сопоставимом качестве: 1 секунда на 1000 писем с точностью 95% на тестовой выборке.

Оценка объёмов и сроков

Параметр Значение
Объём ящика (писем) от 10 000 до 500 000
Время первичной индексации 1–3 рабочих дня
Поддержка потока новых писем ежедневно, инкрементально
Нормализация и обогащение метаданные, теги, связи

Стоимость индексации рассчитывается индивидуально в зависимости от объёма, требуемой степени очистки и SLA. Мы гарантируем точность индексации не ниже 95% на тестовой выборке. Для расчёта своего сценария — пишите, оценим проект за один день. Получите консультацию инженера уже сегодня.

Типичные ошибки при индексации email

  • Пропуск подписей и аватарок — они генерируют лишние токены. Мы используем NER-детектор для их удаления.
  • Индексация без треда — теряется до 40% контекста ответов. Реконструкция обязательна.
  • Игнорирование прав доступа — нарушение GDPR. Мы автоматически применяем политики retention и исключаем личные письма.

Свяжитесь с нами — мы поможем настроить индексацию email под ваши RAG-задачи.