RAG (Retrieval-Augmented Generation) — это паттерн, при котором LLM получает релевантный контекст из вашей базы знаний прежде, чем формулировать ответ. Это то, как ChatGPT с подключёнными документами, Notion AI и большинство B2B-чатботов на нейросетях знают вашу специфику. Под капотом — embeddings (текст превращается в вектор), векторная БД (хранит и ищет векторы по похожести), и LLM (получает топ-k найденных кусков и отвечает).
В этом гайде — полный стек 2026 для русскоязычных проектов через единый шлюз Promptra: модели embeddings (OpenAI text-embedding-3, Cohere v3, Voyage 3), векторные БД (pgvector, Qdrant, Chroma), стратегии chunking, hybrid search, и метрики оценки качества retrieval. Цены в рублях по курсу ЦБ, оплата в рублях по договору, полный пакет закрывающих документов.
TL;DR — RAG-стек за 5 компонентов
- Chunking — режем документы на куски 500–1500 токенов с overlap или по семантическим границам.
- Embedding — превращаем каждый chunk в вектор 1024–3072 dim через embeddings модель.
- Vector DB — храним векторы с metadata в Qdrant или pgvector, индекс HNSW для быстрого поиска.
- Retrieval — на запрос пользователя считаем его embedding, ищем топ-k ближайших векторов (cosine similarity).
- Generation — отдаём найденные chunks как контекст в LLM (Claude Opus 4.7 / GPT-5.5 / Gemini 3.1 Pro), модель отвечает. Эта статья — часть pillar-гида: полный технический гид по LLM API на Python — токены, function calling, streaming, RAG, batch.
С hybrid search и rerank качество retrieve в 2 раза выше чем у чистого vector search.
Шаг 1. Embeddings — какую модель выбрать
Embedding-модель превращает текст в вектор фиксированной длины. Близкие по смыслу тексты получают близкие векторы (по cosine similarity). От качества embeddings зависит всё — никакой LLM не спасёт, если retrieve вернул нерелевантные куски.
Топ-модели 2026 для русского языка:
| Модель | Dim | Контекст | Цена $/1M | Сильные стороны |
|---|---|---|---|---|
| OpenAI text-embedding-3-large | 3072 | 8K | $0.13 | Флагман, Matryoshka (можно урезать) |
| OpenAI text-embedding-3-small | 1536 | 8K | $0.02 | Дёшево, baseline, RU adequate |
| Cohere embed-multilingual-v3.0 | 1024 | 512 | $0.10 | Лучше всех на multilingual задачах |
| Voyage 3 | 1024 | 32K | $0.06 | Premium качество для retrieval |
| Qwen-embed-v2 | 1024 | 8K | $0.05 | Сильная альтернатива на русском |
Через Promptra все доступны по OpenAI-совместимому endpoint'у — меняется только model:
from openai import OpenAI
client = OpenAI(
api_key="sk-promptra-...",
base_url="https://api.promptra.ru/v1",
)
response = client.embeddings.create(
model="text-embedding-3-large",
input=["Текст первого документа.", "Текст второго документа."],
encoding_format="float",
)
vectors = [d.embedding for d in response.data]
print(f"Получили {len(vectors)} векторов размерности {len(vectors[0])}")Подробное сравнение моделей и цен — в материале «Embeddings API из России». Спецификация OpenAI embeddings — в официальном гайде; подробности Voyage 3 — на сайте Voyage AI.

