Превращаем ошибки чата в LoRA данные: гайд 2026 | AiManual
AiManual Logo Ai / Manual.
27 Май 2026 Гайд

Как превратить неправильные ответы чата в обучающие данные для LoRA: пошаговое руководство

Научитесь превращать неверные ответы модели в качественный датасет для дообучения LoRA. Пошаговая инструкция с примерами кода и типичными ошибками.

Ваша модель начала галлюцинировать. Выпустила рандомный код, перепутала факты или написала ответ с полной уверенностью — но неверный. Первая реакция — удалить диалог и забыть. А зря. Каждый такой провал — это золотая жила для дообучения. Если собрать эти ошибки, вручную или полуавтоматически исправить и завернуть в правильный формат, вы получите датасет, который модель сама себе подготовила. Без краудсорсинга, без найма доменщиков — просто перерабатываете собственные баги в фичи. Звучит как алхимия? Нет, это простой пайплайн.

Разберём, как за три шага превратить ленты мусора в обучающий gold-стандарт для LoRA. К концу статьи вы сможете запустить полный цикл от лога до обученной модели на том же оборудовании, где крутится ваш чат.

Почему ошибки — лучший учитель (но не в сыром виде)

Любая LoRA учится на парах «вход → правильный выход». Обычно мы берём размеченные датасеты или пишем синтетику. Но у вас уже есть тысячи примеров, где модель попыталась ответить — и провалилась. Что, если показать ей: «Вот твой старый ответ, он плох, а вот правильный — запомни разницу»?

Это называется contrastive fine-tuning (или pairwise preference learning). Модель учится не просто воспроизводить идеальный ответ, а различать, какой ответ сгенерировала она, а какой — человек. И что именно в её старом ответе не так. Результат — резкое снижение галлюцинаций без потери креативности.

Важно: Сырой лог ошибок — не датасет. Если просто скармливать модели её же плохие ответы как правильные, она только закрепит глюки. Исправление должно быть осознанным и проходить хотя бы минимальный ревью.

На практике лучше брать не сам плохой ответ, а конструкцию вида: User: {вопрос} AI: {старый ответ}. Потом добавлять Fixed: {новый правильный ответ}. Но об этом ниже.

Шаг 1. Логирование: поймать все провалы

Без логов нет данных. Если ваш чат-бот не пишет каждый запрос, ответ и метаданные (температуру, модель, время) — начинать не с чего.

1 Сохраняем диалоги в JSONL

Проще всего добавить middleware в FastAPI/Flask, который сериализует запрос и ответ. Пример минимального лога:

import json
from datetime import datetime

def log_conversation(user_input, model_output, model_id, status_code):
    entry = {
        "timestamp": datetime.utcnow().isoformat(),
        "prompt": user_input,
        "response": model_output,
        "model": model_id,
        "http_status": status_code
    }
    with open("chat_logs.jsonl", "a") as f:
        f.write(json.dumps(entry, ensure_ascii=False) + "\n")

Старайтесь сохранять не только ответ, но и контекст: системный промпт, историю сообщений, параметры генерации. Это пригодится при исправлении.

2 Фильтруем подозрительные ответы

Автоматически отбирать ошибки — сложно, но можно хотя бы снизить шум. В 2026 году уже отлично работают маленькие детекторы галлюцинаций, например hallucheck-1b от Anthropic или open-source FaDir (Fake Detection in Responses).

from hallucinate import HalluDetector
detector = HalluDetector.from_pretrained("anthropic/hallucheck-1b")
score = detector.predict(question, response)
if score > 0.6:  # 0.6 — порог подозрения
    mark_as_possible_error(log_entry)

Можно также использовать низкую температуру и сравнивать ответы с эталонным (если он есть). Но не перемудрите — на старте обойдитесь ручным отбором 50-100 диалогов. Качество тут важнее количества.

💡
Совет: Если не хотите писать детектор, можно нанять фрилансера для просмотра 1000 случайных диалогов и разметки только явных ошибок. Это стоит $200-500, но даёт идеальный seed dataset для первой итерации.

Шаг 2. Исправляем ошибки: чем точнее, тем лучше

Теперь у вас есть список промптов и плохих ответов. Нужно сформировать пару (плохой ответ, исправленный ответ). Исправлять можно вручную, через другую модель (GPT-4.1, Claude 4 Opus, Gemini 2.5 Ultra) или комбинировать.

3 Создаём датасет в формате instruction/response

Лучший формат для LoRA в 2026 — Alpaca-style с дополнительным полем rejected. Hugging Face Datasets поддерживает это нативно. Пример записи:

{
    "instruction": "Объясни разницу между рекурсией и итерацией",
    "input": "",
    "output": "Рекурсия — это вызов функции самой себя...",
    "rejected": "Рекурсия — это тип циклов, когда функция вызывает другую функцию."
}

Поле rejected содержит оригинальный неверный ответ. Можно обучить модель на DPO (Direct Preference Optimization), где loss учитывает и accepted, и rejected. А можно просто убрать плохой вариант и учить на правильном — но тогда теряется контраст.

