Индексация документов для RAG (PDF, DOCX, HTML, Markdown)

Типичный сценарий: клиент загружает 500-страничный PDF с таблицами и многоколоночной версткой, а RAG-система возвращает битые ответы — текст из колонок сливается, заголовки теряются, таблицы превращаются в кашу. Мы знаем, как этого избежать: качественный парсинг — фундамент любого 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

Типичный сценарий: клиент загружает 500-страничный PDF с таблицами и многоколоночной версткой, а RAG-система возвращает битые ответы — текст из колонок сливается, заголовки теряются, таблицы превращаются в кашу. Мы знаем, как этого избежать: качественный парсинг — фундамент любого RAG-пайплайна. За 5 лет мы обработали более 200 проектов разной сложности, и убедились: экономия на парсинге оборачивается потерей точности ответов.

Почему качество парсинга определяет успех RAG?

Современные RAG-системы, такие как те, что строятся на LangChain или LlamaIndex, требуют чистого структурированного текста для корректного чанкования и эмбеддинга. Если на входе — «каша», то и поиск будет хаотичным. Исследования показывают, что до 30% ошибок RAG вызваны именно плохим парсингом исходных документов. Мы используем стек: PyTorch для кастомных моделей, pdfplumber для PDF, BeautifulSoup и markdownify для HTML, python-docx для DOCX.

Какие форматы мы поддерживаем? — индексация документов для

Формат Сложность парсинга Особенности
PDF Высокая Таблицы, колонки, сканы (OCR)
DOCX Средняя Встроенные таблицы, стили
HTML Низкая Мусорные теги, скрипты
Markdown Низкая Готовые заголовки и списки

Как мы парсим сложные PDF?

Возьмем реальный кейс: PDF с бухгалтерской отчетностью — 200 страниц, на каждой таблица с финансовыми данными. Стандартные библиотеки PyPDF2 или pdfminer теряют границы ячеек. Мы применяем pdfplumber с кастомной постобработкой:

from pathlib import Path from dataclasses import dataclass @dataclass class ParsedDocument: text: str metadata: dict source_format: str page_count: int = None class DocumentParser: def parse(self, file_path: str) -> ParsedDocument: path = Path(file_path) ext = path.suffix.lower() if ext == '.pdf': return self._parse_pdf(file_path) elif ext in ['.docx', '.doc']: return self._parse_docx(file_path) elif ext in ['.html', '.htm']: return self._parse_html(file_path) elif ext in ['.md', '.markdown']: return self._parse_markdown(file_path) else: raise ValueError(f"Unsupported format: {ext}") def _parse_pdf(self, path: str) -> ParsedDocument: # Для сложных PDF (с таблицами, колонками) — pdfplumber import pdfplumber with pdfplumber.open(path) as pdf: pages_text = [] for page in pdf.pages: # Сохранение таблиц как markdown tables = page.extract_tables() text = page.extract_text() or "" for table in tables: table_md = self._table_to_markdown(table) text += f"\n\n{table_md}\n\n" pages_text.append(text) full_text = "\n\n---PAGE BREAK---\n\n".join(pages_text) return ParsedDocument( text=full_text, metadata={"source": path, "pages": len(pdf.pages)}, source_format="pdf", page_count=len(pdf.pages) ) def _parse_docx(self, path: str) -> ParsedDocument: from docx import Document doc = Document(path) elements = [] for element in doc.element.body: if element.tag.endswith('p'): # Параграф para = element style = para.style.name if hasattr(para, 'style') else '' text = element.text_content() if style.startswith('Heading'): level = int(style.split()[-1]) if style[-1].isdigit() else 1 elements.append('#' * level + ' ' + text) elif text.strip(): elements.append(text) elif element.tag.endswith('tbl'): # Таблица table = self._extract_table_from_docx(element) elements.append(table) return ParsedDocument( text='\n\n'.join(elements), metadata={"source": path}, source_format="docx" ) def _parse_html(self, path: str) -> ParsedDocument: from bs4 import BeautifulSoup with open(path, 'r', encoding='utf-8') as f: soup = BeautifulSoup(f.read(), 'html.parser') # Удаление скриптов и стилей for tag in soup(['script', 'style', 'nav', 'footer', 'header']): tag.decompose() # Извлечение структурированного текста from markdownify import markdownify text = markdownify(str(soup), heading_style="ATX") return ParsedDocument( text=text, metadata={"source": path, "title": soup.title.string if soup.title else ""}, source_format="html" ) 

