Прямой ответ
RAG (retrieval-augmented generation) — это «сначала найдём релевантные фрагменты ваших документов, потом дадим их модели как контекст». Полностью локальная версия на ноутбуке собирается из четырёх компонентов, и все они бесплатны:
- Эмбеддинг-модель — превращает текст в векторы (например,
nomic-embed-textчерез Ollama илиbge-m3через sentence-transformers): ~0,3–1,5 ГБ RAM. - Векторная база — хранит и ищет векторы: Chroma (проще всего), Qdrant (масштабируемее) или FAISS (библиотека без сервера).
- Локальная LLM для генерации ответа — та же Ollama (7–8B Q4).
- Оркестрация — Python-скрипт или LlamaIndex/LangChain.
Ресурсы: для базы на 10–50 тыс. документов достаточно 16 ГБ ОЗУ без дискретной GPU; эмбеддинги считаются на CPU приемлемо быстро (сотни страниц в минуту).
Требования к железу: считаем честно
- Векторы почти не требуют памяти. 100 000 фрагментов × 768 измерений × 4 байта ≈ 300 МБ. Векторная база — не узкое место даже на ноутбуке.
- Память ест LLM. Ответы генерирует чат-модель: 7–8B Q4 — это 5–6 ГБ. Расчёт VRAM/RAM — в статье про Ollama и LM Studio.
- Индексация документов (первичный прогон эмбеддингов) — разовая операция: CPU справляется, GPU ускоряет в разы, если есть.
- Диск: исходные документы + индексы обычно вдвое больше самой базы документов; NVMe ускоряет холодный старт.
Практический вывод: RAG-стек повторяет требования локального чата (+1–2 ГБ на векторную базу), а не требования обучения моделей.
Шаг 1. Эмбеддинги локально
Простейший путь — через Ollama:
ollama pull nomic-embed-text # ~275 МБ, 768 измерений
import requests
def embed(text: str) -> list[float]:
r = requests.post("",
json={"model": "nomic-embed-text", "input": text})
return r.json()["embeddings"][0]
Альтернатива — sentence-transformers с моделями семейства BGE (bge-small-ru для русского, bge-m3 для мультиязычности): работает полностью офлайн, качество для русского текста у специализированных RU-моделей выше.
Шаг 2. Векторная база: Chroma или Qdrant
Chroma — минимум кода, хранение в локальной папке:
import chromadb
client = chromadb.PersistentClient(path="./chroma_db")
col = client.get_or_create_collection("docs")
col.add(ids=["d1"], documents=["текст..."], embeddings=[embed("текст...")])
res = col.query(query_embeddings=[embed("запрос")], n_results=5)
Qdrant — отдельный сервис (удобно в Docker), фильтрация по метаданным, лучше на больших объёмах. FAISS — когда база это просто индекс в памяти процесса, без сервера.
Выбор для ноутбука: до ~100 тыс. фрагментов — Chroma; больше или нужны сложные фильтры — Qdrant.
Шаг 3. Чанкинг — важнее, чем кажется
Качество RAG на 70% определяется нарезкой документов:
- Фрагменты 500–1000 символов с перекрытием 10–15% — стартовая точка.
- Режьте по смысловым границам (абзацы, заголовки markdown), а не по символам.
- В каждый фрагмент добавляйте контекст: заголовок раздела, имя файла — это заметно улучшает поиск.
- Таблицы и код не режьте пополам: отдельный фрагмент целиком.
Шаг 4. Сборка ответа
Классический цикл: запрос → эмбеддинг → топ-5 фрагментов из базы → промпт «ответь, используя только контекст: {фрагменты}» → локальная LLM. Готовые обёртки: LlamaIndex (llama_index + OllamaEmbedding/Ollama) или LangChain — обе работают с Ollama из коробки и не отправляют данные наружу.
Критичное правило приватности: весь цикл должен оставаться локальным. Проверьте, что в коде нет облачных API-ключей (OpenAI, Cohere) — популярная случайная утечка в туториалах, где локальным заявлен только чат.
Мини-пайплайн целиком: 20 строк на Python
Скелет рабочего локального RAG без фреймворков — удобно, чтобы понять механику:
import chromadb, requests, json
def embed(text):
r = requests.post("",
json={"model": "nomic-embed-text", "input": text})
return r.json()["embeddings"][0]
def ask(question, db, col):
found = db.get_collection(col).query(
query_embeddings=[embed(question)], n_results=4)
ctx = "\n---\n".join(found["documents"][0])
r = requests.post("",
json={"model": "llama3.1:8b", "stream": False,
"prompt": f"Ответь только по контексту.\nКонтекст:\n{ctx}\n\nВопрос: {question}"})
return json.loads(r.text)["response"]
Индексация — цикл col.add() по фрагментам с идентификатором файл:номер_чанка. Для продакшена добавьте LlamaIndex: он берёт на себя загрузчики форматов (PDF, DOCX, HTML), чанкинг и кэш эмбеддингов.
Оценка качества: как понять, что RAG работает
Три быстрых проверки перед тем, как доверять системе:
- Retrieval-тест: возьмите 10 вопросов с известными ответами в базе и проверьте, попадает ли нужный фрагмент в топ-4. Попадание ниже 8/10 — правьте чанкинг и эмбеддинги, а не промпт.
- Проверка на «нет ответа»: задайте вопрос, которого в базе нет — корректная система отвечает «в документах этого нет», а не фантазирует.
- Цитируемость: просите модель указывать идентификатор фрагмента — ответы без ссылок трудно проверять.
Логируйте вопросы и найденные фрагменты в файл: через неделю вы увидите системные провалы (например, все ошибки — на таблицах) и почините именно их.
Ограничения, о которых честно предупреждаем
- Качество 7–8B-модели ограничено: она хуже фронтирных моделей следует инструкциям и чаще «додумывает». Помогает строгий промпт и
n_resultsс запасом. - Эмбеддинги не решают всё: точные совпадения (артикулы, коды ошибок) ищите гибридно — вектор + полнотекстовый поиск (BM25).
- Обновление базы: при изменении документов переиндексация обязательна; заведите привычку хранить хэш документа в метаданных.
- PDF-парсинг — отдельная боль: сканы требуют OCR, таблицы ломаются; для технических документов надёжнее markdown/текстовые источники.
Для аналитиков, у которых «документы» — это витрины и отчёты, RAG дополняет, а не заменяет SQL: связка «SQL к данным + RAG к регламентам» описана в материале про стек Power BI/SQL/Pandas.
Приватность: что именно остаётся на устройстве
Проверьте свой стек по списку: документы не покидают диск (индексация локальная), эмбеддинги считаются локальной моделью (Ollama/sentence-transformers, а не API OpenAI), векторная база лежит в папке проекта (Chroma) или в локальном контейнере (Qdrant), генерация идёт через локальную LLM. Если все четыре пункта выполнены — запросы не уходят в интернет физически; это единственная схема, допустимая для конфиденциальных договоров, медицинских и персональных данных без отдельного согласия. Быстрая самопроверка: отключите Wi-Fi и повторите типовой запрос — рабочий локальный RAG этого не заметит.
FAQ
Хватит ли 16 ГБ без видеокарты? Да: эмбеддинги на CPU, LLM 7–8B Q4 на CPU (медленно, 3–8 ток/с, но приватно), векторная база почти бесплатна по памяти.
Можно ли держать базу в облаке, а модель локально? Можно, но тогда приватность определяется облачным провайдером векторной БД. Полностью локальная схема — Chroma/Qdrant на своём диске.
Какой размер базы имеет смысл для RAG? От нескольких десятков документов (регламенты проекта) до сотен тысяч фрагментов — на ноутбуке оба сценария рабочи; разница только во времени индексации.
Нужен ли GPU? Для инференса 7–8B — желателен, но не обязателен. Для переиндексации больших библиотек GPU экономит часы; требования — в статье про PyTorch и CUDA.
Источники: документация Chroma, Qdrant, FAISS и Ollama (ссылки в шапке).