Однажды нам понадобилось выбрать OCR-модель для RAG-пайплайна. Казалось бы, задача простая: смотришь на лидерборды, берешь лучшую, PROFIT. Но быстро выяснилось, что, во-первых, то, что прекрасно срабатывает на каких-нибудь английских юридических документах, может не потянуть такие штуки как научные формулы, паспортные данные и таблицы на русском языке. А во-вторых, даже если крутой по всем параметрам бенчмарк для оценки качества распознавания говорит, «всё прочитали правильно, я проверил», точность ответов пользователю, который совершает запрос к чат-боту с RAG под капотом, может страдать.

Почему так происходит, зачем мы потратили время на сборку собственного OCR-бенчмарка и пожалели ли мы об этом, рассказываю дальше.

Я Владимир Ловцов, работаю в направлении исследования, развития и внедрения искусственного интеллекта дата-сайентистом. Хочу поделиться с вами историей одной маленькой внутренней задачи, которая в итоге выросла аж в дополнение к коммерческому сервису. Когда работаешь у облачного провайдера, как-то стыдно быть сапожником без сапог, поэтому, как только родился сервис Evolution Managed RAG, мы перешли на его использование для своих внутренних чат-ботов, интегрированных с корпоративными базами знаний. И тут-то обнаружился ряд проблем, которые нельзя было объяснить проблемами самого RAG’а. Их нужно было исправить не только для наших задач, но и, разумеется, для клиентских.

Зачем RAG вообще нужен OCR и почему это не «просто достать текст»

OCR (Optical Character Recognition) — технология перевода изображения, скана или PDF в текст и структуру. В классическом документообороте OCR решает одну задачу: перевести скан в машиночитаемый текст. Всё. Для RAG это совсем другая история: OCR там первый шаг пайплайна, который «кормит» весь последующий процесс.

Если OCR отработал плохо:

  • сплиттер режет документ посередине логической единицы, из-за чего в базу попадают мусорные обрывки;

  • на этапе поиска и извлечения релевантных фрагментов (retrieval) тянется не тот чанк по эмбеддингу: поисковик находит нужную закладку, но текст на ней оборван на полусло…

  • НЁНКЕ. Понимаете, да? Языковая модель честно отвечает на вопрос, но по известному ей обрывку. И никто не замечает, что она несет чушь, пока кто-то не проверит ответ вручную.

Причем плохой OCR в контексте RAG — это не обязательно про оборванные слова, опечатки и перепутанные символы. Это может быть потеря структуры: таблица расплылась в абзац, заголовок потерялся, порядок строк перепутался. CER (доля ошибочно распознанных символов) при этом выглядит вполне прилично, а пайплайн уже сломан. Поисковик не находит нужные строки таблицы, потому что структурно они перестали существовать.

Именно поэтому для RAG недостаточно смотреть только на текстовые метрики. Нам нужна была модель, которая следит не только за корректностью распознавания символов, но и за структурой документа: заголовками, таблицами, иерархией.

Почему публичные бенчмарки не помогли

Мы начали с публичных лидербордов: OCRBench, PubTabNet, Nougat-style. Они не бесполезны, помогли сузить список кандидатов с «все OCR-модели на HuggingFace» до «вот несколько интересных». Но дальше они нас подвели по трем конкретным причинам.

  • Русского языка почти нет. Русская типографика — это отдельная история: кавычки-«елочки», ё и ее отсутствие, длинные составные слова, дореформенная орфография в исторических текстах (не то чтобы она нам прям очень нужна была, но для чистоты не помешает). Ничего этого в публичных датасетах практически нет. Модель, которая хорошо читает англоязычные абстракты, может плохо справляться со статьями на великом-могучем.

  • Фокус на среднем. Публичные бенчмарки сваливают в одну кучу простые сканы, диаграммы, рукописи, таблицы. На выходе одно агрегированное число. По нему невозможно понять, как модель поведет себя именно с вашими документами, например, с расчетным листком сотрудника или сканом паспорта.

  • Структура документа целиком измеряется не так, как нужно RAG. Большинство классических метрик — CER, WER, BLEU — говорят про символьную и словарную точность. Табличные бенчмарки вроде PubTabNet действительно проверяют восстановление таблиц, но не отвечают на наш главный вопрос: сохранит ли модель весь документ как связную Markdown-структуру с заголовками, таблицами, строками и логической иерархией. А для RAG именно это важно.

В общем, мы решили не гадать, корректно ли поведет себя в итоге наш RAG, мы проверили.

Какой датасет мы собрали

