Заявка на поставку металлопроката и металлоконструкций на реальном рынке живет считанные часы. Снабженец строительного объекта отправляет ведомость одновременно в 4-5 заводов и заказывает у того, кто первым прислал официальное коммерческое предложение с точными ценами, весом и сроками отгрузки.

На производстве подготовка такого расчета занимает от 4 до 8 часов рабочего времени квалифицированного сметчика. Пока завод перебивает номенклатуру в Excel и сверяет коэффициенты, заказчик уже подписывает договор с более оперативным поставщиком.

Ниже технический разбор того, как мы автоматизировали этот процесс: почему популярная идея «скормить все в ChatGPT» приводит к прямому кассовому разрыву завода на сотни тысяч рублей, и как выглядит рабочая трехслойная архитектура на стыке Vision OCR, словарей ГОСТ и детерминированного кода.

Обложка: Инженерный расчет спецификаций металлопроката

1. Входящий хаос: как выглядит реальная заявка заказчика

В теории интеграторы любят рассуждать об электронном документообороте и структурированных XML-файлах. В реальности 90% входящих заявок - это информационный хаос:

  1. Размытый скан проектной ведомости с наклонными строками и синей печатью поверх текста.

  2. Фрагмент чертежа КМ/КМД, сфотографированный на телефон прямо со стройплощадки.

  3. Разношерстный Excel от субподрядчика без артикулов и кодов 1С.

  4. Простое сообщение в мессенджере с профессиональным сленгом закупщиков.

Типичный текст сообщения в отделе сбыта выглядит так:

«Добрый день! Нужен расчет на объект: уголок на сотку - 50 хлыстов по 12м, швеллер шестнашка П - 300 метров, лист четверка горячекатаный ст3сп - 15 квадратов, труба сотка стенка 4 - 1.2 км. Резка в размер. Жду расчет сегодня до 14:00.»

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

  • Переводит разговорный сленг («швеллер шестнашка П») в строгую нормативную номенклатуру («Швеллер 16П ГОСТ 8240-97»).

  • Открывает марочники и справочники стандартов, чтобы найти теоретическую массу одного погонного метра или квадратного метра.

  • Перемножает метры на нормативы ГОСТ, суммирует тоннаж, закладывает процент технологического отхода на раскрой (обычно 3-7%).

  • Заходит в 1С:УТ или ERP, проверяет фактические остатки на складе и актуальную закупочную цену за тонну.

  • Добавляет стоимость резки за рез, заводскую наценку, налоги и вручную верстает бланк коммерческого предложения в Word или Excel.

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


2. Эксперимент: почему ChatGPT нельзя подпускать к расчетам

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

Мы провели чистый контролируемый тест на реальной ведомости металлопроката в модели GPT-4o. Скормили позицию:

«Швеллер 16П - 300 метров. Рассчитай теоретическую массу партии в тоннах.»

Результат генерации модели:

Скриншот расчета ведомости в ChatGPT: ошибка в массе на 40%
Скриншот расчета ведомости в ChatGPT: ошибка в массе на 40%

Модель бодро выдала красивое объяснение с формулами и вывела итог: 2,50 тонны.

Проверяем по государственному стандарту ГОСТ 8240-97 (Швеллеры стальные горячекатаные):

  • Теоретическая масса 1 погонного метра швеллера 16П составляет 14,20 кг.

  • Корректная масса партии: 300 м × 14,20 кг/м = 4 260 кг = 4,26 тонны.

Ошибка модели: 1,76 тонны в минус (занижение веса на 41,3%).

Если завод применит этот расчет при цене металла, например, 72 000 рублей за тонну:

  • Корректная себестоимость партии металла: 4,26 т × 72 000 ₽ = 306 720 ₽.

  • Себестоимость по расчету ChatGPT: 2,50 т × 72 000 ₽ = 180 000 ₽.

  • Прямой кассовый убыток предприятия на одной позиции: 126 720 рублей.

Почему языковая модель так ошибается?

Языковая модель - это вероятностный генератор токенов, а не детерминированный калькулятор. Она помнит, что у слова «швеллер» в обучающей выборке часто встречались цифры 8, 10, 14, 16, 20. В процессе предсказания следующего токена она берет правдоподобную плотность стали или справочный вес соседнего типоразмера (например, швеллера 10П или 12П с массой ~8,59 кг/м) и с абсолютной уверенностью выдает галлюцинацию за чистую монету.

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


3. Архитектура рабочего конвейера

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

