Учет расходов и парсинг чеков нейросетью: от фото к отчету

Парсинг чеков нейросетью: схема автоматического учета расходов БЛОГ

⚡️ Кратко: ключевые факты и быстрый ответ

  • Пункт 1: Парсинг чеков нейросетью — это связка из двух слоев: OCR (или QR-код фискального чека) отдает сырой текст, а LLM из семейств Gemini Flash, Claude Sonnet или DeepSeek раскладывает его в поля — сумма, дата, магазин, позиции, категория.
  • Пункт 2: Главное отличие 2026 года — переход от «самопильных» регулярных выражений к схемам структурированного ответа: модель заполняет заданный JSON, а не свободный текст, и это дает точность выше на мятых, косых и засвеченных фото.
  • Пункт 3: Начинайте с QR-кода фискального чека там, где он есть: он дает сумму и дату без распознавания картинки, а модель подключайте только для строк товаров и категоризации — так стоимость обработки падает в разы.
  • Пункт 4: Подводный камень — тихая ошибка: модель может вернуть правдоподобную, но неверную сумму или перепутать дату. Без сверки суммы позиций с итогом чека и контроля баланса по выписке такой трекер опаснее таблицы вручную.

Содержание
  1. Почему ручной ввод чеков съедает вечер: считаем потери
  2. Под капотом: как нейросеть читает чек, QR и PDF-выписку
  3. Сравнение подходов: Gemini Flash, Claude Sonnet, DeepSeek и специализированные API
  4. Банковские выписки: парсинг таблиц без потери структуры
  5. Категоризация расходов: правила, эмбеддинги и ручные исключения
  6. Сборка конвейера: схема ответа, валидация и контроль качества
  7. Инженерная безопасность: маскирование, локальные модели и контуры изоляции
  8. Типичные ошибки: где распознавание ломается и как это лечить
  9. Часто задаваемые вопросы (FAQ)
  10. Насколько точно нейросеть читает мятые чеки с фото — и сколько всё равно придётся править руками?
  11. Облачная LLM или локальная модель на своём сервере — что выгоднее для парсинга чеков?
  12. Как не слить лишнего: что из чека реально нужно отправлять в сторонний API?
  13. Банк не даёт API. Как вытащить операции из выписки?
  14. Как автоматизировать категории трат, чтобы не переписывать их каждый месяц вручную?
  15. 💡 В сухом остатке: главное

Почему ручной ввод чеков съедает вечер: считаем потери

Ручной ввод одного чека отнимает 40–60 секунд, а вместе с ежемесячной сверкой выписки — почти два часа в месяц. За год набегает 21–30 часов, то есть три-четыре полных рабочих дня.

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

И самое неприятное: печатаете вы не так уж много. Основное время съедает не набор текста, а возвращение в контекст. Что за покупка на 2 347 ₽ три недели назад? Бытовая химия или продукты? Ответа в чеке уже нет.

Этап Время на операцию В месяц (≈43 чека)
Ввод чека вручную 40–60 с 29–43 мин
Разбор выписки по карте и счёту 60–90 мин 60–90 мин
Правка категорий и поиск забытых покупок 15–20 мин 15–20 мин
Итого — ≈1 ч 45 мин – 2 ч 30 мин

Цифры в таблице — бытовой сценарий: 8–10 покупок в неделю, часть из них онлайн, плюс пара поездок на транспорте. У семьи с детьми поток выше в полтора-два раза, у одного человека ниже, но порядок величин тот же.

Дальше включается накопление. Первые две-три недели человек честно вносит каждую покупку, потом появляется «потом разберу» — и стопка уезжает в ящик. По нашим наблюдениям, порог, после которого архив перестаёт разбираться вручную, наступает примерно на двух-трёх сотнях необработанных записей: восстановить по ним картину месяца уже дороже, чем начать заново.

Есть и физический дедлайн. Большинство чеков печатают на термобумаге, а она теряет контраст: в шкафу — за 6–18 месяцев, у окна или над обогревателем заметно быстрее. QR-код спасает только сумму, дату и продавца, построчного состава покупки в нём нет.

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

