· 16 мин чтения

Как я построил AI-агента для еженедельной сверки банка с 1С и разбора расходов по счетам

Раз в неделю бухгалтер наших клиентов до 50 РМ открывает банковскую выписку и сверяет её построчно с тем, что легло в 1С:Бухгалтерию — вручную, без чек-листа, на глазок. Расхождения находятся поздно: платёж завис на невыясненных, оплата поставщику задвоилась, эквайринговая выручка легла одной суммой вместо разбивки по заказам. Мы построили AI-агента, который каждую неделю сам забирает выписку, сверяет её с проводками 1С, раскладывает непонятные операции по счетам учёта и присылает не «всё ок», а конкретный список из 5-15 расхождений с описанием и вероятной причиной. Ниже — наша рабочая схема: с конфигами, порогами и именами сервисов, без общих слов про «цифровую трансформацию».

Почему еженедельная сверка — не формальность, а страховка от кассовых разрывов

В компании на 20-50 рабочих мест через расчётный счёт за неделю проходит от 40 до 300 операций: оплаты поставщикам, поступления от покупателей, эквайринг, зарплатные переводы, комиссии банка, конверсия валюты. Бухгалтер разносит их в 1С по мере поступления выписки, но полная сверка «банк = 1С» обычно происходит раз в месяц, перед закрытием — и тогда расхождения уже неделями сидят в учёте.

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

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

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

Отдельная категория, с которой сталкивается почти каждый клиент, — частичные оплаты и банковские комиссии. Формально это тоже расхождение между суммой платежа и суммой документа, но по существу — нормальная механика расчётов, а не ошибка, и учитывать её нужно уже на уровне логики сопоставления, а не только в отчёте бухгалтеру.

Архитектура конвейера: пять компонентов между банком и главной книгой

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

Такое разделение — не архитектурная мода, а практическая необходимость: 80-90% операций в норме сопоставляются точным совпадением по ИНН, сумме и дате безо всякого ИИ, и гонять их через LLM — это лишние деньги и лишняя точка отказа. Модель мы подключаем только там, где формальные правила не справляются.

Физически весь конвейер живёт на выделенном небольшом контейнере (2 vCPU, 4 ГБ RAM хватает с запасом на недельный объём в несколько сотен операций) — либо на инфраструктуре клиента, либо на нашей стороне, если клиент не готов держать своё окружение под это. База 1С при этом не модифицируется и не нагружается ничем, кроме коротких OData-запросов на чтение раз в неделю; коннектор к банку и AI-классификатор работают полностью асинхронно от рабочего дня бухгалтера, поэтому запуск конвейера никак не мешает текущей работе в 1С в течение дня.

Между компонентами мы передаём данные фиксированной JSON-схемой: коннектор банка отдаёт список операций в едином формате независимо от источника, ядро сопоставления возвращает три списка — сопоставлено, кандидат для AI, не найдено. Такой контракт позволяет безопасно перезапускать любой этап отдельно: если сбоил только AI-классификатор, повторный запуск не выгружает заново выписку и проводки из 1С, а обращается к модели только по операциям, которые остались необработанными.

Как мы забираем банковскую выписку: ДиректБанк, kl_to_1c и API банков

Для еженедельного пакетного цикла нам не нужен реалтайм — нужен предсказуемый и полный набор операций за 7 дней. Мы используем один из трёх способов в зависимости от того, что уже настроено у клиента в 1С:Бухгалтерии 3.0.

СпособКак работаетКогда используем
1С:ДиректБанкПрямой обмен с банком из 1С без промежуточных файлов; выписка и статусы платежей приходят в базу автоматическиБанк поддерживает сервис ДиректБанк и клиент уже подключил интеграцию — приоритетный вариант
Формат 1CClientBankExchange (kl_to_1c.txt)Плановая выгрузка из банк-клиента файлом стандарта «Клиент банка», загрузка в 1С обработкой обмена с банкомДиректБанк не поддерживается банком; агент забирает файл по расписанию из папки выгрузки банк-клиента (FTP/сетевая папка)
REST/OpenAPI банкаПрямой запрос списка операций по счёту за период через API банка (у части банков есть отдельный контур для бизнес-клиентов)Банк даёт API с токеном для юрлица — тогда коннектор обращается к нему напрямую, минуя файловый обмен

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

