Как превратить сообщение «нам нужны новые кресла» в нормальную заявку и не заставить ИИ принимать решения, которые лучше оставить коду
В компаниях нерегулярные закупки редко начинаются с аккуратно заполненной формы. Гораздо чаще это письмо с неполной информацией, сообщение в мессенджере или, ещё лучше, фраза брошенная в офисном коридоре: «Нам срочно нужны новые кресла в переговорную». И даже в 2026 году после такой фразы многие считают, что «заказ уже передан в закупки». Их сложно винить, чаще всего у них полно другой профильной работы.
Дальше закупщик начинает работать немного инспектором Колобком: сколько кресел? какие? когда нужны? куда поставить? есть ли бюджет? для чего покупаем?
Для выпускного проекта на моих курсах по промпт-инжинирингу я решила сделать ИИ-ассистента, который помогает собрать эти сведения до того, как заявка попадёт в закупки, и сделать это в максимально комфортной форме для внутреннего заказчика.
Так появился telegram-бот «Закупкин».
Что умеет ассистент
У проекта два основных сценария.
Первый — оформление заявки на закупку. Пользователь пишет потребность обычным текстом, например:
Нужно купить 12 офисных кресел с подлокотниками, до 25 августа, ориентировочная сумма 180 000 рублей, поставка в офис на Лиговский проспект.
Ассистент извлекает уже указанные сведения и не спрашивает их повторно. Затем последовательно запрашивает только то, чего не хватает: бюджетный статус, подразделение, характеристики или другие обязательные данные.
Когда все необходимые поля заполнены, бот показывает итоговую карточку. Зарегистрировать заявку можно только отдельным явным подтверждением пользователя.
Второй сценарий — вопросы по внутренним правилам закупок.
Например: Кто должен согласовать закупку на 210 000 рублей?
Если для ответа не хватает важного условия, например, предусмотрена ли закупка бюджетом, ассистент сначала уточняет его. После этого ищет ответ в базе знаний, а также показывает использованные источники — не для красоты, а чтобы пользователь при желании мог проверить, на каком регламенте или правиле основан ответ.
Именно этот второй контур построен как RAG (подробнее, что это такое, можно почитать тут), то есть генерация ответа с поиском по базе знаний. Финальная база проекта содержит 14 документов и 118 фрагментов.
Почему я не стала отдавать всё LLM
Самая важная архитектурная идея проекта появилась довольно рано: языковая модель хорошо понимает свободный текст, но это не значит, что ей стоит доверять всё подряд. Поэтому ответственность разделена. LLM используется для понимания человеческих формулировок, структурированного извлечения данных, предложения категории и формирования ответа по найденному контексту. А код проверяет обязательные поля, нормализует даты и числа, контролирует состояние черновика, допустимость переходов и возможность регистрации заявки.
Особенно показательно это работает с категориями товаров и услуг. Если категория, к которой стоит отнести указанный товар или услугу, определяется однозначно программными правилами, модель вообще не вызывается. Если предмет новый или неоднозначный, LLM может выбрать вариант только из закрытого классификатора. Затем результат проверяется программно и, если категория была предложена моделью, пользователь должен её подтвердить.
То есть схема получилась примерно такая:
LLM предложила → код проверил → пользователь подтвердил.
Мне нравится этот принцип намного больше, чем идея «пусть нейросеть сама разберётся».
Как устроен ассистент
Дальше будет немного технических терминов. Если какой-то из них незнаком, можно спросить у Фитто, он как раз ждёт вас в правом нижнем углу страницы.
Интерфейсом стал Telegram, для MVP это быстрый и понятный способ проверить сам диалог. Backend написан на Python. Telegram отвечает за пользовательский диалог, aiogram — за работу бота, FastAPI — за серверный API, а PostgreSQL в Supabase хранит заявки, состояния диалогов и базу знаний. Для RAG используется гибридный поиск: embeddings плюс русский полнотекстовый поиск. Результаты объединяются с помощью RRF (Reciprocal Rank Fusion), после поиска модель получает наиболее релевантные фрагменты, но ответ дополнительно проходит программные проверки. Например, шаблоны и учебные примеры нельзя использовать как нормативное доказательство, а конкретные суммы, сроки и статусы проверяются отдельно. Если надёжного основания для ответа нет, бот должен уточнить вопрос или отказаться отвечать.
Проект развёрнут на VPS как systemd-сервис, чтобы бот работал независимо от моего компьютера, автоматически запускался, перезапускался при сбоях и переживал перезагрузку сервера. Для базы данных дополнительно включён Row Level Security: прямой доступ обычных клиентских ролей к серверным таблицам закрыт, а backend работает через серверный service_role.
Что получилось
В финальной версии бот умеет:
- оформлять товарные и сервисные заявки;
- сохранять и восстанавливать незавершённый черновик;
- изменять данные до регистрации;
- разбирать отдельные смешанные сценарии «товар + услуга»;
- определять категории с комбинацией правил и LLM;
- отвечать по внутренней базе знаний с источниками;
- задавать уточняющие вопросы;
- безопасно отказываться от ответов вне своей области.
Тестовая база в процессе работы выросла до более чем тысячи тестов. Отдельно проверялись RAG, многошаговые диалоги и новые формулировки, которых не было в исходных сценариях. Но это всё равно не заменяет реальную работу с пользователями — её я оставляю уже на этап пилота.
Что осталось за границами MVP
Я не пыталась превращать выпускной проект в полноценную корпоративную систему закупок. В текущей версии одна заявка содержит один основной предмет, нет универсальной многопозиционной спецификации, кабинета закупщика, полноценного процесса согласования и интеграций с учётной системой. Это ещё впереди!
Для меня главным вопросом проекта было: получится ли использовать ИИ, чтобы превратить неструктурированное описание потребности в управляемый процесс и при этом не отдавать нейросети критические решения? Получилось. Хотя довольно быстро выяснилось, что написать работающего ассистента — это только начало. Настоящее приключение началось, когда я решила его нормально протестировать, но это уже следующая история...