中文翻译暂不可用,显示俄语原文。
Как вы делаете extraction таблиц из PDF для RAG?
Краткий тезис
Извлечение таблиц из PDF для RAG — это многоэтапный процесс, включающий детекцию (нахождение таблиц на странице), структурное распознавание (восстановление строк, столбцов, объединённых ячеек) и сериализацию в формат, понятный LLM (обычно Markdown или HTML). Ключевые инструменты — Table Transformer (TATR) для детекции, Camelot или Tabula для извлечения структуры, а также pdfplumber и PyMuPDF для тонкой настройки. После извлечения таблицы необходимо правильно чанковать (например, по строкам) и индексировать для поиска, используя как BM25, так и эмбеддинги строк.
1. Проблема: почему таблицы в PDF сложны для RAG
PDF — это формат представления, а не структурированных данных. Таблицы могут быть:
- Настоящими таблицами (созданными в Word/LaTeX и экспортированными с сохранением структуры).
- Изображениями таблиц (отсканированные документы, скриншоты).
- Псевдотаблицами (текст, выровненный пробелами/табуляцией).
Без специальной обработки RAG-система либо теряет табличную информацию (если просто извлекать текст), либо получает «кашу» из строк, что резко снижает качество retrieval и генерации ответа.
Термин: Extraction (извлечение) — процесс преобразования неструктурированного или слабоструктурированного содержимого PDF в машиночитаемые структуры данных (DataFrame, Markdown).
2. Этап 1: Детекция таблиц на странице
Прежде чем извлекать содержимое, нужно понять, где на странице находятся таблицы. Используются два подхода:
2.1 Правила на основе координат (rule-based)
Библиотеки вроде pdfplumber и PyMuPDF анализируют расположение текстовых блоков и линий. Если найдены прямоугольные области с повторяющимися выравниваниями — это таблица.
- Плюсы быстро, не требует GPU.
- Минусы ломается на сложных макетах, изображениях таблиц.
2.2 Нейросетевые детекторы
Table Transformer (TATR) — модель на основе DETR (DEtection TRansformer), обученная на датасетах PubTables-1M, FinTabNet. Она возвращает bounding box для каждой таблицы на изображении страницы.
- Плюсы высокая точность, работает с изображениями (OCR-слой не нужен).
- Минусы требует GPU, медленнее rule-based.
Термин: Bounding box — прямоугольник, заданный координатами (x1, y1, x2, y2), ограничивающий объект на изображении.
# Пример использования TATR через Hugging Face
from transformers import AutoImageProcessor, TableTransformerForObjectDetection
from PIL import Image
import torch
image = Image.open("page.png")
processor = AutoImageProcessor.from_pretrained("microsoft/table-transformer-detection")
model = TableTransformerForObjectDetection.from_pretrained("microsoft/table-transformer-detection")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
# Преобразование outputs в bounding boxes
results = processor.post_process_object_detection(outputs, threshold=0.7)[0]
for box, score, label in zip(results["boxes"], results["scores"], results["labels"]):
if score > 0.7:
print(f"Table detected at {box.tolist()}")
3. Этап 2: Структурное распознавание таблицы
После получения bounding box нужно извлечь строки, столбцы и содержимое ячеек. Основные инструменты:
| Инструмент | Тип | Поддержка объединённых ячеек | Работа с изображениями | Скорость |
|---|---|---|---|---|
| Camelot | Rule-based + Lattice/Stream | Частично (Lattice) | Нет | Средняя |
| Tabula | Rule-based (Lattice) | Нет | Нет | Высокая |
| pdfplumber | Rule-based | Да (через словарь) | Нет | Средняя |
| PyMuPDF (fitz) | Rule-based | Да | Нет | Высокая |
| TATR + структура | Нейросеть | Да | Да | Медленная |
Camelot — наиболее популярный выбор для RAG, так как возвращает pandas DataFrame и поддерживает два режима:
- Lattice — для таблиц с явными линиями границ.
- Stream — для таблиц без линий (основан на пробелах).
Термин: Lattice vs Stream — Lattice использует линии для определения ячеек; Stream анализирует расположение текста на странице.
import camelot
# Извлечение таблиц из PDF
tables = camelot.read_pdf("document.pdf", pages="1-3", flavor="lattice")
for i, table in enumerate(tables):
df = table.df # pandas DataFrame
print(f"Table {i}: {df.shape}")
Если таблица — изображение, нужен OCR (Tesseract, PaddleOCR) перед структурным распознаванием. Затем можно применить TATR-structure (модель для распознавания структуры таблицы из изображения).
4. Этап 3: Сериализация в формат, понятный LLM
LLM плохо понимают сырые DataFrame или HTML с кучей атрибутов. Оптимальные форматы:
- Markdown-таблица — читаема и человеком, и LLM. Легко встраивается в контекст.
- HTML-таблица — сохраняет сложную структуру (colspan, rowspan), но занимает больше токенов.
- JSON — удобен для программной обработки, но LLM может путаться в ключах.
Рекомендация сериализовать в Markdown, если таблица простая (нет объединённых ячеек), иначе — в HTML.
def dataframe_to_markdown(df):
"""Конвертирует DataFrame в Markdown-таблицу."""
header = "| " + " | ".join(df.columns) + " |"
separator = "| " + " | ".join(["---"] * len(df.columns)) + " |"
rows = []
for _, row in df.iterrows():
rows.append("| " + " | ".join(str(cell) for cell in row) + " |")
return "\n".join([header, separator] + rows)
# Пример
markdown_table = dataframe_to_markdown(df)
print(markdown_table)
Термин: Сериализация — преобразование структуры данных (DataFrame) в строку определённого формата для передачи или хранения.
5. Этап 4: Чанкование таблиц
Таблицы могут быть огромными (сотни строк). Подавать их целиком в контекст LLM дорого и неэффективно. Стратегии чанкования:
- По строкам каждые N строк (например, 50) — отдельный чанк. Хорошо для retrieval по строкам.
- По смыслу группировка строк по категориям (если есть столбец-ключ).
- По страницам если таблица разбита на несколько страниц PDF.
Важно при чанковании сохранять заголовки столбцов в каждом чанке, иначе LLM не поймёт контекст.
def chunk_table(df, chunk_size=50):
"""Разбивает DataFrame на чанки по chunk_size строк."""
chunks = []
for start in range(0, len(df), chunk_size):
chunk_df = df.iloc[start:start+chunk_size]
# Добавляем заголовок в начало чанка
header = " | ".join(df.columns)
chunk_text = f"Заголовки: {header}\n" + dataframe_to_markdown(chunk_df)
chunks.append(chunk_text)
return chunks
Термин: Чанк (chunk) — фрагмент документа, который индексируется и возвращается при поиске.
6. Этап 5: Индексация и retrieval для табличных чанков
Для поиска по таблицам можно использовать:
- BM25 — хорошо работает на точных совпадениях чисел, дат, имён.
- Эмбеддинги строк — каждая строка таблицы превращается в вектор (например, через sentence-transformers). Поиск по смыслу.
- Гибридный поиск — комбинация BM25 и эмбеддингов с весами.
Пример индексации строк таблицы
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
model = SentenceTransformer("all-MiniLM-L6-v2")
# Превращаем каждую строку в текст
row_texts = []
for _, row in df.iterrows():
row_text = " | ".join(str(cell) for cell in row)
row_texts.append(row_text)
# Создаём эмбеддинги
embeddings = model.encode(row_texts)
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings)
# Поиск
query = "выручка за 2023 год"
query_emb = model.encode([query])
distances, indices = index.search(query_emb, k=5)
for idx in indices[0]:
print(row_texts[idx])
Термин: Гибридный поиск — объединение результатов лексического (BM25) и семантического (эмбеддинги) поиска, часто через взвешенную сумму релевантностей.
7. Продвинутые техники и подводные камни
7.1 Объединённые ячейки (merged cells)
Camelot Lattice частично поддерживает их, но часто возвращает пустые строки. Решение: постобработка — заполнение пустых ячеек значениями из предыдущей строки/столбца.
7.2 Таблицы-изображения
Требуют OCR + TATR-structure. Можно использовать PaddleOCR для распознавания текста, затем TATR для восстановления структуры.
7.3 Повёрнутый текст
Некоторые PDF содержат текст под углом. Библиотеки вроде pdfplumber могут не распознать. Решение: использовать детектор ориентации (например, через Tesseract) и поворачивать страницу.
7.4 Многостраничные таблицы
Таблица может продолжаться на нескольких страницах. Нужно объединять чанки по ключу (например, номер таблицы). Camelot возвращает таблицы постранично, требуется логика слияния.
7.5 Оценка качества extraction
Метрики: TEDS (Tree Edit Distance for Tables) — сравнивает структуру извлечённой таблицы с эталонной. Для RAG важнее retrieval quality (hit rate, MRR) на табличных запросах.
8. Интеграция в Agentic RAG
В архитектуре Agentic RAG извлечение таблиц может быть отдельным инструментом (tool), который агент вызывает по необходимости. Например:
- Агент получает запрос: «Сравни выручку за 2022 и 2023 из таблицы на странице 5».
- Агент вызывает extract_table(pdf_path, page=5) → получает Markdown.
- Затем агент использует RAG по этому Markdown или напрямую подаёт в LLM.
Термин: Tool (инструмент) — функция, которую LLM-агент может вызвать для выполнения конкретной задачи (извлечение таблицы, поиск в БД, вызов API).
Пет-проект для закрепления
Задача Создать RAG-систему, которая отвечает на вопросы по финансовым отчётам (PDF с таблицами).
Инструменты
- Python, Camelot, pdfplumber, TATR (через Hugging Face), sentence-transformers, FAISS, LangChain или LlamaIndex.
- LLM: OpenAI API или локальная модель (Mistral, Llama).
Шаги:
- Загрузить 5–10 PDF с таблицами (например, отчёты компаний).
- Написать пайплайн: детекция таблиц (TATR) → извлечение (Camelot) → сериализация в Markdown → чанкование по 30 строк.
- Индексировать чанки: для каждого чанка создать эмбеддинг (sentence-transformers) и сохранить в FAISS.
- Реализовать retrieval: по запросу пользователя искать top-3 чанка.
- Подать чанки в LLM с промптом: «Ответь на вопрос, используя только табличные данные».
- Оценить качество: вручную проверить 10 вопросов (например, «Какая выручка в 2023?», «Сравни расходы по кварталам»).
Ожидаемый результат Работающий прототип, который корректно извлекает таблицы и отвечает на фактологические вопросы. Вы получите практический опыт обработки PDF, сериализации и гибридного поиска.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 542 | Как обрабатывать PDF с разной структурой? |
| 544 | Какие стратегии chunking'а вы знаете? |
| 548 | Как вы оцениваете качество retrieval'а? |
| 550 | Что такое гибридный поиск и когда его использовать? |
| 555 | Как вы интегрируете OCR в RAG-пайплайн? |
| 557 | Как вы обрабатываете многостраничные документы? |
Навигация
- Предыдущий: 555
- Следующий: 557
- Индекс: 00. Индекс разборов