«Можно обучить вашего бота отвечать по нашему регламенту?» — этот вопрос мы слышим почти от каждого вуза или колледжа после первого демо. Регламент учреждения — это десятки или сотни страниц внутренних правил, и да, мы можем подключить его к боту. Но не просто «скормить в контекст», как многие думают. Расскажем технически — что работает, что нет.
Почему «скормить всё в контекст» не работает
Современные большие языковые модели (GPT‑4, Claude, GigaChat и аналоги) поддерживают контекстное окно от 8 000 до 200 000+ токенов. Логичное предложение: возьмём 200‑страничный регламент вуза (примерно 100 000 токенов), положим целиком в системный промпт, и при каждом вопросе пользователя LLM будет искать ответ.
На практике этот подход проваливается по четырём причинам:
- Стоимость. Каждый запрос с большим контекстом стоит в 100+ раз дороже короткого. Бот, к которому в день обращаются 500 человек, нагенерит счёт за месяц больше, чем подписка на сам сервис.
- Скорость. Обработка 100 K токенов занимает 15–30 секунд. Пользователь ждёт 30 секунд ответа на «когда родительское собрание?» — закроет чат до получения ответа.
- Точность. Несмотря на большое контекстное окно, LLM имеют тенденцию «терять» информацию из середины длинного контекста (это известный эффект lost in the middle). Релевантный параграф из середины документа может быть проигнорирован, даже если он там есть.
- Галлюцинации. На длинных контекстах модели чаще фантазируют — собирают ответ из обрывков разных частей текста, получая результат, которого в исходнике нет.
Что работает: RAG (Retrieval Augmented Generation)
RAG — это паттерн, при котором мы не загружаем весь документ в контекст. Вместо этого мы заранее разбиваем его на фрагменты, индексируем по смыслу, и при каждом вопросе пользователя находим только релевантные фрагменты и подсовываем их LLM.
Схема в трёх блоках:
- Подготовка (один раз). Разбиваем документ на чанки → каждому чанку считаем embedding → складываем в векторную базу.
- Запрос (на каждый вопрос). Получаем вопрос пользователя → считаем его embedding → ищем топ‑5 ближайших чанков в базе.
- Генерация. Передаём в LLM системный промпт + найденные фрагменты + вопрос → получаем краткий ответ строго по этим фрагментам.
Шаг 1: чанкование по структуре документа
Документ нужно разбить на небольшие фрагменты (чанки). Если резать как попало по фиксированной длине, предложения и пункты регламента ломаются пополам — и фрагмент теряет смысл.
Поэтому мы режем документ по его собственной структуре — по разделам, главам и заголовкам, а не вслепую по длине. Соседние фрагменты слегка перекрываются, чтобы мысль на границе не потерялась, и к каждому фрагменту прикрепляется заголовок раздела, из которого он взят (это пригодится для ссылок на источник — см. шаг 4).
Регламенты часто приходят как PDF или Word, где разметки заголовков нет — просто текст. Мы распознаём в таком тексте «Раздел 3», «Глава 2», «Статья 14» и восстанавливаем структуру перед нарезкой. Там, где структуру выделить не удалось, остаётся аккуратная нарезка с перекрытием как запасной вариант.
Шаг 2: эмбеддинг и индекс
Для каждого чанка мы считаем вектор (embedding) — числовое представление его смысла в N‑мерном пространстве. Похожие по смыслу тексты имеют близкие векторы.
Модель эмбеддингов у нас сменная. По умолчанию — компактная мультиязычная multilingual‑e5‑small: её хватает для коротких русскоязычных запросов, и она работает на скромном железе. Если у учреждения есть требования к качеству или к полной автономности, можно подключить модель помощнее (например, bge‑m3) или считать эмбеддинги локально, не отправляя текст во внешние сервисы.
Векторы храним в нашей базе данных рядом с самими фрагментами — отдельная экзотическая инфраструктура для этого не нужна.
Шаг 3: поиск нужных фрагментов
Когда приходит вопрос, мы считаем его embedding и ищем ближайшие по смыслу фрагменты. Чтобы поиск не промахивался на формулировках, мы комбинируем два сигнала: близость векторов (смысл) и совпадение по ключевым словам (точные термины, коды, названия). Гибрид «смысл + слова» устойчивее, чем каждый сигнал по отдельности.
Но самое важное решение — не каждый вопрос вообще доходит до поиска по регламенту. Сначала запрос проходит через каскад: быстрые правила и ключевые слова, а при необходимости — модель, которая определяет намерение. «Когда у группы пара?» уходит в расписание, «как восстановиться после отчисления?» — в регламент. Это экономит время и деньги и резко снижает шанс, что бот ответит «не из того документа».
Шаг 4: ответ строго по документу
Найденные фрагменты мы передаём модели с жёсткой инструкцией: «Ответь только на основе этих фрагментов. Если ответа в них нет — так и скажи, не выдумывай».
Результат для пользователя выглядит так:
- «Заявление подаётся в течение первых 10 дней семестра. Срок рассмотрения — до 5 рабочих дней. Документ нужно сдать в канцелярию, каб. 105».
- «Источник: Регламент учебной деятельности, Раздел 3».
Ключевое — ответ собирается строго из текста регламента, а не из «общих знаний» модели. И к ответу мы прикладываем ссылку на источник — название документа и раздел, из которого взят фрагмент. Причём ссылку формируем мы сами, из найденного фрагмента, а не просим модель «процитировать»: так бот не может сослаться на несуществующий пункт. Нет источника — не показываем ссылку вообще.
Когда бот говорит «я не знаю»
Самая ценная фича системы — это не способность отвечать. Это способность честно отказаться, когда ответа нет.
Если в найденных чанках нет релевантной информации, бот отвечает, не выдумывая: «По регламенту учреждения у меня нет точного ответа на этот вопрос. Уточните, пожалуйста, в учебной части по адресу: каб. 105 или по почте hello@mycampushub.ru».
Это работает за счёт явного промпта «не выдумывай, если ответа нет — скажи». Плюс мы измеряем confidence по найденным чанкам: если ни один из топ‑5 не имеет достаточной близости к вопросу, мы даже не вызываем LLM, а сразу возвращаем fallback.
Реальный пример с вузом
Один из наших клиентов — региональный вуз. Регламент — больше 200 страниц: поступление, академические задолженности, переводы, отчисления, восстановление, стипендии, общежитие, академические отпуска и так далее.
Что мы сделали:
- Разбили регламент по разделам и главам, посчитали для фрагментов embeddings.
- Подключили поиск по регламенту к существующему боту вуза (он уже отвечал на вопросы о расписании).
- На размеченном наборе вопросов проверили, что нужный раздел реально находится, а на вопросы «не из регламента» бот честно отказывается — и по этим замерам подкрутили пороги.
После запуска заметная часть обращений в учебную часть про «как восстановиться», «когда можно перевестись» и подобные регламентные вопросы ушла в бота.
Что в итоге
Обучить ИИ‑бота отвечать по большому документу — реально, но это не «положить всё в контекст». Это RAG: разбить документ по структуре на фрагменты, посчитать embeddings, искать по смыслу и ключевым словам, отвечать строго по найденному со ссылкой на источник и честно говорить «не знаю», когда ответа в документе нет.
Технически это не так сложно, как кажется — почти все компоненты есть в виде готовых библиотек. Сложно правильно подобрать параметры для конкретного документа: размер чанка, размер overlap, число K в поиске, температуру LLM, формат промпта.
В CampusHub это часть подключения «под ключ» — мы делаем всю настройку, тестируем на реальных вопросах, доводим до production‑готовности. Если у вашего вуза или колледжа есть большой регламент и хочется, чтобы бот по нему отвечал, — оставьте заявку, обсудим вашу специфику.