Я рекомендую использовать DPOLoRA (поддерживается в Unsloth 0.8.0+ и Axolotl 0.8.2+). Для этого датасет должен содержать колонки chosen и rejected. Hugging Face TRL trainer это съест без дополнительных костылей.

4 Приводим датасет к единому шаблону

Если используете чат-формат (как у Qwen 3, Llama 4), оборачивайте диалоги в токены. Пример с токенизатором:

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-7B")

def format_dpo_sample(example):
    prompt = tokenizer.apply_chat_template(
        [{"role": "user", "content": example["instruction"]}],
        tokenize=False,
        add_generation_prompt=True
    )
    return {
        "prompt": prompt,
        "chosen": prompt + example["output"] + tokenizer.eos_token,
        "rejected": prompt + example["rejected"] + tokenizer.eos_token
    }

Не забывайте, что длина в токенах — ресурс. Если модель поддерживает 128k контекста (как Gemini 2.5 или Qwen 3), вы можете скормить всю историю диалога как промпт, а исправление — как chosen.

Шаг 3. Обучаем LoRA на исправленных ошибках

Типичная ошибка новичков — брать слишком много новых данных и выкидывать старые. Модель забывает, как отвечать правильно на другие вопросы. Это катастрофическое забывание. Чтобы его избежать, перемешивайте исправленные примеры с частью оригинального обучающего датасета (скажем, 70% старых данных + 30% новых исправлений).

Запуск на железе FP8 может вызывать underflow (потери точности). Для LoRA лучше использовать FP16/BF16 mixed precision или переключиться на QLoRA с Quanto 4-bit. В Unsloth 0.8.0 добавили опцию --flash_attention_2 и --float8 с динамическим scaling.

python unsloth/train_lora.py \
    --model Qwen/Qwen3-7B \
    --dataset corrected_chat_data \
    --lora_r 16 \
    --lora_alpha 32 \
    --lr 1e-4 \
    --num_train_epochs 1 \
    --max_seq_length 4096 \
    --dtype bfloat16 \
    --load_in_4bit \
    --use_dpo True \
    --output_dir ./lora-corrected

После обучения — обязательное валидационное тестирование. Подайте модели 10-20 вопросов, на которых она раньше ошибалась, и проверьте, что исправления усвоились. Если модель продолжает выдавать старый неверный ответ — значит, обучение не сработало (см. типичные причины).

Подводные камни и как их обойти

  • Перекос в сторону исправлений. Если вы исправили 500 диалогов про Python, модель начнёт отвечать на любой вопрос кодом. Держите доменную балансировку — столько же примеров из других тем.
  • Неправильный prompt format. В DPO промпт должен быть строго одинаковым для chosen и rejected. Если вы используете разные системные сообщения — модель запутается.
  • Игнорирование rejected. Если rejected не содержит явных ошибок (модель и так была права), вы учите модель хуже. Отфильтруйте примеры, где уверенный score низкий.
  • Слишком маленький r в LoRA. Для исправления галлюцинаций нужна ёмкость: r=8 часто не хватает, минимум 16-32.

Помните: качество датасета важнее размера. Лучше 200 тщательно проверенных исправлений, чем 2000 автоматически сгенерированных. Подробнее про создание качественного датасета читайте в отдельном руководстве.

Как НЕ надо делать (и что выйдет вместо LoRA)

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

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

from openai import OpenAI

client = OpenAI()
correction = client.chat.completions.create(
    model="gpt-4.1-2026-05-01",
    messages=[
        {"role": "system", "content": "Ты исправляешь ошибки в ответах ассистента."},
        {"role": "user", "content": prompt},
        {"role": "assistant", "content": bad_response},
        {"role": "user", "content": "Исправь ошибку, если она есть. Если ответ верен, скажи 'OK'."}
    ]
)

Затем проверяем, не ответила ли модель-корректор 'OK'. Если нет — записываем исправленный ответ как chosen, старый — как rejected.

Что дальше: итеративный цикл

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

Этот подход напоминает RLHF (Reinforcement Learning from Human Feedback), но без дорогого рейтинга. Вы просто исправляете очевидные баги. Со временем можно автоматизировать почти всё, оставив человеку только пограничные случаи.

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

Совет: Не пытайтесь исправить все сразу. За одну итерацию берите не больше 200-300 исправленных примеров. И обязательно проверяйте забывание на валидационном сете — проще всего дать модели 50 старых вопросов и сравнить ответы.

Неочевидный бонус: если вы используете одну и ту же модель-исправитель (например, GPT-4.1), вы можете потом отдистиллировать её знания в вашу основную модель через LoRA — это дешевле, чем гнать каждый запрос через дорогой API.

В конце концов, вы получите кастомную версию модели, которая почти не галлюцинирует в вашей предметной области. И всё на основе собственных ошибок. Очевидно же, что обучать модель на её же провалах — самый честный способ улучшить её.

Подписаться на канал