OCR перед LLM: как мерить потери на сканах документов
OCR перед LLM помогает читать сканы договоров и медформ, но ошибки копятся. Разберём метрики, пороги проверки человеком и простой процесс.

Почему скан ломает ответ LLM
Один сбой в OCR легко меняет смысл документа. В договоре строка "штраф не взимается" может превратиться в "штраф взимается", если система пропустит одно "не". В медформе такая же мелочь еще опаснее: "0,5 мг" и "5 мг" на бледном скане выглядят почти одинаково, но решение по ним будет совсем разным.
Проблема в том, что испорченный текст часто выглядит для модели вполне нормальным. OCR перед LLM может выдать ровный, читаемый абзац без явных дыр, хотя по дороге потерял номер поля, перепутал строки в таблице или склеил два соседних блока. Текст выглядит аккуратно, а данные уже ненадежны.
Разница простая. Красивый текст приятно читать. Надежные данные точно сохраняют символы, границы полей, порядок строк и места, где система не уверена. Если OCR угадал слово вместо того, чтобы отметить сомнение, LLM получает ложную уверенность еще до начала анализа.
На сканах это происходит постоянно. Документ могли снять на телефон под углом, распечатать несколько раз, сжать в мессенджере или подписать от руки поверх печатного текста. Штампы, тени, сгибы, серый фон и слабый контраст сильнее всего бьют по коротким словам, цифрам и отрицаниям.
Модель почти никогда не знает, что именно потерялось при распознавании. Она видит только входной текст и пытается собрать из него правдоподобный ответ. Если OCR исказил фразу "аллергии нет" в "аллергия есть", модель спокойно построит резюме, флаги риска и рекомендации вокруг ложного факта. Часто такой ответ звучит уверенно, потому что модель хорошо достраивает пропуски по контексту.
Сильнее всего ошибка бьет по документам, где один символ меняет решение:
- договоры с суммами, сроками, штрафами и условиями расторжения
- медформы с дозировками, аллергиями, диагнозами и датами
- анкеты и заявления с ИИН, номерами полисов и паспортными данными
- лабораторные бланки, где важно не описание, а точное значение в поле
Если документ нужен только для поиска общей темы, мелкие огрехи еще можно пережить. Если по нему надо принять решение, выставить счет, проверить риск или передать пациента дальше по процессу, даже один пропуск в OCR уже ломает весь ответ.
Где OCR чаще теряет смысл
OCR ошибается не только там, где текст плохо виден. Хуже другое: он может распознать символы так, что фраза выглядит правдоподобно, хотя смысл уже уехал. Для LLM это самый опасный случай. Модель видит обычный текст и уверенно строит ответ на испорченной основе.
Часто проблемы начинаются на сканах, которые несколько раз печатали и копировали. Мелкий шрифт плывет, тонкие линии букв пропадают, а цифры слипаются. В договоре это легко превращает "3 000 000" в "300 000" или меняет дату окончания. В медформе одна потерянная запятая в дозировке тоже полностью меняет смысл.
Что ломается чаще всего
- Печати и подписи закрывают слова, даты и суммы. OCR пытается достроить текст и часто ошибается.
- Рукописные пометки на полях смешиваются с основным текстом. Особенно тяжело, когда врач или менеджер пишет поверх печатной строки.
- Таблицы и формы в две колонки ломают порядок чтения. Система может сначала взять правый столбец, потом левый, и собрать фразы из разных строк.
- Чекбоксы и маленькие поля сбивают разметку. Отметка "да" может исчезнуть, а пустое поле иногда читается как символ или цифра.
- Смесь русского, казахского, латиницы и цифр дает тихие ошибки: "O" вместо "0", "I" вместо "1", "А" и "A" выглядят почти одинаково.
Особенно часто смысл теряется в коротких, но важных кусках текста. Это номер договора, ИИН, серия документа, название препарата, единица измерения, срок действия, отметка в чекбоксе. Один неверный символ в длинном абзаце не всегда страшен. Один неверный символ в номере полиса уже ломает весь разбор.
В медформах OCR дополнительно путается из-за смеси печатного шаблона и заполнения от руки. В договорах чаще мешают сноски, мелкие поля, штампы "копия верна", неровный скан и страницы, снятые на телефон под углом.
Если документ выглядит "почти читаемо" для человека, это не значит, что OCR перед LLM сработает хорошо. Человек достраивает смысл по контексту. OCR документ не понимает, он только угадывает символы. Поэтому самые опасные зоны - не самые грязные страницы, а те, где ошибка похожа на правду.
Как считать потери на распознавании
Считать только общий процент совпадения текста мало. Для сканов договоров и медформ лучше разложить ошибку на два этапа: что испортил OCR и что потом неверно поняла сама LLM. Иначе вы увидите плохой итог, но не поймете, где чинить процесс.
Проверка должна идти на одном и том же наборе документов. Сначала сравните результат OCR с вручную исправленным текстом. Потом дайте LLM два варианта входа: чистый эталонный текст и текст после OCR, с одним и тем же промптом. Разница между ответами покажет потери именно на распознавании, а ошибки на эталонном тексте покажут предел самой модели.
Что мерить в тексте и полях
Не все части документа требуют одной и той же метрики. Там, где один символ меняет смысл, смотрите посимвольное совпадение. Это подходит для номера договора, даты, суммы, ФИО, номера полиса, дозировки. Для длинных фраз удобнее пословная метрика. Она лучше показывает, сколько слов OCR потерял, добавил или перепутал.
Полезно считать отдельно:
- посимвольную точность для номеров, дат, сумм и ФИО
- пословную точность для пунктов договора и заметок врача
- долю найденных полей по каждому типу
- долю полей, где значение совпало полностью
Для полей одной точности текста тоже мало. Считайте полноту по каждому полю: номер, дата, сумма, диагноз, ФИО. Удобно держать рядом две метрики: поле вообще найдено и поле распознано без ошибки. Так быстро видно разницу между ситуацией, когда OCR не увидел дату совсем, и ситуацией, когда он увидел ее, но поменял 03.04.2024 на 08.04.2024.
Где ошибка уже меняет решение
Самые дорогие ошибки - смысловые. Их нужно размечать отдельно, даже если общий текст похож на оригинал. Обычно в эту группу попадают перепутанная дата, пропущенное отрицание, неверная единица измерения, лишняя цифра в сумме, подмена ФИО пациента или стороны договора.
Смотрите не только на число ошибок, но и на долю документов, где ошибка меняет решение. Если OCR потерял запятую в длинном абзаце, это неприятно, но не всегда критично. Если он превратил "без аллергии" в "аллергия" или уменьшил сумму договора в десять раз, процесс уже уходит не туда. Для OCR перед LLM это и есть главная метрика: сколько документов после распознавания ведут к неверному выводу, маршруту или действию человека.
Как собрать набор для проверки
Если взять только ровные и чистые сканы, проверка даст слишком красивый результат. Для OCR перед LLM лучше собрать 50-100 реальных документов разного качества. Такой набор быстро покажет, где распознавание путает буквы, режет строки и теряет смысл еще до того, как текст увидит модель.
Берите документы из реального потока, а не из папки с образцовыми файлами. Добавьте фото с телефона, бледные копии, страницы с перекосом, штампами, подписями, складками и плохим светом. Для договоров и медформ именно такие случаи чаще всего ломают итоговый ответ.
Сразу помечайте каждый файл простыми признаками:
- тип документа
- язык или смесь языков
- качество скана по простой шкале, например 1-3
- источник: сканер, телефон, архив, внешняя система
- есть ли рукописные пометки, печати или сильный перекос
Такая разметка потом экономит много времени. Вы не просто увидите общую ошибку OCR, а поймете, где она живет: в старых архивах, в мобильной загрузке или в двуязычных формах.
Команда не обязана вручную переписывать весь текст на каждой странице. Лучше сделать эталон для самых важных полей. В договоре это обычно номер, дата, сумма, стороны, ИИН или БИН. В медицинской форме - ФИО, дата приема, код услуги, диагноз, дозировка. Если разметчик не может уверенно прочитать поле, он должен так и отметить. Угадывать нельзя.
Сразу разделите документы на два набора. Первый нужен для настройки OCR, очистки текста и правил извлечения. Второй храните отдельно для финальной проверки. Не переносите документы туда-сюда после первых тестов, иначе команда подстроится под знакомые сканы и получит ложное чувство точности.
На практике удобно оставить около 70 документов на настройку и 30 на финальную проверку. Если данных мало, не жертвуйте сложными примерами. Один плохо читаемый договор и одна тяжелая медформа обычно полезнее, чем пять идеальных страниц.
Как поставить проверку человеком по шагам
Человек не должен перечитывать весь документ. Ему нужно показывать только те места, где ошибка OCR может поменять смысл: сумму, дату, номер договора, ИИН, диагноз, дозировку. Так проверка обходится дешевле и не тормозит поток.
Для OCR перед LLM удобнее работать не с документом целиком, а с полями. У каждого поля должен быть свой источник: кусок текста, координаты на странице и, если возможно, вырезка фрагмента скана. Тогда проверяющий видит не абстрактную ошибку, а конкретную строку, которую можно быстро подтвердить или исправить.
Рабочая схема
- Сначала прогоните OCR и сохраните не только распознанный текст, но и координаты блоков, номер страницы и оценку уверенности. Без координат потом трудно понять, откуда взялась сумма или фамилия.
- Затем вытяните нужные поля. Для даты, номера договора, ИИН или суммы часто хватает простого шаблона. LLM лучше оставить для свободных формулировок, где текст заметно меняется от документа к документу.
- На размеченной выборке сравните результат с эталоном по каждому полю. Для номера и даты нужна точная проверка символ в символ. Для ФИО и адреса можно считать ошибки по словам, чтобы видеть, где теряется смысл, а где ломается только пунктуация.
- После этого введите правила, по которым документ уходит человеку. Обычно это низкая уверенность OCR, конфликт между двумя способами извлечения, пустое обязательное поле или фрагмент, который влияет на решение.
- Проверяющему показывайте не весь файл, а спорное место: кусок скана, распознанный текст, найденное значение и соседний контекст. Он исправляет поле до финального решения и отмечает причину сбоя.
Что сохранять после проверки
Причина ошибки нужна не для отчета, а для следующего прогона. Полезно держать короткие метки: плохой скан, печать закрыла текст, OCR перепутал цифры и буквы, шаблон взял не тот блок, LLM выбрала соседнее поле.
Например, в договоре сумма "1 500 000" и срок действия должны уходить на ручную проверку, если OCR сомневается или формат не сходится с шаблоном. В медформе человек должен смотреть фамилию пациента, диагноз и дозировку, если хотя бы одно поле прочиталось с пропуском. Один такой фильтр часто экономит часы на разборе ошибок уже после загрузки в систему.
Один поток для договора и медформы
Практичный поток для OCR перед LLM выглядит так: скан попадает в OCR, затем система вытаскивает несколько полей, считает риск ошибки и только после этого отправляет текст в LLM. Если риск высокий, документ сначала смотрит оператор. Если риск низкий, модель работает сразу, а человек проверяет только часть случаев выборочно.
С договором аренды ошибка часто выглядит мелкой, но бьет по смыслу. На скане сумма ежемесячного платежа равна 38 000, а OCR читает ее как 33 000 или 88 000, потому что цифры слиплись, штамп задел строку или скан слишком темный. LLM потом спокойно строит ответ по испорченному тексту: заполняет карточку договора, считает платежи, делает сводку для юриста. Сам оригинал она не видит, если вы не даете ей изображение отдельно.
С медформой риск еще выше. В строке "аллергии не выявлено" OCR иногда съедает частицу "не". Для модели это уже другой факт: она может отметить аллергию как подтвержденную, передать неверный флаг дальше по процессу или отправить случай на лишнюю ручную эскалацию.
Чтобы не проверять весь документ целиком, оператор смотрит только поля, где ошибка особенно дорога:
- в договоре: сумму, дату начала и срок действия
- в медформе: флаги по аллергии, противопоказаниям и срочным отметкам
- в обоих случаях: места, где OCR дал низкую уверенность
Так команда тратит меньше времени. Вместо полной вычитки каждого скана оператору часто хватает 20-30 секунд на узкую проверку. Это особенно заметно, если поток идет сотнями документов в день.
Дальше ручную проверку можно убирать там, где риск низкий. Например, договоры одного шаблона со свежими сканами и печатным текстом часто проходят без проблем. Медформы с ровным бланком тоже можно пускать без обязательной проверки, если система не нашла подозрительных мест, а выборочный контроль не показывает просадку качества.
Смысл такого потока не в том, чтобы сделать OCR идеальным. Задача проще: заранее решить, какие ошибки допустимы, а какие человек должен перехватить до ответа модели.
Частые ошибки в процессе
В цепочке OCR перед LLM дороже всего ошибки, которые ломают решение, а не портят красивую среднюю цифру. Команда видит 97% точности и думает, что все хорошо. Потом один пропущенный "не", одна цифра в сумме или дозировке - и документ уходит не туда.
Поэтому общий процент распознавания сам по себе почти ничего не говорит. Для договоров и медформ лучше отдельно считать поля, где цена ошибки высокая: суммы, даты и сроки; номера договоров, ИИН, полисов и счетов; отрицания вроде "не согласовано"; дозировки, единицы измерения и диагнозы из печатных форм.
Еще одна частая ошибка - настраивать пороги на чистых PDF и ждать того же на сканах. Чистый PDF почти не похож на фото со стола, копию с печатью или серый скан после факса. Если порог уверенности придумали на аккуратных файлах, он начнет либо пропускать мусор, либо отправлять слишком много документов на ручную проверку.
Путаница между ошибками OCR и ошибками разметки ломает всю оценку качества. Допустим, рецензент отметил неверную дату, но сам смотрел на обрезанный фрагмент не той страницы. В отчете это выглядит как провал OCR, хотя движок прочитал дату верно. Держите три причины отдельно: сбой распознавания, сбой разметки, сбой LLM на уже нормальном тексте. Иначе вы чините не тот слой.
Люди тоже часто тратят время зря. Если отправлять на проверку весь документ, проверяющий читает пять страниц ради одного спорного поля. Это медленно и утомляет. Лучше показывать только спорное место: фрагмент изображения, текст OCR рядом и простой вопрос вроде "сумма 1 500 000 или 1 800 000?". Так человек отвечает быстрее и реже ошибается.
Последняя ловушка появляется после замены OCR или модели. Команда обновляет один компонент, смотрит пару свежих файлов и решает, что стало лучше. Через неделю всплывает регрессия на старых шаблонах, печатях или рукописных пометках. Каждый раз прогоняйте один и тот же контрольный набор, иначе сравнения не будет.
Если вы сравниваете несколько LLM после одного OCR-потока, удобно держать их за одним OpenAI-совместимым шлюзом. Например, в AI Router можно менять base_url на api.airouter.kz и прогонять один и тот же набор документов через разные модели без переписывания SDK, кода и промптов. Это помогает сравнивать модели честно, не меняя остальной пайплайн.
Короткий чек-лист перед запуском
Перед запуском стоит проверить не только качество модели, но и дисциплину процесса. OCR перед LLM чаще ломается не на обычных документах, а на тех, где есть бледная печать, перекос, фото с телефона или рукописная пометка.
Если пропустить базовые проверки, система будет выглядеть "почти точной", но ошибки уйдут в самые чувствительные поля. Для договора это может быть сумма или срок. Для медформы - дата, дозировка или код исследования.
- Соберите эталон по важным полям. Не по всему документу, а по тому, что влияет на решение: ФИО, дата, номер договора, сумма, диагноз, дозировка, ИИН.
- Задайте понятный порог, после которого документ уходит человеку. Лучше ставить порог не один на весь файл, а отдельно на рискованные поля и на общий балл распознавания.
- Смотрите статистику по типам документов. Договоры, анкеты, выписки и медформы ошибаются по-разному, и средняя цифра по всему потоку это скрывает.
- Оставляйте в журнале причину каждой ручной правки. Тогда команда быстро увидит, что именно сломалось: OCR спутал символы, шаблон не нашел поле или LLM неверно поняла кусок текста.
- Пополняйте проверочный набор новыми плохими сканами. Добавляйте документы с тенью, печатью поверх текста, низким контрастом, старым факсом и неудачным кадрированием.
Такой список выглядит простым, но он экономит много времени уже в первый месяц. Когда журнал правок ведут аккуратно, быстро становится видно, какие ошибки повторяются и какие документы лучше сразу отправлять на ручную проверку.
Если команда работает в банке, клинике или госсервисе, этот минимум лучше не пропускать. Там цена одной тихой ошибки выше, чем цена лишней проверки человеком.
Что делать дальше
Не пытайтесь охватить весь архив сразу. Лучше взять один сценарий, где ошибка бьет по деньгам или риску: номер договора, сумма, дата окончания или диагноз в медформе.
Хороший первый шаг - оставить только 3-4 поля, без которых процесс дальше не имеет смысла. Так команда быстрее увидит, где OCR перед LLM ломается чаще всего: на бледном штампе, рукописной дате, мелком шрифте или кривом скане после факса.
Если начать с двадцати полей, спор быстро уйдет в детали. Если начать с четырех, уже через неделю можно понять, какой процент документов требует ручной проверки и где пороги стоят слишком низко или слишком высоко.
Дальше нужно договориться не только о модели, но и о людях. Кто смотрит спорные документы? Что считать спорным случаем? За сколько минут проверяющий должен дать ответ? Если этого нет, ручная проверка быстро превращается в очередь без правил.
Обычно хватает простого порядка:
- OCR и LLM извлекают поля и ставят оценку уверенности
- документы ниже порога уходят человеку
- проверяющий исправляет только отмеченные поля, а не весь файл
- исправления попадают в набор примеров для следующего пересмотра
Такой цикл работает лучше, чем редкие большие разборы. Команда видит не абстрактное качество, а живые ошибки: где OCR спутал "8" и "3", где модель пропустила частицу "не", где поле съехало на соседнюю строку.
Раз в месяц стоит пересматривать и пороги, и сам набор примеров. За месяц обычно накапливаются новые типы сканов: другой шаблон договора, новая медицинская форма, хуже качество печати, больше фото с телефона. Если не обновлять выборку, метрика останется красивой только на старых документах.
План на первый месяц простой: выбрать один поток, согласовать ручную проверку, собрать исправления и один раз пересчитать пороги на реальных документах. Этого уже хватает, чтобы убрать самые дорогие ошибки до масштабирования.
Часто задаваемые вопросы
Почему аккуратный текст после OCR еще не значит, что данные верные?
Потому что OCR может выдать аккуратный абзац и при этом потерять смысл. Он часто путает отрицания, цифры, границы полей и порядок строк, а LLM потом уверенно рассуждает уже на неверном тексте.
Какие ошибки OCR чаще всего меняют смысл документа?
Больше всего вредят короткие фрагменты, где один символ меняет решение. Это суммы, даты, дозировки, ИИН, номера договоров, отметки в чекбоксах и слова вроде «нет» или «не».
Как отделить ошибку OCR от ошибки самой LLM?
Сравните два прогона на одном наборе документов. Сначала дайте модели эталонный текст, потом тот же текст после OCR, и используйте один и тот же промпт. Если ответы расходятся, потери пришли из распознавания, а не из самой LLM.
Какие метрики лучше считать для договоров и медформ?
Для номеров, дат, сумм и дозировок берите посимвольную точность. Для длинных фрагментов вроде пунктов договора или заметок врача смотрите точность по словам и отдельно считайте, нашла ли система нужное поле целиком.
Сколько документов нужно для первой проверки?
Обычно хватает 50–100 реальных документов разного качества. Берите не только ровные сканы, но и фото с телефона, бледные копии, страницы со штампами, перекосом и рукописными пометками.
Что лучше отдавать на ручную проверку в первую очередь?
Сначала отправляйте человеку поля, где ошибка дорого обходится. В договоре это сумма, дата начала, срок действия и номер; в медформе — аллергии, диагноз, дозировка, дата приема и срочные отметки.
Что должен видеть проверяющий, чтобы не тратить время зря?
Покажите ему не весь файл, а спорный фрагмент. Дайте вырезку скана, текст OCR рядом, найденное значение и немного соседнего контекста, чтобы он быстро подтвердил или исправил поле.
Хватит одного порога уверенности на весь документ?
Нет, один порог часто скрывает риск. Лучше держать отдельные правила для опасных полей и общий балл для документа целиком, иначе система пропустит тихую ошибку в сумме или дозировке.
С чего начать, если команда не может размечать весь документ?
Не пытайтесь разметить все сразу. Возьмите 3–4 поля, без которых процесс дальше не идет, например номер договора, сумму, дату окончания или диагноз, и настройте проверку только на них.
Как честно сравнить разные LLM на одном OCR-потоке?
Держите OCR, промпт и тестовый набор без изменений, а меняйте только модель. Если вы используете один OpenAI-совместимый шлюз, например AI Router, можно быстро прогнать те же документы через разные LLM и сравнить ответы без правок в SDK, коде и промптах.