RAG + prompt caching: как ускорить retrieval-augmented generation в 2 раза
2026-01-28 · Дмитрий Соколов
RAG + prompt caching
RAG-пайплайны в проде страдают от двух болячек: длинный контекст дорогой, и каждый запрос пересчитывается с нуля. Разбираем, как мы оба фактора смягчили с помощью prompt caching.
Базовая схема
Наш RAG выглядит классически: embedding → top-k retrieval → rerank → prompt assembly → LLM. В среднем в промпт улетало ~6k токенов (5 документов + system prompt + инструкции + история).
При 50k запросов в день это 300M input токенов, основная часть из которых — один и тот же system prompt и инструкции.
Идея
Prompt caching от Anthropic/OpenAI позволяет пометить часть промпта как кешируемую. Если за 5 минут та же начальная последовательность повторится — модель пропускает её и платите только за дельту.
Структурируем промпт так, чтобы стабильная часть шла в начале:
[CACHED] system prompt + инструкции + few-shot examples + knowledge base pins
[VARIABLE] retrieved_docs + user_query + chat_history
Реализация
messages = [
{"role": "system", "content": [
{"type": "text", "text": SYS_PROMPT},
{"type": "text", "text": FEW_SHOT_BLOCK, "cache_control": {"type": "ephemeral"}},
]},
{"role": "user", "content": build_user_message(retrieved, query)},
]
response = client.messages.create(
model="claude-3-sonnet-20240229",
system=messages[0]["content"],
messages=messages[1:],
)
Умное распределение «что кешировать»
Не всё retrieval-содержимое динамическое. У нас есть набор «pin documents» — топ-20 самых часто используемых доков (FAQ, глоссарий, политика). Они попадают в кешируемую часть всегда. Остальное подтягивается динамически.
| Блок | Размер | Стабильность | Кешируем? |
|---|---|---|---|
| System prompt | 400 tok | всегда | да |
| Few-shot examples | 1400 tok | всегда | да |
| Pin documents (top-20) | 2800 tok | раз в день | да |
| Dynamic retrieval (5 docs) | ~2000 tok | на запрос | нет |
| User query + history | ~500 tok | на запрос | нет |
Что получили
| Метрика | До | После |
|---|---|---|
| Средний input cost на запрос | $0.018 | $0.0065 |
| p50 time-to-first-token | 860ms | 420ms |
| Cache hit rate (5-минутное окно) | — | 83% |
Подводные камни
- 5-минутный TTL. Кеш живёт недолго. При низкой частоте запросов выгода падает — имеет смысл добавить «keep-warm» ping раз в 4 минуты.
- Мутные обновления pins. Если пересобирать блок pin-доков каждый час, cache invalidation бьёт по hit rate. Мы пересобираем раз в день ночью.
- Длина cached блока. Anthropic: минимум 1024 токена. Маленькие system prompts нет смысла кешировать.
Вывод
RAG + caching — это не архитектурное решение, а конфигурация. Разделите промпт на стабильную и динамическую часть, замерьте hit rate, следите, чтобы pin-блок обновлялся редко. Экономия 50–70% на input-cost получается почти бесплатно.
← Ко всем постам