Semantic cache ускоряет ответ ценой нового класса ошибок

Обычный exact cache возвращает значение только для одинакового ключа. Semantic cache строит embedding запроса и ищет похожие записи. Это полезно для повторяющихся FAQ и справочных вопросов, но близость векторных представлений не доказывает одинаковый правильный ответ.

Cache miss вызывает новый LLM-call и стоит денег. False hit мгновенно возвращает чужой, устаревший или контекстно неверный ответ. Поэтому оптимизация начинается с качества reuse decision.

1
решение: reuse или generate
2
уровня: exact и semantic
0
reuse без scope

Не путайте четыре вида кэширования

ВидЧто переиспользуетГлавный риск
Prompt cacheВычисление общего input prefixНе кэширует готовый смысловой ответ
Exact response cacheОтвет по идентичному canonical keyНеполный key
Semantic response cacheОтвет похожего запросаFalse semantic hit
Retrieval cacheРезультаты поиска chunksУстаревший corpus

Эти слои имеют разные TTL, invalidation и метрики. Не называйте их одним cache hit в dashboard.

Когда semantic reuse действительно уместен

Хороший кандидатПочемуПлохой кандидат
Стабильный FAQОдин проверенный ответБаланс счёта пользователя
Инструкция по продуктуВерсионируемый corpusТекущая цена или наличие
Объяснение политикиОтвет привязан к версииЮридическое решение по кейсу
Классификация ограниченного набораВалидируемый labelСвободный творческий текст
Повторяющийся helpdeskВысокая частота paraphraseAgent tool plan с side effects

Сначала exact cache, затем semantic

Exact cache дешевле, объяснимее и имеет меньшую вероятность неверного reuse. Постройте canonical request key, измерьте повторяемость и только затем добавляйте embeddings для оставшихся запросов. Это создаёт baseline и показывает верхнюю границу дополнительной пользы.

Normalize

Только безопасные различия.

Exact lookup

Canonical key и version scope.

Semantic lookup

Только после exact miss.

Определите cache eligibility до lookup

Не каждый запрос должен попасть в cache. Детерминированный policy слой проверяет intent, data class, наличие персональных параметров, time sensitivity, side effects и требование свежего retrieval. Модель может помочь классифицировать, но окончательное решение принимает runtime.

Allow response caching only when:
use_case is allowlisted
AND no secrets or sensitive personal data
AND no live transaction state
AND no tool side effects
AND answer is reusable across the selected scope
AND source and policy versions are known
AND response passed validation

Otherwise bypass cache and record the reason.

Cache key обязан включать весь контекст ответа

Одинаковый вопрос может иметь разные ответы для tenant, языка, тарифа, региона, версии продукта и policy. Если эти dimensions не входят в scope, hit становится утечкой или логической ошибкой.

scope_hash = SHA256(
  tenant_id + workspace_or_public_scope
  + actor_policy_hash + locale + region
  + product_version + model_version
  + prompt_version + tool_schema_version
  + retrieval_corpus_version + safety_policy_version
  + output_schema_version
)

Vector search is executed only inside scope_hash.

Нормализация не должна удалять смысл

Можно унифицировать Unicode, пробелы и безопасные представления регистра. Нельзя бездумно удалять числа, отрицания, даты, product IDs, единицы измерения и порядок, если он влияет на запрос.

ОперацияОбычно безопасноРиск
Unicode normalizationДа, после тестовРедкие символы
Whitespace foldingДля обычного текстаКод и таблицы
LowercaseЗависит от языкаIDs и case-sensitive values
Удаление punctuationОсторожноФормулы и отрицания
Удаление чиселНетМеняет вопрос

Embedding model является частью версии cache

Смена embedding model, dimensions или preprocessing меняет геометрию similarity. Не смешивайте vectors разных версий в одном поисковом пространстве. Создавайте новый namespace и прогревайте его отдельно.

  • Храните provider, model ID и dimensions.
  • Версионируйте normalization pipeline.
  • Проверяйте supported distance metric.
  • Не сравнивайте scores между разными индексами.
  • Миграция проходит shadow dual lookup.

Threshold выбирается на размеченных парах

Число similarity из примера документации не является универсальным порогом. Соберите пары запросов: safe reuse, unsafe reuse и hard negatives, различающиеся одним числом, отрицанием, tenant или временем. Постройте precision/recall по threshold.

For each query pair label:
SAFE_REUSE - same correct answer under the same scope
UNSAFE_REUSE - similarity exists, but answer differs

