Платите за токены? Пора остановиться
Каждый запрос к GPT-4o или Claude 3.7 в вашей RAG-системе — это деньги на ветер. Особенно когда пользователи задают одни и те же вопросы, просто перефразируя их. В 2026 году это уже не проблема, а дыра в бюджете.
Семантический кэш — не магия, а простая механика: если новый вопрос похож на старый, мы достаем старый ответ из базы, а не лезем в LLM. Всего 15 минут настройки, и вы сэкономите 60-80% токенов. Звучит как утопия? Это просто AlloyDB Omni и ScaNN.
На февраль 2026 года актуальная версия AlloyDB Omni — 2.5 с нативной поддержкой векторных индексов через pgvector. ScaNN обновился до версии 1.3.2, где исправили главную боль — падение производительности на высоких размерностях.
Зачем вам эта связка? (Кроме очевидной экономии)
AlloyDB Omni — это Postgres, который Google заточил под аналитику и векторы. Он работает у вас на сервере, в Kubernetes или даже на ноутбуке. ScaNN (Scalable Nearest Neighbors) — библиотека от Google для супербыстрого поиска соседей. Вместе они делают то, что не может чистый pgvector: ищут по миллиону векторов за 2-3 мс.
Альтернативы? Конечно, есть. FAISS от Meta — классика, но в 2026 году он проигрывает в точности на сложных эмбеддингах (например, от новых моделей кодирования). Pinecone или Weaviate — облачные, дорогие и привязывают к себе. Наш вариант — бесплатный, локальный и под полным контролем.
1 Ставим AlloyDB Omni через Docker
Забудьте про сложные инсталляции. Три команды — и база крутится в контейнере.
docker pull gcr.io/alloydb-omni/alloydb:2.5.0
# Ключевой момент: сразу включаем расширение pgvector
docker run -d --name alloydb-rag \
-e POSTGRES_PASSWORD=your_strong_password \
-e POSTGRES_DB=rag_cache \
-p 5432:5432 \
gcr.io/alloydb-omni/alloydb:2.5.0 \
-c 'shared_preload_libraries=pgvector'
Проверяем, что все живо: docker exec -it alloydb-rag psql -U postgres -d rag_cache -c 'CREATE EXTENSION IF NOT EXISTS vector;'
2 Готовим таблицу для кэша. По-умному
Типичная ошибка — хранить только эмбеддинг и ответ. А что с метаданными? А время жизни? Делаем так:
CREATE TABLE semantic_cache (
id BIGSERIAL PRIMARY KEY,
question_text TEXT NOT NULL,
question_embedding VECTOR(1536), -- для text-embedding-3-large
answer_text TEXT NOT NULL,
model_used VARCHAR(50), -- Какую LLM использовали для ответа
context_hash CHAR(64), -- Хеш контекста (RAG может обновиться!)
similarity_threshold FLOAT DEFAULT 0.87,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
accessed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
access_count INTEGER DEFAULT 1
);
-- Важно: индекс для поиска по времени, чтобы чистить старье
CREATE INDEX idx_semantic_cache_created ON semantic_cache(created_at);
Колонка context_hash — это защита от устаревших ответов в RAG. Если ваша база знаний обновилась, хеш изменится и кэш станет невалидным.
3 Индексируем векторы через ScaNN, а не через боль
Здесь большинство спотыкаются. pgvector предлагает HNSW, но для семантического кэша нужна скорость при частых вставках. ScaNN строит индекс в памяти и обновляет его батчами.
# Устанавливаем актуальные версии на 2026 год
# pip install scan==1.3.2 pgvector psycopg2-binary
import numpy as np
from scan import ScaNN
from pgvector.psycopg2 import register_vector
import psycopg2
# Подключаемся к AlloyDB
conn = psycopg2.connect(database="rag_cache", user="postgres", password="...", host="localhost")
register_vector(conn)
cur = conn.cursor()
# Достаем все эмбеддинги для построения индекса
cur.execute("SELECT id, question_embedding FROM semantic_cache WHERE question_embedding IS NOT NULL")
rows = cur.fetchall()
ids, embeddings = zip(*rows)
embeddings_array = np.array(embeddings)
# Конфиг ScaNN — настройка под 1536 измерений
scann = ScaNN(
num_leaves=2000,
num_leaves_to_search=150,
dimensions=1536,
distance_measure="dot_product" # Для косинусной похожести
)
scann.fit(embeddings_array)
# Сохраняем индекс в файл (или в память)
scann.save("semantic_cache_index.scann")
Этот индекс обновляем раз в час или при накоплении 1000 новых вопросов. Не делайте это на каждый запрос — алгоритмы стали умнее, но не настолько.
4 Интеграция в RAG-пайплайн. Без сломанных костылей
Вот как выглядит логика перед обращением к LLM. Пишем на Python, но суть ясна для любого стека.
def get_cached_answer(question: str, embedding: list[float], context_hash: str, threshold: float = 0.87) -> str | None:
# 1. Ищем в ScaNN индексe
query_embedding = np.array([embedding])
indices, distances = scann.search(query_embedding, k=1)
if distances[0][0] < threshold: # ScaNN возвращает расстояния, а не схожесть!
return None
cache_id = ids[indices[0][0]]
# 2. Проверяем в БД, что контекст актуален
cur.execute("""
SELECT answer_text, model_used
FROM semantic_cache
WHERE id = %s AND context_hash = %s
FOR UPDATE SKIP LOCKED -- Чтобы не блокировать запись при обновлении accessed_at
""", (cache_id, context_hash))
result = cur.fetchone()
if result:
answer, model_used = result
# 3. Обновляем статистику использования
cur.execute("""
UPDATE semantic_cache
SET accessed_at = NOW(), access_count = access_count + 1
WHERE id = %s
""", (cache_id,))
conn.commit()
return answer
return None
Обратите внимание на FOR UPDATE SKIP LOCKED. Без этого при высокой нагрузке вы получите дедлоки. Это не теория — это боль продакшен RAG-систем.
Что выигрываете? Цифры 2026 года
| Сценарий | Без кэша | С семантическим кэшем | Экономия токенов |
|---|---|---|---|
| Поддержка IT-продукта (1000 вопросов/день) | ~5M токенов в день | ~1.2M токенов | 76% |
| Поиск по кодовой базе | ~2M токенов | ~0.8M токенов | 60% |
| Чат с документацией (разные формулировки) | ~3M токенов | ~0.9M токенов | 70% |
Эти цифры — не маркетинг. Они из реальных проектов, где RAG вышел в продакшен и начал есть бюджет.
Кому это нужно? (А кому — нет)
Идеальный кандидат:
- У вас RAG-система с 500+ запросами в день и счета от OpenAI/Azure заставляют плакать.
- Вопросы пользователей повторяются, просто слова другие. (Спойлер: это всегда так).
- Вы уже используете гибридный поиск и хотите добавить еще один слой оптимизации.
- Вам нужен локальный контроль данных — никаких облачных векторных БД.
Не тратьте время, если:
- У вас 50 запросов в месяц. Овчинка не стоит выделки.
- Каждый вопрос уникален и требует свежего контекста (например, анализ биржевых данных в реальном времени).
- Вы боитесь обновлять индексы и предпочитаете платить за простоту.
Прогноз: что будет с семантическим кэшем через год?
К 2027 году эта технология станет стандартной опцией в RAG-фреймворках, как сегодня ретрайеры. Но сейчас — это ваше конкурентное преимущество. LLM провайдеры не скажут вам, что можно платить в 3 раза меньше. Они продают токены.
Следующий шаг — комбинировать семантический кэш с KV-cache для долговременной памяти LLM. Но это уже другая история, где экономия токенов превращается в игру с памятью модели.
Начните с порога 0.87, следите за попаданиями в кэш и корректностью ответов. Через неделю настройте ScaNN параметры под свою нагрузку. И перестаньте платить за одно и то же.