Шаг 2. Chunking — стратегии разбиения
Документы редко помещаются в один вектор. Нужно разбить на куски (chunks) такого размера, чтобы каждый был семантически целостным и помещался в контекст embedding-модели.
Fixed-size с overlap — baseline
Самый простой подход: режем по N символов с overlap M:
def fixed_chunks(text: str, size: int = 800, overlap: int = 150) -> list[str]:
chunks = []
start = 0
while start < len(text):
end = min(start + size, len(text))
chunks.append(text[start:end])
start += size - overlap
return chunksРаботает, но режет посреди предложений. Качество retrieve среднее.
Semantic chunking — по предложениям/параграфам
Используем nltk или spacy для разбиения на предложения, потом собираем чанки до целевого размера:
from nltk.tokenize import sent_tokenize
def semantic_chunks(text: str, target_size: int = 800, overlap_sentences: int = 2) -> list[str]:
sentences = sent_tokenize(text, language="russian")
chunks = []
current = []
current_size = 0
for sent in sentences:
if current_size + len(sent) > target_size and current:
chunks.append(" ".join(current))
# overlap: берём последние N предложений в следующий chunk
current = current[-overlap_sentences:]
current_size = sum(len(s) for s in current)
current.append(sent)
current_size += len(sent)
if current:
chunks.append(" ".join(current))
return chunksКачество retrieve существенно выше — куски всегда целые.
Hierarchical chunking — лучший на 2026
Идея: индексируем мелкие chunks (для точного поиска), а возвращаем родительские (для богатого контекста):
from dataclasses import dataclass
@dataclass
class HierarchicalChunk:
child_text: str # 200-400 токенов — для embedding и поиска
parent_text: str # 1500-2000 токенов — отдаём в LLM
parent_id: str
child_id: str
def hierarchical_chunks(text: str) -> list[HierarchicalChunk]:
parents = semantic_chunks(text, target_size=2000, overlap_sentences=0)
result = []
for p_idx, parent in enumerate(parents):
children = semantic_chunks(parent, target_size=350, overlap_sentences=1)
for c_idx, child in enumerate(children):
result.append(HierarchicalChunk(
child_text=child,
parent_text=parent,
parent_id=f"p{p_idx}",
child_id=f"p{p_idx}-c{c_idx}",
))
return resultЭто побеждает на 90% задач — точность поиска от маленьких chunks, богатство контекста от больших. Для технических доков — chunking по заголовкам markdown. Для кода — по функциям/классам. Для диалогов — по поворотам.

Шаг 3. Векторная БД — pgvector / Qdrant / Chroma
Сохраняем векторы вместе с metadata (id, source, chunk_text) и ищем по cosine similarity.
pgvector — если у вас уже Postgres
CREATE EXTENSION vector;
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
source TEXT NOT NULL,
chunk_text TEXT NOT NULL,
parent_text TEXT,
embedding VECTOR(1024) -- размерность под Voyage 3 / Cohere
);
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);Запрос top-k:
SELECT id, chunk_text, parent_text, embedding <=> $1 AS distance
FROM documents
ORDER BY embedding <=> $1
LIMIT 10;Из Python через psycopg или asyncpg. Плюс: ACID, обычные SQL-бэкапы, JOIN с реляционными данными. Минус: на сотнях миллионов векторов производительность падает — для такого масштаба нужен Qdrant.
Qdrant — production-grade open-source
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance, PointStruct
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
collection_name="docs",
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
# upsert
points = [
PointStruct(
id=i,
vector=vector,
payload={"source": doc.source, "chunk_text": doc.text, "parent_text": doc.parent},
)
for i, (vector, doc) in enumerate(zip(vectors, chunks))
]
client.upsert(collection_name="docs", points=points)
# search
hits = client.search(
collection_name="docs",
query_vector=query_vector,
limit=10,
query_filter=Filter(must=[FieldCondition(key="source", match=MatchValue(value="manual"))]),
)Qdrant — российская команда, доступен on-prem, до сотен миллионов векторов, фильтрация по metadata из коробки, hybrid search встроенный.
Chroma — для прототипирования
import chromadb
client = chromadb.PersistentClient(path="./chroma_data")
collection = client.create_collection("docs")
collection.add(
embeddings=vectors,
documents=[c.text for c in chunks],
metadatas=[{"source": c.source} for c in chunks],
ids=[c.id for c in chunks],
)
results = collection.query(
query_embeddings=[query_vector],
n_results=10,
)Единственная зависимость pip install chromadb, in-memory или file-based. Для прода с серьёзным трафиком не годится.
Шаг 4. Hybrid search — vector + BM25
Чистый vector search проигрывает на точных совпадениях имён, кодов, дат. Hybrid комбинирует semantic + keyword:
# В Qdrant — встроенный hybrid через named vectors
from qdrant_client.models import Prefetch, FusionQuery, Fusion
results = client.query_points(
collection_name="docs",
prefetch=[
Prefetch(query=dense_query_vector, using="dense", limit=20),
Prefetch(query=sparse_query_vector, using="bm25", limit=20),
],
query=FusionQuery(fusion=Fusion.RRF), # Reciprocal Rank Fusion
limit=10,
)RRF (Reciprocal Rank Fusion) — стандартный способ объединять списки. Формула: score = sum(1 / (k + rank_i)), где k обычно 60. Документ, который попал в топ обоих списков — получает больший score, чем тот, что в топе только одного.
Качество retrieve на технических документах с hybrid обычно растёт на 10–20% Recall@10.