Что меняет ИИ-разбор? Связка оптического распознавания и языковой модели сжимает обработку одного чека до 3–5 секунд и, главное, вытаскивает позиции, а не только итог. Модели семейств Gemini Flash, Claude Sonnet или DeepSeek тянут такую задачу уверенно, если снимок сделан ровно и не под углом.

Готовые сценарии такого конвейера описаны, например, у AI-сканера чеков OpenKlo: агент принимает фото или PDF, вытаскивает сумму, дату, магазин и товары, проставляет категорию и отправляет запись в систему учёта.

Что при этом происходит под капотом — токены, контекст, вызовы инструментов — мы разбирали в материале про устройство ИИ-агента. Спойлер: магия там заканчивается ровно на этапе распознавания, дальше начинается аккуратная инженерия.

💡 Инсайт: экономия не в секундах распознавания. Настоящее узкое горлышко — категоризация и сверка с выпиской. Автоматизируйте сначала их, иначе быстрый ввод чеков просто ускорит накопление мусора в таблице.

Под капотом: как нейросеть читает чек, QR и PDF-выписку

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

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

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

Вторая ступень зависит от того, что именно пришло на вход. Скан или фото — идём в OCR (Tesseract, PaddleOCR и их аналоги). PDF-выписка из банка — сначала проверяем, есть ли текстовый слой: если он есть, распознавать нечего, поля вытаскиваются по координатам и ключевым словам, и это в разы быстрее.

А вот с фискальным QR всё интереснее. В квадратике зашиты дата и время, итоговая сумма, номер фискального документа и фискальный признак. Никаких позиций «хлеб 45 ₽» там нет — только шапка.

⚠️ Подводный камень: QR-код — самый дешёвый путь (ноль токенов), но он даёт только сумму и дату. Если нужна разбивка по товарам и категориям, придётся всё равно читать бумагу целиком. Разработчик SplitMe описывает ровно этот момент: чек по сути таблица, и соблазн решить всё нейросетью велик, но дешевле сначала попробовать QR.

Третья ступень — самая интересная. Сырой текст из OCR похож на кашу: обрезанные названия, слипшиеся цены, случайные символы. Здесь в дело входит языковая модель, и работает она не «как получится», а по схеме.

На вход подаём распознанный текст и строгое описание полей: дата, магазин, итог, список позиций с ценой и количеством. На выходе ждём валидный JSON, который сразу проверяется валидатором. Не прошло — повторяем запрос, а не правим руками.

💡 Инсайт: температура строго в ноль и жёсткая схема ответа дают больше, чем смена модели. Модель семейства ChatGPT с форматом ответа по схеме уже не «фантазирует» поля, а выбирает из того, что реально видит в тексте.

И да, длинный чек на 40 позиций ощутимо раздувает контекст — механика та же, что в любом агентском сценарии, мы её разбирали в материале про токены, контекст и MCP на пальцах. Дешёвый лайфхак: резать документ на блоки по 10–15 строк и склеивать результат, а не гнать простыню целиком.

Что это даёт на практике? Три ступени разделяют ответственность: геометрия отвечает за качество картинки, OCR — за символы, модель — за смысл. Когда что-то ломается, вы сразу видите, на какой ступени, а не гадаете, почему в отчёте за февраль оказался чек из июля.

Сравнение подходов: Gemini Flash, Claude Sonnet, DeepSeek и специализированные API

Короткий ответ: массовые фото чеков выгоднее отдавать Gemini 3.8 Flash, мятые и залитые кофе квитанции — Claude 5.5 Sonnet, текстовые PDF-выписки — DeepSeek-V4, а специализированные API берут фиксированной схемой полей и предсказуемым счётом.

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

