Перейти к содержимому

4.2 · Как устроен RAG: обзор архитектуры

Неделя 4 · RAG · ⏱ ~2–3 ч · Теория

RAG (Retrieval-Augmented Generation) — самый частый паттерн в продуктах на LLM: чат по документации, база знаний компании, поддержка, поиск по договорам. На собеседовании просят нарисовать RAG-систему на доске и объяснить, где она ломается. В главе 4.1 мы научились одному звену — искать тексты по смыслу через эмбеддинги. Здесь видим цепочку целиком, и каждую следующую задачу недели (chunking, индекс, гибридный поиск, цитаты) мы кладём на своё место, а не изучаем изолированно.

У LLM три ограничения: знания заморожены на дате обучения, модель не видит наших приватных данных и уверенно выдумывает, когда не знает. База знаний магазина меняется постоянно: новые тарифы доставки, другие сроки возврата, новые товары с собственной гарантией. Спросить модель «можно ли вернуть вскрытый чай в магазине „Полка“» без контекста — получить правдоподобную выдумку.

Идея RAG: перед генерацией найти релевантные куски наших документов и положить их в промпт. Найти их помогает поиск по смыслу из прошлой главы. Модель отвечает не «из головы», а по предоставленному тексту — как студент на открытом экзамене с конспектом.

Альтернативы и когда они лучше:

Подход Когда подходит
Положить всё в контекст (long context) Документов мало (десятки страниц), они помещаются в окно модели; с prompt caching это бывает дешевле и проще RAG
Fine-tuning Нужно изменить стиль/формат/поведение, а не добавить факты; факты через fine-tuning учатся плохо и устаревают
RAG Документов много, они меняются, нужны ссылки на источник

Статья Anthropic про Contextual Retrieval прямо говорит: если база меньше ~200 тысяч токенов, сначала стоит просто положить её в промпт. Эту планку полезно помнить — это хороший ответ на собеседовании. Наша учебная база знаний (30–50 страниц, которые мы соберём в главах 4.3–4.4) под неё, скорее всего, попадает, и мы честно держим вариант «всё в промпт» как baseline. RAG строим ради ссылок на точный раздел и ради умения, которое нужно на базах в тысячи страниц: там «всё в промпт» уже не работает.

ИНДЕКСАЦИЯ (офлайн, по расписанию / при обновлении доков)
┌─────────┐ ┌───────┐ ┌──────────┐ ┌───────────┐ ┌─────────────┐
│загрузка │──►│ чистка│──►│ chunking │──►│эмбеддинги │──►│ индекс │
│HTML/PDF │ │→ MD │ │+метаданные│ │ (+BM25) │ │ (вектор БД) │
└─────────┘ └───────┘ └──────────┘ └───────────┘ └─────────────┘
ЗАПРОС (онлайн, на каждый вопрос)
┌──────┐ ┌─────────────┐ ┌─────────┐ ┌───────────┐ ┌────────┐ ┌───────┐
│вопрос│─►│переформули- │─►│ поиск │─►│ реранкинг │─►│ промпт │─►│ LLM → │
│ │ │ровка+фильтры│ │ top-50 │ │ top-5 │ │+ куски │ │ответ+ │
└──────┘ └─────────────┘ └─────────┘ └───────────┘ └────────┘ │ссылки │
└───────┘

Это похоже на обычный бэкенд: есть фоновая работа (cron, очереди, прогрев кэша) и горячий путь (запрос пользователя → ответ). Индексация может быть медленной и дорогой, запрос должен быть быстрым.

Каждый этап: что делает и что может сломаться

Заголовок раздела «Каждый этап: что делает и что может сломаться»

Разберём этапы на примере нашего проекта. Его корпус — папка kb/: справочный центр «Полки» в виде Markdown-файлов (delivery.md, returns.md, warranty.md, страницы товаров в products/…). Каждый файл начинается с front matter — блока метаданных между строками --- (title, category, updated, у старой редакции правил — archived: true). Страницы напишем в главе 4.3.

