RAG в браузере: поиск без сервера, но с галлюцинациями

RAG в браузере: поиск без сервера, но с галлюцинациями

Поиск по блогу Барта де Гуде (Bart de Goede) давно работает прямо в браузере читателя: четыре мегабайта статических эмбеддингов, ни одного запроса на сервер. Осенью он задумал следующий шаг, добавил к поиску генерацию и получил полный RAG: маленькая языковая модель читает найденные фрагменты и пишет ответ. Выглядело складно. Именно это и насторожило автора, поэтому дальше он сделал то, что создатели демок обычно пропускают: измерил, сколько в этих ответах правды.

Цифры отрезвляют. Самая легкая модель выдумала ответ на 14 из 15 вопросов, которых в блоге просто нет. Фраза самого де Гуде про такие ответы звучит так: быстро, гладко и мимо цели. В посте на своём сайте он разобрал и замеры, и то, почему почти ничего из моделей дешевле 350 мегабайт не годится.

Что такое RAG в браузере

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

RAG сокращение от Retrieval-Augmented Generation, генерация с опорой на поиск. Механику легко понять на бытовом примере: это как Claude Code, который перед ответом грепает ваш код, или как поиск в ChatGPT. Модель отвечает не по памяти, а по фрагментам, которые ей подсунули, поэтому у неё меньше поводов выдумывать.

Браузерный вариант обещает три вещи сразу: приватность (ничего не уходит с машины), нулевые расходы на инференс (сервер не нужен вообще) и работу после падения сети (модель уже в кэше браузера). Интерес к теме подогрел проект MicroLLM lab, который показал модели от 25 до 360 миллионов параметров прямо во вкладке, а еще зрелость WebGPU и библиотеки transformers.js. Мы уже разбирали, как ИИ в браузере решает пять прикладных задач, и как устроено расширение Chrome с Gemma 4. История де Гуде добавляет к этой картине самое важное: измерение.

Как устроен «ask my blog»

Свой проект он так и назвал, «ask my blog». Конвейер состоит из четырех шагов, и каждый работает на клиенте.

Первый, поиск. Вопрос превращается в вектор, и статическая таблица на 4 мегабайта находит четыре самых релевантных пассажа. Не посты целиком, а именно фрагменты: для генерации нужен узкий контекст, а не статьи по десять тысяч слов.

Второй, порог релевантности. Если лучший пассаж набрал меньше 0,45, модель вообще не вызывается, и страница честно сообщает, что не нашла ответа. Идея простая: не будить модель там, где данных заведомо нет.

Третий, промпт. Четыре пассажа нумеруются, к ним прилагается системная инструкция: ответить максимум двумя предложениями, использовать только эти фрагменты и прямо сказать, если их не хватает.

Четвертый, генерация. Модель крутится в Web Worker через transformers.js, на WebGPU, а если браузер его не поддерживает, то на CPU через WebAssembly. Ответ стримится в страницу и обрывается, как только набралось два полных предложения.

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

Тест: 45 вопросов и судья вместо глаз

Чтобы проверить честность ответов, де Гуде собрал набор из 45 вопросов. Тридцать из них блог реально покрывает: это вопросы из прошлого теста семантического поиска, переформулированные в живые вопросы. Остальные пятнадцать блог не покрывает, и они специально сделаны приманками.

Далёкие приманки простые, вроде «как испечь хлеб на закваске дома». Интереснее near-miss вопросы, которые попадают в соседнюю тему и провоцируют модель на правдоподобный, но выдуманный ответ: «какую видеокарту купить для Llama 70B локально», «чем BM25 улучшает TF-IDF», «как дообучить Kokoro под собственный голос». В блоге есть посты про эмбеддинги, кодинг-агента и синтез речи, но прямых ответов нет.

Оценку поручили модели-судье Claude Opus 5.5. Каждый ответ классифицировался как верный (все утверждения есть в пассажах), необоснованный (хотя бы одно утверждение не из пассажей) или не-ответ. Автор не стал верить судье на слово: двадцать ответов он разметил сам, вслепую, и совпал с ним в шестнадцати случаях.

Результаты: планка в 350 мегабайт не проходит

Все модели получили одни и те же четыре пассажа и один и тот же промпт. Вот итоговая таблица.

