localaiforum
Войти
Руководство › Работа с моделями

RAG: как передать модели свои данные

Знания LLM замёрзли на отсечке обучения; ваши документы меняются еженедельно. Retrieval-augmented generation (RAG) их оттаивает: в момент запроса достать релевантные куски ваших данных, вставить их в промпт и дать модели ответить по доказательствам с цитатами. Модель делает рассуждение; индекс делает память.

Пайплайн, один разбор

Возьмите мануал на 12,000 токенов и пройдите его от начала до конца:

  1. Чанки. Режьте сначала по заголовкам (секции выживают целыми), затем перережьте любую секцию длиннее ~400 токенов, держа ~60 токенов перекрытия (10–15%). Разумные размеры чанков — 200–800 токенов. Результат: примерно 35 чанков.
  2. Эмбеддинг. Каждый чанк становится одним вектором — bge-m3 выдаёт 1,024 float на чанк. На CPU это занимает секунды на весь мануал.
  3. Индекс. Храните векторы + текст + метаданные (файл-источник, путь заголовков) в векторном хранилище.
  4. Ретривал. Эмбеддингьте вопрос, достаньте топ k = 5 чанков по косинусной близости (4–10 — здравый диапазон).
  5. Генерация. Соберите промпт: инструкции, 5 чанков с ID-тегами, вопрос.

Чанкование по смысловым границам бьёт фиксированные окна. Таблица, отрезанная от строки заголовка, или нумерованная процедура, разрезанная на шаге 4, — недоставаемый мусор, как бы хорош ни был эмбеддер.

Две добавки, окупающиеся сразу: храните путь заголовков (manual › §4 › Bolts) как метаданные, чтобы фильтровать и цитировать точно, и эмбеддьте запрос ровно как набрал пользователь — «очистительная» предобработка обычно делает ретривал хуже, а не лучше.

Эмбеддинги: мультиязычное требование

Эмбеддер решает, что значит «похоже». Для корейских и смешанных корейско-английских корпусов выбор узок — англо-моно-эмбеддеры молча проваливаются на корейских запросах, возвращая правдоподобные-но-неверные чанки:

Модель Размерности Заметки
bge-m3 1024 мультиязычная, сильный корейский — безопасный локальный дефолт
nomic-embed-text-v1.5 768 крепкий английский, длинный контекст
all-MiniLM-L6-v2 384 быстрая, англо-центричная, слаба на корейском

Модели эмбеддингов крошечные (0.1–0.6B параметров); ядро CPU прожёвывает тысячи чанков — инференс на CPU. Эмбеддьте корпус один раз, запросы — в момент вопроса. Держите эмбеддер замороженным на индекс: смена модели посреди индекса делает векторы из разных пространств, и оценки близости становятся шумом.

Векторные хранилища

Хранилище Когда
sqlite-vec один пользователь, до ~1M векторов, ноль ops — это файл
ChromaDB локально-первое прототипирование с фильтрами по метаданным
Qdrant продакшен: фильтрация, гибридный поиск, масштаб

Все три работают локально. Начните с sqlite-vec; переезжайте, когда реально упрётесь в его стену, а не раньше.

Сборка промпта

Answer only from the excerpts below. Cite every claim as [n].
If the excerpts do not contain the answer, reply "not in the docs".

[1] (manual §4.2) Torque the M8 bolt to 12 Nm after lubrication...
[2] (manual §7.1) Do not re-use stretch bolts...

Question: what torque spec applies to the M8 bolt?

Цитаты позволяют пользователям проверять, а не доверять слепо. Выход «нет в доках» важен: без него модель выдумает ответ вместо провала формата.

Гибридный поиск и реранкинг

Чисто векторный поиск промахивается по точным строкам — коды ошибок, имена функций, номера деталей, — по которым пригвождает ключевой поиск. Гибрид = BM25 + векторы, слитые reciprocal rank fusion; это почти бесплатно и стабильно лучше любого по отдельности.

Ради качества добавьте реранкер: достаньте 20–50 кандидатов, переранжируйте до топ-5 кросс-энкодером (семейство bge-reranker — та же мультиязычная история, что bge-m3). Реранкер читает чанк и запрос вместе, чего не может одновекторный эмбеддер. Дешёвый рецепт, покрывающий большинство нужд: гибридно достать 25, переранжировать до 5.

Диагностика: промах ретривала или генерации?

Прежде что-то тюнить, ответьте на один вопрос: был ли доставлен правильный чанк?

  1. Напечатайте топ-k чанков для проваливающегося запроса, со счетами.
  2. Если чанк с ответом не в списке — проблема ретривала: чините чанкование, эмбеддинги или поднимайте k.
  3. Если он в списке, но ответ неверный — проблема генерации: модель побольше, промпт получше, реранк, чтобы вытолкнуть дистракторы.

Этот один тест экономит часы тюнинга не той половины пайплайна.

Режимы отказа

Симптом Причина Фикс
Найдены верные документы, ответ неверный дистракторы в топ-k реранк; сузить k
Ответ есть в доках, но не всплывает голод топ-k или плохие границы поднять k; чанковать по заголовкам
Уверенные, но устаревшие ответы индекс старше доков переиндексировать при изменениях
Корейские запросы не находят английские доки моноязычные эмбеддинги bge-m3
Цитаты указывают не на тот чанк чанк потерял метаданные источника хранить источник + заголовок на чанк

Мерьте, а не вайбите

Держите золотой набор из 20–50 реальных вопросов с известными ответами. Оценивайте два числа раздельно: hit rate ретривала (правильный чанк в топ-k?) и корректность ответа. Отслеживайте их после каждого изменения размера чанка, эмбеддера или k. RAG-работа без золотого набора — астрология.

Когда лучше дообучить

Дообучение меняет поведение — формат, стиль, терминологию. Это плохой способ добавлять факты: модель не может цитировать то, на чём тюнилась, а свежие документы означают свежий обучающий прогон. Правило: факты → RAG, поведение → LoRA, и то и другое — только когда исчерпан промптинг: дообучение.

Локальные стеки, от меньшего

Open WebUI поставляется с загрузкой документов и встроенным гибридным ретривалом — начните там, и, возможно, никогда не напишете кода пайплайна. Честное ядро RAG — ~50 строк; напишите его раз, чтобы знать, что делают фреймворки:

chunks = chunk_by_header(read("manual.md"), max_tokens=400, overlap=60)
index = [(embed(c), c) for c in chunks]          # делается один раз

def answer(question):
    hits = topk_by_cosine(embed(question), index, k=5)
    ctx = "\n\n".join("[{}] {}".format(i, c) for i, (v, c) in enumerate(hits))
    prompt = TEMPLATE.replace("{ctx}", ctx).replace("{q}", question)
    return chat(prompt)                           # маленькой локальной модели хватает

Тянитесь к LlamaIndex или LangChain, когда нужны права доступа, обновление по расписанию или каркасы оценки — не ради цикла выше. Для корейских документов конкретно мультиязычные эмбеддинги (bge-m3) не опциональны, а чанкование по заголовкам должно уважать структуру корейских документов (заголовки 장/절) так же, как оно уважает заголовки markdown ##.

Связанные разделы: дообучение · промптинг · структурированный вывод · инференс на CPU