К содержимому
MoranaLabs.
Research14 мин чтения0 просмотров

Сверка двух документов: почему это не diff, а задача сопоставления 

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

0xReality

Задача обычно приходит в одной и той же формулировке: вот два файла, сверьте, там должно сойтись. Дальше кто-то кладет их в сравниватель файлов или тянет ВПР по наименованию, получает стену красного и половину столбца в «#Н/Д» — и на этом сверка заканчивается. Разбирать такой результат дольше, чем сверить глазами.

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

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

Что делает построчное сравнение и почему на документах оно врет

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

Что происходит в документахКак это выглядит в построчном сравненииЧто должно делать сопоставление
Слева сортировка по коду, справа по алфавитуДокумент целиком удален и добавлен зановоСравнивать множества, порядок игнорировать
«Кабель ВВГнг(А)-LS 3х2,5» и «Кабель силовой ВВГ-нг(A)LS 3*2.5 ГОСТ»Две несвязанные строкиНормализация и нечеткое сравнение
Позицию отгрузили с двух складов: одна строка стала двумяОдно удаление и две вставкиСвязь один ко многим с проверкой суммы количеств
Две строки с одной номенклатурой схлопнулись в однуДва удаления и одна вставкаСвязь многие к одному
Поставщик пишет упаковки, у вас в базе штукиРасхождение по количеству в кратность разПриведение к базовой единице
НДС округлен построчно с одной стороны и от итога с другойКопейки почти в каждой строкеДопуск, заданный в деньгах
«Итого», «в том числе НДС», заголовки групп, повтор шапки на второй страницеМусорные совпадения вперемешку с расхождениямиКлассификация строк до сопоставления

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

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

Самый дешевый шаг с самым большим эффектом. Делается отдельно для каждого типа поля и по одним правилам для обеих сторон.

  • Текст. Регистр, схлопывание пробелов, дефис против длинного тире. Отдельно — латиница внутри кириллических слов: буквы a, c, e, o, p, x, y, A, B, E, K, M, H, O, P, C, T, X выглядят одинаково и сравниваются как разные символы. В артикулах встречается постоянно.
  • Обозначения размеров. «3х2,5», «3x2.5», «3*2,5» и «3 х 2.5» — одна и та же величина. Разделитель и десятичную запятую приводим к одному виду до всякого сравнения.
  • Сокращения. Свой словарь: шт, уп, кор, компл, ГОСТ, ТУ, оцинк, нерж. Пополняется он из очереди спорных.
  • Числа и даты. Разряды через пробел, минус в скобках, валюта отдельным полем. Даты — к одному представлению.

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

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

Кандидаты и ключи: от артикула до вектора

Сравнивать все со всем можно, пока документы маленькие. Пара накладных по 200 строк дает 200 × 200 = 40 000 пар, любой ноутбук проглотит это за секунду. Реестр на 5000 строк против такого же дает 25 миллионов пар, и если на каждую считается векторная близость, ждать придется долго. Поэтому перед скорингом идет отбор кандидатов по грубому признаку: совпадение артикула, общие триграммы наименования, одинаковый порядок величины суммы, одна дата. Строка детально сравнивается с двумя-тремя десятками кандидатов вместо всего документа.

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

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

Второе: нечеткое сравнение по токенам обыгрывает посимвольное. Расстояние между строками хорошо ловит опечатки и плохо ловит перестановку слов и лишнее слово в середине. Разбивка наименования на токены с весом по редкости дает то, что нужно: слова «кабель» и «шт» встречаются тысячи раз и различающей силы не несут. Токены «ВВГнг» и «3x2.5» редкие, вся сила в них. Там, где формулировки расходятся принципиально, подключается векторный поиск с переранжированием кандидатов.

Оценка уверенности: как складывать слабые сигналы

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

уверенность = 0,45 × схожесть наименования + 0,25 × совпадение количества + 0,20 × совпадение цены + 0,10 × совпадение единицы измерения

Числа в этой строке — стартовая точка для подбора. Константой их считать нельзя. Подбор простой: размечаете руками 200–300 пар строк из своих документов, прогоняете скоринг, смотрите, на каких весах верные пары уходят вверх, а мусор остается внизу. День работы, зато дальше понятно, почему система решила так.