Архитектура конвейера расчета КП
Архитектура конвейера расчета КП

Слой 1. Семантический парсинг и нормализация номенклатуры (Vision + LLM)

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

  1. Предобработка сканов (OpenCV):

    • Выравнивание угла наклона листа (deskew через преобразование Хафа).

    • Нормализация контраста и приглушение синего канала печатей в цветовом пространстве HSV (без жесткой бинаризации, чтобы не убить полутона и градиенты для мультимодальной сети).

  2. Извлечение таблиц:

    • Мультимодальная модель (Vision API) анализирует разметку документа. В отличие от Tesseract OCR, мультимодальные модели понимают контекст объединенных ячеек, нестандартные заголовки граф и рукописные приписки снабженцев на полях.

  3. Нормализация через системный промпт со строгой схемой: Модель извлекает семантику: семейство проката, калибр и единицы измерения. При этом сам номер стандарта модель не придумывает - точный ГОСТ подтягивается жестким кодом на Слое 2 из реестра соответствий по связке семейства и размера профиля (например, channel + 16П однозначно мапится в ГОСТ 8240-97). Это гарантирует, что модель не подставит устаревший или выдуманный стандарт.

{
  "name": "parse_specification_items",
  "description": "Извлечение позиций металлопроката и параметров заказа",
  "parameters": {
    "type": "object",
    "properties": {
      "items": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "raw_text": { "type": "string", "description": "Исходный текст позиции из заявки" },
            "standard_family": { 
              "type": "string", 
              "enum": ["channel", "angle", "beam", "sheet_hot", "pipe_round", "pipe_profile"],
              "description": "Семейство проката для маппинга на стандарт"
            },
            "profile_size": { "type": "string", "description": "Калибр/размер, например 16П, 100х100х8" },
            "steel_grade": { "type": "string", "description": "Марка стали, например Ст3сп5, 09Г2С" },
            "quantity": { "type": "number", "description": "Числовое значение объема" },
            "unit": { "type": "string", "enum": ["meters", "tons", "pieces", "sq_meters"] },
            "cut_length": { "type": ["number", "null"], "description": "Длина реза/хлыста в метрах, если явно указана для позиции" }
          },
          "required": ["raw_text", "standard_family", "profile_size", "quantity", "unit", "cut_length"]
        }
      }
    },
    "required": ["items"]
  }
}

Модель выдает типизированный JSON. Фраза «швеллер шестнашка П - 300 метров» (где длина хлыста для резки не была задана) преобразуется в валидный объект с cut_length: null:

{
  "raw_text": "швеллер шестнашка П - 300 метров",
  "standard_family": "channel",
  "profile_size": "16П",
  "steel_grade": "Ст3сп",
  "quantity": 300,
  "unit": "meters",
  "cut_length": null
}

Слой 2. Детерминированный расчетный движок (Python + Справочники ГОСТ)

Второй слой - это полностью детерминированный код без использования нейросетей. В систему загружена локальная реляционная база справочных весов по всем государственным стандартам РФ.

Фрагмент расчетного модуля на Python:

from decimal import Decimal, ROUND_HALF_UP

# Детерминированный реестр стандартов по семейству проката (исключает галлюцинации LLM)
FAMILY_TO_GOST = {
    "channel": "ГОСТ 8240-97",
    "angle": "ГОСТ 8509-93",
    "beam": "ГОСТ 26020-83",
    "sheet_hot": "ГОСТ 19903-2015",
    "pipe_round": "ГОСТ 10704-91",
}

# Справочные коэффициенты погонной массы по ГОСТ 8240-97 (кг на 1 метр)
GOST_8240_97_WEIGHTS = {
    "10П": Decimal("8.59"),
    "12П": Decimal("10.40"),
    "14П": Decimal("12.30"),
    "16П": Decimal("14.20"),
    "18П": Decimal("16.30"),
    "20П": Decimal("18.40"),
    "24П": Decimal("24.00"),
}

