🔍 RAG: поиск + генерация
Схема RAG, индексация, чанки, эмбеддинги, векторные БД, промпт и оценка качества.
Теория · ИИ · #rag #llm #embeddings #vector-db
Идея
RAG (Retrieval-Augmented Generation) добавляет в запрос к языковой модели найденные фрагменты ваших данных. Модель отвечает по ним, а не только по памяти: меньше выдумок, свежие и приватные знания без дообучения.
Схема
Документы → разбивка на чанки → эмбеддинги → векторная БД (индексация, один раз)
Вопрос → эмбеддинг → поиск ближайших чанков → промпт + чанки → LLM → ответ (запрос)
Этапы индексации
| Этап | Что делаем |
|---|---|
| Загрузка | PDF, HTML, Markdown, Confluence, БД, чаты |
| Очистка | убрать мусор, навигацию, дубли; сохранить структуру заголовков |
| Чанкинг | делим на куски 200–1000 токенов с перекрытием 10–20%, по границам абзацев и заголовков |
| Метаданные | источник, раздел, дата, права доступа |
| Эмбеддинги | вектор смысла (OpenAI, Cohere, BGE, E5, nomic-embed-text) |
| Хранение | векторная БД |
Векторные хранилища
pgvector (PostgreSQL), Qdrant, Weaviate, Milvus, Chroma, Pinecone, Elasticsearch / OpenSearch (kNN), Redis, FAISS (библиотека).
Поиск
| Приём | Зачем |
|---|---|
| Векторный (косинусная близость) | находит по смыслу |
| Ключевой BM25 | точные термины, артикулы, коды |
| Гибридный (вектор + BM25) | лучшее из двух, объединение через RRF |
| Фильтры по метаданным | права, продукт, версия |
| Реранкинг (cross-encoder, Cohere Rerank, bge-reranker) | переупорядочить топ-N по точной релевантности |
| Переписывание запроса | разворачивает «а он?» в самостоятельный вопрос |
| HyDE | сначала гипотетический ответ, поиск по нему |
Промпт генерации
Ты — помощник по документации. Отвечай ТОЛЬКО по фрагментам ниже.
Если ответа в них нет, скажи «В документах нет ответа».
Приводи ссылки на источники в формате [номер].
Фрагменты:
[1] <текст чанка> (источник: guide.md, раздел «Установка»)
[2] <текст чанка> (…)
Вопрос: <вопрос пользователя>
Минимальный пример (Python)
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer('intfloat/multilingual-e5-base')
chunks = ["Docker — платформа контейнеризации.", "Git — система контроля версий."]
vecs = model.encode(chunks, normalize_embeddings=True)
q = model.encode(["Что такое контейнеры?"], normalize_embeddings=True)
best = int(np.argmax(vecs @ q.T))
context = chunks[best] # дальше передать в LLM вместе с вопросом
Качество и оценка
| Метрика | Что проверяет |
|---|---|
| Recall@k, MRR | нашёл ли поиск нужный чанк |
| Faithfulness | ответ опирается на контекст |
| Answer relevance | ответ отвечает на вопрос |
| Context precision | нет ли лишнего в контексте |
Инструменты: Ragas, TruLens, LangSmith, Phoenix. Соберите набор 50–200 вопросов с эталонами и измеряйте после каждого изменения.
Типичные проблемы
| Симптом | Причина и решение |
|---|---|
| Ответ неточный | чанки слишком большие или маленькие; добавьте реранкер |
| «Не нашёл», хотя есть | нет гибридного поиска, плохие эмбеддинги для языка |
| Выдумки | усильте инструкцию «только по контексту», уменьшите температуру, требуйте цитаты |
| Устаревшее | обновление индекса по расписанию, дата в метаданных |
| Утечка данных | фильтры прав в поиске, а не только в интерфейсе |
RAG, дообучение или длинный контекст
RAG для часто меняющихся знаний со ссылками на источники. Дообучение для стиля, формата, узких задач. Длинный контекст для небольших документов, без индекса.