Подход Стоимость обработки Мятые чеки, блики, плохой свет PDF-выписки Где силён
Gemini 3.8 Flash ≈1× (базовая точка отсчёта) Средне: спасает пачка из 10–20 фото в одном запросе Читает нативно, включая сканы Пакетная ночная обработка архива чеков
Gemini 3.1 Pro ≈3–5× Заметно выше Flash Нативно, тянет длинные документы Многостраничные выписки, где важна связность строк
Claude 5.5 Sonnet ≈5–8× Лучшая устойчивость к геометрии заломов и рукописным пометкам Принимает PDF, длинные файлы приходится резать на части Сложные квитанции и строгий JSON на выходе
DeepSeek-V4 ≈1–2× Слабее на фото: нужен предварительный OCR Хорошо работает с текстовым слоем Дешёвая нормализация названий магазинов и категорий
Специализированные API извлечения За документ, а не за токены Заявлена обработка заломов и теней Да, «из коробки» Фиксированная схема полей: сумма, дата, продавец, позиции

Что это даёт на практике? Универсальная модель всегда отвечает текстом, и этот текст ещё надо привести к структуре. Специализированный сервис возвращает готовые поля, но взамен требует доверия к чужому конвейеру и плохо терпит нестандартные документы.

💡 Инсайт: не выбирайте одну модель на всё. Дешёвый Flash или DeepSeek делает первый прогон, а на эскалацию к Claude Sonnet уходят только те чеки, где не сошлась контрольная сумма позиций с итогом. На типичном архиве личных расходов так улетает в дорогой контур не больше 10–15% документов.

Про мятые чеки есть отдельный нюанс, который редко пишут в маркетинговых материалах. Термобумага выцветает, а тень от пальца на сумме читается моделью как цифра. Наш опыт подтверждает: сжатие фото до 1024–1280 пикселей по длинной стороне почти не влияет на точность, зато кратно снижает расход токенов и время ответа.

⚠️ Подводный камень: любой провайдер может тихо обновить модель, и ваша схема ответа поедет. Держите валидацию на своей стороне: сумма позиций плюс скидка должны сходиться с итогом, дата не может быть из будущего, ИНН продавца — фиксированной длины.

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

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

Банковские выписки: парсинг таблиц без потери структуры

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

Чек живёт по принципу «одна транзакция — один документ». Выписка за месяц — это сотня операций в общем полотне, где дата, контрагент и назначение платежа легко перетекают между строками. Нейросеть, которая хорошо читает фото чека, на такой вёрстке начинает склеивать соседние операции в одну.

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

Канал Что даёт Где ломается
Текстовый слой PDF Полные реквизиты, назначение платежа, ИНН Колонки склеиваются, теряется знак минуса
CSV-экспорт Готовые поля и суммы без разбора вёрстки Кодировка, разделитель, десятичная запятая
Балансовая сверка Контроль корректности всей выборки Не работает без начального остатка

Первый канал — текстовый слой. У выписок из интернет-банка он обычно есть, и вытаскивать его лучше не «в лоб», а с сохранением геометрии: инструменты вроде pdfplumber или pdftotext с ключом -layout держат координаты слов. Дальше модель получает уже не поток букв, а подобие таблицы, и ей остаётся привести колонки к схеме.

Если текстового слоя нет, документ пришёл сканом или защищён паролем, включается распознавание по изображению. Здесь точность падает заметно, и именно на таких файлах всплывают дубли: одну и ту же страницу легко загрузить дважды. Спасает хеш файла и хеш пары «дата + сумма + контрагент».

⚠️ Подводный камень: в PDF расход часто подан как «−1 250,00», а в CSV тот же расход лежит положительным числом в отдельной колонке типа операции. Если не нормализовать знак и не распарсить десятичную запятую с неразрывным пробелом внутри суммы, бюджет молча поедет в противоположную сторону.

Второй канал — CSV. Он скучнее, зато почти всегда точнее: банк сам отдаёт поля. Беда в мелочах — cp1251 вместо UTF-8, точка с запятой как разделитель, сумма в кавычках. Эти три строки настройки экономят часы ручной правки.

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

💡 Инсайт: считайте не «сколько распозналось», а сколько операций прошло балансовую проверку. Расхождение в 1–2 рубля почти всегда означает не округление, а скрытую строку с комиссией, которую модель не увидела.

Логику распределения задач между моделью и кодом мы подробнее разбирали в материале Как работает ИИ-агент: токены, контекст и MCP на пальцах — там же объясняется, почему детерминированные проверки стоит держать вне модели.

