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С пришлось бы выдирать поля регуляркой из свободного текста. А это прямой путь к тихим ошибкам, которые всплывают в самый неудобный момент.
Базовая JSON-схема, которую мы используем как стартовую точку. Под особенности учёта конкретного клиента расширяем — мультивалюта, несколько юрлиц в одной базе и так далее.
{
"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 РМ мы укладываемся в разработку и настройку конвейера за одну-две недели. Окупаемость считаем не в часах бухгалтера, а в снятом риске просрочек оплаты и потерянных счетов — этот риск обычно ощутимее прямой экономии времени.
