AI Ops

Context Engineering vs RAG: когда что использовать

Что такое context engineering?

Context engineering — дисциплина осознанной сборки контекста для LLM-запроса: выбор документов, структурирование данных, управление памятью, оркестрация tool results и RAG-результатов. Отличается от prompt engineering тем, что охватывает весь пайплайн подготовки входных данных, а не только формулировку вопроса.

TL;DR

  • -Context engineering — дисциплина сборки контекста для LLM; RAG — один из её инструментов, а не альтернатива
  • -При низкой нагрузке (до ~50 запросов/день) документ до 200K токенов дешевле загрузить в контекст с prompt caching, чем строить и поддерживать RAG-пайплайн
  • -RAG необходим когда корпус в токенах не вмещается в контекстное окно, при частых обновлениях данных и требованиях к attribution
  • -Prompt caching снижает стоимость повторных запросов на 90% — $0.50 vs $5.00 за 1M токенов на Claude Opus 4.8
  • -Комбинированный подход RAG + context assembly + prompt caching — стандарт production-систем 2026; GraphRAG добавляет граф сущностей для enterprise-корпусов

В 2024 году RAG был ответом на любой вопрос о работе LLM с внешними данными. В 2026 году контекстные окна выросли до 1–2 миллионов токенов, prompt caching снизил стоимость повторных запросов на 90%, а термин «context engineering» оформился в отдельную дисциплину. RAG никуда не делся — но перестал быть единственным решением.

Статья разбирает: что такое context engineering, чем отличается от RAG, когда достаточно long context, когда нужен RAG, и как комбинировать оба подхода. С расчётами стоимости, примерами кода и decision framework. Полную картину дисциплины — шестислойную структуру контекста, паттерны персистентности, изоляцию через субагентов — смотрите в гайде по context engineering.

Что такое context engineering

Андрей Карпати сформулировал определение в июне 2025:

Context engineering is the delicate art and science of filling the context window with just the right information for the next step.

Ключевое слово — «just the right». Не максимум информации. Не минимум. Ровно то, что нужно для следующего шага.

Не prompt engineering

Prompt engineering — как сформулировать вопрос (подробнее — в статье как писать промпты). Context engineering — что подать модели перед вопросом. Разница принципиальная:

АспектPrompt EngineeringContext Engineering
ФокусФормулировка запросаСборка входных данных
ScopeОдин промптВесь пайплайн
КомпонентыРоль, формат, chain-of-thoughtSystem prompt + docs + tools + memory + examples
МетафораКак задать вопрос экспертуКакое досье дать эксперту перед вопросом

Идеальный промпт с плохим контекстом даёт плохой результат. Посредственный промпт с точным контекстом — хороший.

Компоненты context engineering

Контекст LLM-запроса собирается из шести источников:

  1. System prompt — роль, ограничения, стиль поведения
  2. Project context — стек, конвенции, архитектурные решения (CLAUDE.md, .cursorrules)
  3. Retrieved documents — результаты RAG, поиска по коду, grep
  4. Tool results — ответы от API, баз данных, MCP-серверов
  5. Memory — персистентные заметки между сессиями
  6. Few-shot examples — образцы ожидаемого поведения

Context engineering оркестрирует все шесть. RAG покрывает только третий пункт.

Почему это стало дисциплиной

В 2025–2026 совпали три фактора.

Рост контекстных окон. Claude Opus 4.8 и Sonnet 4.6 — 1M токенов (GA с марта 2026). GPT-5.5 — 1M (922K input). Gemini 3.1 Pro — 1M стандартно, 2M в расширенных режимах через API. Когда окно вмещает целую кодовую базу, вопрос меняется: не «как извлечь релевантное», а «что именно положить».

Prompt caching. Anthropic, Google, OpenAI — все запустили кэширование статичного контекста. Cache read у Claude стоит $0.50/MTok вместо $5.00/MTok. Длинный контекст стал в 10 раз дешевле.

AI-агенты. Агентам нужна память между шагами, результаты инструментов, план задачи, контекст проекта. Один промпт это не описывает — нужен пайплайн сборки контекста.

Gartner в июле 2025 заявил: «Context engineering is in, and prompt engineering is out». Тоби Лютке (CEO Shopify) популяризировал термин. Дисциплина получила имя.

Что такое RAG

RAG (Retrieval-Augmented Generation) — паттерн, при котором LLM получает релевантные документы перед генерацией ответа. Три шага:

  1. Retrieve — найти релевантные фрагменты в корпусе
  2. Augment — добавить найденное в промпт
  3. Generate — сгенерировать ответ с учётом контекста

Как RAG работает под капотом

Документы → Chunking → Embedding → Vector Store

Запрос → Embedding → Vector Search → Top-K chunks → LLM → Ответ

Chunking — разбиение документов на фрагменты. Размер чанка определяет гранулярность поиска: слишком мелкие — теряется контекст, слишком крупные — шум.

Embedding — преобразование текста в числовой вектор. Семантически похожие тексты получают близкие векторы.