def calculate_item_cost(item: dict, warehouse_price_per_ton: Decimal, markup_ratio: Decimal = Decimal("1.12")):
    """
    Строгий расчет массы и стоимости позиции с контролем размерностей.
    Метры * (кг/м) = кг -> кг / 1000 = тонны -> тонны * (руб/т) = рубли.
    """
    family = item["standard_family"]
    standard_code = FAMILY_TO_GOST.get(family)
    if not standard_code:
        raise ValueError(f"Неизвестное семейство проката: {family}")

    size = item["profile_size"]
    qty = Decimal(str(item["quantity"]))
    unit = item["unit"]
    
    if standard_code == "ГОСТ 8240-97":
        weight_per_meter = GOST_8240_97_WEIGHTS.get(size)
        if not weight_per_meter:
            raise ValueError(f"Размер {size} не найден в справочнике ГОСТ 8240-97")
            
        if unit == "meters":
            total_weight_kg = qty * weight_per_meter
            total_meters = qty
        elif unit == "tons":
            total_weight_kg = qty * Decimal("1000")
            total_meters = total_weight_kg / weight_per_meter
        else:
            raise NotImplementedError(f"Единица измерения {unit} требует дополнительных параметров")

        total_weight_tons = (total_weight_kg / Decimal("1000")).quantize(Decimal("0.001"), rounding=ROUND_HALF_UP)
        
        # Расчет себестоимости партии и цены с учетом наценки
        base_cost = total_weight_tons * warehouse_price_per_ton
        final_price = (base_cost * markup_ratio).quantize(Decimal("1"), rounding=ROUND_HALF_UP)
        
        return {
            "standard_title": f"Швеллер {size} {standard_code} / {item.get('steel_grade', 'Ст3сп')}",
            "meters": float(total_meters),
            "weight_tons": float(total_weight_tons),
            "base_cost_rub": float(base_cost),
            "final_price_rub": float(final_price)
        }

Актуальные складские остатки сырья и базовая себестоимость подтягиваются из 1С:ERP через стандартный REST API по коду номенклатуры. Алгоритм не имеет права фантазировать: если нужной марки стали нет на складе, позиция помечается флагом requires_procurement.


Слой 3. Human-in-the-loop и сборка официального PDF

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

Конвейер формирует проект коммерческого предложения за 15-20 секунд и отображает его сметчику в удобном интерфейсе:

  1. Зеленый статус: позиции, которые распознаны с уверенностью 99%+ и имеют полное совпадение по номенклатуре склада.

  2. Желтый статус: позиции, где в исходном скане была неразборчивая цифра либо нестандартный раскрой. Сметчик тратит 30 секунд на сверку сомнительной строки.

  3. Генерация чистового КП: после подтверждения инженером движок рендерит официальный PDF-документ на фирменном бланке завода со сквозной нумерацией, таблицей ГОСТ, условиями доставки, факсимиле подписи и круглой печатью организации.

Готовый файл автоматически прикрепляется к сделке в CRM (Битрикс24 или AmoCRM), а ссылка на скачивание отправляется клиенту в WhatsApp или на почту.

Образец официального КП с расчетом ГОСТ
Образец официального КП с расчетом ГОСТ

4. Сравнение производительности: до и после

Мы замерили результаты работы сметного отдела завода до и после внедрения расчетного конвейера на выборке из 350 входящих промышленных спецификаций:

Параметр

Ручной расчет инженера

Автоматизированный конвейер

Время подготовки 1 КП

4 - 8 рабочих часов

20 - 30 секунд на генерацию + 2 мин на валидацию

Вычисление массы

Ручной поиск по бумажным справочникам и формулам в Excel

Детерминированный расчет по базам ГОСТ

Риск ошибки в тоннаже

До 8-12% из-за опечаток и усталости к концу дня

0% (алгоритмическая проверка единиц)

Роль сметчика

Монотонная перебивка строк со сканов в таблицы

Экспертный контроль сомнительных позиций

Скорость ответа клиенту

На следующий рабочий день (сделка часто теряется)

В течение 10-15 минут после обращения

Нагрузка на отдел сбыта

Максимум 8-10 сложных расчетов в день на отдел

До 200 спецификаций в смену без расширения штата


5. Как протестировать логику самостоятельно

Чтобы проверить, как связка Vision-модели и детерминированных словарей ГОСТ отрабатывает на нестандартных таблицах и чертежах без необходимости поднимать контур локально, я собрал открытую песочницу-демо: samartsev.tech/kp.

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


Резюме

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

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


Автор: Алексей Самарцев (samartsev.tech). Обсудить архитектуру пайплайна и нюансы нормализации можно в комментариях или в Telegram: @samartsev_ai.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Ловили ли вы ИИ на грубых ошибках в рабочих расчетах или коде?
0%Постоянно, перепроверяю за нейросетью каждую цифру и строку0
0%Бывало пару раз, но в целом ускоряет рутину0
0%Не использую нейросети для рабочих задач0
100%Посмотреть результаты2
Проголосовали 2 пользователя. Воздержавшихся нет.