Парсинг научных и технических PDF - задача с двумя крайностями. Простые инструменты вроде PyMuPDF извлекают текст за миллисекунды, но ломают таблицы и игнорируют диаграммы. Тяжёлые облачные парсеры сохраняют структуру, но каждый вызов стоит денег и времени. Решение - адаптивный пайплайн, где LLM выступает контролёром качества: анализирует результат дешёвого парсера, выставляет флаг context_structured при обнаружении структурных рисков и запускает перепарсинг проблемных страниц через Azure Layout или Vision LLM. В этой статье разбираем архитектуру, два боевых кейса и результаты stress-теста 18 запусков, который доказывает: бинарному вердикту LLM доверять нельзя, стабильность даёт только чтение текстовой рациональной оценки.
Почему стандартные парсеры PDF ломаются на таблицах и диаграммах
Научные статьи проектируются для чтения человеком, а не для машинного извлечения. Двухколоночная вёрстка, плавающие таблицы, врезанные диаграммы - все эти элементы нарушают линейный порядок текста, который ожидает увидеть парсер. PyMuPDF отлично справляется с простыми одноколоночными страницами: извлекает текст с координатами, определяет шрифты, работает на порядок быстрее облачных аналогов. Но когда в документе встречается таблица с объединёнными ячейками или диаграмма с подписями, разбросанными по разным углам изображения, результат превращается в мешанину из несвязанных фрагментов.
Возьмём классическую статью Attention Is All You Need. Таблица 3 в ней сравнивает BLEU-метрики для разных конфигураций модели Transformer. PyMuPDF честно извлекает все числа и заголовки, но теряет связи между ячейками: значения из третьей колонки могут оказаться приклеенными к заголовку второй, а часть данных смешивается с подстрочными примечаниями. Диаграмма архитектуры Transformer - ещё сложнее. Текстовый парсер видит только подписи к блокам, но не понимает, что стрелки между ними значат, и полностью теряет топологию сети.
Проблема усугубляется тем, что визуально страница выглядит нормально. Открываешь PDF - таблица ровная, диаграмма понятная. Открываешь результат парсинга - набор строк без структуры. Именно для таких случаев нужен механизм, который автоматически определит: «эта страница требует более мощного парсера».
Архитектура адаптивного пайплайна: PyMuPDF как основа, Azure и Vision LLM как страховка
Пайплайн строится вокруг трёх компонентов и одного управляющего элемента - LLM с функцией выдачи структурированного вывода. Схема работы: документ разбивается на страницы, каждая страница сначала проходит через PyMuPDF, результат передаётся LLM для анализа, LLM выставляет флаг context_structured и текстовое обоснование, при обнаружении проблем страница отправляется на перепарсинг нужным инструментом. Такой подход сокращает затраты на 70-90% по сравнению с прогоном всего документа через Azure Document Intelligence - дорогой парсер получает только те страницы, где дешёвый не справился. Детальный разбор эвристик для предварительной классификации страниц мы давали в статье про каскад проверок для выявления таблиц и рисунков.
PyMuPDF: быстрый и дешёвый парсер по умолчанию
PyMuPDF - это Python-обвязка над библиотекой MuPDF, написанной на C. Скорость извлечения текста достигает сотен страниц в секунду на потребительском CPU. Библиотека возвращает текст с точными координатами bounding box каждого блока, строки и символа, что позволяет восстанавливать порядок чтения даже для двухколоночной вёрстки. Для 80-85% страниц типичного научного документа этого достаточно: заголовки, абзацы, простые списки извлекаются корректно.
Ограничения проявляются на элементах с нетривиальным пространственным расположением. Таблицы, где данные выровнены по сетке, PyMuPDF отдаёт как набор строк, перемежая заголовки и значения в порядке их физического расположения в PDF-потоке. Изображения извлекаются как бинарные объекты без анализа содержимого. Именно эти два класса проблем и обрабатывают следующие компоненты пайплайна.
Azure Layout: тяжёлая артиллерия для таблиц
Azure Document Intelligence в режиме Layout Analysis специально спроектирован для извлечения структурированного контента. Модель определяет таблицы как сетки ячеек, сохраняет связи «заголовок-значение», обрабатывает объединённые ячейки и многостраничные таблицы. Результат возвращается в формате, где каждая ячейка имеет координаты, текст и признак принадлежности к заголовку или данным.
Сравнение на Table 3 из Attention paper показательное. PyMuPDF выдал 12 строк текста, где значения BLEU для разных конфигураций перемешаны с названиями метрик. Azure Layout вернул структурированную таблицу с четырьмя колонками и шестью строками данных, где каждая ячейка семантически связана с правильным заголовком. Разница в качестве критична, если результат парсинга пойдёт в RAG-пайплайн: retrieval по запросу «BLEU score для Transformer Big» найдёт точное значение, а не набор разрозненных чисел. О том, как ошибки парсинга влияют на качество retrieval и генерации, мы писали в разборе четырёх этапов пайплайна RAG, где рождаются галлюцинации.
Vision LLM: достройка визуальной информации с диаграмм
Диаграммы - это информация, которая принципиально не переводится в текст через координаты bounding box. Архитектурная схема Transformer содержит блоки «Multi-Head Attention», «Feed Forward», «Add & Norm» и стрелки, показывающие поток данных. PyMuPDF извлечёт подписи к блокам, но потеряет топологию: что за чем следует, где происходят разветвления и суммирования.
Vision LLM решает эту задачу через анализ изображения диаграммы как картинки. Модель получает скриншот страницы или вырезанный фрагмент с диаграммой и генерирует текстовое описание, которое включает: перечень компонентов, направление связей между ними, тип операции в каждом узле. Результат - не просто список слов, а семантически полное описание, которое можно использовать как контекст для downstream-задач. В кейсе с диаграммой Transformer описание включало фразу «выходные данные энкодера подаются на каждый декодерный слой через cross-attention», что невозможно извлечь из текстовых подписей блоков.
Кейс 1: Разбор таблицы Attention paper (Table 3) - как LLM нашла структурный риск
Table 3 в оригинальной статье сравнивает BLEU-метрики для разных конфигураций модели на задаче перевода WMT 2014 English-to-German. Таблица содержит объединённые ячейки в заголовке и числовые значения с разным количеством знаков после запятой, что создаёт неравномерную сетку.
Что пошло не так: сравнение выдачи PyMuPDF и Azure Layout
Результат PyMuPDF для Table 3 выглядел так:
Table 3: Variations on the Transformer architecture.
Model BLEU EN-DE BLEU EN-FR Training
base 27.3 38.1 3.3
(A) 26.3 37.5 3.2
(B) 27.1 38.0 3.3
(C) 26.9 37.9 3.3
(D) 26.8 37.8 3.2
(E) 27.0 38.0 3.3
Big 28.4 41.0 3.3
На первый взгляд, данные на месте. Но обратите внимание: колонка «Training» содержит одинаковые значения 3.3, хотя в оригинале для некоторых вариантов указано другое количество шагов. PyMuPDF скопировал значение из последней строки во все предыдущие из-за особенностей выравнивания текста в PDF-потоке. Кроме того, буквенные обозначения вариантов (A)-(E) потеряли связь с описанием изменений архитектуры, которое в оригинале вынесено в отдельную колонку.
Azure Layout вернул структуру с корректным разделением на 5 колонок: «Model», «BLEU EN-DE», «BLEU EN-FR», «Training cost (FLOPs)», «Description». Каждая ячейка содержит точное значение, включая вариативность training cost для разных конфигураций. LLM, анализируя результат PyMuPDF, выставила флаг context_structured со значением true и обоснованием: «Обнаружено вероятное дублирование значений в колонке Training, отсутствует колонка Description, нарушена связь между буквенными обозначениями вариантов и их описанием». Страница была отправлена на перепарсинг в Azure.
Кейс 2: Диаграмма Transformer - когда текста недостаточно
Архитектурная диаграмма Transformer - это визуальное представление, где ключевая информация закодирована в пространственных отношениях между блоками. Текстовый парсер извлекает надписи внутри прямоугольников: «Input Embedding», «Positional Encoding», «Multi-Head Attention», «Add & Norm» и так далее. Но то, что выход энкодера идёт на вход каждого декодерного слоя, показано стрелками, а не текстом.
Vision LLM, получив фрагмент страницы с диаграммой, сгенерировала описание, которое включало:
«Диаграмма показывает архитектуру Transformer. Слева - энкодер, справа - декодер. Входной текст проходит через Input Embedding и Positional Encoding, затем поступает в стек из N=6 идентичных энкодерных слоёв. Каждый слой содержит Multi-Head Self-Attention и Feed-Forward Network, оба с остаточными связями и нормализацией. Выход энкодера подаётся на каждый декодерный слой через механизм cross-attention. Декодер также получает сдвинутый вправо выходной текст через Embedding и Positional Encoding. Маскированный Multi-Head Self-Attention в декодере предотвращает внимание к будущим позициям. Финальный слой - Linear и Softmax для предсказания следующего токена».
Это описание дополняет текстовый результат парсинга, предоставляя информацию о направлении связей, количестве слоёв и назначении маскирования - всё то, что не содержится в отдельных текстовых подписях блоков.
Stress-тест 18 запусков: почему бинарному вердикту LLM нельзя доверять
Идея простая: LLM анализирует результат парсинга и говорит «да, структура нарушена» или «нет, всё в порядке». Бинарный флаг context_structured управляет маршрутизацией страницы. Но насколько стабилен этот вердикт?
Методология теста: один и тот же документ из 12 страниц прогонялся через пайплайн 18 раз подряд. Для каждой страницы LLM выставляла бинарный флаг и генерировала текстовое обоснование. Температура модели была установлена на 0.1 для минимизации вариативности, но даже при этом параметре результаты удивили.
Из 12 страниц стабильный вердикт (18/18 одинаковых ответов) был получен только для 7. На 5 страницах флаг менялся от запуска к запуску. Страница с Table 3 получила false в 4 запусках из 18, несмотря на очевидную потерю структуры. Страница с простым текстом в двух запусках получила true, хотя PyMuPDF извлёк её корректно. Суммарная accuracy бинарного флага относительно экспертной разметки составила 0.78 - недостаточно для production-пайплайна, где цена ошибки - потеря данных или лишние затраты на перепарсинг.
Анализ нестабильности: когда LLM ошибается
Ключевой инсайт теста: текстовая рациональная оценка стабильнее бинарного флага. В тех же 18 запусках LLM последовательно описывала одни и те же структурные аномалии в Table 3, даже когда итоговый флаг был false. Формулировка «значения в колонке Training выглядят подозрительно одинаковыми, возможно дублирование» появлялась в 16 из 18 обоснований. Но в 4 случаях модель всё равно резюмировала: «структурных нарушений не обнаружено».
Причина - в механизме генерации. Бинарный вердикт - это один токен, на который влияют случайные флуктуации в logits. Текстовое обоснование - это десятки токенов, где семантическая согласованность удерживает модель от противоречий. Практический вывод: решение о перепарсинге должно приниматься не по флагу, а по анализу текстовой оценки. Регулярное выражение, ищущее ключевые слова «дублирование», «потеряна связь», «нарушен порядок», «смешение колонок» в тексте обоснования, дало accuracy 0.94 на том же тесте.
Практические рекомендации: как построить свой адаптивный парсер PDF
На основе описанных кейсов и тестов собраны рекомендации для реализации аналогичного пайплайна:
- Начинайте с PyMuPDF. Для извлечения текста и координат используйте режим «dict» с параметром sort=True - он группирует блоки по колонкам и даёт лучший baseline, чем текстовый режим.
- Проектируйте промпт для LLM под текстовое обоснование. Просите модель перечислить конкретные признаки структурных проблем: дублирование значений, нарушение порядка колонок, отсутствие описаний для буквенных обозначений, потеря связей между заголовками и данными. Бинарный флаг пусть будет, но не используйте его как единственный критерий.
- Парсите текстовую оценку регулярными выражениями. Составьте словарь триггерных фраз на основе 10-20 реальных примеров проблемных страниц. Обновляйте словарь по мере накопления данных.
- Разделяйте маршруты для таблиц и диаграмм. Azure Layout оптимален для таблиц, но бесполезен для диаграмм. Vision LLM - наоборот. Используйте эвристики: если на странице есть изображение с соотношением сторон, характерным для диаграммы, и текстовый результат содержит менее 50 слов - вероятно, нужна Vision LLM.
- Считайте стоимость. Azure Document Intelligence стоит около $1.50 за 1000 страниц в режиме Layout. Vision LLM через API - от $0.01 до $0.05 за изображение в зависимости от модели. PyMuPDF бесплатен. Адаптивный подход окупается при объёмах от 100 страниц в день. Для старта с open-source OCR-моделями полезен наш обзор открытых OCR-моделей 2026 года.
- Логируйте решения. Сохраняйте для каждой страницы: результат PyMuPDF, флаг и обоснование LLM, результат перепарсинга (если был). За месяц накопите датасет для оценки accuracy и сможете заменить LLM-контролёра на обученный классификатор, сократив задержку и стоимость.
Итоговая архитектурная схема: документ → разбиение на страницы → PyMuPDF (все страницы) → LLM-анализ (все страницы) → регулярное выражение по текстовой оценке → маршрутизация проблемных страниц на Azure Layout (таблицы) или Vision LLM (диаграммы) → слияние результатов в итоговый структурированный документ. Пайплайн обрабатывает 100-страничный документ за 15-30 секунд плюс время облачных вызовов для 5-15% страниц.
Для тех, кто работает с документами в интерактивном режиме, а не в batch-обработке, может быть полезен инструмент Koda Desktop - AI-агент для работы с PDF и DOCX через чат. А если вы строите production-пайплайн с несколькими моделями, обратите внимание на опыт Databricks по выбору обвязки для кодинга - методология оценки агентов применима и к выбору парсеров.