Vector Store — база данных для хранения и поиска по векторам. pgvector, Pinecone, Qdrant.

Retrieval — поиск ближайших векторов к запросу пользователя. Top-K результатов попадают в промпт.

Типы RAG

Naive RAG. Простейшая реализация: фиксированный размер чанка, один embedding model, cosine similarity, top-5 в промпт. Годится для прототипов.

Advanced RAG. Hybrid search (vector + BM25), reranking, parent-child chunking, query expansion. Precision@5 растёт с 0.6 до 0.85+.

Agentic RAG. Агент решает, что искать, в каком индексе, сколько раз. Может переформулировать запрос, запросить уточнение, комбинировать результаты из разных источников. Context engineering с RAG как одним из инструментов.

GraphRAG. Подход Microsoft (2024), который строит граф сущностей и связей поверх корпуса. Вместо поиска по плоским чанкам модель обходит граф и находит ответы на «глобальные» вопросы — о связях между документами, трендах, паттернах. К 2026 GraphRAG и его облегчённые аналоги (LightRAG, HippoRAG 2) стали востребованным решением для enterprise-корпусов с плотными связями между документами — там, где нужны ответы на вопросы типа «как связаны A и B» или «что произошло во всём корпусе». Практика 2026: vector + graph в гибриде, маршрутизация по типу запроса.

Adaptive RAG. Классификатор запросов направляет каждый вопрос к подходящей стратегии retrieval на основе сложности: простой фактический вопрос — прямой поиск, сложный аналитический — multi-hop итеративный агент. Практика 2025–2026: RL-обученные агенты (инспирированные подходами OpenAI Deep Research, Search-R1) заменяют фиксированный pipeline «retrieve → generate» на автономный цикл «план → поиск → рассуждение → критика → следующий поиск».

Когда RAG стал стандартом

RAG появился в статье Facebook AI Research в 2020 году. Стал стандартом к 2023–2024, когда контекстные окна были 4K–32K токенов. При таких ограничениях RAG был единственным способом работать с внешними данными.

Context engineering vs RAG: ключевые отличия

Главное: RAG — часть context engineering

RAG — не альтернатива context engineering. RAG — один из инструментов в его арсенале. Сравнивать их — как сравнивать «приготовление еды» и «нарезку овощей». Нарезка — часть процесса.

Аналогия: RAG — библиотекарь, который находит нужные книги. Context engineering — редактор, который решает, какие книги запросить, какие главы выбрать, в каком порядке их прочитать и что из них включить в финальный документ.

Сравнительная таблица

КритерийContext EngineeringRAG
ScopeВесь пайплайн подготовки контекстаТолько retrieval документов
КомпонентыSystem prompt, memory, tools, RAG, examples, structured outputChunking, embedding, vector store, retrieval, reranking
ДанныеЛюбые: код, API-ответы, файлы, памятьДокументы в vector store
ИнфраструктураPrompt caching, MCP, memory filesVector DB, embedding pipeline, indexing
LatencyЗависит от размера контекстаЗависит от retrieval + reranking
Стоимость масштабированияЛинейно с размером контекстаЛинейно с размером корпуса (индексация)
Когда обновлятьПри изменении задачи/проектаПри изменении данных в корпусе
AttributionНе встроенаВстроена (источник = чанк)
Уровень абстракцииOrchestration layerRetrieval component

Четыре стратегии, одна из которых — RAG

Context engineering оперирует четырьмя стратегиями управления контекстом:

СтратегияЧто делаетПримеры
WriteСохраняет информацию вовнеMemory files, scratchpads, CLAUDE.md
SelectИзвлекает релевантноеRAG, grep, code search, MCP tools
CompressСжимает контекстSummarization, compaction, очистка tool results
IsolateИзолирует задачиСубагенты с чистым контекстом

RAG — реализация стратегии Select. Одна из четырёх. Мощная, но не единственная.

Когда достаточно long context без RAG

Правило: если влезает — не усложняй

Контекстное окно Claude Opus 4.8 и Sonnet 4.6 — 1M токенов. Gemini 3.1 Pro — 1M. Один миллион токенов — примерно 750 000 слов, или 3 000 страниц текста.

Если весь корпус помещается в контекстное окно — RAG-пайплайн добавляет сложность без пользы.

Сценарий 1: кодовая база до 100K строк

Средний стартап — 50–80K строк кода. В токенах это ~200–300K. Claude Code загружает нужные файлы в контекст через grep и glob, без vector store. Работает, потому что:

  • Код структурирован (файлы, функции, модули)
  • Поиск по имени точнее semantic search для кода
  • Контекст обновляется при каждом запросе

Сценарий 2: фиксированный набор документов

Внутренняя документация компании — 50 документов, 200K токенов. Обновляется раз в месяц. Два варианта:

Вариант A: RAG-пайплайн

  • Chunking + embedding + vector store + retrieval
  • Инфраструктура: Qdrant/Pinecone + embedding API
  • Поддержка: re-indexing при обновлениях
  • Стоимость: $50–200/мес (vector DB + embedding API)