Отдельно коннектор проверяет полноту периода: если за отчётную неделю в выписке меньше операций, чем в среднем за предыдущие четыре недели (порог мы обычно ставим на уровне минус 40% от скользящего среднего), запуск не проваливается молча, а помечает отчёт флагом «возможно, выписка неполная» — это ловит ситуации, когда банк-клиент не успел выгрузить файл целиком или у ДиректБанка временно не было связи с банком.

Формат 1CClientBankExchange — обычный текстовый файл (кодировка Windows-1251 либо UTF-8 в новых банк-клиентах), размеченный секциями по ключевым словам: файл открывается строкой 1CClientBankExchange с версией формата, дальше идёт секция СекцияРасчетныйСчет с реквизитами счёта организации, а каждая операция описана блоком СекцияДокумент с полями ДатаПоступило, Номер, Дата, Сумма, ПлательщикИНН, ПолучательИНН, НазначениеПлатежа и закрывается строкой КонецДокумента. Коннектор парсит эти блоки построчно простым конечным автоматом, без сторонних библиотек — формат стабилен с 1990-х и почти не меняется между версиями банк-клиентов.

Что и как берём из 1С:Бухгалтерии через OData

Со стороны 1С коннектор читает три сущности через стандартный OData-интерфейс (публикуется на веб-сервере как /odata/standard.odata/): документы поступления и списания по расчётному счёту, регистр проводок и справочник контрагентов. Ничего дополнительно писать в конфигурации не нужно — интерфейс OData включается один раз в настройках публикации базы, доступ — по HTTP Basic Auth под отдельной служебной учётной записью с ролью только на чтение нужных объектов.

GET /base/odata/standard.odata/Document_ПоступлениеНаРасчетныйСчет? $filter=Дата ge datetime'2026-06-30T00:00:00' and Дата le datetime'2026-07-07T00:00:00' &$select=Ref_Key,Дата,Номер,СуммаДокумента,Контрагент_Key,НазначениеПлатежа,Проведен Authorization: Basic {{base64(login:password)}}

Аналогичным запросом читаем Document_СписаниеСРасчетногоСчета для исходящих платежей. Отдельно нам нужен регистр проводок (AccountingRegister_Хозрасчетный) — по нему коннектор строит историю: на какой счёт учёта бухгалтер в прошлом разносил операции с похожим назначением платежа и тем же контрагентом. Эта история — единственный источник «правильных ответов» для AI-классификатора, никакого отдельного обучения модели мы не делаем.

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

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

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

GET /base/odata/standard.odata/Document_СписаниеСРасчетногоСчета? $filter=Дата ge datetime'2026-06-30T00:00:00' and Проведен eq true &$select=Ref_Key,Дата,Номер,СуммаДокумента,Контрагент_Key,НазначениеПлатежа &$expand=Контрагент_Key&$top=500

$expand сразу подтягивает наименование и ИНН контрагента без второго запроса к справочнику, а $top защищает от случайного получения всей истории базы при неверном фильтре по дате. Право на запись мы не просто не выдаём в роли — на уровне публикации веб-сервиса для этой служебной учётной записи отключены методы POST, PATCH и DELETE.

Ядро сопоставления: окна, допуски и порядок применения правил

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