Ключевой вопрос при сборке любого OCR-бенчмарка — откуда взять честный Ground Truth? Ручная разметка сканов дорогая, медленная и сама по себе вносит ошибки. Поэтому мы пошли от обратного: брали документы, у которых уже есть текстовый исходник, и из него рендерили одновременно PDF (вход для модели) и Markdown (эталон для сравнения).

Текст никогда не размечается руками — это принципиально. Такой подход позволяет получить большой датасет без риска «замусорить» эталон человеческими ошибками.

Вот что вошло в наш датасет:

Источник

Что внутри

Зачем

Русская Википедия

Дамп MediaWiki XML, отфильтрованные статьи

Сложная верстка, таблицы, инфобоксы

Академические лекции

LaTeX-исходники

Формулы, многоуровневые заголовки

arXiv

LaTeX

Научные публикации, сложные таблицы, ссылки

Excel

Финансовые таблицы

Широкие таблицы

Сканы паспортов РФ (MIDV)

Российский внутренний паспорт

Чистая OCR-метрика на маленьком сложном тексте

Паспорта из датасета MIDV стоят особняком: там вход уже в виде JPG, а эталонный текст идет вместе с датасетом.

Как мы оценивали OCR-модели
Как мы оценивали OCR-модели

Несколько технических деталей по сборке. Для LaTeX мы использовали fallback-цепочку latexmk → pdflatex → tectonic — статьи с arXiv часто требуют разные пакеты, и такой каскад заметно повышает долю успешно собранных документов. Wiki XML парсился с фильтрацией по размеру и вайт-листу: короткие заглушки и незаполненные статьи в бенчмарк не попадают. Для режима «плоский текст без разметки» мы дополнительно извлекали текстовый слой из PDF мультидвижковым pdf2txt (PyMuPDF → pdfplumber → pypdf).

Почему эталон в Markdown, а не в чистом тексте? Во-первых, LLM читает его практически нативно: #-заголовки, списки и pipe-таблицы — это типичный формат обучающих данных. Во-вторых, он компактнее HTML или XML: меньше токенов на ту же структуру, дешевле prefill, длиннее эффективное окно контекста. В-третьих, по нему удобно чанковать: #/## — границы секций, | — строки таблиц, пустая строка — конец абзаца. Сам по себе такой формат снижает вероятность того, что текст оборвется не на том месте.

Что мы сделали: метрики и пайплайн оценки

Оценку мы разделили на два самостоятельных режима — в зависимости от того, что именно проверяем.

Режим Text: насколько точно распознан текст

Этот режим применялся к двум типам документов: сканам паспортов и PDF, из которых заранее извлекли текстовый слой. Здесь мы смотрим только на то, насколько точно модель воспроизвела символы и слова без учета форматирования.

Использовали пять метрик:

CER — доля неверно распознанных символов. Подробнее об этой метрике — чуть выше в статье.

WER (Word Error Rate) — то же самое, но на уровне слов: какая доля слов распознана неверно, пропущена или добавлена лишняя.

Levenshtein_norm — считает, сколько правок (вставок, удалений, замен символов) нужно сделать, чтобы вывод модели стал эталоном. Результат нормализован на длину текста, чтобы можно было сравнивать документы разного размера.

BLEU — метрика из машинного перевода. Смотрит, насколько совпадают короткие последовательности слов (n-граммы) между эталоном и выводом модели, и учитывает их порядок.

METEOR — похожа на BLEU, но умеет учитывать синонимы и разные формы одного слова. Мы используем ее как вспомогательную: стандартная реализация в библиотеке NLTK заточена под английский язык и для русского с его богатой морфологией она работает не так корректно.

Режим Markdown: насколько точно сохранена структура

Здесь к тем же пяти метрикам добавляется наша собственная — Structural. Она отвечает на вопрос: сохранила ли модель скелет документа: заголовки, таблицы, строки в таблицах?

