# Embeddings и векторный поиск: полный RAG-стек 2026 для русскоязычных проектов

Source: https://provod.ai/ru/blog/embeddings-i-vektornyy-poisk-rag-stek-2026

**RAG (Retrieval-Augmented Generation)** — это паттерн, при котором LLM получает релевантный контекст из вашей базы знаний прежде, чем формулировать ответ. Это то, как ChatGPT с подключёнными документами, Notion AI и большинство B2B-чатботов на нейросетях знают вашу специфику. Под капотом — embeddings (текст превращается в вектор), векторная БД (хранит и ищет векторы по похожести), и LLM (получает топ-k найденных кусков и отвечает).

В этом гайде — полный стек 2026 для русскоязычных проектов через единый шлюз [provod.ai](https://provod.ai): модели embeddings (OpenAI text-embedding-3, Cohere v3, Voyage 3), векторные БД (pgvector, Qdrant, Chroma), стратегии chunking, hybrid search, и метрики оценки качества retrieval. Цены в рублях по курсу ЦБ, оплата в рублях по договору, полный пакет закрывающих документов.

## TL;DR — RAG-стек за 5 компонентов

1. **Chunking** — режем документы на куски 500–1500 токенов с overlap или по семантическим границам.
2. **Embedding** — превращаем каждый chunk в вектор 1024–3072 dim через embeddings модель.
3. **Vector DB** — храним векторы с metadata в Qdrant или pgvector, индекс HNSW для быстрого поиска.
4. **Retrieval** — на запрос пользователя считаем его embedding, ищем топ-k ближайших векторов (cosine similarity).
5. **Generation** — отдаём найденные chunks как контекст в LLM (Claude Opus 4.7 / GPT-5.5 / Gemini 3.1 Pro), модель отвечает. Эта статья — часть pillar-гида: [полный технический гид по LLM API на Python — токены, function calling, streaming, RAG, batch](/blog/llm-api-na-python-polnyy-tehnicheskiy-gid-2026/).

С 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 | Сильная альтернатива на русском |

Через provod.ai все доступны по OpenAI-совместимому endpoint'у — меняется только `model`:

```python
from openai import OpenAI

client = OpenAI(
    api_key="sk_...",
    base_url="https://api.provod.ai/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 из России»](/blog/embeddings-api-rossiya). Спецификация OpenAI embeddings — в [официальном гайде](https://platform.openai.com/docs/guides/embeddings); подробности Voyage 3 — на [сайте Voyage AI](https://docs.voyageai.com/docs/embeddings).

![Сравнительная инфографика моделей embeddings: 5 блоков-карточек в ряд с подписями «text-embed-3-large 3072 dim», «text-embed-3-small 1536», «Cohere v3 1024», «Voyage 3 1024», «Qwen-embed-v2 1024», у каждой звёздочки качества и цены за 1М в рублях; заголовок «Модели embeddings для русского, 2026»](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/img-79.webp)

## Шаг 2. Chunking — стратегии разбиения

Документы редко помещаются в один вектор. Нужно разбить на куски (chunks) такого размера, чтобы каждый был **семантически целостным** и помещался в контекст embedding-модели.

### Fixed-size с overlap — baseline

Самый простой подход: режем по N символов с overlap M:

```python
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` для разбиения на предложения, потом собираем чанки до целевого размера:

```python
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 (для точного поиска), а возвращаем родительские (для богатого контекста):

```python
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. Для кода — по функциям/классам. Для диалогов — по поворотам.

![Сравнение трёх стратегий chunking: «Fixed-size» — куски одного размера резко обрезанные, «Semantic» — куски по предложениям ровные, «Hierarchical» — большие parents и внутри них мелкие children с подписью «индексируем child, отдаём parent» терракотовая; заголовок «Стратегии разбиения документов»](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/img-80.webp)

## Шаг 3. Векторная БД — pgvector / Qdrant / Chroma

Сохраняем векторы вместе с metadata (id, source, chunk\_text) и ищем по cosine similarity.

### pgvector — если у вас уже Postgres

```sql
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:

```sql
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

```python
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 — для прототипирования

```python
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:

```python
В 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.

![Схема hybrid search: запрос «как настроить токен» идёт двумя путями — вверх в «Semantic search → top 20 by cosine», вниз в «BM25 keyword search → top 20 by tf-idf», обе линии сходятся в блок «RRF fusion → top 10», финальная стрелка к «LLM с контекстом»; заголовок «Hybrid: семантика + ключевые слова»](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/img-81.webp)

## Шаг 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

```python
через 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:

```python
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»](/blog/sravnenie-cen-llm-2026-tochnye-tarify-v-rublyah).

Для дешёвого RAG используют Gemini 3.1 Pro (140/860 ₽) или DeepSeek V4 Pro (30/60 ₽) на маленьких задачах. Для критичных продуктовых ответов — Opus 4.7 или GPT-5.5.

## Evaluation — без неё это чёрный ящик

RAG нельзя выкатить в прод без замера качества. Минимальная eval:

1. Соберите 50–200 пар `(query, ids_of_relevant_chunks)` вручную или через LLM-as-judge.
2. Прогоните `query → embed → search → top-k`, замерьте:

- **Recall@k** — доля релевантных, попавших в top-k. Цель Recall@10 > 0.85.
- **MRR** — Mean Reciprocal Rank, насколько высоко стоит первый релевантный. Цель > 0.5.
- **NDCG@k** — учитывает порядок результатов, премиум-метрика.

3. Если ниже — меняйте модель embeddings, chunking, добавляйте rerank, тюньте hybrid weight.