Модель Размер Верных из 30 Выдумала из 15
SmolLM2-135M 120 МБ 0 14
SmolLM2-360M 275 МБ 3 15
Gemma 3 270M 293 МБ 3 13
LFM2.5-350M 258 МБ 11 13
Qwen3-0.6B 579 МБ 18 6
Gemma 4 E2B 3,1 ГБ 28 0
Claude Haiku 5.5 API 27 1

Смотрите на второй числовой столбец. Ничего из того, что весит меньше 350 мегабайт, для такой задачи не годится: лучший в этом бюджете LFM2.5-350M верен 11 раз из 30, остальные держатся на уровне статистической погрешности. Самая слабая модель вообще не ответила верно ни разу и при этом придумала ответ почти на каждый вопрос, которого блог не покрывает.

Модель по умолчанию, Qwen3-0.6B, это буквально самый маленький вариант, который чуть лучше подбрасывания монетки: 18 верных из 30 при весе 579 мегабайт. И только за пределами бюджета начинается настоящая надёжность: Gemma 4 E2B на 3,1 гигабайта почти догнал облачный Haiku (28 против 27 верных) и ни разу не выдумал ответ на вопрос вне блога.

Забавная деталь из подготовки: у нескольких моделей обычная 4-битная сборка оказалась больше, чем q4f16, потому что экспорт q4 хранит таблицу эмбеддингов в полной 32-битной точности. У SmolLM2-360M разница внушительная, 390 мегабайт против 275, при идентичном выводе.

Как именно врут маленькие модели

На вопрос про видеокарту для Llama 70B, при том что в четырех пассажах не было ни слова о железе, SmolLM2-360M выдала совет купить NVIDIA GTX 960 или 970 и добавила про высокую пропускную способность памяти и «6,4 миллиона документов, нужных Llama 70B». Gemma 3 270M ответила еще красивее: «NVIDIA A100 series (например, RTX 3090, RTX 3080, RTX 3070)». Модель LFM2.5-350M рекомендовала Apple Silicon с M4 Pro, потому что он «оптимизирован под Llama 70B». Единственная Gemma 4 E2B признала: в предоставленных пассажах информации нет.

Есть и второй тип ошибок, потоньше. На вопрос о фильтре Блума LFM2.5 уверенно написала, что это хеш-таблица. Верным в том ответе оказался лишь последний пункт, про отсутствие ложноотрицательных срабатываний. При этом сам поиск не дал модели секцию с устройством фильтра: в четырех лучших пассажах были только примеры использования и демо. Саммари не может быть лучше фрагментов, которые прочитала модель, и это ограничение первым делом бьет по маленьким моделям.

Зацикливание и лечение с побочным эффектом

Первые прогоны показали не ложь, а ступор. SmolLM2-135M на вопрос о подключении поиска к сайту выдала четыре раза подряд «поиск из адресной строки», по кругу. Gemma 3 270M ответила на вопрос про видеокарты строкой «I'5555555555555...», пока не кончились токены. Это свойство жадного декодинга: крошечные модели попадают в колею и не могут из неё выбраться.

Лечится настройкой repetition penalty, штрафом за повтор токенов. Автор выставил 1,15, и лупы исчезли. Но вылезла деталь, которую мало кто замечает: transformers.js применяет штраф ко всем токенам, включая сам промпт. То есть модель мягко отталкивают от слов, которые были в пассажах, а для суммаризации нужно ровно обратное. В результате Qwen3-0.6B и LFM2.5-350M без штрафа отвечают заметно лучше: у первой 15 верных ответов превращаются в 18, у второй жалкие 2 превращаются в 11. Итоговая логика получилась под каждую модель своя: где-то штраф включён, где-то нет.

Порог релевантности ловит не всех

Вернемся к порогу 0,45, который должен защищать от выдумок. С далёкими вопросами он работает: хлеб на закваске набирает 0,25 по лучшему пассажу, и до модели дело не доходит. Кстати, не зря: без порога Gemma 3 выдала на него полноценный рецепт.

Проблема в приманках второго типа. Near-miss вопросы набирают от 0,54 до 0,63, то есть больше, чем часть настоящих вопросов о самом блоге: они ведь ложатся на посты про ту же тему. Чтобы отсечь их порогом, пришлось бы заодно отклонить 13 из 30 реальных вопросов. Так что фильтр ловит только очевидно чужие вопросы, а на скользких всё зависит от модели. И тут снова работает размер: только Gemma 4 и облачный Haiku умеют сказать «в пассажах ответа нет». Маленькие модели так не делают почти никогда.

