n8n + LLM-агент: как я убрал ручной ввод входящих счетов из 1С
Каждый второй наш клиент до 50 рабочих мест жалуется на одно и то же: счета от поставщиков приходят на почту, бухгалтер вручную набивает их в 1С, и часть просто теряется в потоке писем. Мы собрали конвейер на n8n с LLM-агентом на Claude, который читает вложение, создаёт черновик поступления в 1С и сам напоминает об оплате. Рассказываю схему узел за узлом — с конфигами, порогами и граблями.
Зачем мы вообще взялись за это
Типичная картина в компании на 20-40 РМ: бухгалтер получает 15-30 счетов в месяц по почте — PDF-вложения, сканы, иногда фото со смартфона поставщика. Каждый счёт нужно открыть, прочитать реквизиты, найти или создать контрагента в 1С, вбить строки табличной части, проверить НДС и не забыть про срок оплаты. При параллельной загрузке (закрытие месяца, отпуск сотрудника) часть счетов оседает в папке «Входящие» и всплывает только при звонке от поставщика с претензией по просрочке.
Мы не стали предлагать клиентам ЭДО-интеграцию как единственный выход — она решает вопрос только с теми контрагентами, кто на неё перешёл, а это меньшинство. Вместо этого мы построили конвейер, который работает с обычной почтой: письмо приходит на выделенный ящик invoices@клиент.ru, автоматика читает вложение, извлекает данные через LLM и кладёт в 1С черновик документа «Поступление товаров и услуг» — бухгалтеру остаётся проверить и провести. Плюс отдельный контур следит за сроками оплаты и сам шлёт напоминания.
Ниже — не пересказ чужого туториала, а наша рабочая схема, которую мы разворачиваем клиентам с самостоятельным n8n на выделенном контейнере и с Claude API в качестве LLM-агента.
Архитектура: пять узлов между почтовым ящиком и проводкой в 1С
Мы намеренно делим конвейер на короткие изолированные шаги, а не на один гигантский workflow с одной AI-нодой в центре — так проще отлаживать и переиспользовать куски под разных клиентов. В n8n это пять логических блоков, реализованных отдельными workflow с вызовом друг друга через Execute Sub-workflow либо через Webhook.
| Блок | Ключевая нода n8n | Роль |
|---|---|---|
| 1. Приём письма | Email Trigger (IMAP), тип n8n-nodes-base.emailReadImap | Слушает ящик invoices@, скачивает вложения, фильтрует мусор |
| 2. Подготовка документа | Code (JavaScript) + Switch | Определяет тип файла, кодирует в base64, готовит content-блок для LLM |
| 3. Извлечение данных | AI Agent (n8n-nodes-langchain.agent) + Anthropic Chat Model + Structured Output Parser | Возвращает строгий JSON с реквизитами счёта |
| 4. Валидация и мэтчинг | Code + HTTP Request (OData/HTTP-сервис 1С) | Проверяет ИНН, ищет контрагента, отсекает дубли |
| 5. Запись в 1С + напоминания | HTTP Request (создание документа) + Schedule Trigger (напоминания) | Создаёт черновик поступления, следит за сроком оплаты |
Каждый блок логирует свой результат в отдельную таблицу Postgres (мы поднимаем её тем же docker-compose, что и сам n8n) — это даёт полный аудиторский след: какое письмо, какой JSON вернула модель, что легло в 1С и с каким статусом.
Приём письма: Email Trigger (IMAP) и фильтрация шума
Мы заводим клиенту отдельный почтовый ящик под счета — не общий бухгалтерский, чтобы триггер не реагировал на переписку и рекламные рассылки. В ноде Email Trigger (IMAP) настройки такие: Mailbox: INBOX, доступ по IMAP через TLS на порту 993, аутентификация — пароль приложения (не основной пароль ящика). В секции Options критично включить Download Attachments: true и выставить Format: Resolved — только в этом режиме вложения приходят как готовые бинарные данные, а не как base64-строка внутри RAW-сообщения, которую пришлось бы парсить вручную.
Отдельная головная боль — дубли и мусор. Мы вешаем на ноду custom email rule по критериям IMAP-поиска: UNSEEN плюс проверку темы/отправителя через дополнительный Filter сразу после триггера (тема содержит «счёт», «invoice», «акт», либо вложение с расширением pdf/jpg/png). Post-processing action ставим в «пометить прочитанным» только после успешного считывания — иначе при перезапуске workflow n8n возьмёт то же письмо повторно и создаст дубль поступления.
Polling-интервал держим на 60 секунд — для потока 20-40 писем в месяц частить чаще смысла нет, а лишняя нагрузка на IMAP-сервер клиента не нужна.
Из PDF и скана — в данные, понятные модели
Тут мы намеренно не городим отдельный OCR-слой (Tesseract, Yandex Vision и т.п.) как обязательный этап. Современные модели Claude принимают PDF и изображения напрямую как content-блок сообщения и сами разбирают текст, таблицы и рукописные пометки внутри одного запроса — это упрощает конвейер и снимает целый класс ошибок распознавания на стыке двух систем.
Code-нода перед вызовом агента делает три вещи: проверяет MIME-тип вложения (pdf, jpeg, png — остальное уходит в очередь на ручную обработку), конвертирует бинарные данные в base64 и собирает JSON-блок нужного формата. Для PDF это document-блок, для фото-скана — image-блок:
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": "{{ $binary.attachment_0.data }}"
}
},
{
"type": "text",
"text": "Извлеки реквизиты счёта по схеме invoice_schema."
}
]
}Есть практическое ограничение по объёму вложения на один запрос (по докам Anthropic — счёт идёт на десятки страниц и порядка 30 МБ на файл), нам этого с запасом хватает — многостраничных счетов от 50 листов у наших клиентов не встречалось. Если письмо приходит без вложения, а сумма и реквизиты просто в теле письма, мы прогоняем через ту же модель текст письма вместо документа — агент один и тот же, меняется только content-блок.
LLM-агент: извлечение структурированных данных
Здесь — сердце конвейера: нода AI Agent (Tools Agent) со связанным Anthropic Chat Model в качестве языковой модели и Structured Output Parser на выходе. Мы не даём агенту вольный текстовый ответ — Structured Output Parser принудительно приводит результат к JSON-схеме, иначе на 1С-стороне пришлось бы регуляркой выдирать поля из свободного текста, а это путь к тихим ошибкам.
Схема, которую мы используем как базовую (расширяем под особенности учёта конкретного клиента — мультивалюта, несколько юрлиц в одной базе):
{
"type": "object",
"properties": {
"supplier_name": {"type": "string"},
"supplier_inn": {"type": "string"},
"supplier_kpp": {"type": "string"},
"invoice_number": {"type": "string"},
"invoice_date": {"type": "string", "format": "date"},
"due_date": {"type": ["string", "null"]},
"currency": {"type": "string"},
"total_with_vat": {"type": "number"},
"vat_amount": {"type": "number"},
"vat_rate": {"type": "string", "enum": ["20", "10", "0", "без НДС"]},
"line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"qty": {"type": "number"},
"unit_price": {"type": "number"},
"amount": {"type": "number"}
}
}
},
"confidence": {"type": "number"}
},
"required": ["supplier_inn", "invoice_number", "total_with_vat", "confidence"]
}Поле confidence модель заполняет сама по инструкции в системном промпте: «оцени от 0 до 1, насколько уверенно ты прочитал реквизиты; если качество скана низкое или часть полей рукописная — снижай оценку». Порог мы ставим на уровне 0.85: всё, что ниже — не идёт в 1С автоматически, а падает в отдельную очередь на ручную проверку бухгалтером (у нас это лист Google Sheets с ссылкой на письмо и распознанный JSON рядом).
Выбор модели — не «одна модель на всё». Мы гоняем базовую экстракцию на более лёгкой и дешёвой модели, а на пересчёт с низкой уверенностью или на счета выше порога суммы — на модели помощнее:
| Сценарий | Модель | Почему |
|---|---|---|
| Чистый PDF-счёт, стандартный шаблон | Claude Haiku 4.5 | Дешевле и быстрее, точности достаточно на структурированных PDF (оценка по нашей практике) |
| Скан низкого качества / рукописные пометки | Claude Sonnet 5 | Выше точность распознавания на «грязных» изображениях |
| Confidence < 0.85 при первом проходе | Повторный запрос на Sonnet 5 | Второй проход другой моделью снижает риск систематической ошибки одной модели |
| Счета выше согласованного с клиентом лимита суммы | Sonnet 5 + обязательная ручная проверка | Финансовый риск важнее экономии на токенах |
Технически переключение моделей в n8n — это просто параметр Model в ноде Anthropic Chat Model, который мы передаём через выражение в зависимости от результата первой Code-ноды (проверка типа файла и эвристики качества).
Валидация, мэтчинг контрагента и защита от дублей
JSON от модели — это гипотеза, а не факт, поэтому дальше идёт слой чистой валидации на Code-ноде без единого обращения к LLM: проверка контрольной суммы ИНН (10 знаков для юрлица, 12 — для ИП, с проверкой контрольных разрядов по стандартному алгоритму ФНС), проверка что total_with_vat = сумма строк + vat_amount с точностью до рубля, проверка что invoice_date не в будущем и не старше разумного срока давности.
Дальше — поиск контрагента. HTTP Request-нода обращается к OData-интерфейсу базы 1С с фильтром по ИНН: GET /base/odata/standard.odata/Catalog_Контрагенты?$filter=ИНН eq '{{ $json.supplier_inn }}'. Если запись найдена — берём её Ref для документа поступления. Если нет — не создаём контрагента автоматически «на лету»: помечаем документ флагом «новый контрагент, требуется проверка» и подставляем реквизиты из JSON как заготовку, финальное решение — за бухгалтером. Это осознанное ограничение: справочник контрагентов — не то место, где хочется автоматических вставок без контроля.
От дублей защищаемся хэшем по связке ИНН + номер счёта + сумма, который пишем в отдельную таблицу Postgres при каждой успешной обработке. Перед созданием документа в 1С проверяем, не встречался ли уже такой хэш за последние 90 дней — это ловит и повторно пересланные письма, и ситуацию, когда поставщик присылает один и тот же счёт с почты и через WhatsApp-пересылку на тот же ящик.
Хотите такой же конвейер для своей 1С
Мы разворачиваем этот конвейер под ключ: свой n8n на выделенном контейнере, HTTP-сервис на стороне вашей 1С, настройка порогов и напоминаний под ваш учёт. Если у вас входящие счета до сих пор набиваются вручную — напишите нам, посмотрим на ваш поток писем и оценим, сколько процентов можно снять с бухгалтера уже в первый месяц.
Запись черновика поступления в 1С
Тут у нас принципиальный выбор в пользу отдельного HTTP-сервиса 1С, а не голого OData для самого создания документа. OData хорошо подходит для чтения и простых справочников, но документ «Поступление товаров и услуг» с табличной частью «Товары» через стандартный интерфейс OData оформляется как отдельные POST-запросы на каждую строку табличной части после создания шапки документа — это лишние round-trip'ы и риск получить документ с частично заполненной табличной частью при обрыве сети посреди пачки запросов. Мы пишем клиенту простой HTTP-сервис на встроенном языке 1С (модуль HTTP-сервиса, метод POST), который принимает один JSON целиком и создаёт документ одной транзакцией.
| Способ | Плюсы | Минусы | Когда используем |
|---|---|---|---|
| Стандартный OData | Ничего писать в 1С не нужно, работает из коробки | Табличная часть — отдельные запросы, нет бизнес-валидации на стороне 1С | Чтение справочников, простые документы без табличных частей |
| Свой HTTP-сервис | Один запрос — весь документ, можно встроить бизнес-логику и статус «черновик» | Требует разработки и поддержки на стороне 1С | Документы с табличными частями: поступления, реализации |
Пример тела запроса, который HTTP Request-нода отправляет на наш эндпоинт:
POST /base/hs/invoice_import/create HTTP/1.1
Content-Type: application/json
{
"Контрагент": "00000012-3456-7890-abcd-000000000001",
"НомерВходящегоСчета": "АА-1042",
"ДатаСчета": "2026-07-01",
"Организация": "ООО Клиент",
"ВалютаДокумента": "RUB",
"СуммаСНДС": 184320.00,
"СтавкаНДС": "20",
"Товары": [
{"Номенклатура": "Бумага офисная А4", "Количество": 50, "Цена": 350.00, "Сумма": 17500.00},
{"Номенклатура": "Картриджи HP 05A", "Количество": 8, "Цена": 4200.00, "Сумма": 33600.00}
],
"Проведён": false,
"Комментарий": "Создано автоматически из письма, требует проверки бухгалтера"
}Ключевое поле — "Проведён": false: документ создаётся черновиком, не влияет на остатки и взаиморасчёты до тех пор, пока бухгалтер его не откроет и не проведёт руками. Это наш компромисс между автоматизацией и контролем — мы убираем набивку данных, но не убираем финальную проверку человеком.
Напоминания об оплате и эскалация
Отдельный, независимый от приёма писем workflow с нодой Schedule Trigger по расписанию (у нас — по будням в 9:00 по Москве, cron-выражение 0 9 * * 1-5) опрашивает 1С через OData на предмет непроведённых и проведённых, но неоплаченных поступлений с приближающимся сроком оплаты. Срок оплаты (due_date) мы либо берём напрямую из счёта, если модель его распознала, либо вычисляем по правилу «дата счёта + отсрочка по договору с этим контрагентом» — отсрочку храним в отдельном регистре сведений в 1С, который заполняется один раз при заведении контрагента.
Пороги эскалации настраиваем индивидуально под клиента, обычно так: за 3 дня до срока — напоминание ответственному бухгалтеру в Telegram; в день срока — повтор напоминания плюс копия руководителю; при просрочке более 2 дней — отдельное сообщение с пометкой «критично» и суммой набежавшей просрочки по всем счетам этого контрагента разом, чтобы не пропустить риск блокировки поставки.
Технически это HTTP Request к Telegram Bot API либо к нашему обычному email-каналу, в зависимости от того, чем клиент пользуется. Формат сообщения — компактный, без вложений, со ссылкой на карточку документа в веб-клиенте 1С, чтобы можно было провести оплату в одно касание.
Что это даёт на практике и где граница автоматизации
По нашей практике на текущих внедрениях доля счетов, которые проходят весь путь без единой ручной правки реквизитов (только финальное подтверждение проведения документа), держится в районе 70-80% — это оценка, не строгий бенчмарк, и сильно зависит от того, насколько разнородны шаблоны счетов у поставщиков клиента. Оставшиеся 20-30% — это низкое качество сканов, нестандартные структуры табличной части, счета на иностранных языках без перевода и редкие случаи, когда модель уверенно, но неверно интерпретирует рукописные правки на счёте.
Мы сознательно не пытаемся дотянуть автоматизацию до 100% — это тот случай, когда последние проценты стоят непропорционально дорого в разработке и не стоят риска пропустить ошибку в проводке. Порог confidence 0.85 и обязательная проверка новых контрагентов — это не техническое ограничение, а осознанная граница ответственности между машиной и бухгалтером.
Из измеримого: время от получения письма до появления черновика в 1С — секунды-минуты вместо дней, когда счёт может пролежать в почте до конца недели. Для компании с 20-30 счетами в месяц это не про экономию рабочего времени бухгалтера (счета и так занимают у него не весь день), а про то, что счета больше не теряются и просрочки по оплате перестают быть сюрпризом.
Частые вопросы
- Нужен ли отдельный сервер под n8n или можно обойтись облаком?
- Мы разворачиваем n8n self-hosted в Docker на отдельном небольшом VPS клиента или на своей инфраструктуре — так вложения счетов и переписка с LLM не проходят через сторонний облачный тариф n8n Cloud, а ключи от 1С и почты остаются под нашим и клиента контролем. Для потока в 20-40 счетов в месяц хватает минимальной конфигурации: 2 vCPU, 4 ГБ RAM, отдельный контейнер Postgres под очереди и логи выполнения.
- Что если скан плохого качества и модель ошибается в цифрах?
- Для этого в схеме есть поле confidence и порог 0.85: всё, что ниже, не создаёт документ автоматически, а падает в очередь на ручную проверку с приложенным письмом и распознанным JSON рядом. Дополнительно мы всегда проверяем контрольные разряды ИНН и сверяем сумму строк с итоговой суммой счёта — это ловит ошибки распознавания ещё до похода в 1С, даже если сама модель была излишне уверена.
- А если в одной базе 1С несколько юрлиц или разные ставки НДС?
- Схема извлечения данных уже включает поле ставки НДС и валюту, а выбор организации-получателя в документе поступления мы завязываем на почтовый ящик, на который пришло письмо — под каждое юрлицо клиента заводим отдельный адрес вида invoices-ооо1@ и invoices-ооо2@, это проще и надёжнее, чем пытаться определить получателя из текста счёта.
- Безопасно ли отправлять счета во внешний LLM с точки зрения защиты персональных данных
- В счетах поставщиков персональных данных физлиц, как правило, нет — только реквизиты юрлиц (ИНН, КПП, наименование, суммы), что не подпадает под 152-ФЗ. Если в конкретном потоке всё же попадаются данные физлиц (например, счета от ИП с указанием паспортных данных), мы либо исключаем такие вложения из автоматической обработки, либо предварительно согласовываем с клиентом использование внешнего API и фиксируем это в договоре на обработку.
- Сколько стоит внедрение и когда оно окупается
- Стоимость зависит от готовности инфраструктуры клиента (есть ли уже сервер под n8n, опубликован ли веб-сервис 1С) и от количества особых случаев в потоке счетов — для типового клиента до 50 РМ мы укладываемся в разработку и настройку конвейера за одну-две недели. Окупаемость считаем не в часах бухгалтера, а в снятом риске просрочек оплаты и потерянных счетов — этот риск обычно ощутимее прямой экономии времени.