Шаг 5. Rerank — последний штрих качества
Поверх hybrid search ставится reranker: модель, которая для каждой пары (query, chunk) даёт точный relevance score. Это дорого (один inference на каждый retrieved chunk), но даёт лучший top-10 из retrieved 50–100.
Топ-модели rerank:
- Cohere rerank-multilingual-v3.0 — production-grade, низкая latency, ~$2 за 1M запросов
- Voyage rerank-2 — premium качество, ~$3 за 1M
- BGE-reranker-v2-m3 — open-source, можно self-host
# через Cohere SDK поверх обычного retrieve
retrieved = vector_search(query, k=50)
rerank_response = cohere_client.rerank(
query=query,
documents=[r.text for r in retrieved],
top_n=10,
model="rerank-multilingual-v3.0",
)
final = [retrieved[r.index] for r in rerank_response.results]Recall@10 после rerank обычно +15–25% над hybrid. Совокупный uplift embedding → +chunking → +hybrid → +rerank — это разница между «работает терпимо» и «работает отлично».
Шаг 6. Generation — отдаём контекст в LLM
Финальный шаг — собираем prompt и вызываем LLM:
def rag_answer(query: str, retrieved_chunks: list[str], model: str = "claude-opus-4-7") -> str:
context = "\n\n---\n\n".join(retrieved_chunks)
system = (
"Ты — ассистент по технической документации. "
"Отвечай ТОЛЬКО на основе предоставленного контекста. "
"Если в контексте нет ответа — скажи 'В документации нет ответа на этот вопрос'. "
"Не выдумывай факты."
)
user = f"Контекст:\n{context}\n\nВопрос: {query}\n\nОтветь подробно."
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user},
],
)
return response.choices[0].message.contentЧто важно:
- Жёсткий system message — заставляет модель не выдумывать вне контекста. Это снижает галлюцинации.
- Указание источников — попросите модель отдавать
[source_1]-references на куски, это даёт пользователю верификацию. - Длина контекста vs стоимость — каждый retrieved chunk это input-токены. На Opus 4.7 (350 ₽ за 1M input) 10 chunks по 1500 токенов = 15K токенов = 5.25 ₽ на запрос. Если запросов 100K в месяц — 525K ₽. Цены — в «Сравнение цен LLM 2026».
Для дешёвого RAG используют Gemini 3.1 Pro (140/860 ₽) или DeepSeek V4 Pro (30/60 ₽) на маленьких задачах. Для критичных продуктовых ответов — Opus 4.7 или GPT-5.5.
Evaluation — без неё это чёрный ящик
RAG нельзя выкатить в прод без замера качества. Минимальная eval:
- Соберите 50–200 пар
(query, ids_of_relevant_chunks)вручную или через LLM-as-judge. - Прогоните
query → embed → search → top-k, замерьте: - - Recall@k — доля релевантных, попавших в top-k. Цель Recall@10 > 0.85.
- - MRR — Mean Reciprocal Rank, насколько высоко стоит первый релевантный. Цель > 0.5.
- - NDCG@k — учитывает порядок результатов, премиум-метрика.
- Если ниже — меняйте модель embeddings, chunking, добавляйте rerank, тюньте hybrid weight.
Дополнительно — end-to-end eval: даёте LLM-судье (через тот же Opus 4.7 / GPT-5.5) пары (query, generated_answer, ground_truth), спрашиваете «насколько ответ точен и обоснован контекстом». Это позволяет ловить регрессии не только в retrieve, но и в формулировке.

