Инженерный блог

Скармливаем казахскую первичку в Document AI: Как мы автоматизировали ад бухгалтера

13.08.2026
Шарафутдинов Р.

Конец месяца в любой казахстанской компании — это время, когда в офисе витает запах кофе, корвалола и ненависти к бумаге. Бухгалтеры, как операторы матричных станций, без остановки вбивают в 1С бесконечный поток первички: акты выполненных работ (АВР), накладные (З-2), счета-фактуры и квитанции. Каждый документ — это минное поле. Поставщик распечатал АВР из кривой ERP-системы, курьер помял его в рюкзаке, а сверху шлепнули жирную синюю печать прямо на БИН компании. Знакомая картина?

Автоматизировать ввод первички пытались многие. На рынке существуют десятки решений, обещающих "мгновенное распознавание". Но реальность сурова. В этой статье мы, инженеры OZAT, расскажем, почему классический шаблонный OCR мертв для казахстанских реалий, и покажем, как мы решили эту проблему раз и навсегда с помощью нейросетей, компьютерного зрения и Google Cloud Document AI.

Почему классический OCR — это боль и страдания?

Исторически автоматизация ввода документов строилась на базе оптического распознавания символов (OCR) — таких движков, как Tesseract или коммерческий Abbyy FineReader. Подход выглядит просто: сканируем документ, получаем полотно текста, а затем натравливаем на него регулярные выражения (RegEx). Ищем слово "БИН", берем 12 цифр после него. Ищем слово "Итого", берем сумму. Что может пойти не так?

Всё. Казахстанская первичка — это хаос, который невозможно загнать в шаблоны.

  • Проблема смещения: Шаблонные OCR-системы привязываются к координатам. Стоит бухгалтеру отсканировать лист чуть криво (под углом 5 градусов) — и координаты "едут". Поле "Сумма" внезапно распознается как "Количество".
  • Адская синяя печать: Это классика. В Казахстане обожают ставить круглую синюю печать ровно на табличную часть или реквизиты. Для Tesseract синие буквы поверх черных цифр превращаются в месиво из пикселей. БИН "123456789012" превращается в "1234S6?89G12". Регулярное выражение падает.
  • Разнообразие форм: Даже стандартная форма АВР (Приложение 50) умудряется выглядеть по-разному в разных учетных системах. Разная ширина колонок, разные шрифты, кто-то добавляет свои поля. Написать универсальный RegEx для табличной части, которая может переноситься на вторую страницу — это задача, от которой седеют бэкенд-разработчики.

В результате, классические OCR-системы в проде дают в лучшем случае 60% точности. Бухгалтеру приходится перепроверять каждый отсканированный документ, исправлять ошибки и ругаться на "тупых программистов". Смысл автоматизации теряется.

Смена парадигмы: Google Cloud Document AI

Поняв, что регулярки и шаблоны ведут в тупик, мы обратили внимание на Document AI от Google Cloud Platform. В отличие от тупого OCR, Document AI — это не просто извлекатель текста. Это мультимодальная нейросеть, которая понимает пространственный и визуальный контекст документа.

Что это значит на практике? Нейросеть смотрит на PDF-файл так же, как человек. Если она видит 12-значный номер в верхнем правом углу, рядом с названием юридического лица, она понимает, что это БИН, даже если само слово "БИН" залито кофем или перекрыто печатью. Ей не нужны строгие координаты. Она анализирует топологию, структуру таблиц, шрифты и взаимосвязь элементов.

Архитектура решения: Custom Extractor под наши реалии

В Document AI есть готовые парсеры (Invoice Parser, Receipt Parser), но они обучены на американских и европейских стандартах. Они отлично понимают Invoice, но пасуют перед нашей Накладной З-2. Поэтому мы использовали Custom Extractor — инструмент, позволяющий обучить собственную Foundation Model от Google на ваших специфичных документах.