1. Загрузка (ingestion). Скачать или прочитать HTML, PDF, Markdown, Confluence… Сломается: JS-рендеринг (страница пустая без браузера), навигация и футеры, попавшие в текст, устаревшие версии страниц. В нашем проекте основной источник — Markdown-файлы kb/ на диске, так что половина этих проблем снимается; веб-страницы — опционально.

2. Чистка. Превратить HTML в чистый Markdown: убрать меню, cookie-баннеры, сохранить заголовки, таблицы и блоки кода. Сломается: таблицы превращаются в кашу, код теряет отступы. Для базы знаний магазина таблицы тарифов доставки и сроков гарантии — самое ценное.

3. Chunking. Нарезать документы на куски, которые потом ищутся по отдельности. Слишком большой кусок — эмбеддинг «размыт», в промпт попадает лишнее; слишком маленький — теряется контекст («этот товар» — какой?). Подробно — гл. 4.3.

4. Метаданные. У каждого чанка: категория (category: доставка, возврат, гарантия…), путь к файлу с якорем раздела, раздел (заголовки-предки), дата обновления, признак архивной страницы (archived). Они нужны для фильтров («только returns», «без архивных») и для ссылок в ответе.

5. Эмбеддинги. Каждый чанк → вектор (гл. 4.1). Плюс обычно параллельно строят лексический индекс (BM25), чтобы точно находить артикулы, названия товаров и промокоды (гл. 5.2).

6. Индекс. Векторная БД или расширение к обычной (sqlite-vec, pgvector, Qdrant). Хранит векторы, текст, метаданные; умеет искать ближайших соседей с фильтром. гл. 4.4.

7. Обработка запроса. Покупатель пишет «а чай-то вскрытый можно сдать обратно?». Это стоит переписать в поисковые запросы («возврат вскрытого чая», «какие товары не подлежат возврату»), определить категорию и поставить фильтр: category = returns, архивные страницы исключить. гл. 5.1.

8. Поиск (retrieval). Векторный поиск и BM25 дают две выдачи, их объединяют (RRF, Reciprocal Rank Fusion — слияние по местам в выдачах, гл. 5.2) → кандидаты, обычно 20–100.

9. Реранкинг. Более точная, но медленная модель (cross-encoder: читает вопрос и кусок вместе и выдаёт оценку релевантности, а не сравнивает готовые векторы) пересортировывает кандидатов, оставляем 3–10. гл. 5.2.

10. Сборка промпта. Инструкция + пронумерованные куски с источниками + вопрос. Правила: отвечать только по кускам, ставить ссылки [1], [2], честно говорить «не нашёл» (в нашем проекте — и передавать вопрос человеку). гл. 5.3.