Вариант B: Long context + prompt caching

  • Все 200K токенов в system prompt
  • Prompt caching: первый запрос $1.25/MTok (5-min cache write), последующие $0.50/MTok
  • Инфраструктура: ноль
  • 200K токенов × $0.50/MTok = $0.10 за запрос (cache read)

При 100 запросах в день: вариант B — $10/день, $300/мес; вариант A — $50–200/мес. При такой нагрузке RAG выгоднее по деньгам, но требует инфраструктуры и поддержки. Long context оправдан при низкой нагрузке — до ~50 запросов/день ($150/мес) или когда стоимость RAG-инфраструктуры учитывается в общей стоимости владения.

Сценарий 3: анализ одного длинного документа

Юридический контракт на 100 страниц (~80K токенов). RAG разрежет его на чанки и потеряет cross-reference между секциями. Long context сохранит структуру целиком — модель видит весь контракт и находит противоречия между разделами, чего чанковый поиск не умеет.

Расчёт стоимости long context

Claude Opus 4.8, 500K токенов в контексте, 100 запросов в день:

РежимСтоимость за запросВ деньВ месяц
Без кэша$2.50$250$7 500
Prompt caching (5-min, cache read)$0.25$25$750
Prompt caching (1-hour, cache read)$0.25$25$750

Cache write (первый запрос): $3.13 (5-min) или $5.00 (1-hour). Но каждый последующий read — $0.25. Окупается со второго запроса.

Claude Sonnet 4.6, те же условия:

РежимСтоимость за запросВ деньВ месяц
Без кэша$1.50$150$4 500
Prompt caching (cache read)$0.15$15$450

Gemini 3.1 Pro, 500K токенов (>200K — long context pricing):

РежимСтоимость за запросВ деньВ месяц
Стандартный$1.25$125$3 750
С context caching~$0.16$16$480

Когда long context не работает

  • Документ > 1M токенов — не влезает в стандартное окно. Gemini 3.1 Pro поддерживает 2M в расширенном режиме, но это исключение
  • Latency-critical — обработка 500K токенов занимает 5–15 секунд. Если нужен ответ за 500ms — не вариант
  • Деградация вниманияисследование Chroma (2025) показало: все 18 протестированных фронтирных моделей (Claude 4, GPT-4.1, Gemini 2.5) демонстрируют монотонное падение F1 с ростом контекста. Наиболее резкая деградация — в диапазоне 100K–500K токенов
  • Часто обновляемые данные — prompt cache инвалидируется при любом изменении контента

Когда нужен RAG

Пять сигналов, что RAG необходим

1. Корпус превышает размер контекстного окна. Enterprise knowledge base, юридическая база прецедентов, научная литература — когда суммарный объём данных в токенах не вмещается в 1–2M токенов (даже при Gemini 3.1 Pro в расширенном режиме). Число документов второстепенно: 10 000 коротких статей < 50M токенов, 500 длинных регуляторных документов — вполне могут занять 200M. RAG извлекает top-10 релевантных фрагментов из любого по размеру корпуса.

2. Данные обновляются часто. Тикеты в Jira, сообщения в Slack, статьи в wiki — данные меняются ежедневно. RAG-индекс обновляется инкрементально. Prompt cache инвалидируется полностью при любом изменении.

3. Нужна attribution. «Откуда этот ответ?» — критичный вопрос для compliance, legal, медицины. RAG возвращает конкретные чанки с metadata (документ, страница, дата). Long context — чёрный ящик: ответ есть, источник неясен.

4. Latency < 1 секунды. Chatbot на сайте. Пользователь ждёт ответ за 500ms. RAG: vector search 20ms + reranking 50ms + LLM с 5K токенами контекста 300ms = 370ms. Long context: LLM с 500K токенами = 5–15 секунд.

5. Оптимизация стоимости при высокой нагрузке. 10 000 запросов в день. RAG подаёт в среднем 5K токенов → $0.025 за запрос (Sonnet). Long context подаёт 500K → $0.15 за запрос (cache read). Разница: $250/день vs $1 500/день.

Расчёт: RAG vs Long Context по стоимости

10 000 запросов/день, Claude Sonnet 4.6 ($3/$15 за MTok):

ПодходТокенов в контекстеСтоимость/запросВ деньВ месяц
RAG (5K retrieved)8K (system + retrieved)$0.024$240$7 200
Long context (без кэша)500K$1.50$15 000$450 000
Long context (cache read)500K$0.15$1 500$45 000
RAG + embedding cost8K + embedding$0.03$300$9 000

При 10K запросов/день RAG в 5 раз дешевле даже кэшированного long context. Плюс RAG-стоимость масштабируется линейно с числом запросов, а не с размером корпуса.

Context engineering без RAG: практические техники

Prompt caching

Самая недооценённая техника 2025–2026. Статичная часть контекста (system prompt, документация, examples) кэшируется на стороне провайдера. Повторные запросы читают из кэша.

Стоимость на Claude:

ОперацияOpus 4.8Sonnet 4.6Haiku 4.5
Base input$5.00/MTok$3.00/MTok$1.00/MTok
Cache write (5-min)$6.25/MTok$3.75/MTok$1.25/MTok
Cache write (1-hour)$10.00/MTok$6.00/MTok$2.00/MTok
Cache read$0.50/MTok$0.30/MTok$0.10/MTok

Cache read — 10% от базовой стоимости. 90% экономии на повторных запросах.

Пример: Anthropic API с prompt caching (Python)

import anthropic

client = anthropic.Anthropic()

# Статичный контекст — кэшируется
system_content = [
    {
        "type": "text",
        "text": "Ты — AI-ассистент юридической компании.",
    },
    {
        "type": "text",
        "text": full_legal_corpus,  # 200K токенов документации
        "cache_control": {"type": "ephemeral"}  # Кэшировать этот блок
    }
]

# Первый запрос: cache write ($6.25/MTok для Opus)
# Все последующие в течение 5 минут: cache read ($0.50/MTok)
response = client.messages.create(
    model="claude-opus-4-8-20260528",
    max_tokens=4096,
    system=system_content,
    messages=[{"role": "user", "content": "Какие риски в разделе 4.2?"}]
)

CLAUDE.md и system instructions

Проектный контекст, который агент читает автоматически. Claude Code загружает CLAUDE.md при каждом запуске — стек, конвенции, архитектурные решения. Cursor использует .cursorrules. Windsurf — .windsurfrules.

Context engineering без RAG: статичный контекст проекта, поданный напрямую в промпт.

# CLAUDE.md
## Стек
- Python 3.12, FastAPI, SQLAlchemy 2.0, PostgreSQL
- Alembic для миграций, pytest для тестов
## Конвенции
- Type hints обязательны
- Pydantic v2 для валидации
- Async handlers по умолчанию
## Архитектура
- Clean Architecture: domain → application → infrastructure
- Repository pattern для доступа к данным

Tool use (MCP)

Вместо pre-loading всех данных в контекст — подтягивание по запросу. Model Context Protocol (MCP) стандартизирует доступ к внешним инструментам — детали реализации в гайде по созданию production MCP-серверов.

// MCP-сервер отдаёт данные по запросу агента
// Агент сам решает, когда и что запросить

// Вместо: загрузить все 500 тикетов в контекст
// Агент вызывает: search_tickets("auth bug priority:high")
// Получает: 3 релевантных тикета, 2K токенов

Агент загружает только то, что нужно для текущего шага. Контекст остаётся чистым.

Memory — персистентность между сессиями

Агент сохраняет знания для будущих сессий. Claude Code записывает паттерны в MEMORY.md. Cursor хранит context в .cursor/rules/.

# MEMORY.md (автоматически обновляется агентом)
## Learned Rules
- В этом проекте используется camelCase для API endpoints
- Миграции именуются: YYYY-MM-DD_description.sql
- Тесты группируются по модулям, не по типам

Это стратегия Write из четырёх стратегий context engineering. Агент пишет заметки для будущего себя.

Structured output

JSON Schema в ответе гарантирует предсказуемый формат. Context engineering на выходе: вместо free-form текста — структурированные данные.

from pydantic import BaseModel

class CodeReview(BaseModel):
    file: str
    severity: Literal["critical", "warning", "info"]
    issue: str
    suggestion: str
    line_range: tuple[int, int]

# LLM возвращает точно эту структуру
# Никакого парсинга, никаких регулярок

Few-shot examples

Вместо fine-tuning — 3–5 примеров в контексте. Дешевле, быстрее, проще обновлять.

## Примеры code review (следуй этому формату):

Файл: auth.py:45-52
Severity: critical
Issue: SQL-инъекция через f-string
Suggestion: Используй параметризованный запрос
---
Файл: utils.py:12
Severity: info
Issue: Неиспользуемый импорт
Suggestion: Удали import os

Few-shot examples занимают 500–2000 токенов. С prompt caching они стоят $0.00025–$0.001 за запрос. Fine-tuning стоит $25+ за тренировку и ограничивает гибкость.

RAG: современный стек 2026

Chunking strategies

Fixed-size chunking. 512–1024 токенов с overlap 10–20%. Просто, предсказуемо, но разрезает семантически связанные блоки.

Semantic chunking. Разбивает по смысловым границам — заголовки, абзацы, смена темы. Embedding каждого предложения → если similarity между соседними предложениями падает ниже threshold → граница чанка. Качество выше, но дороже в обработке.

Parent-child chunking. Мелкие чанки (128–256 токенов) для поиска, но при retrieval возвращается parent (1024+ токенов) для контекста. Точный поиск + полный контекст.

Late chunking. Сначала embedding всего документа одним проходом, потом разбиение на чанки. Каждый чанк сохраняет контекст всего документа в своём embedding. Jina AI предложила подход в 2024, к 2026 он стал стандартом для длинных документов.

# Parent-child chunking с LangChain
from langchain.text_splitter import RecursiveCharacterTextSplitter

