Перейти к содержимому
14 июл. 2025 г.·7 мин чтения

Валидация ответа в CRM и ERP перед записью данных

Разберем, как работает валидация ответа в CRM и ERP перед записью: проверки дат, сумм, статусов, свободного текста, ошибок и ручного разбора.

Валидация ответа в CRM и ERP перед записью данных

Почему записи ломаются

CRM и ERP редко ошибаются из-за "умной" части модели. Гораздо чаще все портит одно поле, которое не прошло простую проверку. Человек читает ответ и понимает смысл. Система ждет точный формат.

Самый частый пример - дата. Модель пишет "5 мая 2025" или "завтра", а поле принимает только 2025-05-05. Для менеджера разница почти незаметна. Для CRM она критична: запись не проходит, задача не создается, интеграция возвращает ошибку.

С суммами та же история. Один ответ приходит как 1250.50, другой как 1 250,50, третий - с символом валюты или текстом про НДС. Пробел, запятая и лишние слова меняют смысл поля. ERP либо отклоняет запись, либо сохраняет неверное число, а бухгалтер потом ищет, откуда взялась разница в счете.

Статусы тоже ломаются на мелочах. В справочнике есть "new", "approved" и "paid", а модель пишет "в работе" или "успешно согласовано". Для человека это похоже на нужный статус. Для системы это чужое значение.

Отдельная проблема - свободный текст там, где его быть не должно. Служебное поле ждет код причины, а модель добавляет комментарий вроде "клиент просил перезвонить после 15:00". Следующий шаг уже не может разобрать запись, потому что вместо короткого значения получил целую фразу.

Одна ошибка редко остается одной. Менеджер открывает карточку, правит ее руками, отправляет данные повторно и иногда создает дубль. Если такое случается десять раз в день, команда теряет часы на скучную ручную работу и перестает доверять автоматизации.

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

Какие поля проверять сначала

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

Удобный порядок такой:

  • даты и время
  • суммы, валюта и НДС
  • статусы, этапы и коды из справочников
  • идентификаторы клиента, сделки, счета
  • поля, где свободный текст запрещен

Даты лучше разбирать первыми, потому что они приходят в самых разных видах. Один сервис отдает "01.02.25", другой - ISO-формат, а модель может написать "завтра". Для записи нужен один формат, одна таймзона и понятное правило для пустого значения. Сразу проверьте и бизнес-логику: дата оплаты не должна быть раньше даты счета.

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

Со статусами часто делают одну и ту же ошибку: разрешают почти любой текст. Так лучше не делать. Статус, этап и код должны приходить только из списка допустимых значений. Если система ждет "paid", а ответ содержит "оплачено полностью", запись лучше остановить и сначала нормализовать значение.

Идентификаторы стоит описать отдельно. У клиента, сделки и счета часто есть внутренний ID, внешний ID и номер для человека. Их легко перепутать. Для каждого поля задайте источник, длину, формат и правило уникальности.

Свободный текст нужен не везде. В полях вроде "статус", "канал", "причина отказа" или "тип договора" его лучше запретить совсем. Иначе вместо чистых данных вы получите "позвонить после 18:00" там, где система ждет короткий код.

Как собрать правила

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

Потом для каждого поля задайте простую карту: тип значения, допустимый формат, границы и список разрешенных вариантов. Для даты это может быть YYYY-MM-DD и запрет на прошедший месяц. Для суммы - число, две цифры после запятой, верхний предел и валюта из справочника. Для статуса - только значения из вашего списка, без "почти согласовано" и других вольных формулировок.

Обычно хватает четырех вопросов:

  • что именно проверяем
  • какое значение считаем нормой
  • когда блокируем запись
  • когда показываем только предупреждение

Жесткий отказ и предупреждение лучше разделить сразу. Если дата не парсится, запись не должна уходить в систему. Если сумма сильно отличается от средней по этому типу сделки, можно сохранить черновик и показать предупреждение оператору. Такой подход экономит время: критичные ошибки машина ловит сама, спорные случаи человек смотрит вручную.