11. Генерация и пост-обработка. Ответ, ссылки на разделы (kb/returns.md#opened-tea-returns), проверка, что ссылки ссылаются на реально выданные куски.

Ошибка RAG почти всегда в retrieval, а не в генерации. Если нужного куска нет в контексте, лучшая модель не ответит правильно (или выдумает). Поэтому метрики делятся на две группы:

  • Retrieval: hit rate@k (попал ли нужный кусок в топ-k), recall@k (какая доля всех нужных кусков попала в топ-k), MRR (насколько высоко стоит первый нужный кусок).
  • Generation: faithfulness (ответ опирается на куски, а не выдуман), answer relevance (отвечает ли на вопрос), корректность ссылок.

Начинаем с первой группы: она дешёвая (не нужен LLM), детерминированная и показывает, где болит. Весь путь недель 4–5 построен на одной идее — маленький набор вопросов с известными ответами (golden set) и цифра hit rate после каждого улучшения. Систематические evals будут дальше в плане, здесь — их минимальная форма.

Contextual Retrieval: зачем читать вводную часть уже сейчас

Заголовок раздела «Contextual Retrieval: зачем читать вводную часть уже сейчас»

Одна из частых причин промахов retrieval сидит ещё в индексации — в том, как кусок оторван от своего документа. Anthropic описывает эту проблему: чанк, вырванный из документа, теряет контекст. Кусок «Гарантия — 12 месяцев со дня покупки» без указания товара почти бесполезен: это лампа «Свет» или «Свет мини»? Решение — перед эмбеддингом приписать к каждому чанку короткое пояснение, сгенерированное LLM по всему документу («Этот фрагмент со страницы товара „Лампа «Свет»“, раздел „Гарантия“, описывает срок гарантии»). Плюс BM25 рядом с эмбеддингами и реранкинг. Сейчас нужно понять проблему, решение будет в гл. 5.2. Для документов с заголовками есть дешёвый вариант того же: приписывать к чанку хлебные крошки заголовков (Товары > Лампа «Свет» > Гарантия) — это мы сделаем уже в гл. 4.3.

Архитектурные решения, которые надо принять заранее

Заголовок раздела «Архитектурные решения, которые надо принять заранее»

Этапы понятны; для каждого нужен конкретный инструмент. Часть решений проще принять один раз сейчас, чем менять посреди проекта.

Вопрос Варианты Решение для нашего проекта (по умолчанию)
Язык проекта Python / другой язык (JS, Go…) Python: самая богатая экосистема RAG, и весь курс на нём
Эмбеддинги API / локально Локально (Ollama или Sentence Transformers): у DeepSeek эмбеддингов нет; конкретная модель — по итогам сравнения в гл. 4.1
Хранилище sqlite-vec / pgvector / Qdrant sqlite-vec: один файл, знакомый SQLite
Лексический поиск BM25 в памяти / FTS5 в SQLite Начинаем с rank_bm25, FTS5 — как улучшение
Генерация Любая LLM с API DeepSeek (deepseek-flash), офлайн-вариант — Ollama; Claude/OpenAI для сравнения; имя модели и base_url из .env
Реранкер API / локальный cross-encoder Локальный cross-encoder (Sentence Transformers)
Интерфейс CLI / Streamlit / Telegram CLI для отладки, потом Streamlit или бот
Обновление Полная переиндексация / инкрементальная Хэш содержимого чанка → не дублировать (гл. 4.4)

Общая схема подходит любому RAG, но у нашего корпуса есть свои ловушки — именно на них будут построены проверки в следующих главах.

  • Точные идентификаторы: артикулы, промокоды, названия вроде «Свет» и «Свет мини», коды отказа оплаты. Чистые эмбеддинги их плохо различают → нужен гибридный поиск.
  • Похожие разделы на разных страницах: раздел «Гарантия» есть на каждой странице товара, правила возврата — в returns.md и в архивном returns-2025.md → фильтры по category и archived обязательны, иначе ответ про одну лампу склеится с гарантией другой, а действующие правила — со старыми.
  • Версии: старая редакция правил возврата лежит рядом с новой. В метаданных храним archived и дату обновления; архив по умолчанию из поиска исключаем.
  • Таблицы тарифов и гарантий — ключевой контент; не резать их пополам. Отдельно — числа, которые расходятся между страницами (порог бесплатной доставки в delivery.md и в promo.md), и вопросы, ответ на которые собирается из двух разделов.
  • Безопасность: проект работает только с публичной базой знаний. Ему не нужны данные клиентов, он не открывает базы магазина и ничего не меняет в заказах.

Архитектура RAG от провайдера не зависит. Меняется только то, кто стоит в двух «модельных» квадратиках схемы: эмбеддинги и генерация. К генерации относятся ещё переписывание запроса и, по желанию, contextual-пояснения к чанкам.

ИНДЕКСАЦИЯ: ... ─► chunking ─► [эмбеддинги: Ollama bge-m3 / Sentence Transformers] ─► sqlite-vec
ЗАПРОС: вопрос ─► [rewrite: DeepSeek или Ollama] ─► поиск ─► реранкер (локальный cross-encoder)
─► [ответ: DeepSeek; Ollama для приватного; Claude/OpenAI для сравнения] ─► ответ + ссылки
  • Эмбеддинги — локально. На ноябрь 2026 у DeepSeek нет эндпоинта эмбеддингов, подробно — в главе 4.1 · Эмбеддинги руками на numpy. Берём Ollama (/api/embed) или Sentence Transformers.
  • Генерация — DeepSeek. На ноябрь 2026 по странице Models & Pricing в API две модели: deepseek-flash (сейчас это DeepSeek-V4.1-Flash-1017) и deepseek-v4-pro. У обеих окно 1M токенов, JSON-вывод и tool calls, и у обеих по умолчанию включён режим рассуждения (thinking). Базовый URL для OpenAI SDK — https://api.deepseek.com. Имена моделей и цены меняются: имя модели держим в .env и проверяем страницу.
  • Реранкер — локально. Эндпоинта реранкинга на ноябрь 2026 нет ни у DeepSeek, ни у Ollama (в их документации его не найти). Cross-encoder запускается через Sentence Transformers, подробно — в гл. 5.2.
  • Безопасность. База знаний магазина публична (это его справочный центр), поэтому куски базы и вопросы о ней отправлять в облачные модели, включая DeepSeek, можно. Нельзя подмешивать в вопросы или в индекс что-то из приложения магазина: заказы, данные клиентов, журнал событий, ключи платёжного провайдера. Настоящие сообщения покупателей (имена, телефоны, номера заказов) в облако не уходят: для тестов на сообщениях клиентов берём выдуманные тексты или локальную модель. Серверы DeepSeek в Китае, но правило касается любого облачного провайдера. Если позже понадобится RAG по приватным данным, вся цепочка (эмбеддинги + генерация) — только на Ollama.

Что это меняет в решении «RAG или всё в контекст»

Заголовок раздела «Что это меняет в решении «RAG или всё в контекст»»

Планка «меньше ~200K токенов — попробовать положить всё в промпт» из статьи Anthropic зависит от окна и цены. У DeepSeek окно 1M, а кэширование контекста включено автоматически для всех (гайд Context Caching): повторяющийся префикс запроса берётся с диска и стоит в десятки раз дешевле. На 13.11.2026 у deepseek-flash в непиковое время вход при попадании в кэш стоит $0.003 за 1M токенов, при промахе $0.15, выход $0.60. В пиковые часы (01:00–04:00 и 06:00–10:00 UTC в будни) цены вдвое выше. Кэш best-effort: попадание не гарантировано, а неиспользуемый кэш очищается через часы или дни.

Весь kb/ «Полки» почти наверняка влезет в 1M, так что вариант «вся база знаний в промпт» на DeepSeek — дешёвый и честный baseline: держим его в голове и сравниваем с ним. RAG всё равно нужен: ответ должен ссылаться на конкретный раздел, архивные правила нельзя показывать модели наравне с действующими, а база знаний настоящей компании быстро дорастает до тысяч страниц и миллионов токенов, которые не влезут и в 1M. Наша маленькая база — полигон, на котором видна каждая ошибка retrieval.

Что нужно RAG Claude OpenAI DeepSeek Ollama
Эмбеддинги Своих нет (рекомендован Voyage AI) Есть Нет → Ollama / Sentence Transformers Есть, локально
Эндпоинт реранкинга Нет (у партнёров вроде Voyage, Cohere) Нет Нет → локальный cross-encoder Нет → Sentence Transformers
Генерация ответа Да Да Да, deepseek-flash / deepseek-v4-pro Да; качество зависит от размера модели и памяти компьютера
Окно контекста Смотри документацию модели Смотри документацию модели 1M токенов Ограничено моделью и памятью; задаётся num_ctx
Кэш длинного префикса Явный, через cache_control Автоматический (смотри гайд OpenAI) Автоматический; поля prompt_cache_hit_tokens / prompt_cache_miss_tokens в usage Платы нет — платим временем своего компьютера
Встроенные цитаты (Citations) Да В Chat Completions нет (что есть в других API OpenAI — смотри документацию) Нет; Anthropic-совместимый эндпоинт DeepSeek поле citations игнорирует Нет
Куда уходят данные США США Китай Никуда

Вывод для проекта: цитаты делаем вручную ([n] + проверка кодом, глава 5.3), эмбеддинги и реранкер — локально, генерация — DeepSeek. Ollama — полностью офлайн-вариант и путь для всего приватного.

Ограничение железа. Эмбеддинг-модели маленькие (bge-m3 ~1.2 GB), а размер локального генератора упирается в память: при 8 GB RAM — модели класса 3–4B (qwen3:4b, ~2.5 GB), при 16 GB — 7–8B, при 32 GB и больше — 14B и крупнее. Эмбеддинги, реранкер и генератор, загруженные одновременно, складываются по памяти, плюс всё, что ещё работает на машине. Это ещё одна причина, почему генерация здесь на DeepSeek: база знаний публичная, и отправлять её можно.

Практика этой главы — схема и решения, провайдеры здесь только подписи на квадратиках. Подписываем их честно: «эмбеддинги: Ollama bge-m3 (локально)», «генерация: DeepSeek deepseek-flash, имя модели из .env», «реранкер: Sentence Transformers (локально)», «Claude/OpenAI — опционально, для сравнения». На будущее запомним правило для evals: судья (LLM-as-judge) должен быть сильнее модели, которую он оценивает. Например, ответы deepseek-flash или локальной модели проверяет deepseek-v4-pro или Claude.

  1. Открываем Eugene Yan: Patterns for Building LLM-based Systems → читаем введение и раздел «Retrieval-Augmented Generation» (≈45 мин). Обратим внимание на: почему retrieval важнее генерации, гибридный поиск (BM25 + эмбеддинги), ANN-индексы, пример с тем, как классический поиск помогает там, где эмбеддинги промахиваются. Раздел про evals — бегло, он пригодится позже.
  2. Открываем Anthropic: Contextual Retrieval → читаем вводную часть до раздела с реализацией контекстных эмбеддингов, плюс заметку про базы меньше 200K токенов (≈20 мин). Выписываем формулировку проблемы «чанк теряет контекст» и цифры улучшения retrieval из статьи — к ним вернёмся в гл. 5.2.
  3. Открываем DeepLearning.AI short courses → находим в каталоге курс по RAG (там их несколько, набор меняется; искать по слову «RAG» или «Retrieval») и смотрим первые 2–3 урока на 1.5x (≈45 мин). Цель — увидеть, как кто-то другой рисует ту же цепочку; все ноутбуки проходить не нужно.
  4. Сравниваем три источника с диаграммой из «Теории» этой главы: какие этапы у кого есть, у кого нет (≈15 мин). Записываем расхождения — это вопросы, которые прояснятся в следующих главах.
  5. Открываем DeepSeek: Models & Pricing и Context Caching (≈20 мин). Выписываем текущие имена моделей, окно контекста, цены входа с попаданием и с промахом кэша, пиковые часы, как работает автоматический кэш и какие поля usage его показывают.
  6. Открываем DeepSeek: Anthropic API → таблицу совместимости (≈10 мин). Ищем, что происходит с cache_control и citations (на ноябрь 2026 оба игнорируются). Это пример того, что «совместимый API» ≠ «те же возможности».
  7. Если страница ещё не прочитана в главе 4.1, открываем Ollama: Embeddings (≈10 мин), чтобы подписать квадратик «эмбеддинги» на своей схеме.
  • «Подключим RAG — и галлюцинаций не будет». Нет: если retrieval нашёл не то, модель уверенно ответит по неправильному куску. RAG снижает, а не устраняет выдумки; цитаты и отказ «не нашёл» — обязательная часть.
  • Улучшать генерацию, когда сломан поиск. Типичная ошибка — неделю тюнить промпт, хотя нужного куска просто нет в топ-5. Сначала hit rate.
  • Нет golden set. Без 20 вопросов с известными ответами любое «стало лучше» — ощущение. Собираем его с первого дня.
  • Устаревший индекс. База знаний обновилась, индекс — нет. Храним дату загрузки и хэш страницы.
  • Смешение страниц в одном ответе: без фильтров по метаданным легко получить «гибрид» из гарантии двух похожих ламп или из старых и новых правил возврата.
  • Слишком много контекста. 30 чанков в промпте — дорого, медленно и модель теряет важное в середине. Лучше 5 хороших после реранкинга.
  • Фреймворк как чёрный ящик. LlamaIndex/LangChain собирают RAG в 10 строк, но отлаживать их сложнее. Поэтому сначала руками, а фреймворк — в гл. 5.4 для сравнения.
  • Создаём projects/02-support-kb-rag/notes/rag.md.
  • Рисуем схему своего RAG по базе знаний магазина (ASCII в Markdown, или Mermaid — GitHub его рендерит; или картинка из Excalidraw, сохранённая рядом). Обе фазы: индексация и запрос. Для каждого этапа подписываем:
    • вход и выход (например, «Markdown-файл из kb/ → текст + front matter + якоря заголовков»);
    • конкретный инструмент, который планируем использовать (можно с вопросом: «sqlite-vec?»);
    • номер задачи плана, где он будет сделан (гл. 4.3, гл. 4.4, гл. 5.1, гл. 5.2, гл. 5.3).
  • Ниже схемы — таблица метаданных чанка: поле, тип, пример, зачем нужно. Минимум: category, archived, url (путь к файлу с якорем, например kb/returns.md#opened-tea-returns), section, chunk_key, doc_hash, loaded_at.
  • Раздел «Риски»: 5 вещей, которые могут пойти не так именно с базой знаний магазина (архивные правила, похожие товары, расходящиеся числа…), и что мы с ними сделаем.
  • Раздел «Golden set (черновик)»: первые 10 вопросов, на которые система должна отвечать, с ожидаемой категорией и страницей. Примеры: «Можно ли вернуть вскрытый чай?» (kb/returns.md), «Сколько стоит доставка 3 кг в другой город?» (kb/delivery.md), «Какая гарантия на лампу „Свет“?» (kb/products/lamp-light.md), «Почему не прошла оплата?» (kb/payment.md), «Действует ли промокод вместе со скидкой?» (kb/promo.md). Плюс 3 вопроса, на которые ответа в базе нет («Какая служба доставки самая надёжная?») — для проверки отказа и передачи человеку в гл. 5.3.
  • Раздел «Решения»: заполненная таблица архитектурных решений из теории с нашими выборами. В строках «Эмбеддинги», «Генерация», «Реранкер» указываем провайдера и причину (основной путь: Ollama/Sentence Transformers + DeepSeek; Claude/OpenAI — для сравнения).
  • Раздел «Данные и провайдеры»: таблица «какой текст куда уходит» (куски базы знаний → DeepSeek; вопросы → DeepSeek; эмбеддинги → только локально) и правило «ничего из приложения магазина и никаких настоящих сообщений клиентов в этот проект».

Пример фрагмента в Mermaid:

flowchart LR
  A[Load kb/ Markdown] --> B[Front matter + anchors] --> C[Chunk by headings] --> D[Embed] --> E[(sqlite-vec)]
  Q[Question] --> R[Rewrite + detect category] --> S[Vector + BM25] --> T[Rerank] --> P[Prompt with sources] --> L[LLM answer with citations]
  E --> S
  • В notes/rag.md есть схема обеих фаз, где у каждого этапа подписаны вход/выход, инструмент (с провайдером) и задача плана.
  • Есть таблица метаданных, список рисков, черновик golden set из 10+3 вопросов и таблица решений.
  • Можем за 3 минуты устно провести кого-то по схеме и сказать, где чаще всего ломается RAG.

Вопрос 1

Какие три ограничения LLM решает (или смягчает) RAG?

Знания заморожены на дате обучения; модель не видит приватных/специфичных данных; модель выдумывает, когда не знает. RAG даёт актуальный контекст и позволяет ссылаться на источник.

Вопрос 2

Документация на 60 страниц (~80K токенов), меняется раз в год. Что попробовать первым?

  • a) RAG с векторной БД
  • b) fine-tuning
  • c) положить всё в контекст, возможно с prompt caching
  • d) обучить свою модель эмбеддингов

