Практическое руководство

Как измерять влияние OCR на RAG по русскоязычным документам

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

Уровень: средний Чтение: до 9 минут Результат: схема проверок для собственного корпуса

Почему общей оценки недостаточно

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

  1. OCR и нормализация: изображение страницы превращается в текст и структуру.
  2. Извлечение: индекс и поисковый модуль выбирают подходящие фрагменты.
  3. Генерация: модель отвечает по найденному контексту.

Если измерять только правильность ответа, источник дефекта остаётся неизвестным. Например, неверная сумма может появиться из-за потерянного столбца при OCR, неудачной нарезки таблицы, пропуска нужного фрагмента поиском или ошибки генератора при чтении корректного контекста.

Практическая цель оценки — не получить одну «красивую» цифру, а построить диагностическую цепочку: страница → распознанный фрагмент → найденный фрагмент → ответ.

1. Зафиксируйте единицу оценки

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

{
  "document_id": "doc-0042",
  "page": 7,
  "region_id": "doc-0042-p007-r03",
  "region_type": "table",
  "source_image": "corpus/doc-0042/page-007.png",
  "ocr_text": "Итого: 125 400,00 руб.",
  "gold_text": "Итого: 125 400,00 руб."
}

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

2. Соберите небольшой, но стратифицированный набор

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

  • обычный печатный текст;
  • таблицы с объединёнными ячейками и многострочными заголовками;
  • печати, подписи и текст поверх фона;
  • переносы слов и узкие колонки;
  • смешанные кириллические и латинские символы;
  • сканы с поворотом, шумом или низким контрастом;
  • страницы, где ответ зависит от числа, даты или реквизита.

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

3. Измерьте OCR отдельно

Для линейного текста используйте посимвольную и пословную долю ошибок:

CER = редакционное_расстояние(символы_эталона, символы_OCR)
      / число_символов_эталона

WER = редакционное_расстояние(слова_эталона, слова_OCR)
      / число_слов_эталона

CER лучше показывает подмены вроде «С»/«C», «О»/«0» и «В»/«B». WER сильнее реагирует на пропуски, слияния и неправильные границы слов. Перед расчётом храните два варианта текста:

  • сырой — чтобы видеть реальные ошибки OCR;
  • нормализованный — чтобы оценить текст после допустимой обработки.

Не удаляйте пунктуацию, пробелы и переносы до сырой оценки: так можно скрыть дефекты, влияющие на реквизиты и таблицы.

Проверки для русскоязычных документов

Риск Что считать Почему это важно для поиска
Переносы Доля ошибочно сохранённых и ошибочно склеенных переносов «государст- венный» меняет токены и ухудшает точное совпадение
Смешанные алфавиты Подмены кириллицы латиницей в словах и идентификаторах Визуально одинаковые строки могут иметь разные кодовые точки
Числа и даты Точное совпадение нормализованного значения Одна ошибка меняет сумму, номер договора или дату
Таблицы Полнота ячеек и правильность связей «заголовок — значение» Правильные слова бесполезны, если значение попало в другой столбец
Печати Обнаружение области и точность читаемых ключевых полей Текст печати может загрязнять основной абзац или содержать реквизит

4. Проведите парный тест извлечения

Главная проверка влияния OCR — сравнение двух индексов при неизменных настройках поиска:

  • индекс A: текст, полученный OCR;
  • индекс B: вручную исправленный эталон тех же фрагментов.

Используйте одинаковые границы фрагментов, метаданные, модель представления, поисковый запрос и значение top_k. Иначе разница перестанет отражать только OCR.

Для каждого вопроса заранее укажите идентификаторы релевантных фрагментов. Затем рассчитайте:

  • Recall@k: попал ли хотя бы один нужный фрагмент в первые k результатов;
  • MRR: насколько высоко находится первый релевантный фрагмент;
  • дельту OCR: значение метрики на эталоне минус значение на OCR.
delta_recall_at_5 = recall_at_5_gold - recall_at_5_ocr
delta_mrr = mrr_gold - mrr_ocr

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

5. Отделите генерацию контрольными контекстами

Для каждого вопроса выполните три прогона генератора с одинаковыми параметрами:

  1. с контекстом, найденным в OCR-индексе;
  2. с контекстом, найденным в эталонном индексе;
  3. с заранее выбранным правильным эталонным фрагментом.