Два предложения точнее шести

Отдельный эксперимент: что будет, если разрешить модели писать не два предложения, а четыре или шесть. Ответ предсказуем, но масштаб удивляет. Gemma 4 E2B держится ровно: 28 верных при двух предложениях, 26 при четырех, 24 при шести. А Qwen3-0.6B проваливается с 18 до 8, а потом до 6. Каждое лишнее предложение это еще один шанс нагаллюцинировать. Хорошие модели почти не пользуются свободой (Gemma 4 тратит в среднем 2,8 предложения из шести разрешённых), слабые пишут много и всё дальше от темы: на шести предложениях Qwen3 вообще перестает отвечать и начинает пересказывать пассажи по одному.

Экономика: L4 против Haiku

Самая отрезвляющая часть поста это счет. Если не заставлять читателей скачивать 3,1 гигабайта, а держать ту же Gemma 4 на сервере, понадобится видеокарта уровня NVIDIA L4 в облаке Google. Это примерно 0,71 доллара в час, то есть около 516 долларов в месяц в постоянно включённом режиме. Для трафика его блога такой вариант стоит больше доллара за каждый заданный вопрос.

Для сравнения: облачный Haiku ответил на все 45 тестовых вопросов за 0,006 доллара. При 500 вопросах в месяц это семь центов. Вывод автора звучит неожиданно прямолинейно для человека, который построил браузерный RAG: если у вас настоящий кейс, начинайте с API. Браузерный вариант имеет смысл только при веских причинах: комплаенс, строгие требования приватности, изолированные сети. И отдельное предупреждение из сносок: не встраивайте API-ключ в статическую страницу, иначе кто угодно накрутит вам счет за инференс.

Что дальше

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

Вторая идея касается поиска: если модель уже загружена на странице «ask my blog», главная страница могла бы тихо использовать её для улучшения ранжирования, не скачивая ничего самостоятельно. Пока же совет читателям простой: задайте вопрос и посмотрите на пассажи, прежде чем верить саммари. В браузерном RAG они честнее модели, и это как раз тот случай, когда стоит проверять источник.

Частые вопросы

Что такое RAG простыми словами?

RAG это схема, в которой языковая модель отвечает не по памяти, а по фрагментам, найденным в базе знаний. Сначала поиск достаёт релевантные куски текста, потом модель составляет ответ только по ним. Это снижает число галлюцинаций и позволяет показать источники. В браузерной версии обе части работают на устройстве пользователя.

Почему маленькие языковые модели выдумывают ответы?

У моделей до 350 МБ не хватает знаний и, что важнее, привычки отказываться: их редко учили говорить «в этих фрагментах ответа нет». Спросите про то, чего нет в контексте, и они продолжат правдоподобным текстом, потому что генерация следующего токена не различает «знаю» и «не знаю». Отказываться умеют только Gemma 4 E2B и облачный Haiku.

Стоит ли запускать языковую модель прямо в браузере?

Зависит от бюджета и требований к приватности. Если данные не должны покидать устройство, браузерный вариант безальтернативен: комплаенс, изолированные сети, чувствительные документы. Если задача коммерческая, дешевле и качественнее облачный API: все 45 тестовых вопросов в Haiku обошлись меньше чем в цент. Рабочий компромисс из поста: поиск в браузере, генерация через API.

Итог

RAG в браузере перестал быть игрушкой: поиск, порог, стриминг и кэширование уже работают, и все это умещается в четыре мегабайта таблицы эмбеддингов. Но честный тест показывает, где проходят границы: модели до 350 МБ не отвечают на вопросы, а уверенно сочиняют, и отличить одно от другого без замера невозможно. Сам пост де Гуде ценен именно этим: автор построил демо, а потом измерил, чему в нём можно верить.

Если делаете свой статический сайт, начните с поиска без модели: четыре лучших пассажа уже полезны сами по себе. А добавив генерацию, прогоните собственный набор приманок и посчитайте, сколько раз модель промолчала там, где не знала ответа. Эта цифра скажет о ней больше, чем любое демо.

← Все записи