Локальний RAG без векторів: SQLite FTS5 і BM25 для пошуку по коду
Чому щільні векторні індекси навантажують машину розробника і як SQLite FTS5 з BM25 дає швидший і точний пошук по коду за малої частки пам'яті.
Кілька років рецепт локального пошуку по коду був той самий: порізати репозиторій на фрагменти, перетворити кожен фрагмент на ембединг на 1536 вимірів і тримати індекс HNSW живим у фоновому процесі. Це здавалося сучасним, ніби в ноутбука з'явився маленький пошуковик, що розуміє зміст коду. Але на завантаженій робочій станції цей рецепт має ціну, про яку рідко пишуть у README.
Гучні цифри навколо локального векторного пошуку вражають: високі оцінки пошуку в MTEB, мільйони токенів коду, перетворені на ембединги за хвилини, «миттєвий семантичний інтелект» на споживчому залізі. Та якщо читати нотатки про пам'ять, а не маркетинг, картина інша. Щільна векторна індексація купує повноту видачі ціною пропускної здатності пам'яті, RAM або VRAM і передбачуваності.
Коли «вектори всюди» впираються в стіну пам'яті
Запустіть векторну базу поруч із локальною LLM, IDE і кількома Docker-контейнерами, і вона не простоюватиме. Вона тримає в RAM або VRAM великі графові структури, змагається з іншими інструментами за пропускну здатність і приносить семантичний дрейф: шукаєте точний рядок ERR_AUTH_EXPIRED, а отримуєте код, який лише якось стосується автентифікації.
Тому чимало команд тихо повертаються до нативних алгоритмів на C, а саме до SQLite FTS5 з BM25. Замість векторної математики для локальних запитів вони використовують детерміноване ранжування за частотою термінів і знаходять точні ідентифікатори швидше ніж за 5 мілісекунд.
Зіставлення понять проти передбачуваної швидкості
Це не дрібне налаштування. Це змінює те, як будуються інструменти для розробників. Замінивши локальні векторні накладні витрати на FTS5, ви відмовляєтеся від теоретичного зіставлення за змістом заради ощадного і швидкого виконання.
- Ефективність: відмова від щільної індексації звільняє гігабайти пам'яті. Робота, яка витрачала близько 200 мс на обчислення ембедингів, нативно завершується менш ніж за 5 мс.
- Точність: пошук точних ключових слів та імен функцій, наприклад
getUserById(), повністю детермінований, тож індекс не поверне тіла сторонніх функцій.
Два підходи порівнюються так:
[Dense Vector RAG Flow]
Code Query -> Generate Vector Embeddings -> HNSW Index Search -> Semantic Drift Risk -> LLM Context
[Deterministic BM25 Flow]
Code Query -> Native SQLite C-Index -> Exact Keyword Match (5ms) -> Minimal LLM Context
Симптоми, які ви, можливо, вже бачили
Кожен, хто запускає локальних агентів чи пошук по коду, напевно помічав тертя:
- Конкуренція за ресурси. Вентилятор розкручується, батареї вистачає на дві години, а локальний інференс ледве повзе, бо фоновий рушій відбирає пам'ять.
- Штраф за точний збіг. Пошук конкретного рядка помилки чи змінної повертає п'ять файлів, близьких до автентифікації за змістом, але не той єдиний файл, де є потрібний прапорець.
Порівняння пліч-о-пліч, з приблизними цифрами:
| Параметр | Локальна векторна БД (Chroma, Qdrant) | SQLite FTS5 (BM25) |
|---|---|---|
| Споживання пам'яті | Близько 1,5–4 ГБ RAM або VRAM | Близько 15–30 МБ RAM |
| Затримка пошуку | 120–400 мс, переважно на ембединги | Менше 5 мс, нативний C |
| Точний збіг ідентифікаторів | Слабкий, схильний до дрейфу | Сильний, детермінований збіг за ключовими словами |
| Системні накладні витрати | Фонові демони, прив'язки до C++ | У простої нічого не працює |
| Найкраще підходить для | Широкого тематичного пошуку по тексту | Точних запитів по коду, логах і локальному RAG |
Вважайте це орієнтовними цифрами: результати залежать від розміру корпусу, вибору моделі та заліза.
Що це означає для техлідів
Рефлекс під'єднувати векторну базу до кожної локальної задачі згасає. Корисніша звичка зберігати пропорції. Майстерність старшого архітектора не в тому, щоб втиснути важчу ШІ-інфраструктуру в ноутбуки розробників. Вона в тому, щоб зрозуміти, коли десять рядків нативного коду або SQLite-файл на 30 МБ кращі за нейронний конвеєр, що вимірюється гігабайтами.
У міру того як інструменти пришвидшуються, а процеси стають компактнішими, перемагатимуть не стеки з найбільшими моделями. Переможуть ті, що випускають чистий код без зайвої ваги. Це не робить ембединги марними: для нечітких питань на рівні понять у звичайному тексті вони й далі виправдані. Але щоб знайти точний ідентифікатор у кодовій базі, почніть із дешевого детермінованого інструмента і додавайте вектори лише там, де він не впорався.