УровеньКритерий сопоставленияЧто происходит дальше
1. Точное совпадениеИНН контрагента + сумма день-в-день (до копейки) + дата операции совпадает с датой документа 1СПомечается «сопоставлено», в отчёт не попадает
2. Совпадение с окном по датеИНН + сумма совпадают, дата расходится в пределах ±3 календарных дней (банковский клиринг, выходные)Автосопоставление, но с пометкой «в пределах окна» для выборочной проверки
3. Совпадение с допуском по суммеИНН и дата совпадают, сумма расходится не более чем на 1% или на фиксированный порог (по умолчанию 50 ₽ — комиссия банка, курсовая разница)Автосопоставление с пометкой причины расхождения суммы
4. Нечёткое совпадение по контрагентуИНН в назначении платежа отсутствует (агрегированный эквайринг, самозанятые), сравнение по наименованию с порогом similarity ≥ 0.85Передаётся в AI-классификатор для финального решения
5. Не найденоНи один из предыдущих уровней не дал кандидата, либо найдено более одного равнозначного кандидатаПередаётся в AI-классификатор как расхождение с описанием ситуации

Конфигурация порогов вынесена в отдельный файл, чтобы не трогать код при настройке под нового клиента:

matching: date_window_days: 3 amount_tolerance_pct: 1.0 amount_tolerance_abs_rub: 50 fuzzy_name_threshold: 0.85 lookback_days_for_history: 180

На уровнях 1-3 модель вообще не вызывается — это чистая арифметика и сравнение строк, порядка 100-200 строк на Python с использованием rapidfuzz для нечёткого сравнения наименований. По нашей практике через эти три уровня проходит основная масса операций малого бизнеса — открытым остаётся десяток-другой в неделю.

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

Частичные оплаты обрабатываются отдельным правилом внутри уровня 3: если сумма операции меньше суммы открытого документа 1С, но совпадает с остатком к оплате по этому документу, движок помечает операцию не расхождением, а «частичной оплатой» и связывает её с исходным документом без похода к модели. Комиссии эквайринга и банка распознаются по ключевым словам в назначении платежа (комиссия, эквайринг) в сочетании с суммой в типичном для эквайринга диапазоне 1,5-3% от смежной по дате операции поступления — такие строки автоматически уходят на счёт 91.02 без участия AI-классификатора. А вот платёж, закрывающий сразу несколько документов частями, правилами мы не разбираем принципиально: слишком много вариантов разбивки, поэтому такая операция уходит в AI-классификатор с пометкой «требует распределения», а решение всё равно остаётся за бухгалтером.

AI-классификация: промпт, tool use и на чём мы экономим токены

Операции, которые не разложились правилами, уходят в Claude с принудительным вызовом инструмента (tool use, tool_choice: {"type": "tool", "name": "classify_operation"}) — модель обязана вернуть строго структурированный JSON, а не рассуждение в свободной форме. Схема инструмента задаёт обязательные поля:

{ "name": "classify_operation", "input_schema": { "type": "object", "properties": { "account": {"type": "string", "description": "Счёт учёта, например 60.01, 76.09, 91.02"}, "discrepancy_type": { "type": "string", "enum": ["дубль_платежа", "агрегированный_эквайринг", "комиссия_банка", "аванс_без_счета", "новый_контрагент", "курсовая_разница", "не_определено"] }, "suggested_counterparty": {"type": ["string", "null"]}, "confidence": {"type": "number"}, "comment": {"type": "string"} }, "required": ["account", "discrepancy_type", "confidence", "comment"] } }

В системный промпт мы кладём выжимку плана счетов клиента и 150-300 последних размеченных операций из регистра проводок как few-shot — это статичный блок на каждую неделю почти без изменений, поэтому мы помечаем его cache_control: {"type": "ephemeral"} и получаем экономию по прайсу Anthropic на повторных обращениях в пределах TTL кэша. При confidence ниже 0.75 мы не доверяем ответу модели с первого раза и переспрашиваем на более сильной модели.

Пример того, что реально уходит в модель для одной операции четвёртого уровня (данные обезличены и упрощены):

Операция банка: 02.07.2026, сумма 18 400 ₽. Назначение платежа: "Оплата по реестру эквайринга за 01.07.2026, комиссия банка учтена" ИНН плательщика в назначении отсутствует. История за 180 дней: 14 похожих операций на счёте 62.02 с последующим зачётом, 3 операции — на счёте 91.02 как комиссия. Определи account, discrepancy_type, suggested_counterparty, confidence, comment.