В сухом остатке: нейросеть приводит хаос вёрстки к схеме, код нормализует единицы и знаки, а баланс говорит, можно ли этому верить. Уберите любой из трёх слоёв — и выписка превратится в лотерею.

Категоризация расходов: правила, эмбеддинги и ручные исключения

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

Порядок именно такой, и он неслучаен. Дешёвые детерминированные проверки должны отсекать основную массу чеков ещё до того, как вы отправите запрос в модель. Иначе каждый поход в магазин будет стоить денег и секунд ожидания.

Первая ступень — справочник мерчантов. В банковской выписке почти всегда есть MCC, четырёхзначный код категории торговой точки, и это самый надёжный сигнал. Проблема в том, что в QR-чеке такого кода обычно нет, зато есть название продавца в свободной форме: «ООО РОМАШКА», «Romashka LLC», «Ромашка ТД».

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

Вторая ступень нужна там, где точного совпадения нет. Здесь в дело идут эмбеддинги: имя мерчанта превращается в вектор, и мы ищем ближайшие соседи среди уже размеченных названий по косинусной близости.

Тут и вылезает главная боль. «Магнит» у дома и «Магнит Косметик» семантически почти неразличимы, а категории у них разные. То же с «ВкусВилл» и «Вкусвилл» в разном регистре, с «Перекрёстком» и «Перекресток-Экспресс».

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

Как выбирать порог? Универсального значения нет, но эмпирическое правило такое: высокая близость — присваиваем автоматически, средняя зона — помечаем «под вопросом» и спрашиваем пользователя, низкая — считаем мерчанта новым. Точные числа подбираются на вашей же истории разметки, а не берутся из статьи.

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

Ступень Источник решения Когда срабатывает Приоритет
Ручное исключение Пользователь Всегда для конкретного мерчанта Наивысший
Справочник Нормализованное имя + MCC Точное совпадение Высокий
Эмбеддинги Косинусная близость Близость выше порога Средний
Модель LLM с таксономией в промпте Мерчант неизвестен Низкий

Новый мерчант, которого нет в справочнике, уходит на четвёртую ступень: LLM получает список ваших категорий и название продавца, а на выходе отдаёт одну из них либо честное «не знаю». Ответ попадает в очередь на подтверждение человеком.

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

Аккуратно стоит обойтись и с правами на эти правила. Массовое редактирование исключений через API агента — это ровно та история, где важно разграничение доступа: подробный разбор механики мы делали в материале про права доступа ИИ-агента.

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

Сборка конвейера: схема ответа, валидация и контроль качества

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

Первый уровень — схема. Не парсите свободный текст регулярками, это дорога в ад: модель сегодня вернёт «1 234,50 ₽», завтра «1234.5», а послезавтра добавит пояснение в скобках. Просите строгий JSON с фиксированным набором полей, ограничениями длины и перечислением допустимых валют.

Сумму держите строкой с регуляркой на формат, а не числом с плавающей точкой. Классический баг: 0.1 + 0.2 вdouble даёт хвост, и позиции перестают сходиться с итогом. Валидируем через Decimal.

import datetime
from decimal import Decimal

SCHEMA = {
  "type": "object",
  "required": ["merchant", "total", "currency", "purchased_at", "items"],
  "additionalProperties": False,
  "properties": {
    "merchant":     {"type": "string", "minLength": 2, "maxLength": 120},
    "total":        {"type": "string", "pattern": r"^\d{1,7}\.\d{2}$"},
    "currency":     {"type": "string", "enum": ["RUB", "USD", "EUR", "KZT"]},
    "purchased_at": {"type": "string", "format": "date"},
    "items": {"type": "array", "minItems": 1,
              "items": {"type": "object", "required": ["name", "price"],
                        "properties": {"name": {"type": "string"},
                                       "price": {"type": "string"}}}}
  }
}

class Rejected(Exception):
    def __init__(self, code, detail):
        self.code, self.detail = code, detail

