Локальный fine-tuning для русскоязычных задач
Разбираем, когда локальный fine-tuning окупает обучение и поддержку, а когда внешний API точнее, дешевле и быстрее выходит в продакшен.

Локальная донастройка выгодна не тогда, когда у команды накопилось много текстов, а когда поведение модели можно стабильно описать примерами, проверить на собственном наборе задач и использовать достаточно часто, чтобы покрыть постоянные расходы. В остальных случаях внешний API обычно покупает не только токены. Он покупает доступ к более сильной базовой модели, обновлениям, резерву мощности и чужой дежурной смене.
Для русскоязычной задачи выбор особенно легко исказить. Красивый ответ на литературном русском еще не означает, что модель правильно разбирает банковские сокращения, склоняет названия населенных пунктов, не меняет смысл юридической оговорки и возвращает строгий JSON. И наоборот, небольшая локальная модель может писать суше, но лучше выполнять узкую операцию после аккуратной донастройки.
Я принимаю решение через четыре независимые границы: данные, скорость их изменения, качество на собственных evals и полную стоимость владения. Требование хранить данные внутри контура идет отдельно. Оно может закрыть внешний API до экономического сравнения, но само по себе не делает fine-tuning хорошей идеей: иногда правильный ответ состоит в локальном инференсе базовой модели с retrieval и строгой постобработкой.
Fine-tuning меняет поведение, а не подменяет базу знаний
Fine-tuning стоит применять к повторяемому поведению: формату ответа, стилю классификации, выбору допустимого действия, извлечению полей, нормализации терминов или следованию внутренней разметке. Он плохо подходит для фактов, которые меняются каждую неделю. Если модель должна знать свежий тариф, остаток товара, редакцию инструкции или фамилию ответственного, эти сведения лучше получать из источника во время запроса.
Команды часто смешивают три разных задачи. Первая состоит в том, чтобы научить модель форме ответа. Вторая дает ей актуальный контекст. Третья ограничивает допустимые действия. Донастройка помогает с первой, retrieval или вызов инструмента решает вторую, а схема ответа и проверяющий код держат третью. Если запихнуть все три в веса, обновление одного регламента превращается в новый обучающий прогон, а запрет на опасное действие остается вероятностным.
Русский язык добавляет неприятные пограничные случаи. В разметке сущностей важны падежи и вложенные названия. В поддержке встречаются опечатки, латиница внутри кириллицы, транслит и продуктовые сокращения. В юридическом тексте одно «не» меняет результат. Обучающий набор должен содержать такие случаи явно. Тысяча почти одинаковых, аккуратно написанных запросов дает меньше информации, чем несколько сотен примеров, которые покрывают реальные способы поломки.
Есть простой тест до запуска обучения. Уберите из предполагаемого датасета внутренние факты и подставьте вместо них фиктивные значения. Если желаемый ответ по-прежнему можно однозначно разметить, задача похожа на fine-tuning. Если разметчик вынужден открыть базу знаний или узнать текущую дату, модель нуждается в контексте во время инференса.
Не стоит донастраивать модель только ради того, чтобы «она знала нашу документацию». Этот совет популярен, потому что обещает один артефакт вместо поискового индекса, прав доступа и сборки контекста. На практике веса не дают удобного способа удалить устаревший абзац, показать источник ответа или применить доступ на уровне документа. Для меня это достаточная причина оставить изменяемые знания вне весов.
Объем данных считают по разнообразию решений
Количество строк ничего не говорит без числа независимых решений, которые модель должна освоить. Сто тысяч автоматически созданных пар могут повторять одну и ту же схему. Две тысячи проверенных диалогов могут охватывать десятки намерений, отрицательные примеры, отказы, длинный контекст и редкие русские формулировки. Считать нужно покрытие, противоречия и качество меток.
Я начинаю с карты классов поведения. Для каждого класса фиксирую обычные случаи, трудные границы и примеры, где правильный ответ состоит в отказе или передаче человеку. Затем смотрю, сколько примеров остается после удаления дублей по смыслу, а не по хешу строки. Если один источник дал большую часть данных, отдельный тестовый набор должен прийти из другого периода или канала, иначе модель просто выучит манеру этого источника.
Универсального порога «достаточно N примеров» нет. Для выбора одного из пяти устойчивых классов может хватить сравнительно небольшого, но чистого корпуса. Для генерации развернутых ответов по множеству продуктов потребуются намного более широкое покрытие и оценка отдельных свойств. Чем свободнее ответ, тем дороже разметка и тем труднее доказать улучшение.
Полезнее записать паспорт набора:
- единица разметки и допустимые ответы;
- доля примеров, прошедших двойную проверку;
- распределение по классам, каналам и длине;
- период, из которого взяты данные;
- известные пробелы и запрещенные источники.
Такой паспорт быстро выявляет ложную экономию. Если письма клиентов нельзя использовать для обучения без очистки и правового основания, их номинальный объем не входит в доступный корпус. Если эксперты расходятся в ответах, модель не устранит спор. Она воспроизведет смесь несовместимых правил. Сначала владельцу процесса придется утвердить правило и пересобрать метки.
Синтетические примеры полезны для расширения формулировок и проверки редких веток, но не должны определять эталон. Сильная внешняя модель может породить гладкий русский текст и одновременно внести неверный термин или снять важное ограничение. Эксперт проверяет смысл, а генератор только предлагает варианты. В тестовый набор синтетика обычно не попадает: иначе ученик оценивается на почерке учителя.
Частые изменения съедают выигрыш от обучения
Если правило меняется быстрее, чем команда может собрать данные, переобучить адаптер, прогнать evals и безопасно развернуть версию, хранить правило в весах невыгодно. Частота релизов модели должна следовать частоте изменения поведения, а не частоте изменения справочника.
Представим классификатор обращений для поддержки. Названия очередей и ответственные меняются раз в месяц, но логика определения срочности стабильна годами. Модель может локально определять срочность и тип проблемы, а таблица маршрутизации во время запроса сопоставит результат с текущей очередью. Переобучать модель из-за переименования отдела было бы дорогой ошибкой.
Другой случай возникает, когда меняется сама политика ответа. Банк добавляет новый вид мошеннического сценария, и старый ответ теперь опасен. Тут адаптер действительно нуждается в новой версии, но выпуск нельзя свести к обучающему job. Нужны обновленная разметка, регрессионный набор, сравнение с текущей моделью, решение об откате и период наблюдения. Срочное изменение промпта или правила в коде часто попадет в продакшен быстрее и останется прозрачнее.
Разделите срочность изменения и его срок жизни. Временный запрет на операцию может понадобиться через час и исчезнуть через неделю. Его место в конфигурации или проверяющем коде, где владелец видит дату и причину. Новая устойчивая категория обращений, которая уже накопила подтвержденные примеры, подходит для следующей версии адаптера. Этот фильтр не дает превратить каждую реакцию бизнеса в обучающий датасет.
Я оцениваю «налог на обновление» в часах людей и простоях процесса. В него входят поиск новых случаев, их обезличивание, экспертная разметка, обучение, проверка, сборка образа, нагрузочный тест и выпуск. Если исправление проходит через три подразделения и окно изменений, даже дешевый GPU не делает цикл дешевым.
Версионирование должно связывать модель с данными и оценкой. Документация MLflow Tracking прямо описывает run как запись параметров, метрик, версии кода и артефактов. Для LLM этого мало без версии шаблона, токенизатора, набора evals и правил очистки. Но сама идея верна: ответ «мы обучали примерно на мартовской выгрузке» не годится для расследования.
Минимальная запись релиза может выглядеть так:
release: support-intent-2026-04
base_model: model-family/revision
adapter: sha256:...
train_dataset: support-train-v17
eval_suite: support-eval-v9
prompt_template: chat-v6
decision:
metric: critical_recall
threshold: 0.97
rollback_to: support-intent-2026-02
Такой файл не доказывает качество, но не позволяет потерять причинную связь. Если команда не может восстановить базовую ревизию и набор данных, локальная модель уже создала риск, даже когда сегодняшние ответы выглядят приемлемо.
Размещение данных не равно локальному обучению
Требование держать данные в российском контуре сначала определяет допустимые маршруты запроса, журналов, резервных копий и артефактов. Только после этого выбирают способ улучшить качество. Локальный инференс, локальный fine-tuning и локальное хранение данных связаны, но это разные решения.
Проверьте весь путь, а не адрес API. В запросе могут быть персональные данные, коммерческая тайна или банковская информация. Копии появляются в трассировке приложения, очереди повторов, системе наблюдаемости, дампе ошибки, датасете неудачных ответов и бэкапе. Если обучение идет внутри контура, а трейс с исходным текстом уходит наружу, граница размещения уже нарушена независимо от архитектуры модели.
152-ФЗ нельзя превращать в наклейку «on-prem значит законно». Команда должна определить роли участников обработки, категории данных, цели, сроки хранения, порядок удаления и меры защиты вместе с юристом и специалистом по информационной безопасности. Техническая схема затем реализует это решение. Она не заменяет его.
Есть четыре практических варианта. Внешний API допустим, если согласованный провайдер обрабатывает данные в нужной юрисдикции и договорная схема подходит. Выделенный инференс держит модель и запросы в контролируемой среде без обучения. Адаптер обучается локально, а базовые веса остаются неизменными. Полное обучение или продолженное предобучение меняет гораздо больше весов и требует совсем другого бюджета и контроля. Слово «локальный» не сообщает, какой вариант выбран.
Отдельно разберите обучающие данные. Текст, который разрешено обработать ради ответа клиенту, не автоматически разрешено сохранять для улучшения модели. Нужны минимизация, маскирование, управление доступом и процедура удаления. После обучения удаление одной записи из весов нельзя надежно показать обычным запросом к базе. Если обязанность удалить данные вероятна, лучше не включать такие данные в обучение без утвержденной процедуры.
Гибридная схема часто разумнее жесткого выбора. Чувствительный поток идет в модели внутри российского ЦОДа, обезличенные и низкорисковые задачи могут обращаться к внешним моделям, а маршрутизатор применяет правила до отправки. При этом evals должны измерять каждый маршрут: разные модели способны расходиться в формате, отказах и русской терминологии.
Побеждает модель с лучшими собственными evals
Средний балл публичного русскоязычного бенчмарка не отвечает, правильно ли модель решает вашу задачу. Решение принимают по закрытому набору примеров из будущего рабочего потока, где каждая метрика связана с ценой ошибки.
Набор нужно заморозить до основной серии экспериментов. Иначе исследователь видит провалы, добавляет похожие примеры в обучение и постепенно превращает тест в учебник. Для частых итераций держите как минимум development-набор для выбора подхода и закрытый acceptance-набор для решения о выпуске. После релиза добавляйте новые классы ошибок, но сохраняйте старые тесты для регрессии.
Одна итоговая точность скрывает опасные обмены. Для извлечения реквизитов считайте качество по каждому полю и долю ответов, прошедших схему. Для классификации обращений смотрите recall критического класса и матрицу ошибок. Для генерации ответа отдельно проверяйте фактическую опору на контекст, соблюдение запретов, полноту и качество русского языка. Оценка человеком нужна там, где правило нельзя надежно выразить кодом.
Я использую парное сравнение вслепую, когда ответы свободные. Эксперт видит исходный запрос и два ответа без имени модели, выбирает лучший или ничью и отмечает конкретную причину. Порядок ответов случайный. Это снижает влияние бренда и не заставляет оценщика придумывать псевдоточную шкалу от одного до десяти.
Запись результата должна позволять пересчитать решение:
{
"case_id": "refund_0142",
"slice": ["ru", "typo", "policy_refusal"],
"expected_action": "handoff",
"candidate_action": "answer",
"schema_valid": true,
"policy_pass": false,
"latency_ms": 184,
"cost_units": 27
}
cost_units здесь лучше реальных цен для воспроизводимого теста: команда может хранить число входных и выходных токенов или нормированную стоимость, а тариф применять отдельной таблицей. Кодовый валидатор ловит формат и запреты, эксперт разбирает смысловые ошибки. Если fine-tuned модель улучшила среднее качество, но чаще отвечает вместо обязательной передачи человеку, выпускать ее нельзя.
Сравнивайте не только локальный адаптер с одной внешней моделью. Нужны хотя бы текущий продакшен, сильная внешняя модель с тем же контекстом и локальная базовая модель без адаптера. Последняя показывает вклад обучения. Иногда почти весь прирост дает новый шаблон или retrieval, а адаптер добавляет стоимость и ухудшает редкий срез.
Полная стоимость начинается после успешного эксперимента
Цена GPU-часа обучения обычно занимает слишком много внимания. Для адаптерной донастройки обучение может быть коротким, а сервис будет работать месяцы. Поэтому основную сумму часто создают инференс, резерв мощности, инженерная поддержка, разметка и повторные релизы.
Считайте стоимость на одинаковом полезном объеме. Один запрос к внешнему API и один локальный запрос нельзя сравнить, если локальная модель требует повторной генерации, более длинного промпта или ручной проверки. Подходящая единица может быть «тысяча успешно обработанных документов» или «обращение, закрытое без исправления оператором».
Годовая модель затрат выглядит так:
TCO = данные + эксперименты + инфраструктура инференса + резерв + наблюдаемость + релизы + дежурства + аудит + цена ошибок
В данных учтите экспертов, очистку, разметку и хранение версий. В инфраструктуре учитывайте не среднюю загрузку, а пик и требования к времени ответа. Резерв включает запасной узел или приемлемый план деградации. Цена ошибок включает ручную перепроверку, возвраты, пропущенные обращения и расследования.
Внешний API тоже имеет скрытые статьи. Команда поддерживает маршрутизацию, таймауты, повторные запросы, контроль лимитов, оценку новых версий и договорную работу. Но провайдер обычно распределяет капитальные расходы и эксплуатацию между многими клиентами. При небольшом или рваном трафике это трудно победить собственным кластером.
Локальный вариант получает преимущество при высокой, предсказуемой загрузке и подходящей модели, которую можно плотно обслуживать на уже оплаченной инфраструктуре. Преимущество исчезает, если ради редких пиков приходится держать простаивающие ускорители. Батчинг улучшает экономику фоновых задач, но не спасает интерактивный сервис с жесткой задержкой.
Не закладывайте бесплатный труд ML-инженера. Кто-то будет обновлять драйверы, рантайм и образ, следить за памятью, расследовать падения, проверять новые базовые ревизии и дежурить во время релиза. Если такого владельца нет, стоимость не равна нулю. Она просто проявится в первом инциденте.
Расчет стоит вести в трех сценариях: ожидаемая нагрузка, высокий спрос и деградация. Для каждого задайте входные и выходные токены, параллелизм, целевую задержку, допустимый процент отказов и часы поддержки. Точка безубыточности появляется там, где накопленная разница переменных затрат покрывает постоянные расходы и следующий цикл обновления. Если результат переворачивается от небольшой поправки к загрузке, бизнес-решение пока неустойчиво.
Адаптер дешевле полного обучения, но не бесплатен в продакшене
Для большинства прикладных русскоязычных задач я сначала проверяю LoRA или другой parameter-efficient подход, а не изменение всех весов. Документация Hugging Face PEFT описывает QLoRA как обучение LoRA-адаптеров поверх базовой модели, загруженной с четырехбитной квантизацией. Это снижает требования к памяти во время эксперимента, но не обещает нужного качества и не отменяет стоимость инференса.
У адаптера есть сильное эксплуатационное свойство: небольшие наборы весов можно версионировать отдельно от базы. Несколько задач способны делить одну базовую модель. Но совместимость становится жесткой: адаптер связан с семейством, ревизией, токенизатором и способом загрузки. Незаметное обновление базы может изменить ответы, даже если файл адаптера не трогали.
Сервинг нескольких адаптеров выглядит заманчиво, пока не появляются требования к изоляции. Документация vLLM допускает обслуживание LoRA-адаптеров и их динамическую загрузку. Для внутреннего стенда это удобно. В продакшене динамическая загрузка из произвольного пути расширяет поверхность управления, поэтому список адаптеров, источник артефактов и права на активацию должны быть ограничены.
Квантизация тоже требует отдельного eval. Она меняет численное представление весов и может затронуть редкие классы сильнее среднего результата. Проверяйте тот артефакт, который реально обслуживает запросы, с тем же рантаймом, параметрами генерации и шаблоном чата. Оценивать исходную модель в высокой точности, а выпускать квантизованную сборку значит тестировать не тот продукт.
Полное дообучение всех весов оправдано намного реже. Оно требует больше вычислений, сложнее хранится и повышает цену ошибочного эксперимента. Продолженное предобучение на отраслевом корпусе может научить модель языковым закономерностям домена, но затем все равно понадобится instruction-tuning и проверка поведения. Большая коллекция документов сама по себе не делает этот путь рациональным.
Практичный порядок таков: сначала сильный промпт и retrieval, затем локальная базовая модель, потом адаптер, и лишь после доказанного ограничения рассматривается более тяжелое обучение. Это не лестница зрелости, которую обязаны пройти все. На любом шаге можно остановиться, если evals и экономика уже подходят.
Решение должно пережить проверку через полгода
Хороший выбор можно объяснить цифрами и ограничениями, а не предпочтением команды. Я делаю единый decision record для всех кандидатов и запрещаю использовать слова «дешево», «быстро» и «безопасно» без измерения. В документ входят версия каждого кандидата, дата теста, набор evals, параметры генерации, профиль нагрузки, схема размещения и владелец расчета. Без этого через два месяца никто не вспомнит, сравнивали ли адаптер с прежним промптом или с уже улучшенным.
Сначала вношу результаты acceptance-eval. Для каждого обязательного среза стоят отдельная метрика и порог, а не только среднее значение. Рядом записываю задержку на типичном и пиковом запросе, число отказов, потребление памяти и стоимость полезной операции. Если модель не проходит запретный сценарий, экономические клетки для нее уже не имеют значения.
Затем описываю размещение обычным потоком данных. Для внешнего API указываю, куда идут запрос, метаданные, журналы, повторы и резервные копии, кто имеет доступ и как выполняется удаление. Для локального варианта рисую тот же путь, включая наблюдаемость и хранилище артефактов. Фраза «внутри контура» без названных систем слишком легко скрывает внешний сборщик ошибок или общий бакет.
Изменяемые знания во всех вариантах остаются отдельной строкой. Если кандидат требует зашить справочник в веса, я добавляю цену каждого обновления и задержку до его выпуска. Если используется retrieval, фиксирую время переиндексации, контроль прав и поведение при пустой выдаче. Так архитектуры сравниваются по одной рабочей функции, а не по эффектной демонстрации.
Постоянные расходы разделяю по владельцам. Внешний API требует интеграции, контроля лимитов, договорной работы и повторной оценки версий. Локальная база добавляет инфраструктуру, резерв, обновление рантайма и дежурства. Адаптер добавляет подготовку данных, обучение, реестр совместимости и регрессионный выпуск. Такое разбиение мешает спрятать работу одной команды в бюджете другой.
Последняя часть документа посвящена выходу из решения. Для API записываю, сколько кода и evals потребуется для смены провайдера. Для локальной базы проверяю переносимость рантайма и формата весов. Для адаптера сохраняю базовую ревизию, токенизатор, данные и рецепт обучения. Архитектура без проверенного отката может оказаться самой дорогой именно в тот день, когда ее качество перестанет устраивать бизнес.
После таблицы нужен порог решения. Например: локальный кандидат проходит все обязательные policy-тесты, не уступает текущему решению больше допустимого значения на общем качестве, выдерживает задержку на пике и дает экономию в консервативном сценарии. Порог задают до финального прогона, иначе команда подгонит объяснение под понравившуюся модель.
Внешний API выигрывает, когда объем невелик или непредсказуем, нужна максимальная способность модели рассуждать, требования к размещению позволяют выбранный маршрут, а поведение часто меняют промптом и контекстом. Он также разумен как эталон качества, даже если итоговый продакшен будет локальным.
Локальная базовая модель выигрывает, когда размещение строго ограничено, retrieval и проверяющий код дают нужное качество, а трафик оправдывает инфраструктуру. Fine-tuning добавляется, когда остается устойчивый разрыв именно в поведении и обучающие примеры закрывают этот разрыв на отдельном acceptance-наборе.
Локальный fine-tuning становится экономически убедительным при сочетании условий: стабильная задача, качественная разметка, частые однотипные запросы, доступная инфраструктура и команда, которая умеет выпускать модели как обычный продакшен-сервис. Отсутствие хотя бы двух условий обычно возвращает преимущество API или локальной базе без обучения.
RU LLM позволяет команде сохранить OpenAI-совместимый клиент и выбирать между маршрутизацией к внешним моделям и open-weight моделями в российских ЦОДах. Такой слой удобен для честного A/B-сравнения, но решение о fine-tuning все равно должны принять ваши evals и расчет TCO.
Зафиксируйте срок пересмотра решения. Тарифы, базовые модели, нагрузка и требования меняются независимо друг от друга. Через полгода команда должна поднять исходный расчет, подставить фактические токены, часы поддержки и цену ошибок, затем снова прогнать закрытый набор. Если локальная модель держится только на старых предположениях, ее пора заменить, даже когда команда вложила в нее много труда.
Часто задаваемые вопросы
Сколько данных нужно для локального fine-tuning русской LLM?
Фиксированного числа нет: важнее разнообразие решений, чистота меток и покрытие редких ошибок. Начните с карты поведения и считайте примеры после смысловой дедупликации, а не строки в выгрузке.
Можно ли обучить модель на всей внутренней документации?
Технически корпус можно использовать, но изменяемые факты лучше получать через retrieval. Веса неудобны для точечного обновления, удаления сведений, разграничения доступа и показа источника.
Когда RAG лучше fine-tuning?
RAG лучше для фактов, которые меняются, зависят от прав пользователя или требуют ссылки на источник. Fine-tuning выбирают для устойчивого формата и поведения, а эти подходы часто используют вместе.
Гарантирует ли локальная модель соблюдение 152-ФЗ?
Нет. Нужно проверить весь путь данных, роли участников, цели обработки, журналы, бэкапы, сроки хранения и удаление. Локальный сервер закрывает только часть технической схемы.
Как сравнить fine-tuned модель с внешним API?
Прогоните одинаковый закрытый acceptance-набор через текущий продакшен, внешний API, локальную базу и адаптер. Сравнивайте обязательные policy-проверки, качество по срезам, задержку и стоимость успешно выполненной операции.
Что дешевле, LoRA или полный fine-tuning?
LoRA обычно требует меньше памяти для обучения и дает компактный отдельный артефакт. Полный fine-tuning меняет больше весов, поэтому его вычислительная и эксплуатационная цена выше, а преимущество нужно отдельно доказать.
Нужно ли переобучать модель при каждом обновлении базы знаний?
Нет. Держите изменяемые сведения в поисковом индексе, базе или инструменте и подавайте их во время запроса. Переобучение нужно, когда меняется само желаемое поведение.
Какие расходы чаще забывают в TCO локальной LLM?
Обычно забывают экспертную разметку, резерв мощности, наблюдаемость, нагрузочные тесты, выпуск версий, дежурства и цену ошибок. GPU-час обучения может оказаться небольшой частью годовой суммы.
Подходит ли синтетический датасет для русскоязычной донастройки?
Он подходит для расширения формулировок и редких веток после экспертной проверки. Не позволяйте генератору определять эталон и не стройте весь тестовый набор из ответов модели-учителя.
Когда стоит оставить внешний API в продакшене?
Оставляйте API, если нагрузка мала или рваная, сильная базовая модель заметно лучше на ваших evals, а согласованный маршрут данных допустим. Собственный кластер не окупается только потому, что один запрос кажется дешевле.