c). Документы маленькие и стабильные — проще и надёжнее положить их целиком в промпт; RAG — лишняя сложность, fine-tuning плохо учит факты.

Вопрос 3

Какие этапы у фазы индексации, по порядку?

Загрузка → чистка → chunking (с метаданными) → эмбеддинги (и лексический индекс) → запись в индекс.

Вопрос 4

Почему в RAG по базе знаний магазина нужна фильтрация по метаданным?

Одинаковые разделы («Гарантия», «Возврат») есть на многих страницах, а рядом с действующими правилами возврата лежит архивная редакция; без фильтра по category и archived в контекст попадут куски чужой страницы или старых правил, и ответ смешает их.

Вопрос 5

Где чаще всего ломается RAG — в retrieval или в генерации? Как это проверить дёшево?

В retrieval. Дёшево проверить hit rate@k на golden set: попал ли нужный кусок в топ-k — без вызова LLM.

Вопрос 6

Что такое hit rate@k?

Доля вопросов, для которых хотя бы один правильный кусок оказался в первых k результатах поиска.

Вопрос 7

Какую проблему описывает статья Anthropic про Contextual Retrieval?

Чанк, вырезанный из документа, теряет контекст (о каком товаре, разделе, редакции правил речь), поэтому плохо находится и плохо понимается; предлагают приписывать к чанку сгенерированное пояснение и сочетать эмбеддинги с BM25 и реранкингом.