Два требования к этой части. Каждый признак должен уметь возвращать состояние «данных нет»: пустой артикул с одной стороны обнуляет вес артикула, расхождением он не является. И вся арифметика обязана быть объяснимой — рядом со связкой лежит разбор, какой признак сколько дал. Оператор, который видит «совпало 0,82», работать не может. Оператор, который видит «наименование 0,7, количество и цена точно, единица разная», решает вопрос за пять секунд.

Назначение и связи многие ко многим

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

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

После этого прохода остаются нераспределенные строки с обеих сторон. Вот они и есть материал для связей многие ко многим:

  1. Один ко многим. Берем свободную строку слева и подмножество свободных строк справа с тем же артикулом. Сумма их количеств совпала с количеством исходной строки — это разбивка: отгрузили с двух складов, разбили по сериям, довезли партиями.
  2. Многие к одному. Зеркальный случай: в заказе позиция шла двумя строками, в накладной ее свернули в одну.
  3. Многие ко многим. На длинных периодах: три отгрузки закрыты двумя платежами. Проверяется совпадением сумм подмножеств.

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

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

Округления и единицы: где расхождение законно

Сравнение денег на точное равенство гарантирует поток ложных расхождений. Считаем, откуда они берутся. НДС округляется до копейки построчно, каждая строка дает погрешность до половины копейки. На документе в 40 строк максимальное законное расхождение итога составляет 40 × 0,5 = 20 копеек. Одна сторона считает налог от итога, вторая построчно — разойдутся именно эти копейки.

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

С единицами измерения похожая история, только цена ошибки выше. Поставщик пишет «уп» и подразумевает коробку из двенадцати, в вашей карточке упаковка шесть. В обоих документах стоит «10 уп», в штуках это 120 против 60, а сумма сходится до копейки — расхождение целиком спрятано в единице измерения. Количества приводятся к базовой единице по коэффициенту из справочника, сравниваются уже базовые. Если коэффициент для пары неизвестен, система не имеет права вычислить его из отношения количеств и принять за факт. Такая строка уходит человеку. Один раз угаданная кратность разъезжается по остаткам и всплывает на инвентаризации через квартал.

Порог и очередь на ручное решение

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

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

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

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

Тип сверки, метод, типичная ошибка

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

Тип сверкиМетод сопоставленияТипичная ошибка
Накладная против заказаПозиции по артикулу и наименованию, сверка количеств и цен, связи один ко многимЧастичная отгрузка засчитана как недостача, довоз идет вторым документом
Акт сверки взаиморасчетовДокументы по номеру, дате и сумме, затем сальдо нарастающим итогомРазный период и разный момент признания: отгрузка у одного, получение у другого
Реестр платежей против выпискиСумма, дата и разбор номеров счетов из назначения платежаОдин платеж закрывает несколько счетов, связь многие ко многим не построена
Данные ЭДО против учетной базыИдентификатор документа и бизнес-ключ из ИНН, номера, даты, суммыДубли контрагентов, документ падает на вторую карточку
Новый прайс против старогоАртикул с проверкой наименования на неизменностьАртикул переиспользован под другой товар, рост цены выглядит как скидка
Остаток против инвентаризацииКод номенклатуры вместе с характеристикой, серией и складомПересорт: характеристика проигнорирована, итог сходится, товар лежит не тот
Две версии договораСтруктурное сопоставление пунктов, текстовое сравнение внутри парыСверили суммы и приложения, пропустили сроки и ответственность

Про строку с ЭДО есть отдельный разбор, где именно расходятся суммы с учетной системой: сверка ЭДО и данных 1С. Классы расхождений и формат отчета описаны на странице сверки документов: пилот от 350 000 ₽, четыре недели до первого отчета, старт на выгрузках без доступа в базу.

Версии договоров: другая единица сравнения

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

Из обоих файлов вытаскивается структура: нумерация вида 1., 1.1., 1.1.1., заголовки разделов, приложения. Затем пункты сопоставляются между версиями тем же аппаратом, что и позиции накладной. По номеру пункта сопоставлять нельзя: вставили один пункт в начало, и вся нумерация ниже съехала на единицу. Работает комбинация заголовка и текста с нечетким сравнением и глобальным назначением.

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

