# RAG или дообучение: когда что, и сколько это стоит

Спектр адаптации модели: feature extraction, LoRA, частичное и полное дообучение. Разбираем, когда RAG не хватает и как выбрать метод под задачу и железо.

> For the index of this section of the site, see [llms.txt](https://anetlab.ru/llms.txt)

22 октября 2026 г.9 мин чтения

# RAG или дообучение: когда что, и сколько это стоит

Спектр адаптации модели: feature extraction, LoRA, частичное и полное дообучение. Разбираем, когда RAG не хватает и как выбрать метод под задачу и железо.

[Виктор Бузин](https://anetlab.ru/about.md) · Founder & Principal Engineer, AnetLab

16+ лет в enterprise-разработке: .NET, AI/LLM-системы, RAG, MCP. Автор материала и практик в студии.

## Почему этот вопрос возникает

Есть два способа вложить в модель то, чего она не знает. Первый — добавить знания снаружи: положить документы в индекс, подобрать релевантные чанки, передать их в контекст. Это retrieval-augmented generation, RAG. Второй — изменить саму модель: взять предобученные веса и переучить часть из них на своих данных. Это fine-tuning.

Документная половина RAG — отдельная работа: привести файл к виду, который модель читает, и не потерять по дороге таблицы, форматирование и объединённые ячейки. У нас эту часть закрывает [Contextum](https://anetlab.ru/products/contextum.md).

Обычно RAG выбирают по умолчанию, и на то есть причины: он не требует вычислительного центра, его можно обновить за минуты, и он оставляет в ответе ссылку на источник, по которой можно проверить факт. Дообучение выглядит дороже и менее гибко. Но у RAG есть границы, и в Enterprise-системах они проявляются регулярно.

RAG плохо работает в трёх случаях. Первый: задача требует не факта, а поведения. «Ответь в формате XML по такой-то схеме», «классифицируй обращение по 12 фиксированным категориям», «исправь тон ответа так, чтобы он звучал как наш». Знание тут ни при чём — нужна выученная процедура.

Второй: инструкция длинная и повторяется на каждом вызове. Если требование занимает 800 токенов и уходит в каждый запрос, вы платите за эти токены и задержку при каждом вызове. Выученное поведение в весах стоит один раз.

Третий: требуется изолированный контур. Если данные нельзя отдавать наружу — ни в облачную модель, ни в индекс, — дообучение локальной модели оставляет данные на своей машине.

## Спектр, а не один переключатель

Fine-tuning — не один метод, а спектр. Техники различаются тем, сколько параметров модели им разрешено менять, и это напрямую определяет требования к данным, железу и к тому, насколько модель сохранит общие способности.

| Техника | Что меняется | Данные и вычисления | Когда применять |
| --- | --- | --- | --- |
| Feature extraction | Веса модели заморожены, обучается только новая «голова» | сотни–тысячи примеров; вычисления низкие, хватает CPU | Классификация или регрессия поверх эмбеддингов, когда задача близка к тому, что модель уже умеет |
| PEFT (LoRA) | Базовая модель заморожена, обучаются небольшие адаптерные матрицы | объём умеренный; вычисления низкие–умеренные, реально на одной потребительской видеокарте или на Apple silicon | Рабочая лошадка большинства прикладных проектов |
| Частичное дообучение | Размораживаются последние слои, ранние остаются заморожены | объём умеренный; вычисления умеренные | Когда возможностей адаптеров не хватает, а обучать всю модель слишком дорого |
| Полное дообучение | Меняются все параметры | тысячи и больше примеров; вычисления высокие, нужна реальная GPU с памятью под градиенты и состояния оптимизатора | Максимальная адаптация, когда есть данные, есть вычислительный бюджет, а задача сильно отличается от предобучения |

Порядок в таблице — не случайный: техники выстроены по тому, сколько весов модели им разрешено менять. Первым идёт feature extraction — он ничего не ломает: исходная модель остаётся нетронутой, рядом появляется маленькая обучаемая надстройка. Если её достаточно, задача закрыта, а общие способности модели остаются нетронутыми.

Следом идёт LoRA: базовая модель заморожена, меняются только адаптерные матрицы. Обучается мало, но не поверх модели, а внутри неё — низкоранговые матрицы встраиваются в слои и подстраивают их поведение.

Дальше граница проходит по числу размороженных весов. Частичное дообучение размораживает последние слои, полное — все параметры. На этом участке спектра растёт и объём требуемых данных, и расход памяти — вплоть до разницы в десятки гигабайт, о которой речь ниже.

## Почему LoRA вытеснил полное дообучение

Полное дообучение требует памяти на порядок больше, чем кажется. Чтобы обновить параметр, нужно хранить не только сам вес, но и его градиент, и состояние оптимизатора. Для большой модели это десятки гигабайт VRAM, которые нужно удерживать одновременно с самой моделью.

LoRA решает это принципиально иначе. Базовая модель замораживается, а вместо обновления её весов в сеть добавляются низкоранговые адаптерные матрицы — маленькие trainable-параметры, которые перехватывают путь сигнала. Обучается сотня или тысяча миллионов параметров вместо миллиардов.

По данным исследований, которые приводит Вэй-Мэн Ли в обзоре fine-tuning в журнале CODE, LoRA восстанавливает 95–99% качества полного дообучения на большинстве задач — при существенно меньшем расходе памяти и места на диске. И есть второй эффект, который важнее: поскольку базовые веса не трогаются, общие способности модели сохраняются заметно лучше. Риск катастрофического забывания — когда модель забывает всё, чему её научили раньше, и хороша только в узкой задаче, — при LoRA заметно ниже.

Отсюда практическое правило, которое формулирует Ли: начинайте с feature extraction, если не хватает — сразу переходите к LoRA. Полное дообучение — инструмент для меньшинства случаев, где есть и данные, и аппаратный бюджет, чтобы это оправдать.

## Как выглядит код

Стек Hugging Face устроен так, что один и тот же код работает на Windows, macOS и Linux: библиотеки сами выбирают самое быстрое доступное железо. Метод адаптации задаёт [PEFT](https://huggingface.co/docs/peft/index) — библиотека, в которой реализован и LoRA. Дообучение начинается с выбора метода.

```
from peft import LoraConfig, TaskType, get_peft_model
from transformers import AutoModelForCausalLM

base = AutoModelForCausalLM.from_pretrained(
    "google/gemma-4-12B-it",
    dtype="auto",
    device_map="auto",
)

config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,                      # ранг адаптера
    lora_alpha=32,             # масштаб обновления
    lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
)

model = get_peft_model(base, config)
model.print_trainable_parameters()
```

Последняя строка печатает то, ради чего всё затевалось: сколько параметров обучаемо и какой это процент от общей модели. В примере из обзора на DistilBERT это выглядит как `trainable params: 741,893 || all params: 67,699,210 || trainable%: 1.0959` — то есть обучается около процента, а остальное заморожено.

Базовые веса в примере — [google/gemma-4-12B-it](https://huggingface.co/google/gemma-4-12B-it) с Hugging Face.

Полное дообучение отличается одной строкой — вместо адаптера параметры модели размораживаются напрямую:

```
for parameter in model.parameters():
    parameter.requires_grad = True
```

Именно здесь появляется требование к VRAM: полный набор параметров, их градиенты и состояния оптимизатора должны поместиться одновременно. На потребительской видеокарте это, как правило, недостижимо для моделей рабочего размера.

Разница видна и по тому, что именно сохраняется на диск. При LoRA рядом с базовой моделью лежат файлы адаптера — обычно десятки мегабайт. При полном дообучении сохраняется новая копия всех весов, и это уже десятки гигабайт на каждую версию модели. Практическое следствие для команд: адаптеры можно держать в git рядом с кодом, экспериментировать с ними и откатываться, а полные веса приходится хранить отдельно, как артефакт.

Есть и третий вариант, который в .NET-контуре выглядит естественнее всего: оставить дообучение на стороне Python-сервиса и вызывать его по HTTP. Модель обучается там, где есть GPU, а .NET-приложение работает с уже обученным адаптером через привычный эндпоинт. Оркестратор при этом остаётся в .NET — разделяется только обучение, а не архитектура.

## Порядок принятия решения

Пять условий, при которых fine-tuning оправдан. Их проверяют до того, как команда начинает считать бюджет на обучение.

**Формат.** Задача требует конкретного формата или стиля вывода, который промптинг не обеспечивает надёжно. Классификатор, который обязан вернуть одну из 12 меток, — классический пример.

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

**Примеры.** Паттерн трудно описать словами, но легко показать примерами: тон компании, доменные сущности, специфический разбор документов.

**Офлайн.** Модель должна работать офлайн, на устройстве, в изолированном контуре — и меньшая дообученная модель на узкой задаче обходит большую универсальную.

**Исчерпанный RAG.** RAG не дал нужного результата. RAG отлично даёт модели новые факты, но плохо учит новому поведению или стилю. Это принципиальное различие, а не вопрос настройки индекса.

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

Отдельно стоит сказать про порядок экспериментов, потому что он определяет бюджет. Правильная последовательность — снижать неопределённость на каждом шаге, а не начинать с самого дорогого:

1.  Сначала промпт. Если модель не соблюдает формат — уточняйте инструкцию, добавляйте примеры, разбирайте ответ на части.
2.  Затем RAG. Если не хватает фактов — сначала чините извлечение и ранжирование, а не дообучение.
3.  Затем feature extraction. Если задача сводится к классификации поверх эмбеддингов — обучаете маленькую «голову», базовая модель не трогается.
4.  Затем LoRA. Когда поведение или стиль закрепить иначе нельзя, и данных хватает хотя бы на сотни примеров.
5.  Полное дообучение — последний шаг, и только если остальные не дали результата.

Шаг, который чаще всего пропускают, — классификация поверх эмбеддингов. Дорабатывать под классификацию всю модель, когда достаточно обучить поверх эмбеддингов линейный классификатор, — это обычно на порядок дороже при сопоставимом результате. Такое обучение занимает минуты и десятки мегабайт, а не часы и десятки гигабайт.

## Как проверить, что дообучение дало эффект

Дообучение меняет модель, поэтому старую методику оценки на месте не заменить. Проверять нужно две вещи отдельно: качество на целевой задаче и сохранность общих способностей.

Целевая задача измеряется на отложенном наборе, которого модель не видела в обучении. Здесь важна честность разделения: примеры из теста, просочившиеся в обучение, дают качество, которого в продакшене не будет.

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

Отдельная тонкость — длина примеров. Длинные диалоги в обучении учат модель воспроизводить их длину, а не решать задачу. Если средняя длина примера в обучении вдвое больше, чем в бою, вы получите модель, которая раздувает ответы. Стоит проверять распределение длин до обучения, а не после.

Общие способности проверяются отдельным набором. Это тот случай, где «модель стала лучше в своей задаче» и «модель стала лучше» — разные утверждения. Замер только целевой задачи покажет рост и промолчит о деградации.

Практический порядок выглядит так: зафиксировать baseline на текущей модели с промптом и RAG, затем обучить LoRA, затем измерить обе оси на одном и том же наборе. Если целевая задача не дала прироста, дообчение не окупило потраченного — и это дешёвый вывод, если сделать его до того, как модель поедет в контур.

## Практические выводы

*   Fine-tuning — это спектр из четырёх техник, а не один переключатель. Порядок применения: feature extraction, затем LoRA, и только потом полное дообучение.
*   LoRA даёт 95–99% качества полного дообучения на большинстве задач при заметно меньшем расходе памяти и меньшем риске катастрофического забывания.
*   Полное дообучение требует видеокарты, в которой одновременно помещаются веса, градиенты и состояния оптимизатора. Это вопрос бюджета, а не настройки.
*   RAG и дообучение решают разные задачи: RAG даёт новые факты, дообучение учит новому поведению. Одно не заменяет другое.
*   Любое дообучение требует двух замеров: прирост на целевой задаче и отсутствие деградации общих способностей.

## Похожие статьи

*   [Архитектура enterprise AI: четыре решения, которые всё определяют](https://anetlab.ru/blog/enterprise-ai-architecture.md)
*   [RAG на .NET: архитектура, которая переживает продакшн](https://anetlab.ru/blog/rag-na-dotnet.md)
*   [Оценка качества RAG на .NET: Recall@5, MRR и гейт релиза](https://anetlab.ru/blog/rag-evaluation-dotnet.md)
*   [Инженерное лидерство в AI-продуктах: оценка, роли, поставка](https://anetlab.ru/blog/engineering-leadership-ai.md)

## CTA

Если задача упирается в «модель не соблюдает формат» или «инструкция слишком дорогая на каждом вызове», начните с замера: зафиксируйте baseline на промпте и на RAG, а решение о дообучении принимайте по разнице. Чаще всего оказывается, что хватает промпта и структуры ответа — и тогда бюджет команды остаётся на измерение качества, а не на обучение.

Разобрать задачу под ваш стек — [напишите нам](https://anetlab.ru/contact.md).

Читайте также

21 октября 2026 г.AI/LLM

### [Contextum: конвейер документов в Markdown для AI-агента](https://anetlab.ru/blog/contextum-document-pipeline.md)

AnetLab Contextum: конвейер из пяти стадий между агентом и LLM — конвертация в Markdown, сжатие контекста, идемпотентная доставка и честный реестр потерь.

[Читать разбор](https://anetlab.ru/blog/contextum-document-pipeline.md)

[.NET](https://anetlab.ru/blog/?tag=.NET)[RAG](https://anetlab.ru/blog/?tag=RAG.md)

20 октября 2026 г.AI/LLM

### [Оценка качества RAG на .NET: Recall@5, MRR и гейт релиза](https://anetlab.ru/blog/rag-evaluation-dotnet.md)

Как измерять качество RAG на .NET: Golden Set из 50–100 вопросов, расчёт Recall@5 и MRR, измерение faithfulness и eval-как-гейт-релиза в CI.

[Читать разбор](https://anetlab.ru/blog/rag-evaluation-dotnet.md)

[.NET](https://anetlab.ru/blog/?tag=.NET)[RAG](https://anetlab.ru/blog/?tag=RAG.md)[Оценка качества](https://anetlab.ru/blog/?tag=%D0%9E%D1%86%D0%B5%D0%BD%D0%BA%D0%B0%20%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B0.md)