Вопрос 8

Что не так в этом промпте?

Вот документы: {chunks}
Ответь на вопрос пользователя максимально полно, используя свои знания: {question}

«Используя свои знания» прямо разрешает отвечать не по документам — это открывает дорогу галлюцинациям. Нет требования ссылок, нет инструкции говорить «не нашёл», куски не пронумерованы и без источников.

Вопрос 9

Чем реранкинг отличается от первичного поиска?

  • a) это то же самое
  • b) реранкер точнее, но медленнее, и применяется к небольшому числу кандидатов
  • c) реранкер работает до эмбеддингов
  • d) реранкер нужен только для BM25

b). Первичный поиск быстрый и грубый по всей базе, реранкер (cross-encoder) медленнее, но точнее, и пересортировывает 20–100 кандидатов.

Вопрос 10

Зачем хранить у чанка doc_hash и loaded_at?

Хэш страницы — чтобы при повторной загрузке пропускать неизменённые страницы и переэмбеддить только изменившиеся (дубликаты чанков отсекает chunk_key); дата — чтобы понимать актуальность и показывать её пользователю.

Вопрос 11

Почему fine-tuning — плохой способ «научить» модель актуальным правилам доставки и возврата магазина?

Fine-tuning плохо запоминает конкретные факты, не даёт ссылок на источник и устаревает при каждом изменении базы знаний — переобучать дорого, а RAG-индекс обновляется загрузкой.