Модель в такой ситуации обычно возвращает account: 62.02, discrepancy_type: агрегированный_эквайринг и невысокий confidence около 0.6-0.8 — видит неоднозначность между авансом и комиссией, и именно такие операции конвейер выносит на подтверждение бухгалтеру, а не проводит молча.

СценарийМодельПочему
Массовая классификация операций уровня 4-5Claude Haiku 4.5Дешёвый и быстрый первый проход, для однотипных формулировок назначения платежа точности достаточно (по нашей практике)
confidence < 0.75 после первого проходаClaude Sonnet 5Более точное распознавание нестандартных формулировок назначения платежа
Ежемесячный контроль качества классификатораClaude Opus 4.8Разово прогоняем через более мощную модель выборку решений за месяц, чтобы поймать систематический перекос порогов

По прайсу платформы на момент публикации (актуальные цифры лучше сверять на странице pricing) ориентир такой: Haiku 4.5 — около 1 $/5 $ за миллион входных/выходных токенов, Sonnet 5 — около 3 $/15 $, Opus 4.8 — около 5 $/25 $; при пакетной обработке раз в неделю через Batch API можно рассчитывать на скидку порядка 50% к обеим частям цены. При 20-40 операциях в неделю, требующих обращения к модели, это заведомо не бюджетообразующая статья расходов клиента.

Хотите такую же еженедельную сверку для своей 1С

Мы разворачиваем этот конвейер под ключ: коннектор к вашему банку (ДиректБанк, kl_to_1c или API), сервисную учётную запись OData в 1С только на чтение, настройку порогов сопоставления под ваш поток операций и отчёт в Planfix или на почту. Напишите нам — посмотрим на вашу выписку за пару недель и покажем, сколько расхождений всплывёт уже в первом отчёте.

Еженедельный цикл целиком: от таймера до задачи в Planfix

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

# /etc/systemd/system/bank-recon.timer [Timer] OnCalendar=Mon *-*-* 07:00:00 Persistent=true [Install] WantedBy=timers.target

Сервис bank-recon.service запускает питоновский раннер, который последовательно вызывает коннектор банка, коннектор 1С, ядро сопоставления, при необходимости — AI-классификатор, и на выходе формирует таблицу расхождений в Excel (openpyxl) с тремя листами: «Сопоставлено автоматически», «Требует внимания» (уровни 4-5 с предложением модели) и «Не найдено соответствие». Каждая строка листа «Требует внимания» снабжена ссылкой на карточку документа 1С и колонкой discrepancy_type из ответа модели.

Готовый отчёт уходит по двум каналам: файл прикладывается к новой задаче в Planfix на ответственного бухгалтера с дедлайном на текущую неделю, а краткая сводка (число операций, число расхождений, сумма под вопросом) летит в Telegram руководителю. Мы намеренно не автоматизируем разноску найденных расхождений в 1С — агент только предлагает счёт и причину, проводит документ всегда человек.

Если на момент запуска недоступен API банка или Anthropic (кратковременный сбой сети, плановые работы), раннер не падает молча и не пропускает неделю: операции, которые не удалось обработать, помечаются статусом «отложено» и автоматически подхватываются следующим запуском без дублирования уже готовых результатов — повторный прогон идемпотентен, потому что каждая операция идентифицируется уникальным ключом банка (номер и дата документа), а не порядковым номером в файле.

Персональные данные в банковской выписке и требования 152-ФЗ

Банковская выписка — не то же самое, что счета поставщиков: помимо реквизитов юрлиц в ней регулярно встречаются операции с физическими лицами — зарплатные переводы, выплаты самозанятым и ИП по номеру телефона или карте, возвраты подотчётных сумм. Такие строки содержат ФИО, а иногда и номер карты — это персональные данные по 152-ФЗ, и передавать их во внешний API без правовых оснований мы не готовы.