def verify(payload, today=None):
    today = today or datetime.date.today()
    total = Decimal(payload["total"])
    if total <= 0:
        raise Rejected("SUM_NON_POSITIVE", payload["total"])

    items_sum = sum(Decimal(i["price"]) for i in payload["items"])
    drift = abs(items_sum - total)
    if drift > Decimal("0.05") * len(payload["items"]):   # 5 копеек на позицию
        raise Rejected("SUM_MISMATCH", f"{items_sum} vs {total}")

    d = datetime.date.fromisoformat(payload["purchased_at"])
    if d > today:
        raise Rejected("DATE_FUTURE", d.isoformat())
    if (today - d).days > 365 * 3:
        raise Rejected("DATE_TOO_OLD", d.isoformat())
    return payload

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

Второй слой — контроль качества. Каждый отказ не выбрасываем, а пишем в журнал: файл-источник, сырой ответ модели, код ошибки, название модели и дата. Позже по этой таблице видно, что чинить: промпт, качество фото или конкретный банк с нестандартной вёрсткой.

Код Причина Что делать
SUM_MISMATCH Позиции не бьются с итогом Повторный проход с обрезанным фото
DATE_FUTURE Модель приняла срок годности за дату покупки Подсказка в промпте с областью даты
DATE_TOO_OLD Чек старше трёх лет Ручная проверка, не автоприём
SCHEMA_INVALID Ответ не прошёл по JSON-схеме Повтор с температурой 0

Долю отбраковки держите как метрику здоровья конвейера. Ориентир — 2–5 %: выше значит проблема с промптом или качеством снимков, ноль значит валидатор слишком мягкий и мусор уже течёт в базу.

⚠️ Подводный камень: не просите модель самой считать итог, НДС и скидки. Арифметику делает код, модель только извлекает напечатанные числа — иначе получите красивые, но неверные суммы.

Как устроены сами вызовы модели и зачем здесь ограниченный контекст, мы разбирали в материале как работает ИИ-агент: токены, контекст и MCP на пальцах. Практика показывает: жёсткая схема плюс журнал отказов экономят больше времени, чем любая попытка «умнее попросить» модель.

Инженерная безопасность: маскирование, локальные модели и контуры изоляции

До отправки во внешний API из документа вырезают всё, что прямо идентифицирует человека и платёжное средство: ФИО, номер карты, адрес, телефон, номер счёта. Модели отдают только сумму, дату, название точки и список позиций.

Логика простая: распознавание строки «Магнит, 12.10, 843,50 ₽» не требует знания, чья это карта. Значит, лишнее в запрос не идёт. Работает это как конвейер обезличивания на входе в контур: сначала нормализация текста после OCR, потом замена чувствительных сущностей на плейсхолдеры вида <PERSON_1> или <CARD_4>, и только потом запрос к модели.

Ключевая деталь — словарь обратных подстановок. Соответствие «плейсхолдер → исходное значение» живёт в локальной базе и наружу не уходит никогда. Модель вернула JSON с <PERSON_1> — на нашей стороне он разворачивается обратно. Такой подход даёт бонус: по одному и тому же чеку можно прогнать несколько моделей и сравнить результат, не раскрывая данные повторно.

⚠️ Подводный камень: регулярка на номер карты не ловит номер, разбитый пробелами или переносами строк в PDF-выписке. Перед маскированием текст нужно склеить и нормализовать, иначе часть идентификаторов уедет в запрос как есть.

Первый контур изоляции — локальный OCR и детерминированный парсер. Tesseract или PaddleOCR снимают текст с картинки на своём железе, дальше регулярки и шаблоны достают 70–80% полей вообще без нейросети. LLM подключается только к тому, что не разобралось: нестандартная вёрстка, слипшиеся позиции, рукописные правки.

Что это даёт на практике? Отправляется не фотография на 2–3 МБ, а килобайт текста. Объём запроса падает на два порядка, а вместе с ним и поверхность утечки: изображение чека с адресом и последними цифрами карты остаётся в локальном хранилище.

Теперь про «держать распознавание у себя». Тысяча чеков после OCR — это порядка 0,7–1 млн входных токенов, то есть совсем немного. На таких объёмах облачные Gemini 3.8 Flash или Claude 5.5 Sonnet стоят копейки, и экономить на своём железе смысла нет.