Работает она так:

  1. Берем два Markdown-файла — эталонный и тот, что выдала модель — и простыми регулярками считаем в каждом: сколько заголовков (строки, начинающиеся с #), сколько таблиц (блоки с символом |) и сколько строк в этих таблицах.

  2. Считаем, насколько модель совпала с эталоном по каждому из трех показателей (всего заголовков, таблиц, строк): делим меньшее значение на большее. Если в эталоне 5 заголовков, а модель нашла 4 — совпадение 0.8. Если модель нашла 10 (нагаллюцинировала лишние) — 0.5, то есть штраф симметричный в обе стороны.

  3. Усредняем соотношение по тем категориям, где элементы вообще были. Итоговое число — от 0 до 1: 1 означает, что структуры идентичны, 0 — модель полностью потеряла или выдумала структуру.

Метрика намеренно простая: она не пытается сравнивать содержимое ячеек или вложенность заголовков. Но этого достаточно, чтобы сразу увидеть, если модель начала разворачивать таблицы в текст или терять разделы — именно такие регрессии важнее всего отловить в первую очередь.

Параллельно с оценкой мы настраивали конфигурацию запуска моделей. Меняли параметры сервера инференса (vLLM), разрешение входного изображения, текст системного промпта и каждый раз сразу замеряли, как это влияет и на качество, и на скорость работы. Это позволило совместить два процесса: и выбрать лучшую модель, и подобрать для нее оптимальные настройки. Финальные цифры в таблицах ниже — именно с этими конфигурациями.

Что вышло

Тестировали две модели: deepseek-ai/DeepSeek-OCR-2 и zai-org/GLM-OCR. Медианные значения по датасету.

Markdown-режим (структурный)

Модель

WER ↓

CER ↓

Levenshtein_norm ↓

Structural ↑

DeepSeek-OCR-2

0.43

0.34

0.34

0.70

GLM-OCR

0.42

0.30

0.30

0.36

Text-режим (плоский текст)

Модель

WER ↓

CER ↓

Levenshtein_norm ↓

BLEU ↑

METEOR ↑

GLM-OCR

0.33

0.08

0.08

0.75

0.83

DeepSeek-OCR-2

0.38

0.18

0.16

0.67

0.86

А теперь наглядно
А теперь наглядно

Ключевые наблюдения:

  • На чистом тексте GLM лучше. CER 0.08 против 0.18 — это принципиальная разница. На паспортных сканах MIDV GLM также чуть лучше.

  • На структуре DeepSeek почти вдвое впереди. 0.70 против 0.36 по Structural: DeepSeek сохраняет таблицы и Markdown-иерархию, GLM тяготеет к разворачиванию таблиц в плоский текст.

  • METEOR у DeepSeek выше, несмотря на худший CER. 0.856 против 0.825 — DeepSeek лучше по этой вспомогательной метрике, что говорит о более высоком лексическом сходстве с эталоном.

Кейс: таблица без сетки

Лучше один раз увидеть. Берем таблицу «Национальный состав Волгограда» из Википедии. Вот как она выглядит в PDF на входе модели:

Обратите внимание: визуально это даже не таблица в привычном смысле — нет ни сетки, ни линий, ни подсветки колонок. Просто три столбика текста, выровненных пробелами. Чтобы понять, что это таблица, OCR-модели нужно считать пространственную структуру: одинаковое количество колонок в каждой строке, выравнивание по вертикали, общую шапку. DeepSeek-OCR-2 это распознал и собрал из визуального layout полноценную Markdown-таблицу. GLM-OCR — нет, для него это осталось линейным текстом.

Эталон (GT):

| Национальность | Численность, чел. | Доля     |
|----------------|-------------------|----------|
| Русские        | 811 228           | 78,91 %  |
| Армяне         | 7866              | 0,77 %   |
| Татары         | 4463              | 0,43 %   |
| Азербайджанцы  | 3356              | 0,33 %   |
| Украинцы       | 2462              | 0,24 %   |
| Казахи         | 2207              | 0,21 %   |
| Другие         | 196 454           | 19,11 %  |
| Итого          | 1 028 036         | 100,00 % |

DeepSeek-OCR-2: структура таблицы сохранена, цифры распознаны корректно:

| Национальность | Численность, чел. | Доля  |
|---|---|---|
| Русские       | 811 228   | 78,91 %  |
| Армяне        | 7866      | 0,77 %   |
| Татары        | 4463      | 0,43 %   |
| Азербайджанцы | 3356      | 0,33 %   |
| Украинцы      | 2462      | 0,24 %   |
| Казахи        | 2207      | 0,21 %   |
| Другие        | 196 454   | 19,11 %  |
| Итого         | 1 028 036 | 100,00 % |

GLM-OCR: таблица развернута в плоский текст, разделители колонок потеряны полностью:

Русские 811 228 78,91 %
Армяне 7866 0,77 %
Татары 4463 0,43 %
Азербайджанцы 3356 0,33 %
Украинцы 2462 0,24 %
Казахи 2207 0,21 %
Другие 196 454 19,11 %
Итого 1 028 036 100,00 %

С точки зрения CER оба вывода почти эквивалентны — все символы на месте, ошибок мало. Но для RAG это разные истории: с выводом DeepSeek у пайплайна появляется возможность обрабатывать таблицу по строкам и ячейкам, а вывод GLM выглядит как один длинный абзац. Кроме того, Markdown-таблица обычно лучше сохраняет связи «строка — колонка — значение» для последующей работы LLM. Именно эту разницу и ловит Structural-метрика: 0.70 vs 0.36 в медиане — это ровно про такие случаи.

По итогам этого сравнения мы завезли DeepSeek-OCR-2 в Evolution Foundation Models. Решающим оказалось лидерство по Structural на нашем датасете: для OCR-этапа RAG-пайплайна сохранение разметки важнее, чем последний процент CER в общем случае.

Что хочется доделать

Бенчмарк уже отвечает на свой главный вопрос — какую модель выбрать под наши сценарии. Дальше его хочется развивать в двух направлениях.

Расширение датасета. Сейчас он покрывает основные интересные нам типы документов, но есть, куда расти. Хочется добавить новые домены: договоры и юридические документы, бухгалтерскую и финансовую отчетность с многостраничными таблицами, техническую документацию с диаграммами и кодовыми блоками, презентации и отчеты со смешанной версткой. Полезной будет и англоязычная часть — чтобы видеть, где именно русский язык вносит свою сложность, а где модель просто слаба сама по себе.

Улучшение метрики структуры. Текущий Structural работает довольно просто, его достаточно, чтобы поймать главные регрессии, но «качество» структуры можно мерить и тоньше. Логичный следующий шаг — LLM-as-a-judge поверх текущей метрики: модель-судья сравнивает пару «эталон / OCR-выход» и оценивает уже семантическую близость структуры.

Итог

Главный вывод за рамками конкретного сравнения двух моделей: под прикладную задачу почти всегда нужен свой бенчмарк. Это не значит, что публичные бесполезны — наоборот, именно они и помогли нам сузить пространство до короткого списка кандидатов: смотреть подряд все доступные OCR-модели нет ни смысла, ни ресурса. Но дальше публичные числа отвечают на вопрос «какая модель в среднем лучше», а в проде важно другое: какая модель лучше на ваших документах, в вашем формате выхода и в вашем инференс-стеке.

Самое полезное наблюдение — выбор только по текстовым метрикам мог бы привести нас не туда. На плоском тексте обе модели дают хороший результат, а GLM-OCR по CER заметно лидирует. Но для RAG важна не только посимвольная точность: если модель теряет таблицы, заголовки и грубую Markdown-структуру, downstream-пайплайн начинает работать с другим документом. Без отдельной Structural-метрики этот разрыв легко пропустить.

Подход легко перенести на свой домен: меняются источники Ground Truth, при необходимости поверх Structural дописываются доменные метрики — остальной пайплайн остается тем же:

  • Шаг 1. Найдите исходники с готовым текстом. LaTeX, MediaWiki XML, Excel, HTML, Markdown — что угодно, где у документа уже есть структурированный текстовый источник.

  • Шаг 2. Отрендерьте входы и эталоны из одного источника. Из исходника генерируйте PDF или изображение для модели и текстовый/Markdown-эталон для сравнения. Никакой ручной разметки — это принципиально для честного GT.

  • Шаг 3. Добавьте доменные метрики. Базовые CER/WER обязательны. Structural — хорошая отправная точка для любого документного домена. Поверх нее можно добавить специфику: для юридических документов — совпадение нумерации статей и пунктов, для финансовых — сохранность итоговых строк таблиц.

  • Шаг 4. Гоняйте бенчмарк параллельно с тюнингом деплоя. Не последовательно, а одновременно. Меняете параметр — сразу замеряете качество и скорость. Иначе не поймете, улучшение от модели или от настройки.

Если остались вопросы по реализации — пишите в комментарии, расскажу подробнее.

Комментарии (2)


  1. badsynt
    04.06.2026 08:08

    Столкнулся с тем фактом, что вход LLM_OCR очень легко отравляется. Иногда целенаправленно, но бывает и случайно. В результате вместо объекта Х устойчиво распознается объект У. У старых традиционных OCR таких глюков не было. Если Вы распознаете не “бла-бла-бла”, а цифры, которые затем идут в расчеты, то это очень больно. И с этим надо что-то делать. И вот на это хотелось бы бенчмарк. С другой стороны. такие вещи могут быть частично исправлены правильным пайплайном (например консенсус трех разных LLM, проверка устойчивости к возмущениям и т.п.), но что-то вменяемых примеров не нашел.


    1. lovets18 Автор
      04.06.2026 08:08

      Добрый день! 

      Согласен, что LLM OCR может быть менее устойчивым, готовых публичных бенчмарков такого рода я тоже не видел. Отчасти предложенный в статье подход можно доработать аугментациями картинок и пдф - по крайней мере для случаев, когда изображение портится случайно. Причём можно аугментировать не всё изображение, а случайный патч (а-ля dropout): проверяем, ломается ли модель только в этом месте или ошибка расползается дальше. А чтобы бороться с этим в проде, кажется, проще всего дублировать чтение классическим OCR и сверять с выходом OCR LLM. Сюда еще можно докинуть multimodal LLM на постобработку для повышения качества.