Процесс состоял из нескольких инженерных шагов:

1. Разметка данных (Data Labeling) прямо в облаке

Для начала нам понадобился датасет. Мы взяли 200 реальных казахстанских АВР и Накладных (с печатями, подписями, кривыми сканами и артефактами). Загрузили их в Cloud Storage. Затем в консоли Document AI открыли встроенный инструмент разметки.

Задача разметчика — выделять bounding boxes (прямоугольники) вокруг нужных данных и присваивать им классы (сущности). Мы определили следующие сущности:

  • supplier_name (Название поставщика)
  • supplier_bin (БИН поставщика)
  • invoice_date (Дата документа)
  • total_amount (Итоговая сумма)
  • line_items (Родительская сущность для табличной части)
    • item_name (Наименование работы/услуги)
    • item_quantity (Количество)
    • item_price (Цена)
    • item_amount (Сумма)

2. Обучение модели (Fine-Tuning)

Разметив 150 документов для обучения (Training set) и 50 для тестирования (Test set), мы запустили процесс тренировки. Google Cloud берет свою предобученную мощную LLM-модель (Foundation Model), которая уже понимает, что такое "документ", "таблица" и "текст", и дообучает её веса под наши конкретные классы.

Обучение заняло несколько часов. Когда мы посмотрели на Evaluation Metrics, результаты нас поразили. F1 Score (гармоническое среднее между точностью и полнотой) для БИН составил 0.98, а для табличных строк — 0.95. Модель научилась безошибочно вытаскивать товары из многостраничных накладных, игнорируя синие печати и подписи!

3. Интеграция с бэкендом и 1С

Обученная модель (Processor) была задеплоена и получила свой уникальный Endpoint в GCP. Теперь нам нужно было связать её с учетной системой клиента — 1С:Предприятие.

Архитектура продакшена выглядит так:

  1. Секретарь кладет пачку первички в сканер. Сканер по FTP отправляет PDF-файлы на наш микросервис (написанный на Node.js).
  2. Микросервис, крутящийся в бессерверной среде Cloud Run, получает PDF и по gRPC отправляет его в API Document AI.
  3. Document AI возвращает гигантский JSON (содержащий текст, сущности, геометрию, уверенность распознавания).
  4. Наш микросервис парсит этот JSON (код приведен ниже), собирает аккуратный объект данных и отправляет его по HTTP/REST в опубликованный веб-сервис 1С.
  5. В 1С автоматически создается документ "Поступление ТМЗ и Услуг", прикрепляется PDF-файл, и бухгалтеру остается только нажать кнопку "Провести".

Магия в коде: Парсим ответ от Document AI

Самое сложное при работе с Document AI — это парсинг его ответа. API возвращает не просто текст, а сложную графовую структуру. Вот как мы написали обработчик на Node.js для вытаскивания таблиц и шапки документа:

const { DocumentProcessorServiceClient } = require('@google-cloud/documentai').v1;
const client = new DocumentProcessorServiceClient();