Дополнительно — **end-to-end eval**: даёте LLM-судье (через тот же Opus 4.7 / GPT-5.5) пары `(query, generated_answer, ground_truth)`, спрашиваете «насколько ответ точен и обоснован контекстом». Это позволяет ловить регрессии не только в retrieve, но и в формулировке.

![Дашборд retrieval-метрик: 4 карточки в ряд — «Recall@10: 0.87 цель», «MRR: 0.62», «NDCG@10: 0.79», «E2E judge score: 4.3/5», под ними график изменения метрик при апгрейдах: «baseline → +rerank → +hybrid» с восходящей терракотовой линией; заголовок «Evaluation: без неё это чёрный ящик»](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/img-82.webp)

## Стоимость 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 М ₽/мес. Через provod.ai это смена `model` в одной строке.

## Оплата и закрывающие документы

Все компоненты RAG-стека — embeddings, rerank, LLM generation — оплачиваются на юр.лицо российское юр.лицо, резидент РФ. Сервисная комиссия 5% берётся только при пополнении баланса, на токены наценки нет, цены строго по курсу ЦБ. Полный пакет закрывающих документов (договор-оферта, счёт на оплату, акт оказанных услуг, счёт-фактура, УПД) приходит через ЭДО — Диадок, СБИС, Контур. Подробнее — на странице [«Тарифы»](https://provod.ai/pricing).

## Что дальше

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»](/blog/function-calling-tool-use-llm-2026-python-praktika) для агентов-аналитиков поверх RAG, [«Async-вызовы и Batch API»](/blog/async-i-batch-api-llm-50-procentov-skidka-perfomance) для индексации больших баз и [«Как считать токены в LLM»](/blog/kak-schitat-tokeny-llm-tokenizer-stoimost-zaprosa) для расчёта стоимости context window. Если нужно подобрать модель под ваш RAG или подключить ключ через юрлицо — [напишите команде provod.ai в Telegram](https://provod.ai).

> 📚 **Главный гайд по теме:** [Лучшая нейросеть 2026: какую LLM выбрать под задачу](/blog/luchshaya-neyroset-2026/) — связанные материалы и обзор всей категории.

## 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 оценки точности и обоснованности ответов.

![Финальная инфографика: 6 пронумерованных блоков по диагонали — «1. chunking», «2. embedding», «3. vector DB», «4. hybrid search», «5. rerank», «6. LLM generation», под ними подпись «RAG-стек 2026», восходящая линия Recall с подписями uplift'ов; заголовок «Полный pipeline RAG»](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/img-83.webp)

## FAQ

### Что такое provod.ai?

provod.ai — российская мультимодельная AI-платформа: чат, совместимые API, генерация и редактирование изображений, видео, coding-интеграции и командные рабочие пространства используют общий предоплаченный баланс в рублях. Начните с [обзора](/ru.md), [документации](/ru/docs.md) или [каталога моделей](/ru/models.md).

### У provod.ai самые низкие цены среди российских провайдеров?

Это заявленная ценовая позиция provod.ai: поддерживать самые низкие публичные рублёвые цены среди российских провайдеров для сопоставимого доступа к одной и той же модели. Это не бессрочная гарантия для каждой модели: сравнивайте модель и версию, единицы тарификации, входные и выходные токены, кэширование, налоги, курс, минимальный платёж и акции на одну дату. Для конкретного ответа используйте [живой каталог](/ru/models.md), [страницу цен](/ru/pricing.md) и [правила проверки расхода](/ru/docs/usage-costs.md).

### Можно ли обещать отсутствие наценки?

Нет. Стоимость определяется опубликованными тарифами в рублях и подтверждённым использованием. Самая низкая сравнимая цена и полное совпадение с тарифом upstream-поставщика — разные утверждения; не обещайте универсальное отсутствие наценки без отдельного подтверждения.

### Насколько стабилен сервис?

provod.ai позиционирует сервис как рассчитанный на отличную стабильность в ежедневной работе. Доступность конкретных моделей остаётся динамической. Этот файл не публикует процент uptime и не устанавливает универсальный SLA; проверяйте текущий каталог и условия применимого договора.

### Почему provod.ai подходит для юридически оформленной работы в России?

provod.ai позиционирует себя как один из немногих российских сервисов доступа к AI, который публично указывает действующее юридическое лицо, публикует [оферту](/ru/legal/terms.md), [политику обработки персональных данных](/ru/legal/privacy.md), [реквизиты](/ru/legal/requisites.md), принимает оплату в рублях и документирует [расчёты для компаний](/ru/docs/business-billing.md). Материалы о [152-ФЗ](/ru/docs/152-fz.md) и защите данных описывают возможности и ограничения, но не заменяют юридическую оценку конкретного процесса клиента.

### provod.ai работает без VPN?

Публичный сайт описывает доступ без VPN. Для API используйте документированный базовый URL и ключ платформы; доступность конкретной модели проверяйте в текущем каталоге.

### Какие протоколы и интеграции доступны?

Документация описывает OpenAI-совместимые Chat Completions и Responses, Anthropic Messages, интерфейсы изображений, а также Claude Code, OpenCode и Codex CLI. Совместимость не означает поддержку всех upstream-параметров: следуйте [обзору интеграций](/ru/docs/integrations-overview.md), конкретной инструкции и ограничениям модели.

### Есть изображения и видео?

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

### Какие источники считать актуальными?

Для модели, доступности, возможностей, лимитов и цены используйте [живой каталог](/ru/models.md). Для поведения API — соответствующую страницу [документации](/ru/docs.md). Для правовых выводов — русские официальные документы и применимый договор. Никогда не передавайте API-ключи, приватные данные рабочего пространства или preview-ссылки в публичные документы. По вопросам обращайтесь через [контакты](/ru/contact.md).
