RAG (Retrieval Augmented Generation) architecture concept page. Shows the full pipeline: ingestion (load -> chunk -> embed -> store in Qdrant + BM25) and query (embed -> ANN search -> hybrid retrieval -> RRF fusion -> rerank -> LLM with cache). Demonstrates progression from Naive RAG to Advanced RAG (hybrid + rerank + query rewriting + HyDE) to Modular RAG per Gao 2024. Includes 5 scenarios: naive RAG baseline, hybrid retrieval with BM25+dense+RRF, advanced RAG with rewrite/HyDE/rerank, ingestion pipeline, and semantic cache hit. Includes 2 ADRs covering when complexity is worth it and vector DB / embedding model selection.
LLM великолепно генерализуют, но у них три фундаментальных ограничения, которые делают «голый» chat-API непригодным для большинства production-задач. Первое — фиксированный training cutoff: модель не знает событий после даты тренировки, не знает твою кодовую базу, не знает изменений в Stripe API за последние полгода. Второе — галлюцинации: на вопросы вне её знаний модель уверенно сочиняет правдоподобный текст, потому что её objective — генерировать плавный следующий токен, а не «отказаться при неуверенности». Третье — нет verifiability: даже когда модель права, пользователь не может проверить откуда факт, потому что нет источника.
RAG (Retrieval Augmented Generation) решает все три: при запросе пользователя система ищет релевантные документы в собственной базе знаний, кладёт их в context, и LLM отвечает «опираясь на эти страницы» — с цитатами. Свежесть данных контролируется индексацией (webhook/CDC из source), фактическая точность — retrieval-системой, доверие — citations. Это превращает LLM из универсального энциклопедиста-с-памятью-2024-года в эксперта по твоим данным «здесь и сейчас», с возможностью ткнуть пальцем в источник.
Альтернативы (fine-tuning на корпусе, long-context dumping всей базы в prompt каждый раз) либо дороги (fine-tune стоит десятки тысяч и сложно обновлять), либо не масштабируются (200K context window не вмещает корпоративную вики из 100K документов, и стоимость per-query становится запретительной). RAG — это правильная декомпозиция: retrieval отвечает за «что показать модели», generation — за «как сформулировать ответ».
«LLM — это умный, но забывчивый эксперт. Прежде чем спросить, положи перед ним нужные страницы из учебника. RAG — это система "положи нужные страницы". Качество RAG приблизительно равно качеству retrieval, не качеству LLM.»
Из этой модели следует главное практическое правило: 80% работы по качеству RAG — это retrieval (chunking, embedding model, hybrid search, reranking, фильтрация по метаданным), а не выбор «более умной» LLM. Перейти с GPT-4o-mini на Claude Opus при плохом retrieval даст +5% качества; добавить hybrid search и reranker даст +30-40%.
Диаграмма показывает «продвинутую» (Advanced/Modular по Gao 2024) топологию production-RAG, разбитую на пять функциональных групп.
Client / API — точка входа: пользователь обращается к RAG API gateway (api), который оркестрирует весь pipeline. На самом узле gateway висят два ADR: про выбор уровня сложности (Naive vs Advanced vs Modular) и про выбор vector DB и embedding-модели. Капасити gateway 5000 RPS в 2 репликах — это типичная цифра для среднего SaaS с RAG-фичей.
Pre-retrieval (query understanding) — три узла, которые препарируют запрос ДО поиска: rewriter (LLM Haiku разрешает кореференции, расширяет аббревиатуры, генерит multi-query вариации), hyde (генерит гипотетический документ-ответ для embeded-эмбеддинга, решает query/doc length mismatch), q-embedder (Voyage-3 или text-embedding-3-small, превращает текст в 1024–1536-мерный вектор).
Retrieval (hybrid: dense + sparse) — параллельный двухконтурный поиск: qdrant (dense ANN search через HNSW, ловит semantic similarity, «автомобиль» ≈ «тачка») и bm25 (Elasticsearch/Tantivy, sparse keyword match, ловит точные термины, uuids, error codes). Результаты сливаются в rrf через Reciprocal Rank Fusion: score(d) = sum 1/(k + rank_i(d)), k=60.
Post-retrieval (rerank + context) — reranker (Cohere Rerank-3 или BGE Reranker v2-m3 self-host) применяет cross-encoder к топ-50 кандидатам, сортируя их по true relevance (сравнивает query+chunk вместе, в отличие от bi-encoder retrieval-эмбеддингов). ctx-builder берёт топ-5 после reranking, упорядочивает их (важное в начале И конце, mitigate «lost in the middle»), упаковывает в prompt.
Generation (LLM + semantic cache) — cache (Redis с semantic-hash lookup по embedding similarity > 0.97) делает short-circuit для повторяющихся запросов; llm (Claude Sonnet 4.7) генерит финальный ответ с citations.
Ingestion pipeline (offline) — отдельная нижняя группа: loader (S3/Notion/Confluence connector), chunker (semantic boundaries, 500 tokens + 50 overlap), doc-embedder (Voyage-3, batch 256). Финальная запись dual-write: вектора в Qdrant, текст с tokenization в Elasticsearch.
naive-rag (NAIVE — q → embed → top-K → LLM). Baseline: один embedder, vector top-10, dump в prompt, LLM отвечает. 2 недели прототипа, latency ~2s, hit@10≈0.68, faithfulness≈0.71. Это фундамент для измерений: без baseline и eval-set весь дальнейший tuning превращается в vibes-driven engineering.
hybrid-rrf (HYBRID — BM25 + dense + RRF). Добавляем sparse retrieval параллельно dense, сливаем через RRF, добавляем reranker. На запросе «Stripe webhook HTTP 429 idempotency-key collision» dense embedding промахивается на токенах «HTTP 429», но BM25 ловит exact-match. RRF объединяет ranks. Результат: hit@10≈0.84 (+24%), precision@5≈0.79 (+30%).
advanced-rewrite (ADVANCED — rewrite + HyDE + rerank). Для коротких/ambiguous запросов («why slow?») добавляем pre-retrieval: rewriter превращает в полноценный запрос с context, HyDE генерит гипотетический документ-ответ и эмбедит ЕГО (а не сырой запрос — это решает query/doc length mismatch для FAQ-стиля корпуса). Latency растёт до 2.5s, но hit@10≈0.91, faithfulness≈0.92.
ingestion (INGEST — load → chunk → embed → store). Offline pipeline. Notion webhook → 10K docs delta → 80K chunks (500 tok target, 50 overlap, semantic boundaries) → dual-write: Voyage-3 batch 256 в Qdrant ($4.80 на 80K chunks) + ES bulk insert. Подчёркивает Contextual Retrieval (Anthropic Sept 2024): к каждому chunk добавляется preamble «This chunk is from section X of doc Y» через Haiku, даёт -49% retrieval failures.
cache-hit (CACHE — semantic hash short-circuit). Identical или near-identical запросы (top-1 vector similarity > 0.97) возвращают cached answer без LLM call. 30% hit rate типичен для knowledge-base RAG, экономия -$5K/1M запросов, p99 latency 80ms вместо 2000ms.
ADR-001 — Naive RAG vs Advanced vs Modular: когда complexity оправдана. Лестница, а не one-shot выбор: (1) Naive первым: 2 недели, eval-set из 100 query-doc-answer троек (synthetic + manual review), baseline hit@K и faithfulness. (2) Recall < 0.7 → добавь BM25 + RRF (k=60). Обязательно для domains с rare entities (uuids, error codes, proper nouns) — embedding-модели промахиваются на токенах, не виденных в pretraining. +15-25% recall, 1 неделя. (3) Precision < 0.6 → cross-encoder reranker (Cohere Rerank-3 managed, $2/1K queries, ~150-200ms; или BGE Reranker v2-m3 self-host). +20-40% precision. (4) Short/ambiguous queries → query rewriting + HyDE. (5) Modular RAG только для multi-hop/agentic — если 80% запросов single-fact lookup, не плати +2-3s и +complexity. Anti-pattern: «сразу LangChain + LlamaIndex + Cohere + reranker + HyDE + multi-query» без eval-set → получаешь slow expensive black box, не понимаешь какой компонент помогает. Eval-driven incremental: добавь компонент → измерь diff → keep/drop.
ADR-002 — Vector DB и embedding model: трудно реверсимые решения. Re-embed = full re-index, недели работы плюс storage cost ($3000 для 100M chunks × 500 tok через Voyage-3). Decision tree: уже Postgres + <10M vectors → pgvector (один backup, transactional consistency, нулевая операционная сложность); >10M vectors + payload-heavy фильтры (tenant, year, topic) → Qdrant (filterable HNSW first-class, где pgvector сваливается в brute-force WHERE post-filter); plug-and-play без SRE → Pinecone (но vendor lock-in, $2K+/month); billion-scale + GPU → Milvus/Vespa. Embedding model: text-embedding-3-small как default (cheap, 1536-dim); recall не хватает на technical/legal/medical → Voyage-3 (asymmetric prefixes для query vs doc, +5-10% recall на rare entities); privacy-sensitive или multilingual → BGE-M3 self-host. Anti-patterns: одна embedding model для query и doc без asymmetric prefix; embedding upgrade hot-swap (ada → 3-small) без full re-import — distance metrics несовместимы, retrieval сломан тихо; «сразу Pinecone» когда pgvector справится. Quantization включаем когда RAM bottleneck — int8 safe default, binary только после rerank.
embeddings-basics, vector-similarity-ann, qdrant-vector-db, chunking-strategies, reranking, ai-evals, llm-safety-guardrails, prompt-engineering