For every candidate threshold calculate:
accepted-hit precision
accepted-hit recall
false-hit severity-weighted loss
expected saved inference cost
embedding + storage + review cost

Choose threshold under a minimum precision gate.

Один global threshold почти всегда слаб

Разные intents и языки имеют разные score distributions. FAQ о настройке может терпеть paraphrase, а вопрос со сроком или версией требует exact constraints. Применяйте threshold по use case, locale и risk tier, но не создавайте сотни необслуживаемых правил без данных.

P
precision gate
R
reuse coverage
L
severity-weighted loss

Candidate проходит не только similarity

После vector search проверьте scope, eligibility, source versions, TTL, locale, response schema, safety flags и статус validation. Можно дополнительно использовать дешёвый reranker или rule-check по критичным сущностям.

Reuse gate
  1. Точный scope hash.
  2. Similarity выше calibrated threshold.
  3. Совпадают критичные entities.
  4. Entry не истёк.
  5. Source versions актуальны.
  6. Prompt/model/schema совместимы.
  7. Response прошёл quality gate.
  8. Safety policy разрешает reuse.
  9. Entry не revoked.

Cache entry хранит доказательства происхождения

Недостаточно сохранить query, vector и answer. Добавьте scope, versions, timestamps, sources, validation, safety, usage и invalidation tags. Raw sensitive prompt хранится только при необходимости и по retention policy.

entry_id, scope_hash
canonical_query_hash, embedding_ref, embedding_version
response, response_schema_version
model_version, prompt_version, policy_version
source_ids_and_versions, generated_at
validated_at, validator_version, quality_status
expires_at, invalidation_tags, revoked_at
hit_count, last_hit_at
data_class, encryption_key_ref

Freshness определяется данными, а не только TTL

Фиксированный TTL удобен, но изменение документа должно инвалидировать ответ сразу. Назначьте dependency tags: product version, policy ID, catalog snapshot, source document. Событие обновления помечает связанные entries revoked либо переключает versioned namespace.

СтратегияПлюсМинус
TTLПростоОкно устаревания
Event invalidationБыстро после changeНужна надёжная доставка
Versioned namespaceAtomic cutoverНужно прогревать
Read-time version checkСильная свежестьДополнительная latency
Manual revokeIncident responseНе основной механизм

Stampede возникает и у semantic cache

После массовой invalidation много одинаковых miss одновременно идут в LLM. Используйте single-flight по canonical cluster, короткий lease на regeneration, jittered TTL и bounded refresh queue. Не заставляйте user request ждать бесконечный rebuild.

  • Один leader генерирует candidate.
  • Followers ждут ограниченное время или обходят cache.
  • Failed generation не записывается как valid.
  • Negative cache для terminal invalid requests имеет короткий TTL.
  • Refresh не вытесняет interactive quota.

Tenant isolation проверяется до vector search

Запрос к общему vector index без tenant filter уже нарушает boundary, даже если результат отфильтровали позже. Используйте namespace или mandatory pre-filter и повторную ownership-проверку. Public cache - отдельный явный scope, а не запись без tenant ID.

Scope

Trusted tenant и policy context.

Search

Только внутри разрешённого partition.

Verify

Ownership и versions после retrieval.

Cache poisoning начинается с плохой записи

Если атакующий добился сохранения вредоносного или неверного ответа, semantic cache масштабирует его на похожие запросы. Кэшируйте только outputs из allowlisted workflow, прошедшие schema, safety и quality validation. Разделяйте запись и чтение правами.

Poisoning defense
  1. Write path аутентифицирован.
  2. Только eligible use cases.
  3. Output schema валидна.
  4. Tool errors не кэшируются.
  5. Prompt injection не попадает в answer.
  6. Sources и versions сохранены.
  7. Quality status обязателен.
  8. Mass insert и unusual hits вызывают alert.
  9. Есть revoke и purge по тегу.

Персонализация резко сужает reuse

Ответ, использующий историю, тариф, регион или права пользователя, нельзя отдавать другому actor только потому, что вопрос похож. Либо включайте эти dimensions в scope, что снижает hit rate, либо кэшируйте общий reusable skeleton и подставляйте проверенные персональные данные после.

ПодходБезопасностьHit rate
Global answerТолько публичный static contentВысокий
Tenant scopeОрганизационные данныеСредний
User scopeПерсональный контекстНизкий
Cached skeletonДанные подставляет backendВысокий для шаблона