Считать надо не цену токена, а объём архива и требования к приватности. Когда на входе десятки тысяч документов в месяц или выписки на 60–100 страниц, картина меняется: модель на 8–14 млрд параметров в квантовании Q4 укладывается в 6–10 ГБ видеопамяти и уверенно тянет извлечение полей из готового текста. Как это разворачивается на потребительской видеокарте, мы разбирали в материале про квантование LLM: GGUF и AWQ для запуска 70B на домашнем ПК.

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

💡 Инсайт: заведите флаг «документ содержит чувствительные сущности» и роутинг по нему. Обычные продуктовые чеки уходят в облако за скорость, а зарплатные ведомости и медицинские счета автоматически обрабатываются только локально. Один флаг закрывает большую часть рисков без потери качества.

Последний слой — сетевой. Исходящий трафик идёт через прокси с белым списком доменов, телеметрия SDK отключена, ключи лежат в секрет-хранилище и подставляются как YOUR_API_KEY из переменных окружения, а не из кода. Логи запросов хранят хеши, а не тела документов. Правовые нормы динамичны и требуют предварительной проверки юристами компании.

Типичные ошибки: где распознавание ломается и как это лечить

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

Начнём с самой частой беды. Человек фотографирует чек под лампой, глянцевый слой бликует, и половина строки «наименование» превращается в белое пятно. Модель не ошибается — она просто не видит символов и достраивает по смыслу, а это уже выдумка.

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

Отдельная история — термобумага. Она выцветает за месяцы, а от нагрева в кармане или на торпеде просто чернеет. Скан такой бумаги даёт серый фон и рваный контраст, поэтому перед отправкой в модель стоит прогнать снимок через обесцвечивание и повышение контраста. Дешевле и надёжнее, чем гонять повторные запросы.

Копейки — самая коварная категория. Скидки, округления и налог считаются на кассе по своим правилам, и сумма позиций почти никогда не совпадает с «ИТОГО» до копейки. Прикинем на пальцах: тридцать восемь строк набежали на 2 314,90 ₽, а итог в чеке — 2 314,88 ₽. Разница в 2 копейки выглядит мелочью, но она ломает любой автоматический контроль и плодит ложные срабатывания.

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

Симптом Причина Лечение
Белые пятна в наименованиях Блик, съёмка под лампой Переснять без вспышки, рассеянный свет, обрезка фона
Серый фон, «шумные» символы Выцветшая термобумага Обесцвечивание, контраст, бинаризация до отправки
Расхождение на 1–5 копеек Скидки и округления на кассе Поле «итог» брать как есть, позиции не подгонять
Позиций меньше, чем в чеке Обрезка контекста, склейка строк Резать чек на блоки по 20–25 строк и собирать результат

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

Часто задаваемые вопросы (FAQ)

Насколько точно нейросеть читает мятые чеки с фото — и сколько всё равно придётся править руками?

Точность зависит не от модели, а от качества входной картинки. Выцветшая термобумага, блик от лампы, чек, снятый под углом на коленке, — вот где начинаются потери. Модели семейств Gemini Flash, Claude Sonnet или GPT-6.x на чистом скане или PDF с текстовым слоем выдают структуру почти без ошибок, а на смятом фото в тёмном подъезде — уже нет.

Рабочая схема — два контура. Сначала быстрый OCR (Tesseract, PaddleOCR или встроенный OCR облака) вытаскивает текст, затем LLM приводит его к структуре: дата, магазин, итог, позиции. Если OCR уверен в символах, модель не гадает по картинке, а работает с чистым текстом — ошибок заметно меньше.

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

Публичных замеров точности под ваш поток чеков не существует — не верьте красивым процентам из лендингов. Соберите контрольный набор из 100–200 своих реальных фотографий, прогоните через кандидатов и посчитайте долю чеков, которые ушли на ручную правку. Это единственная цифра, которая вам что-то скажет.

Облачная LLM или локальная модель на своём сервере — что выгоднее для парсинга чеков?

Считайте не «умность» модели, а стоимость одного чека. Порядок величин такой: изображение чека в визуальной модели съедает примерно 1–2 тысячи токенов, структурированный ответ с 15–25 позициями — ещё 500–800. Итого 2–3 тысячи токенов на документ. Тысяча чеков — это 2–3 миллиона токенов.