Каждому правилу нужен короткий код. Не оставляйте длинные тексты в логах единственным способом понять сбой. Коды вроде DATE_01, AMOUNT_02, STATUS_01 и TEXT_03 проще искать в логах, дашбордах и тикетах. Рядом можно хранить понятное описание для людей.

Свободный текст лучше проверять отдельно. Если поле должно брать значение из справочника, запретите любой текст вне списка. Если комментарий все же нужен, задайте лимит по длине, запрет на персональные данные и стоп-слова вроде "уточнить позже" или "не знаю".

Последний шаг часто пропускают. Зря. Прогоните правила на живых примерах из потока. Возьмите 50-100 реальных ответов модели и посмотрите, где она пишет "следующая пятница", "1,2 млн", "примерно 20%" или несуществующий статус. На таких примерах правила становятся точнее очень быстро.

Даты без сюрпризов

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

Для записи лучше выбрать один канонический формат: например, YYYY-MM-DD для даты и YYYY-MM-DDTHH:MM:SS+03:00 для даты со временем. Интерфейс может показывать дату привычно, но в базе и API формат должен быть один. Иначе 03.04.2025 легко превращается то в 3 апреля, то в 4 марта.

Дальше нужны базовые проверки на существование даты. Система должна сразу отклонять 31 апреля, 30 февраля и 2025-02-29. При этом 2024-02-29 принять можно, потому что это високосный год. Такие проверки кажутся очевидными, но именно на них часто сыплются импорт и автозаполнение.

Отдельная ловушка - конец месяца. Если модель извлекла "оплата до конца месяца", не подставляйте дату записи и не выбирайте последний день по догадке. Лучше вернуть ошибку и попросить точную дату. Здесь догадки обходятся дороже, чем повторный запрос.

Со временем та же проблема. Если в ответе есть встреча на 10:00, система должна знать часовой пояс. Для московской команды 10:00 по Москве и 10:00 UTC - это разные события. Храните смещение или явный timezone и проверяйте, что источник и CRM одинаково понимают время.

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

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

Суммы, валюты и НДС

Оставьте SDK как есть
Переведите CRM и ERP на единый OpenAI-совместимый эндпоинт без переписывания интеграций.

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

Если этого не сделать, система примет "1 250 000 руб." как строку, а не как сумму. Дальше начинаются тихие ошибки: не сходятся отчеты, ломаются фильтры, счет уходит не в тот маршрут согласования.

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

Диапазон особенно полезен там, где у процесса есть понятные рамки. Если заявка на расход обычно не превышает 500 000 рублей, сумма в 50 000 000 должна остановить запись и отправить документ на повторную проверку. Так можно поймать не только ошибки модели, но и кривой ввод из источника.

С НДС и скидкой лучше не гадать по тексту. Поле "с НДС" не заменяет отдельную проверку ставки и расчета. Если пришло "НДС 20%", система должна проверить, что ставка разрешена, база не отрицательная, а итоговая сумма сходится. Со скидкой то же самое: храните отдельно процент, сумму скидки и итог после скидки. Иначе строка вроде "скидка 10, итог 99 000" пройдет, даже если математика не бьется.

Простой пример: из счета пришло "1 200 000 ₽, включая НДС 20%, скидка 5%". Перед записью система должна получить не эту строку, а набор полей: 1200000.00, RUB, VAT=20, discount=5. Если хотя бы одно поле не прошло проверку, запись лучше остановить сразу.

Статусы и справочники

Статус нельзя принимать "как есть" из ответа модели. Для CRM и ERP это почти всегда ломает запись: модель пишет "счет готов", а система ждет строго draft или issued. Если поле связано со справочником, пропускайте только то значение, которое уже есть в этом справочнике.

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

Не смешивайте внутренние и клиентские названия. Внутри системы может жить код invoice_sent, а менеджер в письме пишет "счет отправлен". Для записи храните одно каноническое значение, а для интерфейса - отдельное отображаемое имя. Тогда интеграции не спорят между собой, а людям все равно удобно работать.

Полезно держать рядом таблицу синонимов и сокращений. Она убирает много шума без ручной правки каждого ответа. Например, "счет выставлен", "счет отправлен" и "инвойс ушел" можно сводить к issued, а "в работе", "обрабатывается" и "на исполнении" - к in_progress.