Вопрос 12

Какие этапы RAG в стеке «DeepSeek + Ollama» выполняются локально и почему?

  • a) только генерация
  • b) эмбеддинги и реранкинг, потому что у DeepSeek нет для них эндпоинтов
  • c) всё идёт в DeepSeek
  • d) только BM25

b). На ноябрь 2026 у DeepSeek нет ни эмбеддингов, ни реранкера. Эмбеддинги делает Ollama или Sentence Transformers, реранкинг — локальный cross-encoder, а DeepSeek отвечает за генерацию и переписывание запроса.

Вопрос 13

Код переводят с Claude на Anthropic-совместимый эндпоинт DeepSeek и рассчитывают на встроенные Citations и cache_control. Что произойдёт?

По таблице совместимости DeepSeek оба поля игнорируются. Цитат с гарантией не будет, а кэш у DeepSeek работает сам, автоматически по префиксу. Цитаты придётся делать вручную: [n] + проверка кодом.

Вопрос 14

Почему куски базы знаний магазина можно отправлять в DeepSeek, а выгрузку заказов и переписки с клиентами для «RAG по истории обращений» нельзя?

База знаний — публичный справочный центр магазина, утекать там нечему. Заказы и переписка содержат персональные данные клиентов (имена, телефоны, адреса), а такие данные не уходят ни в одну облачную модель; у DeepSeek к тому же серверы в Китае. Такой RAG строится целиком на Ollama, локально.

Теперь режем базу знаний на куски: 4.3 · Chunking: сравнить 3 стратегии, затем строим полноценный индекс в 4.4 · Векторная БД + загрузка базы знаний.