# Parent: крупные чанки для контекста
parent_splitter = RecursiveCharacterTextSplitter(
    chunk_size=2000,
    chunk_overlap=200,
)

# Child: мелкие чанки для точного поиска
child_splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=50,
)

# При поиске: находим child → возвращаем parent

Embedding models (2026)

МодельРазмерностьЦена/MTokMTEB ScoreКогда использовать
text-embedding-3-large (OpenAI)3072$0.13~64.6Высокая точность, English-first
text-embedding-3-small (OpenAI)1536$0.02~62.3Бюджетный вариант
Cohere Embed v41024$0.12~66.3Мультиязычность, единственная multimodal-модель (текст + изображения)
Voyage 3.52048$0.06~65+Лучший retrieval для кода, юридических и медицинских текстов; 32K context
BGE-M3 (open-source)1024$0 (self-host)~64+Self-hosted, без vendor lock-in

Рекомендация: для большинства задач — text-embedding-3-small ($0.02/MTok). Для production с высокими требованиями к quality — Voyage 3.5 (особенно для домен-специфичного контента) или Cohere Embed v4 (мультимодальность и мультиязычность).

Vector stores

РешениеТипLatency (1M vectors)СтоимостьКогда использовать
pgvectorExtension к PostgreSQL5–8ms (HNSW)$0 (часть PostgreSQL)Уже есть PostgreSQL, <5M vectors
QdrantStandalone, Rust3–5msSelf-hosted / $25+/мес cloudPerformance-critical, >5M vectors
PineconeManaged SaaS10–20ms$70+/мес (Serverless)Zero-ops, масштаб до миллиардов
WeaviateStandalone, Go5–10msSelf-hosted / $25+/месMultimodal, GraphQL API
ChromaDBEmbedded1–3ms (small datasets)$0Прототипы, <100K vectors

pgvector — правильный старт для 90% проектов. Если PostgreSQL уже в стеке (а в 2026 это почти всегда так), pgvector устанавливается одной командой:

-- Установка pgvector (Supabase — включён по умолчанию)
CREATE EXTENSION IF NOT EXISTS vector;

-- Таблица для документов
CREATE TABLE documents (
    id BIGSERIAL PRIMARY KEY,
    content TEXT NOT NULL,
    metadata JSONB DEFAULT '{}',
    embedding VECTOR(1536)  -- text-embedding-3-small
);

-- HNSW индекс — быстрый approximate search
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

RAG-пайплайн на Supabase + pgvector (Python):

import openai
from supabase import create_client

supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
embeddings = openai.OpenAI()

async def index_document(content: str, metadata: dict):
    """Индексация документа: chunking → embedding → store"""
    chunks = semantic_chunk(content, max_tokens=512)

    for chunk in chunks:
        response = embeddings.embeddings.create(
            model="text-embedding-3-small",
            input=chunk
        )
        vector = response.data[0].embedding

        supabase.table("documents").insert({
            "content": chunk,
            "metadata": metadata,
            "embedding": vector
        }).execute()


async def search(query: str, top_k: int = 5) -> list[dict]:
    """Semantic search: query → embedding → vector search"""
    response = embeddings.embeddings.create(
        model="text-embedding-3-small",
        input=query
    )
    query_vector = response.data[0].embedding

    # pgvector cosine similarity search
    results = supabase.rpc("match_documents", {
        "query_embedding": query_vector,
        "match_threshold": 0.7,
        "match_count": top_k
    }).execute()

    return results.data