Если совпадения нет, не пытайтесь угадать. Отправляйте запись на разбор и сохраняйте исходный ответ отдельно. Это дешевле, чем потом исправлять карточки, счета и отчеты.

Рабочая схема простая: сначала нормализация через таблицу синонимов, потом проверка по справочнику, потом проверка перехода из текущего статуса в следующий. Звучит скучно, но именно такие правила защищают систему от тихих поломок.

Где запретить свободный текст

Свободный текст нужен не везде. Чаще всего все ломается там, где система ждет код, число или значение из справочника, а модель пишет человеческую фразу. Поле status_code не должно принимать "клиент почти согласен", а currency не должно получать "рубли, если можно".

Жесткий запрет нужен в полях, где ошибка сразу портит запись или ломает обмен между системами. Это коды статусов и этапов, ИНН, КПП, артикулы, номера договоров, валюта, ставка НДС, тип документа, идентификаторы менеджера, склада и контрагента.

В таких полях пропускайте только точный формат: число, код из списка, дату по шаблону, короткий enum. Любой лишний символ лучше считать ошибкой, а не "почти верным" ответом.

Отдельная проблема - служебные фразы модели. Она может вернуть "вот заполненные поля", "не удалось определить" или "нужна проверка человеком". Такие куски стоит срезать до валидации. Если после очистки поле все равно не проходит правило, не записывайте его.

Ищите персональные данные там, где их не должны хранить. Например, в поле order_comment модель иногда складывает телефон, почту или паспортные данные из письма клиента. Если это поле не предназначено для таких данных, запись надо остановить или отправить на ручную проверку. Для команд с требованиями по 152-ФЗ это обычная защита.

Еще один полезный фильтр - запрет HTML, markdown и переносов строк почти везде, кроме длинных заметок. Теги, списки, звездочки, обратные кавычки и многострочный текст часто означают, что модель вернула объяснение вместо значения поля.

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

Пример на заявке и счете

Смените base_url без правок
Подключите RU LLM и используйте те же SDK, код и промпты без изменений.

Клиент пишет в форме: "Прошу выставить счет на 12 500 рублей до 5 мая. Срочно, позвоните мне". Человек понимает такую фразу сразу. CRM или ERP - нет. До записи систему лучше заставить разложить текст по полям и отбросить лишнее.

Модель достает из сообщения три значения: сумму, дату и статус оплаты. Например, она может вернуть сумму 12500, дату 05.05 и статус ожидает счет. Дальше решение принимает уже не модель, а набор правил.

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

Если модель вернула "12 500 рублей", правило убирает пробел, отделяет валюту и сохраняет сумму в нужном виде, например 12500.00 и RUB. Если дата счета должна быть в формате 2025-05-05, правило приводит "до 5 мая" к этому виду. Когда год нельзя определить без ошибки, запись не проходит автоматически.

Со статусом проверка еще жестче. Фраза "срочно, позвоните мне" не должна попасть в поле статуса, даже если модель решила, что это часть ответа. Система отклоняет запись, потому что такого статуса нет в справочнике и поле запрещает свободный текст. Эту фразу можно перенести в комментарий менеджера, но не в статус счета.

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

Частые ошибки

Проблемы начинаются не на совсем битых данных, а на "почти нормальных" значениях. Формат может пройти, а смысл - нет. Дата выглядит верно, хотя попадает в нерабочий период. Сумма записывается без ошибки, хотя не сходится с валютой или ставкой НДС.

Частая промашка - считать пустую строку обычным значением. Для системы поле как будто заполнено, а для бизнеса там пусто. В итоге менеджер видит карточку с пробелом вместо статуса, срока оплаты или номера договора, а ошибка всплывает уже в отчете или интеграции.

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

На практике чаще всего мешают пять вещей:

  • проверили шаблон даты, но не проверили, допустима ли она для процесса
  • приняли пустую строку, потому что она технически не null
  • записали в одно поле статус, причину и комментарий
  • исправили ответ модели, но не сохранили исходный вариант
  • отклонили запись, но не сохранили код правила и причину

