RAG-пайплайн на своих данных: минимальная схема
RAG не обязан начинаться с векторной базы. Разбираем минимальную схему: когда достаточно длинного контекста, а когда нужен полноценный retrieval.
5 мин · · Обновлено · разработка · rag
RAG обычно объясняют через связку «эмбеддинги → векторная база → топ-к чанков → генерация», и половина статей сразу начинается с выбора векторной БД. На практике для небольшого и среднего корпуса документов эта связка часто избыточна, а шлюз zukko эмбеддинги не отдаёт — здесь только генерация текста и веб-поиск. Разберём, что из этого реально собирается и когда векторный поиск всё-таки нужен.
Когда векторная база не нужна вообще
У моделей Claude и GPT в каталоге контекст 1,000,000 токенов (у glm-5.3 и glm-5.3-flash — 128K). Это примерно 700-800 тысяч слов — целая база знаний среднего размера компании, набор внутренней документации или сотня договоров помещаются в один запрос без всякого retrieval. Если корпус укладывается в такой объём, минимальная схема RAG — это не пайплайн, а один системный промпт:
curl https://api.zukko.pro/v1/messages \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1500,
"system": "'"$(cat knowledge_base.md | jq -Rs .)"'",
"messages": [{"role": "user", "content": "Как оформить возврат оборудования по договору аренды?"}]
}'Перед тем как городить векторную базу, стоит посчитать реальный объём данных через бесплатный подсчёт токенов — часто оказывается, что корпус заметно меньше лимита контекста:
curl https://api.zukko.pro/v1/messages/count_tokens \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model": "claude-opus-5-5", "messages": [{"role": "user", "content": "'"$(cat knowledge_base.md | jq -Rs .)"'"}]}'Учтите цену такой схемы: вся база знаний оплачивается как входные токены в каждом запросе. У вендоров повторное чтение из кэша промптов стоит ~10% цены входа, а в Zukko кэшированные токены идут по обычной цене — для сценариев с большим повторяющимся контекстом реальная разница в цене меньше, чем при сравнении прайсов «в лоб».
Когда retrieval всё-таки нужен
Если корпус растёт быстрее контекста — сотни тысяч документов, логи, тикеты за годы — засовывать всё в промпт перестаёт работать: растёт цена запроса и модель хуже фокусируется на релевантном фрагменте среди шума. Здесь нужен классический retrieval: эмбеддинги считаются любым отдельным сервисом эмбеддингов (шлюз zukko их не предоставляет — это чисто генеративный API), результаты хранятся в любой векторной базе на ваш выбор, а сам шлюз используется только на этапе генерации ответа по найденным чанкам:
import requests
# retrieval - свой векторный поиск, вне zukko
relevant_chunks = vector_search(query, top_k=8)
context = "\n\n---\n\n".join(chunk.text for chunk in relevant_chunks)
resp = requests.post(
"https://api.zukko.pro/v1/messages",
headers={
"Authorization": "Bearer fetch_ваш_ключ",
"anthropic-version": "2023-06-01",
},
json={
"model": "claude-sonnet-5",
"max_tokens": 1000,
"system": f"Отвечай только на основе этих фрагментов:\n\n{context}",
"messages": [{"role": "user", "content": query}],
},
)Разделение чёткое: retrieval — ваша инфраструктура, генерация — вызов /v1/messages или /v1/chat/completions.
Гибридная схема: tool calling вместо жёсткого пайплайна
Вместо того чтобы всегда сначала искать, а потом генерировать, можно отдать модели решение о том, нужен ли retrieval вообще, через /v1/responses с описанием инструмента поиска:
curl https://api.zukko.pro/v1/responses \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6-sol",
"input": "Сколько у нас открытых договоров с автопродлением на 2027 год?",
"tools": [{
"type": "function",
"name": "search_documents",
"description": "Ищет релевантные фрагменты во внутренней базе документов",
"parameters": {"type": "object", "properties": {"query": {"type": "string"}}}
}]
}'Модель сама решает, вызывать ли search_documents (ваша функция retrieval на стороне приложения) или отвечать напрямую, если вопрос не требует обращения к базе. /v1/responses принимает и строку, и массив сообщений, и список инструментов, что удобно для такого агентного шаблона.
Веб-поиск как источник для внешнего контекста
Если часть RAG-системы должна отвечать на вопросы про внешний мир, а не только про внутренние документы — например, «сравни наши условия с рыночными» — для моделей без встроенного поиска есть отдельный вызов:
curl https://api.zukko.pro/v1/web-search \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{"query": "средние ставки аренды коммерческой недвижимости 2026"}'Результат подмешивается в контекст следующего запроса тем же способом, что и внутренние чанки — с точки зрения генерации разницы между «внутренний retrieval» и «веб-поиск» нет, оба просто дают текст в system или user-сообщение.
Кэш для повторяющихся вопросов
В RAG для поддержки или базы знаний одни и те же вопросы задают многократно. Если ответ должен быть детерминированным при одинаковом наборе найденных чанков, есть смысл ставить заголовок X-Zukko-Cache: true (temperature: 0 тоже включает кэш, но только у моделей, которые принимают этот параметр; Claude-модели — claude-sonnet-5, claude-opus-5-5 — могут отклонить temperature, отличную от 1, с ошибкой 400, поэтому им его не передавайте) — повторный одинаковый запрос от того же пользователя вернётся из кэша мгновенно и бесплатно (X-Zukko-Cache: hit в ответе), кэш для чата живёт до 7 суток. Важно: кэш срабатывает только при полном совпадении тела запроса — и формулировки вопроса, и набора чанков, и параметров; «почти одинаковые» вопросы в него не попадают, а сами попадания не пишутся в /v1/usage. Экономия появляется там, где популярный вопрос приходит в той же формулировке и retrieval возвращает тот же набор чанков день за днём.
Оценка стоимости и выбор модели по этапу
Для этапа генерации ответа по найденным чанкам обычно пробуют claude-sonnet-5 или gpt-5.6-sol — задача не требует расширенного рассуждения, если чанки уже релевантны; для простых выборок цитат можно проверить и более дешёвые gpt-5.6-luna или glm-5.3 ($0.10/$0.10). claude-opus-5-5 имеет смысл пробовать там, где ответ требует сопоставления нескольких документов и явного вывода (например, «есть ли противоречие между пунктом 4.2 договора А и пунктом 7.1 договора Б») — по цене в Zukko он не отличается от Sonnet 5 и Sol ($0.30/$0.30), так что проверьте на своих задачах, какая модель даёт результат лучше.
Ошибки, характерные для RAG-пайплайна
404 model_not_found в тестах часто всплывает, если в конфиге агента остался старый id модели после миграции (а модель, выключенная в каталоге, отвечает 503 model_disabled) — стоит сверяться со свежим списком через GET /v1/models, он публичный и не требует ключа. 422 idempotency_conflict встречается, если retry-логика пайплайна переиспользует один Idempotency-Key для запросов с разным набором найденных чанков — ключ должен зависеть не только от вопроса пользователя, но и от версии контекста, который в него подставили. Обрыв ответа на середине генерации почти всегда означает нехватку max_tokens, а не проблему с retrieval — если модель должна процитировать несколько длинных фрагментов, стоит закладывать больше токенов на выход, чем для короткого ответа на прямой вопрос.
Итог: для небольшого корпуса RAG — это системный промпт и большой контекст, без единого дополнительного сервиса. Для растущего корпуса — свой retrieval плюс генерация через API, где выбор модели зависит от того, нужен ли просто пересказ найденного или сопоставление нескольких источников.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Промпт-инъекция: что это и как защитить бота и агентаОбъясняем, как работает промпт-инъекция через пользовательский ввод и чужие документы, и какие меры снижают ущерб: изоляция данных, права инструментов, лимиты ключа.
- Свой прокси к нейросети на Node.js: не показывать API-ключ во фронтендеНебольшой сервер на Express между вашим фронтендом и API нейросети: ключ остаётся на сервере, а модели, длина запроса и частота ограничены.
- DeepSeek API на Python: запросы, стриминг, JSON и обработка ошибокГотовый код для DeepSeek V4.1 Flash и V4 Pro на OpenAI SDK: запрос, стриминг, разбор JSON и аккуратная обработка ошибок.
- Промпт-инжиниринг: примеры и 12 готовых шаблонов для работыДвенадцать шаблонов промптов для рабочих задач: что в них написано, почему именно так и сколько стоит один вызов по API.