Стоимость RAG на 1M документов
Пример экономики для базы 1M документов, средний размер 500 токенов, 10K запросов в день:
| Статья | Расчёт | Сумма |
|---|---|---|
| Embedding индексации | 500M токенов × $0.06 (Voyage 3) | ~430K ₽ разово |
| Vector DB | Qdrant on-prem (4 vCPU, 32GB RAM) | ~25K ₽/мес |
| Embedding запросов | 10K × 50 токенов × 30 дней | ~650 ₽/мес |
| Rerank | 10K × 50 × 30 (Cohere v3) | ~6500 ₽/мес |
| LLM generation (Opus 4.7) | 10K × 15K input + 800 output | ~2.27 М ₽/мес |
| LLM на дешёвом (Gemini 3.1 Pro) | 10K × 15K input + 800 output | ~700K ₽/мес |
Главная статья — это LLM-generation. Если ответы не требуют флагмана — переход с Opus 4.7 на Gemini 3.1 Pro экономит 1.5 М ₽/мес. Через Promptra это смена model в одной строке.
Оплата и закрывающие документы
Все компоненты RAG-стека — embeddings, rerank, LLM generation — оплачиваются на юр.лицо российское юр.лицо, резидент РФ. Сервисная комиссия 5% берётся только при пополнении баланса, на токены наценки нет, цены строго по курсу ЦБ. Полный пакет закрывающих документов (договор-оферта, счёт на оплату, акт оказанных услуг, счёт-фактура, УПД) приходит через ЭДО — Диадок, СБИС, Контур. Подробнее — на странице «Тарифы».
Что дальше
RAG в 2026 — это не один запрос к LLM с приклеенным контекстом. Это связка: chunking → embedding → vector DB → hybrid search → rerank → generation, и evaluation поверх каждого слоя. С правильной архитектурой Recall@10 переваливает 0.9, end-to-end judge score выходит за 4.5/5, и продукт перестаёт галлюцинировать. Полезные следующие шаги: «Function calling и tool use» для агентов-аналитиков поверх RAG, «Async-вызовы и Batch API» для индексации больших баз и «Как считать токены в LLM» для расчёта стоимости context window. Если нужно подобрать модель под ваш RAG или подключить ключ через юрлицо — напишите команде Promptra в Telegram.
> 📚 Главный гайд по теме: Лучшая нейросеть 2026: какую LLM выбрать под задачу — связанные материалы и обзор всей категории.
FAQ
Какая модель embeddings лучше для русского языка в 2026?
По бенчмаркам хорошо работают Cohere embed-multilingual-v3.0 (1024 dim), Voyage 3 (1024 dim, premium), OpenAI text-embedding-3-large (3072 dim). Для дешёвых пайплайнов — text-embedding-3-small или Qwen-embed-v2. Разница в качестве — единицы процентов, выбирайте по цене-скорости-dimensions.
Какую векторную БД взять?
pgvector — если уже Postgres и до 5М векторов. Qdrant — production-grade, российская команда, до сотен миллионов векторов, hybrid из коробки. Chroma — только для прототипирования. Для прода в РФ — Qdrant или pgvector.
Какие стратегии chunking работают?
Hierarchical: parent 1500–2000 токенов индексируется по child 200–400, при retrieve возвращается parent. Побеждает на 90% задач. Также — semantic chunking по предложениям через nltk, для технических доков — chunking по заголовкам markdown.
Что такое hybrid search?
Комбинация семантического поиска (через embeddings) и keyword-поиска (BM25). Объединение через RRF (Reciprocal Rank Fusion). Качество retrieve растёт на 10–20% Recall@10. Qdrant поддерживает hybrid из коробки.
Сколько стоит embeddings для 1M документов?
Около 430K ₽ разовая индексация на Voyage 3. После индексации запросы дешёвые: один query embedding — 50 токенов. Главная статья — LLM-generation, выбор Opus 4.7 vs Gemini 3.1 Pro может разнести бюджет в 3 раза.
Как оценить качество retrieval?
Соберите 50–200 пар (query, relevant_chunks), замерьте Recall@k и MRR. Цель Recall@10 > 0.85, MRR > 0.5. Дополнительно — LLM-as-judge для end-to-end оценки точности и обоснованности ответов.