Потеря исходного ответа особенно неприятна. Если оператор поправил сумму вручную, а оригинал исчез, потом уже нельзя понять, кто ошибся: модель, правило или человек. Для разбора инцидентов полезно хранить обе версии - исходную и нормализованную.

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

Быстрая проверка перед запуском

Держите логи в РФ
Храните логи и бэкапы запросов внутри РФ, когда поток затрагивает персональные данные.

Запуск без короткого чек-листа почти всегда заканчивается ручной чисткой записей. Пара часов на финальную проверку обычно экономит дни на разборе дублей, неверных сумм и сломанных статусов.

Перед стартом проверьте несколько простых вещей. У каждого поля должен быть явный формат. Дата приходит только в одном виде, сумма хранится как число, валюта берется из списка, а не из свободного ввода. Для полей со справочниками нужен список допустимых значений. Если модель вернула "в работе", а CRM ждет только "new", "approved" или "rejected", запись получает отказ.

Каждый отказ должен иметь свой код и понятный текст. Оператору важно сразу видеть разницу между ошибкой формата, пустым значением и конфликтом со справочником. Тесты тоже стоит гонять не только на идеальных ответах. Они должны ловить пустые поля, спорные даты вроде 03.04.25 и шумный текст, где вместе смешаны комментарий, сумма и статус.

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

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

Если трафик LLM идет через RU LLM, удобно привязать ID запроса к записи в CRM или ERP и смотреть причину отказа рядом с аудитом запроса. Для команд с требованиями 152-ФЗ это еще и упрощает хранение логов и разбор ошибок внутри РФ.

Хороший быстрый тест - прогнать 20-30 реальных примеров из старых заявок или счетов. Если система уверенно обрабатывает пустые поля, лишние слова, опечатки и редкие статусы, запуск пройдет заметно спокойнее.

Что делать дальше

Не пытайтесь закрыть все поля за один спринт. Полная схема из десятков правил почти всегда буксует. Лучше взять 5-10 полей, которые чаще всего ломают запись: дату документа, сумму, валюту, ставку НДС, статус, идентификатор клиента или номер счета.

Такой подход быстрее дает результат, потому что вы чините самые дорогие ошибки. Если запись падает из-за трех полей в 80% случаев, нет смысла начинать с редких исключений.

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

Для начала хватит четырех метрик:

  • доля отказов по каждому полю
  • частые причины отказа
  • сколько ошибок нашли до записи
  • где правило срабатывает слишком часто

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

Если за месяц стало меньше битых записей и меньше ручных исправлений по этим 5-10 полям, подход работает. Дальше его уже можно спокойно масштабировать на остальные части процесса.

Часто задаваемые вопросы

Зачем проверять ответ модели до записи в CRM или ERP?

Потому что ошибка в одном поле ломает всю запись. Проще остановить ответ на входе, чем потом чистить базу, ловить дубли и вручную чинить суммы или статусы.

Какие поля лучше валидировать в первую очередь?

Сначала берите даты, суммы, валюту, НДС, статусы и идентификаторы. Эти поля чаще всего роняют запись, потому что система ждет точный формат, а не смысл "примерно похож".

Какой формат даты лучше использовать?

Выберите один формат и держите его везде. Для даты обычно хватает YYYY-MM-DD, а для даты со временем — полного значения со смещением, чтобы CRM и источник одинаково понимали момент времени.

Что делать с датами вроде «завтра» или «в конце месяца»?

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

Как проверять сумму, валюту и НДС?

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

Можно ли принимать статус в свободной форме?

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

Где свободный текст нужно запретить совсем?

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

Что делать, если значение не прошло проверку?

Если поле не парсится или нарушает правило, остановите запись и покажите причину рядом с полем. Для спорных случаев можно сохранять черновик и отправлять его оператору, а не гадать за него.

Нужно ли сохранять исходный ответ модели и причину отказа?

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

Как внедрять валидацию без риска для команды?

Начните с режима наблюдения на 5–10 самых проблемных полях. Через неделю-две посмотрите, где правила ловят настоящие ошибки, и только потом включайте жесткий отказ для дат, сумм и кодов статусов.