ИИ-поиск по базе знаний прямо на главной: RAG, источники и follow-up за один вызов
- ИИ-поиск
- RAG
- LightRAG
- Astro
- SSR
- Pagefind
- поиск по сайту
- AEO
На главной webshturm.ru теперь живой ИИ-поиск по базе знаний сайта, встроенный прямо в hero: посетитель задаёт вопрос обычными словами и получает связный ответ из материалов сайта со ссылками на страницы-источники и тремя уточняющими вопросами (стиль Perplexity), а рядом — блок «Точные совпадения» из полнотекстового поиска. Это и удобный поиск, и витрина наших возможностей в ИИ-разработке — клиент видит работающий продукт, а не слайд про «мы умеем ИИ». Ниже — как это устроено: RAG, серверный эндпоинт, три follow-up за один вызов модели, гибрид с полнотекстовым поиском и защита публичного ИИ-эндпоинта.
Зачем встраивать ИИ-поиск в hero
Обычный поиск по сайту возвращает список страниц — дальше посетитель читает сам и сопоставляет. Это работает, но требует усилий: нужно угадать ключевые слова и пролистать выдачу. ИИ-поиск снимает этот шаг — понимает вопрос целиком и сразу даёт ответ по делу.
Мы поставили его не на отдельную страницу, а в самый заметный блок главной. Причина двойная: во-первых, это полезный инструмент навигации по сайту; во-вторых — демонстрация. Компании, которая делает ИИ-решения, логичнее показать работающий ИИ прямо на витрине, чем рассказывать о нём текстом.
При этом мы не отказались от классического поиска: ИИ-ответ основной, а быстрые точные совпадения идут рядом как fallback. Если ИИ временно недоступен — полнотекстовый поиск продолжает работать.
Архитектура: поток запроса
Виджет в hero — островок интерактивности (Svelte island) — отправляет вопрос на серверный эндпоинт сайта (SSR, рендер на запрос). Эндпоинт сначала проходит защиту, затем делает один запрос к базе знаний и возвращает уже разобранный результат: текст ответа, массив источников и до трёх follow-up-вопросов. Сама модель и база знаний живут на серверной стороне — браузер никогда не обращается к ним напрямую.
RAG: ответ только из базы знаний сайта
Под капотом — RAG (retrieval-augmented generation): система сначала достаёт релевантные фрагменты из базы знаний сайта, а потом модель формулирует ответ только на их основе. Это принципиально отличается от «спросить general-purpose модель»: ответ не из общих знаний модели, а из материалов конкретного сайта.
Жёсткие правила (guardrail) встроены в запрос:
- Отвечать только из контекста базы знаний компании; не выдумывать.
- Не обещать конкретные цены, сроки и гарантии — это всегда решение человека.
- Если ответа в контексте нет — честно сказать, что вопрос лучше обсудить напрямую.
К ответу прикладываются ссылки на страницы-источники. Это и проверяемость (можно открыть первоисточник целиком), и мягкий возврат на нужную страницу сайта. Ссылки формируются с учётом аудитории страницы: для одной версии сайта — канонические адреса, для зеркала «Руководителю» — соответствующие ему пути.
Эвристика «нет ответа»
ИИ-поиск, который уверенно отвечает на всё, опаснее отсутствия поиска — он подрывает доверие. Поэтому есть эвристика обоснованности: если модель отвечает в духе «не нашёл информации» или ответ ничем не подкреплён в базе (нет ни источников, ни ссылок-маркеров) — мы не показываем его. Вместо выдумки посетитель видит мягкое сообщение и предложение обсудить задачу. Честное «не знаю» лучше уверенной ошибки.
Три follow-up за один вызов модели
Follow-up-вопросы (как в Perplexity) помогают углубиться в тему, не формулируя новый запрос с нуля. Наивная реализация — отдельный вызов модели «придумай вопросы по этому ответу». Мы сделали иначе: просим их в том же единственном вызове.
Guardrail завершается просьбой добавить в самом конце скрытый блок вопросов — по одному на строку. На стороне эндпоинта мы парсим этот блок, берём до трёх вопросов и вырезаем его из видимого текста ответа. Посетитель видит чистый ответ плюс три кнопки «Спросить дальше»; клик по кнопке подставляет вопрос и запускает новый поиск.
Выгода одного вызова: дешевле (один запрос к модели вместо двух), быстрее (нет второго round-trip) и дружит с кэшем — весь результат, включая follow-up, кэшируется целиком.
Гибрид с полнотекстовым поиском
Параллельно ИИ-запросу виджет на клиенте обращается к полнотекстовому поиску (Pagefind — статический индекс, собираемый при сборке сайта) и показывает топ-совпадения в сворачиваемом блоке «Точные совпадения». Это даёт лучшее из двух миров: ИИ — для смыслового ответа, полнотекстовый — для точных вхождений и как страховка.
Если полнотекстовый поиск недоступен — блок просто скрыт, ИИ-ответ не страдает. И наоборот: если недоступен ИИ — работает полнотекстовый. Два независимых канала, и оба отказоустойчивы по отдельности.
Кстати, починка самого полнотекстового поиска оказалась отдельной историей: он молча не возвращал результатов из-за политики безопасности контента (CSP), которая блокировала WebAssembly-модуль индекса. Лечится разрешением
wasm-unsafe-evalвscript-src— а не «пустым индексом», как казалось сначала.
Защита публичного ИИ-эндпоинта
Открытый ИИ-эндпоинт — это и потенциальный абьюз, и расход бюджета модели. Защита — четыре уровня (порядок важен):
- Кэш ответов (TTL ~1 час) — повтор одного вопроса бесплатный и мгновенный, не доходит до модели. Ключ кэша учитывает аудиторию страницы, чтобы версии сайта не пересекались по ссылкам-источникам.
- Глобальный дневной потолок запросов — защита бюджета модели; при превышении отдаём кэш, если он есть, иначе — мягкий отказ.
- Лимит с одного адреса в минуту — типовая защита от флуда.
- SmartCaptcha при подозрении — если адрес превысил лимит, запрашиваем капчу; валидный токен пропускает запрос. Мы переиспользовали уже работающую на сайте интеграцию SmartCaptcha (та же, что на форме контактов), не заводя новых ключей.
Ещё одно правило: эндпоинт никогда не отдаёт наружу серверную ошибку из-за модели. Сбой поиска (сеть, таймаут, ошибка) превращается в мягкий ответ «временно недоступно» — а не в 500-ю страницу. Для посетителя деградация плавная: ИИ замолчал — работает обычный поиск.
Честное ограничение: счётчики и кэш — в памяти процесса. Они не переживают перезапуск и не шарятся между репликами. Для одного экземпляра приложения этого достаточно; при горизонтальном масштабировании лимиты и кэш нужно вынести во внешнее хранилище.
Тайпрайтер: ответ «печатается»
Ответ приходит на клиент целиком, но «печатается» посимвольно (тайпрайтер) — это привычная для ИИ-интерфейсов динамика, она делает витрину живой. Мы уважаем системную настройку prefers-reduced-motion: если посетитель отключил анимации — ответ показывается сразу целиком. Область ответа помечена aria-live, чтобы скринридеры озвучивали появление текста.
Что мы из этого вынесли
- Один вызов модели на ответ + источники + follow-up. Скрытый блок вопросов в том же ответе экономит вызовы, ускоряет отклик и идеально кэшируется. Два вызова там, где хватает одного, — типичная переплата.
- Эвристика «нет ответа» важнее красивого ответа. ИИ-поиск без неё рано или поздно уверенно соврёт. Отказ показать необоснованный ответ — это фича, а не слабость.
- Гибрид надёжнее монолита. Два независимых канала (ИИ + полнотекстовый) деградируют по отдельности — посетитель почти никогда не остаётся совсем без поиска.
- Публичный ИИ-эндпоинт защищается слоями. Кэш гасит повторы, потолок бережёт бюджет, лимит и капча — абьюз. И главное — наружу не уходит 5xx из-за модели.
- Диагностика обманчива. «Поиск не находит ничего» выглядело как пустой индекс, а корнем была политика безопасности, блокировавшая WebAssembly. Не маскируйте ошибки в клиенте — это съедает часы на ложный след.
Ссылки
- LightRAG vs RAG vs GraphRAG: какой выбрать для документации компании — про сам движок базы знаний
- Как мы делали этот сайт: Astro, LightRAG, 152-ФЗ — стек и подход к этому сайту
- Канал поддержки в MAX: AI-первая линия — та же AI-первая линия в мессенджере
Хотите такой же ИИ-поиск по своей базе знаний — на сайте, в поддержке или внутри продукта? Напишите нам, обсудим под ваш контент и требования.