Отдельная категория находок — пункты без пары. Пункт, которого нет в старой версии, важнее любой правки внутри существующего текста. Именно так в договор въезжают автопролонгация и односторонний отказ.

Почему у модели нет последнего слова

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

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

Разделение обязанностей поэтому жесткое. Факт «что изменилось» устанавливает детерминированный слой: структурное сопоставление плюс текстовое сравнение внутри пары. Он воспроизводим и проверяется глазами по двум файлам. Модель работает поверх, объясняет и ранжирует, и каждое ее утверждение обязано вести к точной цитате из обеих версий. Какие пункты договора читать первыми — сроки, ответственность, приемку, автопролонгацию, право менять цену в одностороннем порядке — и как держать этот разбор на своем железе, разобрано отдельно: ИИ-юрист и поиск рисков в документах.

Как подготовить два документа к сверке

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

  1. Выгружайте данные таблицей. Одна строка на позицию, CSV, xlsx или xml. PDF-печатка означает, что перед сопоставлением встанет извлечение — отдельная задача со своей ценой.
  2. Уберите из таблицы все, кроме позиций. Объединенные ячейки, подытоги, повторы шапки, пустые разделители. Настраивается один раз в выгрузке.
  3. Дайте ключевые колонки. Код позиции с каждой стороны, артикул контрагента, наименование, количество, единица, цена, сумма. Без артикулов сверка работает, но серая зона будет шире.
  4. Договоритесь о периоде и моменте признания. По какой дате режем: отгрузки, поступления, проведения. Заметная часть строк в акте сверки расходится по одной этой причине: стороны режут период по разным датам.
  5. Выгрузите справочник единиц и кратностей упаковок отдельным файлом, вместе с коэффициентами пересчета к базовой единице.
  6. Разметьте руками 200–300 пар строк. Это и материал для подбора весов, и приемочная выборка.
  7. Зафиксируйте допуск в деньгах. Копейки на строку, копейки на документ. Проценты не используйте.
  8. Определите, какое расхождение требует действия. Иначе отчет на тысячу строк утонет в копеечных отклонениях и его никто не откроет.

Когда сопоставление не нужно

Четыре ситуации, в которых честный ответ — «задача другая».

  • С обеих сторон есть общий надежный ключ. Номер заказа и код позиции присутствуют в обоих файлах и заполнены везде. Это соединение таблиц по ключу, запрос на десять строк кода. Нечеткая логика тут лишняя.
  • Пара документов на два десятка строк раз в месяц. Описать правила дороже, чем сверить глазами. Автоматизация окупается на регулярном потоке.
  • Две версии одного файла с сохраненным порядком строк. Выгрузка из одной системы за два дня, тот же экспорт, та же сортировка. Обычное построчное сравнение справится и будет точнее.
  • Справочники в хаосе с обеих сторон. Дубли контрагентов, позиции «Товар без названия 3», артикулы, переиспользованные под разные товары. Сопоставлять пока не с чем: сначала порядок в данных, потом автоматика.

Что дальше

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

  • #
  • #автоматизация
  • #договоры
  • #документооборот
  • #сверка документов
  • #сопоставление данных
ПоделитьсяTelegramX
рассылка

Новые статьи — на почту

Лонгриды про ML в проде, edge и компьютерное зрение — сразу после выхода.

Канал в Telegram: morana.log

Без спама. Нажимая «Подписаться», соглашаетесь с обработкой персональных данных

бесплатный pdf-гайд

Edge AI или облако: когда тащить нейросеть на железо

Признаки, фреймворк выбора и прикидка экономии — короткий PDF-гайд на почту.

PDF · 5 страниц · без спама. Нажимая «Получить», соглашаетесь с обработкой персональных данных

Читать дальше
— заявка

Опишите задачу  ответим как инженеры. 

Оставьте имя и Telegram — остальное обсудим. Без брифов на 40 слайдов и звонков по три раза.

Отвечаем за пару часовотвечает инженер, а не отдел продажNDA по запросу

Сюда напишем — это быстрее всего

Или сразу написать в Telegram

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