Поэтому до передачи операции в AI-классификатор коннектор прогоняет маскирование: зарплатные и подотчётные операции (счета 70, 71, 73, 76 с признаком «расчёты с физлицами») вообще не уходят в LLM — они категоризируются детерминированным правилом по шаблону назначения платежа, потому что категория для них и так фиксирована планом счетов. В LLM попадает только текст назначения платежа с вырезанными ФИО (по регулярному выражению плюс список известных сотрудников из справочника физлиц 1С, который коннектор подгружает отдельным закрытым запросом и никуда не передаёт), сумма и дата.

Отдельно фиксируем это в договоре с клиентом на обработку: агент работает как обработчик персональных данных в объёме, ограниченном обезличенными операциями, а полный список операций с ФИО остаётся только внутри контура клиента и не покидает 1С и наш сервер сопоставления.

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

Что показывает практика: цифры, границы и где агент ошибается

По нашим текущим внедрениям доля операций, которые проходят уровни 1-3 ядра сопоставления без единого обращения к модели, держится в районе 80-90% — это оценка по практике, а не строгий бенчмарк, она зависит от того, насколько активно клиент пользуется агрегированным эквайрингом и переводами через СБП без указания ИНН. Из оставшихся 10-20% AI-классификатор уверенно (confidence ≥ 0.75) закрывает большую часть, и в финальный список расхождений для бухгалтера попадает обычно 5-15 строк в неделю — как раз тот объём, который реально просмотреть за 10-15 минут, а не за час ручной сверки.

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

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

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

Частые вопросы

Нужно ли подключать ДиректБанк, если банк-клиент и так работает?
Нет, это не обязательно. Если у клиента уже настроен только классический банк-клиент, коннектор просто забирает плановую выгрузку в формате 1CClientBankExchange (kl_to_1c.txt) по расписанию из папки выгрузки — для еженедельного пакетного цикла разница с ДиректБанком не критична, реалтайм здесь не нужен.
Может ли агент сам провести документ в 1С по результатам сверки?
Мы сознательно этого не делаем. Агент только предлагает счёт учёта и причину расхождения через OData на чтение и отчёт для бухгалтера — финальную разноску и проведение документа всегда выполняет человек. Автоматическая запись в бухгалтерский контур без проверки — это риск, который несопоставим с экономией нескольких минут.
Что если у банка нет ни ДиректБанка, ни API для юрлиц?
Тогда единственный вариант — плановая выгрузка файла из веб-банка или банк-клиента в формате 1CClientBankExchange, которую коннектор забирает по расписанию (вручную выгруженный клиентом файл кладётся в общую папку, либо мы настраиваем автоматическую выгрузку, если банк-клиент это поддерживает). Качество и полнота сверки от этого не страдают, меняется только способ доставки файла.
Безопасно ли отправлять данные о зарплате и физлицах во внешний AI-сервис?
Мы этого не делаем: операции с признаком расчётов с физлицами (зарплата, подотчётные суммы, выплаты самозанятым) исключены из AI-классификации и разбираются детерминированными правилами, а в модель уходит только обезличенный остаток — сумма, дата и назначение платежа без ФИО. Это зафиксировано отдельным пунктом в договоре на обработку персональных данных с клиентом.
Сколько занимает внедрение и что нужно от клиента на старте?
От клиента нужен доступ к выписке (ДиректБанк, файл выгрузки или API банка) и включённый интерфейс OData в 1С с отдельной служебной учётной записью на чтение — это делается один раз. Для типового клиента до 50 РМ настройка коннекторов, порогов сопоставления и первого тестового отчёта занимает одну-полторы недели, после чего конвейер работает по расписанию без нашего постоянного участия.
📄
Скачайте подробный разбор в PDF Кейсы, статистика, типовые ошибки и чек-лист самопроверки — 12 страниц
Скачать PDF

Подпишитесь на разборы ITfresh

Раз в неделю — практичные материалы по ИТ для бизнеса: без спама, только польза.