-- Supabase Edge Function для semantic search
CREATE OR REPLACE FUNCTION match_documents(
    query_embedding VECTOR(1536),
    match_threshold FLOAT,
    match_count INT
)
RETURNS TABLE (
    id BIGINT,
    content TEXT,
    metadata JSONB,
    similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN QUERY
    SELECT
        d.id,
        d.content,
        d.metadata,
        1 - (d.embedding <=> query_embedding) AS similarity
    FROM documents d
    WHERE 1 - (d.embedding <=> query_embedding) > match_threshold
    ORDER BY d.embedding <=> query_embedding
    LIMIT match_count;
END;
$$;

Reranking

Vector search возвращает top-20 кандидатов. Reranker переоценивает их точнее. Двухступенчатая архитектура: быстрый recall (vector search) → точный precision (reranker).

МодельЦенаКачествоКогда
Cohere Rerank v3.5$2/1K searchesВысокоеProduction, multilingual (100+ языков)
BGE Reranker v2.5$0 (self-host)Среднее-высокоеSelf-hosted, бюджет
Jina Reranker v2$0.02/1K queriesВысокоеБаланс цена/качество
import cohere

co = cohere.Client(api_key="...")

# Vector search вернул 20 кандидатов
candidates = await search(query, top_k=20)

# Reranker переоценивает релевантность
reranked = co.rerank(
    model="rerank-v3.5",  # Cohere Rerank v3.5, апрель 2026
    query=query,
    documents=[c["content"] for c in candidates],
    top_n=5  # Оставляем top-5
)

# reranked.results — отсортированы по точной релевантности

Hybrid search: vector + BM25

Vector search находит семантически похожее. BM25 находит точные совпадения (keyword search). Hybrid search покрывает оба сценария.

# Reciprocal Rank Fusion (RRF) — простой способ объединить результаты
def reciprocal_rank_fusion(
    vector_results: list,
    bm25_results: list,
    k: int = 60
) -> list:
    """Объединяет vector и keyword search через RRF."""
    scores = {}

    for rank, doc in enumerate(vector_results):
        scores[doc["id"]] = scores.get(doc["id"], 0) + 1 / (k + rank + 1)

    for rank, doc in enumerate(bm25_results):
        scores[doc["id"]] = scores.get(doc["id"], 0) + 1 / (k + rank + 1)

    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

pgvector + PostgreSQL Full-Text Search — hybrid search без дополнительной инфраструктуры:

-- Hybrid search: vector similarity + text relevance
SELECT
    d.id,
    d.content,
    -- Нормализованные скоры
    (1 - (d.embedding <=> query_embedding)) * 0.7 AS vector_score,
    ts_rank(d.fts, plainto_tsquery('english', query_text)) * 0.3 AS text_score,
    -- Комбинированный скор
    (1 - (d.embedding <=> query_embedding)) * 0.7 +
    ts_rank(d.fts, plainto_tsquery('english', query_text)) * 0.3 AS combined_score
FROM documents d
WHERE
    d.fts @@ plainto_tsquery('english', query_text)
    OR (1 - (d.embedding <=> query_embedding)) > 0.5
ORDER BY combined_score DESC
LIMIT 10;

GraphRAG и LightRAG

К 2026 году Microsoft GraphRAG из академической статьи превратился в production-инструмент. Идея: вместо индексации плоских чанков — строить граф сущностей и отношений поверх корпуса, а при поиске обходить граф. Это даёт принципиально другой класс ответов.

Когда нужен GraphRAG:

  • Вопросы о связях между документами («какие компании работали с X», «как менялась позиция Y во времени»)
  • Глобальный суммаризирующий анализ всего корпуса
  • Тематические и паттерн-поисковые запросы

LightRAG — облегчённая альтернатива от HKU (2024). Тот же граф сущностей, но без тяжёлой инфраструктуры Microsoft. По качеству сопоставим с GraphRAG при 10–30× меньшей стоимости и 6–13× меньшей латентности.

Практика 2026: production-стеки для enterprise-корпусов с богатой семантикой связей всё чаще используют гибрид vector + graph, маршрутизируя запрос к нужному индексу по типу вопроса.

# Упрощённая маршрутизация: vector vs graph
def route_query(query: str) -> str:
    """Определяем стратегию retrieval по типу запроса."""
    relational_signals = [
        "как связаны", "отношения между", "что общего у",
        "как менялось", "кто работал с", "паттерн"
    ]
    if any(signal in query.lower() for signal in relational_signals):
        return "graph"  # GraphRAG / LightRAG
    return "vector"  # Обычный vector search + reranking

Agentic RAG

Классический RAG: запрос → search → результат. Agentic RAG: агент решает стратегию поиска.

# Agentic RAG: агент выбирает стратегию
tools = [
    {
        "name": "search_docs",
        "description": "Semantic search по документации",
        "parameters": {"query": "str", "top_k": "int", "filters": "dict"}
    },
    {
        "name": "search_code",
        "description": "Поиск по кодовой базе (grep, AST)",
        "parameters": {"pattern": "str", "file_types": "list[str]"}
    },
    {
        "name": "search_tickets",
        "description": "Поиск по Jira/Linear тикетам",
        "parameters": {"query": "str", "status": "str"}
    },
    {
        "name": "graph_search",
        "description": "GraphRAG — поиск по графу сущностей для вопросов о связях",
        "parameters": {"query": "str", "depth": "int"}
    }
]

# Агент получает вопрос: "Почему auth ломается после деплоя?"
# Агент решает:
# 1. search_code("auth", file_types=["py"]) — найти auth-модуль
# 2. search_tickets("auth deploy bug", status="recent") — найти связанные тикеты
# 3. search_docs("deployment auth configuration") — проверить документацию
# 4. При необходимости переформулирует запрос и повторяет поиск
# Комбинирует результаты и отвечает

Agentic RAG — context engineering в действии. Агент не просто извлекает документы, а оркестрирует поиск по нескольким источникам.

Decision framework: что выбрать

Блок-схема

Размер корпуса данных?
├── < 200K токенов
│   └── → Long context (всё в промпт + prompt caching)
├── 200K – 1M токенов
│   ├── Данные статичны?
│   │   ├── Да → Long context + prompt caching
│   │   └── Нет → RAG (инкрементальный индекс)
│   ├── Latency < 1с?
│   │   ├── Да → RAG
│   │   └── Нет → Long context допустим
│   └── Бюджет ограничен + высокая нагрузка?
│       ├── Да → RAG (меньше токенов на запрос)
│       └── Нет → Long context проще
└── > 1M токенов
    └── → RAG (обязательно)
        ├── Нужна attribution? → RAG с metadata
        ├── Вопросы о связях между документами? → GraphRAG / LightRAG
        ├── Complex multi-hop queries? → Agentic RAG
        └── Multilingual? → Cohere Embed v4 / BGE-M3

Матрица решений

СценарийРазмер данныхОбновленияLatencyРекомендация
Чатбот поддержки500+ документовЕженедельно<1сRAG + reranking
Code assistant50–100K строкПостоянно2–5с допустимоLong context (grep/glob)
Legal research100K+ документовРедкоНе критичнаRAG + hybrid search
Документация продукта20–50 документовЕжемесячно<2сLong context + cache
Customer analytics1M+ записейЕжедневно<500msRAG + structured retrieval
Onboarding assistant30 internal docsРаз в квартал<3сLong context + cache
Research assistant10K+ papersЕженедельноНе критичнаAgentic RAG + GraphRAG + reranking

Реальные сценарии

Customer support bot. 2000 статей FAQ, обновляются еженедельно, нужен ответ за 1 секунду, нужна ссылка на источник. → RAG. Hybrid search (vector + BM25) + Cohere Rerank + attribution через metadata.

Code assistant (Claude Code). Кодовая база 80K строк, обновляется непрерывно, latency 2–5с допустима, нужен полный контекст файлов. → Long context. Grep/glob для retrieval, весь файл в контекст, CLAUDE.md для проектных конвенций.

Legal research. 50 000 судебных решений, обновляются ежемесячно, нужна точная citation, запросы сложные (перекрёстные ссылки, связи между прецедентами). → Agentic RAG + GraphRAG. Parent-child chunking, hybrid search, reranking, граф сущностей для связей между делами, agent решает стратегию поиска.

Internal knowledge base. 40 документов, 150K токенов, обновляются раз в месяц, 50 запросов/день. → Long context + prompt caching. Все документы в system prompt, cache read за $0.10/запрос. Стоимость: $5/день = $150/мес. RAG-инфраструктура обойдётся дороже.

Комбинированный подход

RAG + Context Engineering — не either/or

Production-системы 2026 комбинируют оба подхода. RAG отвечает за retrieval. Context engineering — за assembly.

┌─────────────────────────────────────────────────┐
│                Context Assembly                  │
│  (Context Engineering — orchestration layer)     │
├─────────────────────────────────────────────────┤
│                                                  │
│  1. System Prompt          ← Статичный, cached   │
│     ├── Role definition                          │
│     ├── Project context (CLAUDE.md)              │
│     └── Output format                            │
│                                                  │
│  2. Retrieved Context      ← RAG pipeline        │
│     ├── Vector search results                    │
│     ├── BM25 keyword matches                     │
│     └── Reranked top-K                           │
│                                                  │
│  3. Tool Results           ← On-demand via MCP   │
│     ├── Database queries                         │
│     ├── API responses                            │
│     └── Code search results                      │
│                                                  │
│  4. Memory                 ← Persistent storage  │
│     ├── Previous conversation summary            │
│     ├── User preferences                         │
│     └── Learned patterns                         │
│                                                  │
│  5. Few-shot Examples      ← Cached at the end   │
│                                                  │
│  → Assembled Context → LLM → Response            │
│                                                  │
└─────────────────────────────────────────────────┘

Пример архитектуры: support bot с комбинированным подходом

async def handle_query(user_query: str, user_id: str) -> str:
    """Комбинированный подход: RAG + context engineering."""

    # 1. System prompt (cached, стратегия Write)
    system = build_system_prompt(
        role="support_agent",
        company_policies=CACHED_POLICIES,  # prompt caching
        output_format=TICKET_SCHEMA
    )

    # 2. RAG retrieval (стратегия Select)
    relevant_docs = await rag_search(
        query=user_query,
        top_k=5,
        rerank=True
    )

    # 3. User context (стратегия Select — tools)
    user_history = await get_recent_tickets(user_id, limit=3)
    user_plan = await get_subscription_plan(user_id)

    # 4. Memory (стратегия Write/Select)
    conversation_summary = await get_conversation_memory(user_id)

    # 5. Assembly (Context Engineering — оркестрация)
    context = assemble_context(
        system=system,
        retrieved_docs=relevant_docs,      # RAG результаты
        user_context={
            "history": user_history,
            "plan": user_plan
        },
        memory=conversation_summary,
        examples=FEW_SHOT_SUPPORT_EXAMPLES  # Cached
    )

    # 6. Сжатие если нужно (стратегия Compress)
    if count_tokens(context) > MAX_CONTEXT:
        context = compress_context(context, target_tokens=MAX_CONTEXT)

    # 7. LLM call
    response = await llm.generate(context=context, query=user_query)

    # 8. Сохранить в memory (стратегия Write)
    await update_conversation_memory(user_id, user_query, response)

    return response

Когда комбинация необходима

  • Персонализация. RAG находит документы, но ответ нужно адаптировать под пользователя (план, историю, предпочтения). Без context engineering получается generic ответ.

  • Multi-source retrieval. Данные в нескольких системах: docs в vector store, тикеты в Jira, код в Git. RAG не знает про Jira. Context engineering оркестрирует все источники.

  • Stateful conversations. RAG — stateless. Каждый запрос независим. Для диалога нужна memory — стратегия Write. RAG + memory = комбинированный подход.

  • Quality optimization. RAG вернул 5 чанков. Но один — дубликат, другой — устаревший. Context engineering фильтрует, дедуплицирует, расставляет приоритеты.

Метрики и оценка

Метрики качества контекста

МетрикаЧто измеряетКак считать
RelevanceНасколько контекст релевантен запросуLLM-as-judge: «оцени релевантность 1–5»
CoverageПокрывает ли контекст все аспекты вопроса% аспектов вопроса, на которые есть данные в контексте
Noise ratioДоля нерелевантного контентаТокены нерелевантного / общие токены
Token efficiencyСколько полезных токенов на единицу стоимостиRelevance score / cost per query

RAG-метрики

Precision@K — из K извлечённых документов, сколько релевантны.

Precision@5 = 4 релевантных из 5 извлечённых = 0.80

Recall@K — из всех релевантных документов в корпусе, сколько попали в top-K.

10 релевантных документов в корпусе, 4 попали в top-5 → Recall@5 = 0.40

MRR (Mean Reciprocal Rank) — на какой позиции первый релевантный документ.

Первый релевантный на позиции 2 → RR = 1/2 = 0.50
Среднее по всем запросам = MRR

NDCG (Normalized Discounted Cumulative Gain) — учитывает не только наличие, но и позицию каждого релевантного документа.

End-to-end метрики

МетрикаЧто измеряетИнструменты
Answer accuracyПравильность ответаEval set + LLM-as-judge
FaithfulnessОтвет основан на контексте, а не на hallucinationRAGAS, DeepEval
Hallucination rate% утверждений без основания в контекстеRAGAS faithfulness metric
Latency (p50, p95)Время от запроса до ответаLangfuse, LangSmith
Cost per queryПолная стоимость: embedding + retrieval + LLMBilling API + custom tracking

Eval pipeline

from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall
)