async function parseKazakhInvoice(projectId, location, processorId, filePath) {
  // Указываем путь к нашему Custom Extractor процессору в Google Cloud
  const name = `projects/${projectId}/locations/${location}/processors/${processorId}`;
  
  const fs = require('fs').promises;
  const imageFile = await fs.readFile(filePath);
  
  const request = {
    name,
    rawDocument: {
      content: Buffer.from(imageFile).toString('base64'),
      mimeType: 'application/pdf',
    },
  };

  // Отправляем скан на обработку в Document AI
  console.log('Отправка документа в Document AI...');
  const [result] = await client.processDocument(request);
  const document = result.document;
  
  const extractedData = { items: [] };

  // Функция для безопасного извлечения текста по якорям (Text Anchors)
  const getText = (textAnchor) => {
    if (!textAnchor || !textAnchor.textSegments || textAnchor.textSegments.length === 0) return '';
    let text = '';
    for (const segment of textAnchor.textSegments) {
      const startIndex = segment.startIndex || 0;
      const endIndex = segment.endIndex;
      text += document.text.substring(startIndex, endIndex);
    }
    return text.trim();
  };

  // Парсинг извлеченных сущностей
  for (const entity of document.entities) {
    const entityType = entity.type;
    const entityValue = entity.mentionText || getText(entity.textAnchor);

    // Собираем шапку документа
    if (entityType === 'supplier_bin') extractedData.bin = entityValue;
    if (entityType === 'total_amount') extractedData.totalAmount = entityValue;
    if (entityType === 'invoice_date') extractedData.date = entityValue;
    
    // Парсим табличную часть (Вложенные сущности / Line Items)
    if (entityType === 'line_items' && entity.properties) {
      for (const item of entity.properties) {
        let row = {};
        for (const prop of item.properties) {
          // Вытаскиваем наименование, количество, цену и сумму
          row[prop.type] = prop.mentionText || getText(prop.textAnchor);
        }
        extractedData.items.push(row);
      }
    }
  }

  console.log('Успешно распознано:', JSON.stringify(extractedData, null, 2));
  return extractedData;
}

// Пример вызова:
// parseKazakhInvoice('my-gcp-project', 'eu', 'a1b2c3d4e5f6', './nakladnaya.pdf');

Смотреть код на GitHub (OZAT-kz)

Обратите внимание на функцию getText(textAnchor). Это важнейший паттерн при работе с Document AI. Нейросеть возвращает не всегда готовый текст сущности (mentionText), а часто указывает "индексы" (start/end) в глобальном массиве текста документа. Мы должны сами "вырезать" нужный кусок текста по этим координатам. Это позволяет избежать потери данных при сложных форматированиях.

Результаты и ROI: Цифры говорят за себя

До внедрения системы, отдел бухгалтерии из 4 человек тратил суммарно около 40 человеко-часов в неделю только на ручной ввод первичных документов от сотен поставщиков. Это была монотонная, изнуряющая работа, приводящая к неизбежным опечаткам (перепутали цифру в сумме, указали не тот БИН).

Время обработки 1000 накладных (в часах)

Попытка внедрить коробочный OCR на базе регулярных выражений сократила время до 15 часов, но добавила новую боль: бухгалтеры тратили нервы на ручное исправление неверно распознанных копеек и "съехавших" таблиц.

Переход на Google Cloud Document AI (Custom Extractor) изменил всё. Время обработки 1000 документов сократилось до 30 минут машинного времени. Бухгалтеру больше не нужно ничего вбивать. Документ появляется в 1С сам. Человек выступает лишь в роли контролера, который глазами пробегается по цифрам и нажимает "ОК".

Резюме

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

Google Cloud Document AI доказал, что способен "переварить" даже самую суровую казахстанскую первичку: с синими печатями, подписями поверх текста, кривым сканированием и нестандартными шаблонами. Да, обучение Custom Extractor требует времени и понимания ML-процессов, но ROI (окупаемость инвестиций) этой архитектуры исчисляется месяцами, а сэкономленные нервы бухгалтеров — бесценны.

Если ваша компания всё ещё тонет в бумагах, а отдел ввода данных разрастается — приходите в OZAT. Мы покажем, как заставить нейросети работать на вашу бухгалтерию.

💡 Совет OZAT: Готовы к внедрению? Рассчитайте архитектуру и бюджет через Scope Builder или пройдите бесплатный ИИ-аудит.

Рустам Шарафутдинов

Рустам Шарафутдинов

Автор инженерного блога

Эксперт в области архитектуры Google Cloud и Senior Full-Stack разработчик с более чем 15-летним опытом. Специализируется на отказоустойчивых архитектурах, оптимизации высоконагруженных проектов и интеграции AI (Vertex AI).

Экспертность: GCP, Kubernetes, Микросервисы, React, Node.js

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