Категории
CRM СЭД для счетов: скелет ТЗ для Hermes-агента и сколько это стоит
22.10.2026 | из категории: Нейросети
Разбираем готовую внутреннюю систему согласования входящих счетов и превращаем её в воспроизводимый шаблон задачи для AI-агента. Плюс — честный расчёт бюджета: генерация ТЗ, стоимость прогона и во что обходится рабочая CRM «под ключ».
01Идея: что именно строим
Есть класс внутренних систем, которые не ведут учёт, а наводят порядок в процессе. Конкретный пример — CRM СЭД для входящих счетов: счёт поставщика проходит маршрут от заявки менеджера до оплаты и закрытия в 1С, а система отвечает за согласование, сроки, историю и прозрачность «кто что сделал и когда».
Почему это хороший кандидат для агентной генерации:
- Логика конечна. Четыре роли, тринадцать статусов, таблица переходов. Это формализуется в ТЗ почти без двусмысленностей.
- Интерфейс шаблонный. Дашборды, таблицы, карточка с кнопками по статусу — предсказуемый набор экранов.
- Интеграции изолированы. 1С и распознавание — два независимых стыка, которые можно замокать и подключить позже.
- Проверяемость. Жизненный цикл счёта покрывается сквозным тестом, а не «на глаз».
02Скелет ТЗ для Hermes-агента
Ниже — структура промпта/ТЗ, которую можно отдавать агенту по частям. Каждый блок самодостаточен: агент генерирует один слой, получает проверку и идёт дальше. Дробить на этапы важно — так ошибка в модели данных не тянет за собой все шаблоны.
Блок 0. Контекст и рамки
# РОЛЬ АГЕНТА Ты — senior Django-разработчик. Сгенерируй монолитное приложение на Django 6 + PostgreSQL 17, серверные шаблоны, Bootstrap 5. # ЖЁСТКИЕ РАМКИ - Нет API-слоя и SPA. Всё рендерится на сервере. - Часовой пояс Europe/Moscow, USE_TZ=True, интерфейс на русском. - Все действия, меняющие статус, — только POST + CSRF. - Все настройки интеграций — через .env, с безопасными дефолтами. - Никаких секретов в коде и в git. # РЕЗУЛЬТАТ ЭТАПА Структура приложений: core, users, invoices, payments, notifications. Заглушки settings.py, urls.py, manage.py. Без бизнес-логики.
Блок 1. Модель данных
# СУЩНОСТИ User(role in {manager, head, bookkeeper, treasurer}, is_admin) Counterparty(name, full_name, inn, kpp, guid_1c, is_active, raw_json) Branch(name) Invoice( number UNIQUE, date, counterparty FK PROTECT, branches M2M, amount DECIMAL(12,2) CHECK > 0, purpose, file, status in 13 значений, created_by FK, payment_order_number, payment_date, error_screenshot, raw_json, created_at, updated_at ) InvoiceStatusHistory(invoice FK, from_status, to_status, changed_by, changed_at, comment) RecognitionTask(file, status, invoice FK, error, created_at) CounterpartyRequest(status, inn, kpp, name, author, handler, linked_counterparty, reject_reason) Timer(invoice FK, kind, deadline, state, reminded_at) Notification(user FK, text, is_read, invoice FK, created_at) # ПРАВИЛА - История статусов пишется АВТОМАТИЧЕСКИ при сохранении Invoice (сравнение старого и нового status в save()). - Автор изменения берётся из thread-local, который заполняет middleware. - Удаление контрагента запрещено при наличии счетов (PROTECT). - Пропавшие из 1С контрагенты деактивируются, а не удаляются. # ПРОВЕРКА ЭТАПА pytest: модели создаются, история пишется, PROTECT срабатывает, amount <= 0 отклоняется.
Блок 2. Статусная машина
# СТАТУСЫ (13) draft, pending, approved, in_accounting, registered_in_1c, pending_payment, payment_sent, payment_failed, needs_clarification, paid, rejected, overdue, closed_in_1c # ПЕРЕХОДЫ — ЕДИНСТВЕННЫЙ ИСТОЧНИК ПРАВДЫ draft --submit--> pending (manager, свой, номер+дата+сумма>0) pending --approve--> approved (head) pending --reject--> rejected (head, причина обязательна) approved --accept--> in_accounting (bookkeeper) in_accounting --enter_1c--> registered_in_1c (bookkeeper, ТОЛЬКО при успехе 1С) registered_in_1c --send_payment--> pending_payment (bookkeeper) pending_payment --pay--> paid (treasurer, номер п/п + дата) pending_payment --send_bank--> payment_sent (treasurer) pending_payment --fail--> payment_failed (treasurer, причина из 7) payment_sent --fail--> payment_failed (treasurer) payment_failed --retry--> pending_payment (treasurer) payment_failed --return--> needs_clarification (treasurer) paid --close_1c--> closed_in_1c (bookkeeper) # ЖЁСТКОЕ ТРЕБОВАНИЕ Переход enter_1c выполняется только если 1С вернула success=true. При ошибке связи статус НЕ меняется, пользователь видит текст ошибки. «Внесён в 1С» = факт создания документа, а не нажатие кнопки. # ПРОВЕРКА ЭТАПА Сквозной тест: draft -> ... -> closed_in_1c на замоканной 1С. Тест на отказ 1С: статус остаётся in_accounting.
Блок 3. Права и доступ
# ТРИ НЕЗАВИСИМЫХ СЛОЯ (намеренное дублирование) 1. Декоратор роли на каждом view. 2. Middleware: проверка префиксов URL по роли. 3. Проверка владения счётом для manager. # ВИДИМОСТЬ СПИСКА manager: только свои счета head: pending, approved, paid, rejected, overdue bookkeeper: все treasurer: pending_payment, payment_sent, paid, payment_failed # ПОВЕДЕНИЕ ПРИ ЗАПРЕТЕ Не 403, а мягкий редирект на собственный дашборд роли. (Зафиксировать это явно — иначе агент поставит 403.) # ПРОВЕРКА ЭТАПА Тест на каждую роль x каждый защищённый URL.
Блок 4. Экраны
# СПИСОК ЭКРАНОВ (минимум) login, register, 4 дашборда по ролям, /invoices/ (список), карточка счёта, создание, редактирование, оплата с реквизитами, «не проведён», бухгалтерская операция, закрытие в 1С, загрузка на распознавание, заявки на контрагента (3 экрана), 2 отчёта, уведомления, таймеры. # КАРТОЧКА СЧЁТА — ГЛАВНЫЙ ЭКРАН Данные + цветной статус + история лентой + блок кнопок, который зависит от роли И статуса. Кнопки — формы POST, не ссылки GET. Модальные окна: подтверждение, причина отказа, комментарий, отправка копии на почту. # ПРОВЕРКА ЭТАПА Снимок карточки для каждой пары (роль, статус): какие кнопки видны.
Блок 5. Интеграции (заглушки + реальный код)
# 1С: ЧТЕНИЕ КОНТРАГЕНТОВ (OData) GET {ONEC_BASE_URL}/{ONEC_COUNTERPARTY_RESOURCE} Basic auth. Терпимый разбор полей: Ref_Key|GUID, ИНН|INN, КПП|KPP, Наименование|Description, НаименованиеПолное. Синхронизация: create / update by GUID / deactivate missing / skip без GUID (ручные записи не трогать). # 1С: СОЗДАНИЕ СЧЁТА (HTTP-сервис) POST {ONEC_BASE_URL}/hs/invoice/create JSON: number, date, counterparty_guid, amount (строка 2 знака), purpose, branches[]. Ответ: {success, guid, number_1c, error}. Ошибка связи или не-200 => статус счёта не меняется. # РАСПОЗНАВАНИЕ (внешний FastAPI-сервис) POST {RECOGNITION_URL}/recognize, файл PDF/JPG/PNG/TIFF до 10 МБ. Ответ: {success, fields{number,date,amount,counterparty_inn, counterparty_name,purpose}, confidence{}, error}. Создаётся ЧЕРНОВИК, не готовый счёт. Поиск контрагента: ИНН -> точное имя -> подстрока -> служебный «Не определён» (inactive, вне выпадающих списков). # ПРОВЕРКА ЭТАПА Тесты на заглушках: успех, отказ, таймаут, не-JSON.
Блок 6. Автоматика и сроки
# ПРОВЕРКИ (пороги в коде, не в настройках) pending > 2 дней -> письмо руководителям + timer in_accounting > 1 день -> бухгалтерам + timer pending_payment > 3 дней-> казначеям + timer timer истёк -> напоминание адресату напомнили + 24ч -> эскалация руководителю payment_sent + 24ч -> auto-fail (требует timer при send_bank!) # РАСПИСАНИЕ Проверки — каждые 5 минут. Синхронизация контрагентов — 03:00. На Windows django-crontab не работает => внешний планировщик. Явно указать это в ТЗ, иначе агент «забудет» про Windows. # ПРОВЕРКА ЭТАПА Тест: таймер создаётся при send_bank и через сутки даёт payment_failed.
Блок 7. Приёмка
# ЧЕК-ЛИСТ (агент обязан приложить отчёт)
[ ] check --deploy без критических ошибок
[ ] нет неприменённых миграций
[ ] быстрые тесты (модели, права) — зелёные
[ ] полный прогон — без падений
[ ] сквозной маршрут на замоканных 1С и распознавании
[ ] отказ 1С не меняет статус
[ ] auto-fail через 24ч работает
[ ] все действия со статусом — POST + CSRF
[ ] .env.example без секретов, DEBUG=False в примере
[ ] регистрация закрыта флагом
03Какой моделью генерировать ТЗ и код
Задача делится на две разные по природе части, и для них подходят разные модели.
| Этап | Что делаем | Тип модели | Рекомендация |
|---|---|---|---|
| ТЗ и декомпозиция | Из описания процесса собрать блоки 0–7, таблицу переходов, чек-лист | Сильная reasoning-модель, длинный контекст | Флагманская модель с «рассуждением» (reasoning-режим). Важна способность держать 40+ страниц описания и не терять инварианты. |
| Модель данных + миграции | Django-модели, PROTECT, автоистория, thread-local | Кодовая модель среднего размера, сильная в Python | Модель уровня «сильный код-ассистент». Достаточно, если ТЗ уже зафиксировано. |
| View + шаблоны | Много однотипных экранов, Bootstrap | Быстрая дешёвая модель | Младшая/средняя модель по образцу первых 2–3 экранов. Экономия 5–10x без потери качества. |
| Интеграции 1С и распознавание | HTTP-клиенты, разбор ответов, обработка ошибок | Reasoning-модель + кодовая | Сначала reasoning для контракта обмена, потом кодовая для реализации. Ошибки здесь дорогие. |
| Тесты и сквозной сценарий | pytest, моки 1С, e2e | Reasoning-модель | Та же флагманская: тесты — это спецификация, модель должна «понимать» инварианты. |
| Ревью и поиск дефектов | Сверка кода с таблицей переходов | Reasoning-модель, отдельный прогон | Обязательно другая сессия/модель, чем писала код. Самопроверка слабее. |
Общее правило: чем выше цена ошибки, тем «умнее» модель. Логика маршрута, права и интеграции — флагман. Шаблоны и CRUD-экраны — младшая модель по образцу. Смешивать нельзя: дешёвая модель на статусной машине даст красивый, но неверный код.
04Сколько стоит на выходе
Считаем в двух разрезах: стоимость генерации (токены, прогоны, правки) и стоимость рабочей системы (если бы её делали люди). Цифры — порядок величин для планирования, а не смета.
Генерация агентом
Разброс определяется числом итераций: агент почти всегда ошибается в автоистории, правах и обработке отказа 1С. Каждая такая правка — отдельный прогон с контекстом.
Рабочая система «под ключ»
| Статья | Оценка | Комментарий |
|---|---|---|
| Генерация агентом | $60–300 | Токены и прогоны |
| Приёмка и правки человеком | 40–120 ч | Ревью, ручные сценарии, доводка UX |
| Интеграция 1С | 20–60 ч + программист 1С | Публикация HTTP-сервиса и OData — на стороне 1С |
| Развёртывание распознавания | 8–24 ч | Сервис + ядро разбора + локальная модель |
| Инфраструктура и бэкапы | 4–16 ч | PostgreSQL, планировщик, архив media |
| Безопасность перед публикацией | 8–24 ч | POST вместо GET, закрыть регистрацию, DEBUG off |
Для сравнения: та же система, написанная людьми с нуля, — это ориентировочно 400–800 часов разработки плюс интеграционная часть. Агентная генерация снимает основную часть «механического» кода (модели, CRUD, шаблоны), но не снимает стоимость интеграций, приёмки и безопасности. Именно они формируют нижнюю границу бюджета.
05Где агент обязательно ошибётся
По опыту разбора подобных систем — список повторяющихся мест. Заложите их в ТЗ явно и проверяйте тестами.
- Смена статуса через GET. Агент любит делать кнопки ссылками. Требуйте POST + CSRF и тест, что GET не меняет статус.
- «Внесён в 1С» по нажатию. Соблазн поставить статус до ответа 1С. Инвариант: статус меняется только при
success=true. - Автоистория. Забывает писать историю в
save()и теряет автора изменения. Нужен thread-local + middleware. - Права. Ставит 403 вместо мягкого редиректа и забывает проверку владения для менеджера.
- Авто-отказ. Проверка есть, а таймер при отправке в банк не создаётся — сценарий 24 часов не наступает. Классический дефект.
- PROTECT на контрагенте. Делает каскадное удаление и рвёт историю счетов.
- Секреты. Тянет ключи в код или в пример конфига. Требуйте
.env.exampleбез значений.
06Вывод
CRM СЭД для счетов — почти идеальный полигон для агентной генерации: конечная логика, шаблонный интерфейс, изолированные интеграции. Скелет ТЗ из семи блоков превращает «сделай CRM» в воспроизводимый процесс с проверяемыми этапами.
По деньгам: генерация — десятки-сотни долларов, рабочая система — единицы-десятки тысяч, и разница почти целиком уходит на интеграции, приёмку и безопасность. Модель выбирайте по цене ошибки: reasoning — на ТЗ, тесты и ревью; кодовая — на реализацию; дешёвая — на шаблоны. Если Hermes умеет маршрутизировать модели, это даст больше экономии, чем любой отдельно взятый флагман.