Не кэшируйте agent plans как готовое действие

План, tool arguments и approval зависят от текущего state. Можно кэшировать read-only справочную часть или шаблон декомпозиции, но runtime заново проверяет preconditions и строит proposal. Cached output никогда не является разрешением на side effect.

  • Approval не переносится между requests.
  • Idempotency key не хранится как reusable response.
  • Tool catalog/version входит в scope.
  • Живые данные перечитываются.
  • Policy decision выполняется заново.

Метрики должны отличать полезный hit от любого hit

МетрикаСмысл
Exact hit rateПовтор идентичного canonical request
Semantic candidate rateНайдено выше raw threshold
Accepted hit rateПрошли все reuse gates
Accepted-hit precisionДоля действительно корректного reuse
False-hit severityВзвешенный ущерб ошибок
Cost per accepted answerLLM + embeddings + cache + review
Freshness rejectionСколько candidates устарели
Cross-scope rejectionПроверка isolation policy

ROI считается после учёта embeddings и ошибок

Экономия inference уменьшается на embedding calls, vector search, storage, replication, invalidation, engineering и manual review. False hit может стоить больше десятков правильных hits. Считайте ожидаемую ценность по сегментам.

net_value = avoided_LLM_cost
  + avoided_latency_value
  - embedding_cost
  - cache_storage_and_search
  - invalidation_and_operations
  - review_cost
  - severity_weighted_false_hit_loss

cost_per_accepted_answer = total_system_cost / accepted_answers

Shadow rollout отделяет поиск от выдачи

  1. Соберите baseline запросов, качества, latency и cost.
  2. Включите exact cache.
  3. Запустите semantic lookup в shadow без выдачи.
  4. Разметьте candidates и откалибруйте thresholds.
  5. Разрешите low-risk FAQ небольшой cohort.
  6. Показывайте provenance и feedback control.
  7. Следите за false hits и freshness.
  8. Расширяйте intents по одному.
  9. Держите мгновенный bypass и purge.

Production-чек-лист semantic cache

Перед включением reuse
  1. Use case разрешает одинаковый reusable answer.
  2. Exact cache работает отдельно.
  3. Eligibility policy детерминирована.
  4. Scope включает tenant, policy и все versions.
  5. Нормализация не удаляет смысл.
  6. Embedding pipeline версионируется.
  7. Threshold откалиброван на hard negatives.
  8. Metadata и freshness gates обязательны.
  9. Entries имеют provenance и validation.
  10. Event invalidation и manual revoke работают.
  11. Vector search изолирован до retrieval.
  12. Poisoning и mass insert отслеживаются.
  13. Side effects никогда не разрешаются cache hit.
  14. Метрики считают precision и severity.
  15. Shadow, canary, bypass и purge протестированы.
Что такое semantic cache для LLM?
Это хранилище запросов, embeddings и проверенных ответов, которое ищет семантически похожий предыдущий запрос и при выполнении policy возвращает его ответ без нового LLM-вызова.
Чем semantic cache отличается от prompt caching?
Prompt caching переиспользует вычисление одинакового префикса input, но модель всё равно генерирует новый ответ. Semantic response cache возвращает ранее созданный ответ целиком на похожий запрос.
Как выбрать similarity threshold?
На размеченном наборе safe и unsafe query pairs, включая hard negatives с числами, отрицаниями и версиями. Выберите порог под минимально допустимую accepted-hit precision и стоимость false hits.
Можно ли использовать один cache для всех клиентов?
Только для явно публичного стабильного контента в отдельном scope. Клиентские записи ищутся внутри tenant namespace или обязательного pre-filter, а ownership проверяется повторно.
Как обновлять устаревшие ответы?
Комбинируйте TTL, dependency tags, события изменения источников и versioned namespaces. При инциденте нужны manual revoke и purge; при lookup проверяются source и policy versions.
Какие ответы нельзя кэшировать?
Секреты, персональные и транзакционные ответы, live state, непроверенные outputs, ошибки tools, юридические решения по конкретному кейсу, approvals и agent actions с side effects.
Как защититься от cache poisoning?
Ограничить write path, кэшировать только allowlisted workflow после schema, safety и quality validation, сохранять provenance, мониторить массовые inserts и необычные hits и иметь быстрый revoke.
Как понять, что semantic cache окупается?
Считать net value и cost per accepted answer, включая embeddings, vector search, storage, invalidation, review и severity-weighted false-hit loss, а не только число сэкономленных LLM calls.
← Все статьи блога