Со временем у тебя накопится сотни заказов, карточек материалов, записок мастеров. Клиент спрашивает: «такая же, как делали у Петровых два года назад, но этажей три». Ты хочешь, чтобы LLM-ассистент «вспомнил» тот заказ. Запихнуть всю историю в промпт — дорого. Нужен поиск по базе с подачей нужных кусков в промпт. Это и есть RAG (Retrieval-Augmented Generation). А contextual retrieval — его улучшенная версия от Anthropic.
<context>.Когда ты режешь большой документ (скажем, полную карточку заказа Петровых) на чанки по 500 слов, из каждого чанка «выпадает» окружение: кто клиент, когда делали, какая лестница. Строка «использовали дуб 40мм» сама по себе плохо находится на запрос «как делали у Петровых».
Перед эмбеддингом каждого чанка дописываем к нему короткий контекст — кто клиент, когда, о чём заказ. Делает это сама LLM: даём ей полный документ и чанк, просим написать 1–2 предложения контекста. Пример:
исходный чанк:
«использовали дуб 40мм, марш 2800, ширина 900»
контекстуализированный чанк:
«Заказ Петровых от 2024-03 (2-этажный дом, маршевая лестница):
использовали дуб 40мм, марш 2800, ширина 900»
Что здесь происходит: теперь этот чанк найдётся и на запрос «Петровы», и на «двухэтажная маршевая», и на «дуб 40». Точность поиска в разы выше.
Благодаря prompt caching один и тот же документ подставляется для каждого своего чанка, но кешируется — и обработка архива выходит около $1 за миллион токенов документа. Это разовая стоимость: контекстуализированные чанки сохранил — дальше они используются бесплатно.
Честно: для MVP — нет. Пока заказов меньше
50–100, можно обходиться SQL-поиском по полям
(WHERE wood_type = ? AND floors = ?) и подачей
найденных карточек целиком в промпт. Это не RAG, но работает до
определённого масштаба.
Contextual retrieval пригодится, когда:
// Добавляешь расширение в Postgres
CREATE EXTENSION IF NOT EXISTS vector;
// Таблица с чанками
CREATE TABLE kb_chunks (
id BIGSERIAL PRIMARY KEY,
source_type TEXT, -- 'order' | 'material' | 'note'
source_id BIGINT,
text TEXT NOT NULL, -- контекстуализированный текст
embedding vector(1536) -- размерность под text-embedding-3-small
);
// Индекс для быстрого поиска
CREATE INDEX ON kb_chunks USING ivfflat (embedding vector_cosine_ops);
Что здесь происходит: pgvector добавляет тип
vector в Postgres. Храним текст + его эмбеддинг.
Поиск — обычный SQL-запрос с оператором <=> (косинусная
дистанция) и ORDER BY … LIMIT 20.
text-embedding-3-small OpenAI
(дешёвые, достаточно точные).