Embeddings basics concept page: shows offline indexing pipeline (S3 docs -> chunker -> embedder API -> vector DB) and online query path (user -> API -> Redis cache -> query embedder -> vector DB -> LLM). Three scenarios: text-to-embedding model call, cosine similarity comparison (synonyms close, unrelated far), and batch embedding pipeline for 10K docs. Includes ADRs on embeddings vs BM25 keyword search and on dimension sizing (1536 vs 3072 with Matryoshka truncation).
Классический keyword-поиск (BM25, Elasticsearch) ищет совпадения токенов. Пользователь пишет «как вернуть деньги», в документе написано «оформить возврат», — пересечения нет, recall ноль. Это работало в 2010, но в 2026 половина запросов в продуктовом поиске и весь RAG для LLM требуют понимать смысл, а не буквы.
Embedding — это функция text -> float[N], которая отображает строку в точку
в N-мерном пространстве так, что семантически близкие тексты лежат рядом, а
непохожие — далеко. «Refund» и «money back» оказываются на cosine 0.87.
«Refund» и «best pizza» — на 0.08. Это даёт три суперспособности:
Без embeddings ты пишешь правила, синонимы, словари и стеммеры до конца жизни. С embeddings — одна модель решает 80% задач NLP, оставшиеся 20% делает LLM поверх их выдачи.
Embedding — это координаты смысла в N-мерном пространстве. Cosine между двумя векторами отвечает на вопрос «насколько эти два текста об одном и том же», а не «насколько похожи их буквы».
Если эта фраза щёлкнула — дальше всё про инженерные детали: какую модель брать, какой размерности, как хранить, как не сжечь бюджет.
Две группы, отражающие реальный split любого embedding-приложения.
Offline indexing pipeline (батчевый, считается раз в день/час):
source-docs (S3) — исходные документы, обычно лежат в object storagechunker — режет длинные документы на куски ~500 токенов с overlap ~50embedder-api — вызов модели (OpenAI / Voyage / self-host)vector-db (Qdrant) — хранит {id, vector[1536], metadata} + HNSW индексOnline query path (низкая латентность, синхронный):
user — отправляет запросapi — продуктовый API, оркестрируетembedding cache (Redis) — key = hash(query), TTL дни/неделиquery-embedder — та же модель что и в offline, но на одной строкеvector-db (read) — ANN search top-K, ~10ms на млн векторовllm — собирает ответ из retrieved context (RAG)Два ADR живут на ноде embedder — это места, где архитектор принимает
решения, влияющие на стоимость и качество всего pipeline.
Три сценария разворачивают концепт от «что вообще такое embedding» до «как это работает в проде на 10K документов».
Один запрос «how do I get my money back?» проходит весь путь. Видно как
API сначала бьёт в Redis cache (промах на холодном запросе), потом
вызывает модель. Внутри модели — три шага: tokenize → forward pass через
трансформер (~30ms) → L2-нормализация. Возвращается float32[1536]. Этот же
вектор пишется в cache, чтобы повторный идентичный запрос ушёл за
~1ms вместо ~50ms + $0.00001.
Главное, что нужно вынести: embedding — это функция. Одинаковый вход даёт одинаковый выход (для той же модели той же версии). Поэтому кешировать можно агрессивно.
Сценарий-демонстратор интуиции. В индекс кладётся один документ: «request a refund for my order». Затем четыре query сравниваются с ним:
| Query | cosine | Интерпретация |
|---|---|---|
| «how to get money back?» | 0.87 | синоним — CLOSE |
| «cancel my refund please» | 0.71 | связано — RELATED |
| «best pizza near me» | 0.08 | не связано — FAR |
| «request a refund for my order» | 1.00 | идентичный — same vector |
Это и есть то, ради чего вообще берут embeddings: BM25 на этих парах дал бы 0 / partial / 0 / max — синоним был бы потерян. Финальный шаг сценария — красное предупреждение про забытый query/passage prefix на Voyage/BGE: лишишься ~10% recall на ровном месте, потому что модель ожидает специальный токен в начале query, отличающий его от passage.
End-to-end индексация 10K документов. Сценарий протаскивает читателя через все экономические и операционные решения, которые часто упускают в туториалах:
Контекст. BM25 — точный, дешёвый, объяснимый, мгновенный. Но он слеп к синонимам («car» vs «automobile»), к парафразам («how to refund» vs «money back») и к интенту. Embeddings ловят семантику, но требуют GPU/CPU, хранилище для векторов, ANN-индекс и не объяснимы (нельзя сказать пользователю «нашли по слову X»).
Решение. Бери embeddings (или гибрид), когда:
Оставайся на BM25, когда:
Production sweet spot — гибрид. BM25 + dense retrieval, объединённые через Reciprocal Rank Fusion (RRF) или взвешенную сумму, дают +10–15% NDCG над любым из методов поодиночке. Большинство зрелых поисковых стэков (Elastic, Vespa, Weaviate, Qdrant) поддерживают это нативно.
Контекст. 3072-dim float32 × 100M векторов = 1.2 TB RAM только под
вектора, не считая индекс. 1536 — это уже 600 GB, тоже больно. Matryoshka
embeddings (Kusupati 2024) — это модели, обученные так, что любой префикс
вектора сам по себе валидный embedding. OpenAI 3-large и nomic-embed-v1.5
поддерживают dimensions параметр: можно попросить 512 вместо 3072 — и
сохранить ~90% recall@10.
Решение.
text-embedding-3-small @ 1536 ($0.02/1M tok).
Не думай, бери.query:, passage:). Забудешь —
recall падает на 10–20%. Это не баг моделей, это by design.text-embedding-ada-002 и text-embedding-3-small разные. Нельзя
мигрировать «постепенно», нужен полный re-index.XJ-99201 так, что найдут
XJ-99202 и сломают пользователя./concepts/vector-similarity-ann — что происходит после embedding:
HNSW, IVF, ScaNN, как искать top-K за O(log N) среди миллиардов векторов./concepts/rag-architecture — полный RAG-стэк: chunking strategies,
hybrid retrieval, re-ranking, prompt assembly, hallucination control.