# Eval dataset: вопрос + эталонный ответ + контекст
eval_results = evaluate(
    dataset=eval_dataset,
    metrics=[
        faithfulness,          # Ответ основан на контексте?
        answer_relevancy,      # Ответ релевантен вопросу?
        context_precision,     # Извлечённый контекст точен?
        context_recall,        # Контекст покрывает все аспекты?
    ]
)

# Результат:
# faithfulness: 0.92
# answer_relevancy: 0.88
# context_precision: 0.85
# context_recall: 0.78 → нужно улучшить retrieval

Итог

Context engineering и RAG — не конкуренты. Context engineering — дисциплина. RAG — один из инструментов внутри неё.

Четыре правила:

  1. Данные влезают в контекстное окно и не меняются часто — long context + prompt caching. Проще, дешевле, надёжнее.

  2. Корпус большой, данные обновляются, нужна attribution или latency — RAG. С hybrid search и reranking.

  3. Нужны ответы о связях между документами, паттернах, глобальном анализе корпуса — GraphRAG или LightRAG. Граф сущностей там, где плоский vector search не справляется.

  4. Production — комбинация. RAG для retrieval, context engineering для assembly, prompt caching для экономии. Граф — там, где нужны связи. Одно без другого работает хуже, чем оба вместе.

Контекстные окна продолжат расти. Стоимость токенов — падать. Но принцип останется: качество ответа определяется не количеством токенов в контексте, а их релевантностью. Context engineering — про это.