Дальше простая формула: (число чеков × токены на чек ÷ 1 000 000) × цена за миллион токенов у провайдера. Тарифы меняются, поэтому берите актуальный прайс на день расчёта, а не цифры из чужой статьи годичной давности.

Локальный контур (открытые визуально-языковые модели плюс OCR на своём железе) окупается в двух случаях: поток большой и стабильный либо данные нельзя выпускать за периметр. Минусы честные — нужен GPU, обновления моделей и инженер, который всем этим занимается.

Компромисс, который чаще всего и выбирают: дешёвая быстрая модель (например, Gemini Flash или DeepSeek) на типовые чеки, дорогая (Claude Sonnet, Gemini Pro, GPT-6.x) — только на те, где дешёвая вернула низкую уверенность или не сошлась сумма.

Как не слить лишнего: что из чека реально нужно отправлять в сторонний API?

В чеке почти никогда не нужны ФИО покупателя, полный номер карты (его там и нет), адрес и прочие идентификаторы. Для учёта расходов хватает суммы, даты, названия магазина и перечня позиций. Всё остальное вырезайте ещё до отправки.

Практика простая: на устройстве или в своём бэкенде обрезаете изображение до области с таблицей позиций, вырезаете QR и служебные поля, а в промпт кладёте только текст. Так модель видит меньше, а риск утечки падает.

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

И не кладите ключи доступа в мобильное приложение. Токен к API живёт на сервере, приложение ходит только к вашему шлюзу — иначе ключ вытащат из apk за вечер.

Банк не даёт API. Как вытащить операции из выписки?

Сначала проверьте, что есть. У большинства банков в интернет-банке лежит выгрузка в CSV или Excel — это самый дешёвый и точный путь, никакая нейросеть там не нужна, достаточно разобрать колонки. Если банк отдаёт PDF с текстовым слоем, хватит pdftotext или pdfplumber.

Нейросеть подключайте на третьем шаге — когда пришёл скан, скриншот или PDF-картинка без текста. Здесь модель работает хорошо: она вытягивает дату, сумму, знак операции и описание, даже если вёрстка у каждого банка своя.

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

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

Как автоматизировать категории трат, чтобы не переписывать их каждый месяц вручную?

Начните с правил, а не с нейросети. «Пятёрочка», «Магнит», «Перекрёсток» — это «Продукты», и здесь достаточно справочника названий магазинов с нормализацией: убрать кавычки, привести к нижнему регистру, отрезать лишние приставки вроде города в скобках.

На незнакомых мерчантах включайте сравнение векторных представлений названий: «Кофемания» окажется близка к «кофе», «Шоколадница» — к «кафе». Работает лучше, чем точное совпадение строк, и не требует обучения.

Ключевое — порог уверенности. Если модель уверена, категория проставляется сама. Если нет, пользователь видит одну карточку с вариантами на выбор, а не весь список трат. И каждая правка должна запоминаться как новое правило — тогда через пару недель ручной работы станет заметно меньше.

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

💡 В сухом остатке: главное

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

Чек-лист для внедрения на практике:

  • ✅ Шаг 1: Соберите тестовый набор из 30–50 своих реальных чеков и 2–3 банковских выписок — на мятых, засвеченных и старых документах, а не только на идеальных сканах.
  • ✅ Шаг 2: Зафиксируйте схему извлечения (JSON со строгими типами полей: сумма числом, дата в ISO, магазин, список позиций) и запретите модели добавлять поля от себя.
  • ✅ Шаг 3: Введите автоматическую валидацию — сумма позиций против итога, дата не из будущего, дубликат по хешу QR или по комбинации дата плюс сумма плюс магазин.
  • ✅ Шаг 4: Оставьте человеку кнопку «поправить» и складывайте правки в отдельный журнал: это единственный честный источник данных для дообучения правил категоризации.

Обсудить материал и поделиться своими бенчмарками можно в комментариях к блогу.

Редактор
Оцените автора
Добавить комментарий

Отправляя данную форму вы соглашаетесь с политикой конфиденциальности сайта