Структурированное извлечение метаданных

class MetadataExtractor: def extract(self, doc: ParsedDocument) -> dict: metadata = doc.metadata.copy() # Извлечение заголовков для навигации headers = re.findall(r'^#{1,3}\s+(.+)$', doc.text, re.MULTILINE) metadata['headers'] = headers[:20] # Первые 20 заголовков # Извлечение дат date_pattern = r'\b\d{1,2}[./]\d{1,2}[./]\d{2,4}\b' dates = re.findall(date_pattern, doc.text) if dates: metadata['dates_mentioned'] = dates[:5] # Язык документа from langdetect import detect try: metadata['language'] = detect(doc.text[:1000]) except Exception: metadata['language'] = 'unknown' return metadata 

Подготовка к индексации

После парсинга документы чанкируются (разбиваются на фрагменты), эмбеддируются и загружаются в векторную БД. Ключевой момент: сохранение структурных маркеров (заголовки, номера страниц) в метаданных чанков для обеспечения атрибуции источника в ответах RAG.

Для 1000-страничного PDF полный цикл (парсинг → чанкинг → эмбеддинг → индексация): 5-15 минут при использовании OpenAI Embeddings API. Собственные GPU на базе Triton Inference Server ускоряют эмбеддинг в 2-3 раза.

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

  • Аудит документов: анализ типов, объема, сложности.
  • Разработка пайплайна: парсеры, чанкер, эмбеддер, загрузчик.
  • Интеграция с векторной базой: Qdrant, ChromaDB, pgvector — на ваш выбор.
  • Тестирование на метриках: recall@k, precision@k, latency p99.
  • Документация и обучение: передача кода, описание архитектуры, обучение вашей команды.
  • Поддержка: 3 месяца гарантии на баги и адаптацию под новые форматы.

Сравнение: готовые сервисы против кастомного решения

Критерий Готовые сервисы (например, Unstructured.io) Наше кастомное решение
Качество извлечения таблиц Среднее (до 70%) Высокое (95%+)
Поддержка редких форматов Ограничена Любые форматы под заказ
Контроль над метаданными Минимальный Полный контроль
Стоимость на 10 000 страниц ~$500/мес Единоразово + поддержка
Интеграция с вашим стеком Через API Глубокое встраивание

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

  1. Аналитика: вы присылаете 2-3 образца документов, мы оцениваем сложность и сроки.
  2. Проектирование: выбираем стек (Hugging Face Embeddings, vLLM, etc.), проектируем пайплайн.
  3. Реализация: пишем код парсеров и интеграцию с вашей RAG-системой.
  4. Тестирование: прогоняем на ваших данных, подгоняем чанкинг и эмбеддинги.
  5. Деплой: разворачиваем в вашей инфраструктуре (AWS, GCP, on-prem).

Ориентировочные сроки: от 2 недель до 2 месяцев в зависимости от объема и сложности. Стоимость рассчитывается индивидуально под каждый проект.

Стратегии чанкования: как разбивка влияет на точность RAG

Выбор стратегии чанкования напрямую влияет на recall@5 в вашем RAG. Слишком большие чанки (2000+ токенов) снижают точность поиска. Слишком маленькие (64 токена) теряют контекст.

Проверенные стратегии:

  • Fixed-size с overlap: чанки по 512 токенов, перекрытие 64 токена. Хорошо для однородных текстов без сложной структуры.
  • Sentence window: чанк = предложение + 2–3 предложения по бокам. Высокий recall, подходит для FAQ.
  • Heading-based: разбивка по заголовкам документа. Идеально для технической документации и нормативов.
  • Semantic chunking: нарезка по семантическим границам (SBERT cosine similarity). Лучшее качество, но требует дополнительных вычислений.

Мы тестируем несколько стратегий на ваших документах и выбираем по метрикам recall@5 и MRR.

Получите консультацию — пришлите образцы документов, и мы в течение 1 рабочего дня дадим оценку. Наш опыт: 200+ проектов, 5 лет на рынке, гарантия качества на каждый этап.