Интерпретация проста:

  • если вариант 3 неверен, проблема находится в генерации, инструкции или неоднозначном вопросе;
  • если вариант 3 верен, а вариант 2 неверен, исследуйте поиск и нарезку;
  • если вариант 2 верен, а вариант 1 неверен, измерено влияние OCR;
  • если правильный фрагмент найден, но ответ неверен только на OCR-тексте, OCR исказил содержимое внутри контекста.

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

6. Безопасно автоматизируйте прогон

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

dataset: evaluation/ocr_rag_ru.jsonl
indexes:
  ocr: evaluation/index_ocr
  gold: evaluation/index_gold
retrieval:
  top_k: [1, 3, 5, 10]
  use_same_chunks: true
generation:
  temperature: 0
report:
  group_by:
    - region_type
    - scan_quality
    - script_mix
  redact_source_text: true

Пример команды для локального оценочного скрипта:

python -m evaluation.run \
  --config evaluation/config.yml \
  --output evaluation/results.json

Команда безопасна при условии, что модуль уже существует и пути проверены. Она не требует передачи ключей в аргументах командной строки. Если система использует внешний API, секреты следует получать из штатного хранилища окружения, не записывать в конфигурацию и не включать исходный текст документов в отчёт без необходимости.

Как проверить результат

Готовый отчёт должен позволять пройти от агрегированной метрики к конкретному примеру. Минимальная строка отчёта содержит:

{
  "question_id": "q-018",
  "region_type": "table",
  "gold_region_ids": ["doc-0042-p007-r03"],
  "ocr_rank": null,
  "gold_rank": 1,
  "ocr_answer_ok": false,
  "gold_answer_ok": true,
  "oracle_answer_ok": true,
  "error_stage": "ocr_or_ocr_index"
}

Это иллюстративный пример. Значение null здесь означает, что нужный фрагмент не вошёл в проверяемую выдачу.

Перед выводами проверьте четыре условия:

  1. в обоих индексах совпадают идентификаторы и границы фрагментов;
  2. запросы и параметры поиска идентичны;
  3. эталон действительно содержит ответ и размечен на правильной странице;
  4. каждая крупная дельта подтверждается ручным просмотром изображения, OCR-текста и выдачи.

Практический итог — таблица приоритетов. Например, высокая дельта Recall@5 у таблиц вместе с низкой полнотой связей «заголовок — значение» указывает, что сначала стоит улучшать структурное распознавание или представление таблиц, а не менять генеративную модель.

Типовые ошибки оценки

  • Одна итоговая точность. Она не показывает, на каком этапе возник дефект.
  • Разные чанки в парном тесте. Тогда одновременно измеряются OCR и стратегия нарезки.
  • Только CER. Низкая посимвольная ошибка не гарантирует сохранность структуры таблицы.
  • Агрессивная нормализация. Автозамена латинской C на кириллическую С может исправить слово, но повредить артикул или код.
  • Оценка по простым страницам. Редкие, но важные печати и таблицы исчезают внутри среднего.
  • Изменение нескольких компонентов сразу. Нельзя приписать улучшение OCR, если одновременно заменены индекс, модель поиска и промпт.
  • Оценка только найденных примеров. Так исключаются именно те вопросы, для которых OCR разрушил поиск.
  • Передача чувствительных документов в отчёт. Для диагностики часто достаточно идентификатора, типа ошибки и сокращённого обезличенного фрагмента.

Ограничения

Эталонная расшифровка тоже может содержать ошибки, особенно в повреждённых сканах и рукописных элементах. Метрики линейного текста плохо описывают пространственные отношения. Результаты зависят от языка запросов, способа индексации, модели представления и состава корпуса, поэтому их нельзя автоматически переносить на другую коллекцию.

Парный тест показывает влияние OCR в зафиксированной конфигурации RAG, но не доказывает, что конкретное исправление будет лучшим по стоимости и задержке. Иногда выгоднее добавить поиск по метаданным, сохранить таблицу в структурированном виде или направлять сложные страницы в отдельный обработчик.

Минимальный набор проверок

Если ресурсы ограничены, начните с пяти измерений:

  1. CER на обычном тексте и отдельно на реквизитах;
  2. точное совпадение чисел, дат и идентификаторов;
  3. полнота ячеек и связей в таблицах;
  4. дельта Recall@5 между OCR- и эталонным индексами;
  5. три генеративных прогона: OCR-контекст, эталонный поиск и правильный контекст.

Этого достаточно, чтобы перестать обсуждать «качество RAG» как одну величину и увидеть, где теряется информация. Дальше расширяйте набор теми классами ошибок, которые дают наибольшую дельту на вашем корпусе.