Часто задаваемые вопросы

В чём разница между context engineering и RAG?
RAG — техника извлечения релевантных документов из корпуса через embeddings и vector search. Context engineering — более широкая дисциплина, которая включает RAG как один из инструментов наряду с prompt caching, tool use, memory, few-shot examples и structured output.
Когда long context заменяет RAG?
Когда весь корпус данных помещается в контекстное окно (до 1M токенов у Claude Opus 4.8/Sonnet 4.6, GPT-5.5, Gemini 3.1 Pro), данные не меняются часто, нагрузка невысокая и задержка обработки длинного контекста приемлема. С prompt caching стоимость падает на 90%, что делает long context конкурентоспособным по цене при умеренном числе запросов.
Когда RAG всё ещё необходим?
Когда суммарный объём корпуса в токенах не вмещается в контекстное окно (а не просто «много документов» — важен размер в токенах), при ежедневных обновлениях данных, требованиях к attribution (показать источник), строгих ограничениях по latency (<500ms) и при необходимости semantic search по разнородным данным.
Можно ли комбинировать context engineering и RAG?
Да, и это стандартный подход в production. RAG отвечает за retrieval релевантных фрагментов, context engineering — за их сборку, приоритизацию, дедупликацию и размещение в контекстном окне. Одно без другого работает хуже.