Claude знает миллионы фактов, может рассуждать и писать код. Но он не знает, как именно твоя компания отвечает клиентам, какие категории обращений у тебя есть и в каком формате должен быть отчёт. В уроке 5.1 мы решали это через RAG — подкладывали нужные документы в промпт. Fine-tuning решает это иначе: мы берём готовую модель и дообучаем её на своих примерах. После дообучения модель «знает» твой стиль, формат и терминологию — без длинных инструкций в каждом запросе.
В уроке 2.4 (Prompt Engineering) мы научились писать хорошие инструкции для модели. Это работает для большинства задач. Но есть ситуации, когда даже идеальный промпт не справляется:
Ситуация 1: Нестабильный формат
Промпт: "Отвечай строго в формате JSON с полями category, sentiment, priority"
Реальность: в 90% случаев модель слушается. В 10% — добавляет пояснения,
меняет названия полей или забывает про JSON.
Ситуация 2: Длинные повторяющиеся инструкции
Каждый запрос начинается с 500 токенов инструкций:
"Ты — классификатор обращений. Категории: возврат, доставка, оплата..."
При 10 000 запросов в день — 5 000 000 лишних токенов. Это деньги.
Ситуация 3: Специфический стиль
Промпт: "Отвечай дружелюбно, коротко, с конкретными шагами"
Реальность: модель понимает "дружелюбно" по-своему.
А нужно — точно как в 500 реальных ответах службы поддержки.
Ситуация 4: Специальная терминология
Модель пишет "заболевание сердца" вместо "I25.1 по МКБ-10".
Медицинская, юридическая, финансовая терминология —
модель знает её, но не использует по умолчанию в нужном формате.
Все эти проблемы объединяет одно: модели нужно изменить поведение, а не дать новые факты. RAG даёт факты. Fine-tuning меняет поведение.
Fine-tuning (дообучение) — процесс, при котором готовую модель дополнительно тренируют на твоих примерах. Модель не учится с нуля. Она уже умеет понимать язык, рассуждать, генерировать текст. Fine-tuning добавляет поверх этого новый навык — как второй слой знаний.
Базовая модель (GPT-4o, Claude, Llama)
Умеет: понимать язык, рассуждать, отвечать на вопросы, писать код
Не умеет: писать в стиле твоей компании, классифицировать
по твоим категориям, следовать твоему формату
│
│ Fine-tuning
│ (показываем 200-5000 примеров "вход → правильный выход")
▼
Дообученная модель
Умеет всё то же самое + новый навык:
✓ Пишет в стиле твоих документов
✓ Классифицирует по твоим категориям
✓ Отвечает в точном формате без напоминаний
Представь опытного врача, который закончил медицинский университет и умеет всё. Но он никогда не работал в скорой помощи. Ты отправляешь его на месячную стажировку — он смотрит 500 реальных случаев, видит, как заполнять протоколы, какие решения принимать за секунды. После стажировки он всё ещё тот же опытный врач — но теперь он знает специфику скорой помощи.
Fine-tuning — это стажировка для модели. Базовые знания остаются. Добавляется специализация.
В курсе мы изучили три подхода. Каждый решает свою задачу:
┌──────────────────────────────────────────────────────────────────┐
│ ТРИ СПОСОБА АДАПТИРОВАТЬ МОДЕЛЬ │
│ │
│ 1. Промпт-инженерия (урок 2.4) │
│ Что делаем: пишем подробную инструкцию в промпте │
│ Что меняется: контекст запроса │
│ Модель: остаётся той же │
│ Данные: в промпте (каждый раз) │
│ Обновление: мгновенно — поменял промпт и готово │
│ Стоимость: бесплатно (но длинный промпт = больше токенов) │
│ │
│ 2. RAG (урок 5.1) │
│ Что делаем: ищем нужные данные и вкладываем в промпт │
│ Что меняется: контекст запроса (динамически) │
│ Модель: остаётся той же │
│ Данные: в векторной базе (обновляются мгновенно) │
│ Обновление: добавил документ в базу — сразу доступен │
│ Стоимость: база + embeddings + токены контекста │
│ │
│ 3. Fine-tuning (этот урок) │
│ Что делаем: дообучаем модель на своих примерах │
│ Что меняется: сама модель (её параметры) │
│ Модель: создаётся новая версия │
│ Данные: «вшиты» в модель при обучении │
│ Обновление: нужно переобучать (часы + деньги) │
│ Стоимость: обучение + использование дороже базовой модели │
│ │
└──────────────────────────────────────────────────────────────────┘
Промпт-инженерия = должностная инструкция
Каждое утро даёшь сотруднику памятку: "Отвечай так-то, формат такой-то."
Работает, но памятку нужно давать каждый раз.
RAG = справочник на столе
Сотрудник не помнит все цены и правила — но у него есть справочник.
Когда клиент спрашивает — он находит ответ и говорит.
Справочник можно обновить в любой момент.
Fine-tuning = обучение и стажировка
Сотрудник прошёл тренинг: 500 примеров, как отвечать клиентам.
Теперь он делает это автоматически, без памятки и справочника.
Но если правила поменялись — нужен новый тренинг.
Задача решается хорошим промптом (с примерами)?
│
├── ДА → Промпт-инженерия. Не усложняй.
│
└── НЕТ → Модели нужны конкретные факты или документы?
│
├── ДА → RAG. Данные в базе, обновляются мгновенно.
│
└── НЕТ → Модель должна изменить стиль, формат или поведение?
Промпт слишком длинный и дорогой на масштабе?
│
├── ДА → Fine-tuning.
│
└── НЕТ → Вернись к промпту.
Скорее всего, он недостаточно хорош.
Принцип: промпт → RAG → fine-tuning. Начинай с простого. Усложняй только когда простое не работает.
Этот принцип — из исследования Anthropic «Building Effective Agents». Он работает и для агентов (урок 5.2), и для адаптации моделей.
Источник: Anthropic — Building Effective Agents
https://www.anthropic.com/research/building-effective-agents
1. Стабильный формат вывода
Модель ВСЕГДА должна отвечать JSON с конкретными полями.
Промпт работает в 90% — fine-tuning даёт 99%.
2. Специфический стиль
500 примеров реальных ответов поддержки →
модель воспроизводит тон, длину, структуру точно.
3. Экономия на масштабе
10 000 запросов/день × 500 токенов инструкции = 5 000 000 токенов.
С fine-tuning: инструкция не нужна → экономия 10x по токенам.
4. Специализированная терминология
Медицинские коды, юридические формулировки, внутренний жаргон.
Модель выучивает не просто слова, а как и когда их применять.
1. Нужны актуальные данные
Fine-tuning — это снимок данных на момент обучения.
Через неделю данные устарели → нужно переобучать.
Используй RAG — данные обновляются мгновенно.
2. Нужны факты из конкретных документов
"Какая цена у товара X?" — fine-tuning может запомнить неточно.
RAG найдёт точный фрагмент из прайс-листа.
3. Мало данных (< 50 примеров)
Fine-tuning требует минимум 50 примеров.
Рекомендуется 200-500 для хорошего качества.
Если данных мало — используй few-shot промпт (2-5 примеров в промпте).
4. Задача решается промптом
Попробуй сначала. Добавь few-shot примеры (урок 2.4).
Если промпт работает в 95%+ случаев — fine-tuning не нужен.
Не нужно знать математику. Достаточно понимать принцип — он простой.
ШАГ 1: Подготовка данных
Собираешь примеры: "вот вход → вот правильный выход"
Формат: файл JSONL (каждая строка — один пример)
Количество: 200-500 примеров для хорошего результата
ШАГ 2: Обучение
Загружаешь файл в API провайдера (OpenAI, Google, и др.)
Провайдер прогоняет модель через твои примеры
Модель корректирует свои параметры на каждом примере
Занимает 10-60 минут
ШАГ 3: Использование
Получаешь имя новой модели (например, ft:gpt-4o-mini:personal::abc123)
Используешь через тот же API, что и обычную модель
Промпт теперь можно сократить — модель уже знает формат
Модель проходит через все примеры несколько раз. Каждый полный проход называется эпоха (epoch).
Пример обучения:
Вход: "Товар пришёл сломанным, хочу вернуть деньги"
Правильный выход: {"category": "return", "sentiment": "negative"}
Что делает модель на каждом примере:
1. Получает вход
2. Генерирует свой ответ: {"category": "question", "sentiment": "neutral"}
3. Сравнивает с правильным ответом — видит, что ошиблась
4. Чуть-чуть корректирует свои параметры, чтобы в следующий раз
ответить ближе к правильному
Ошибка уменьшается с каждой эпохой:
Эпоха 1: ████████████████████░░░░░ 80% ошибок (модель ещё не выучила)
Эпоха 2: ██████████░░░░░░░░░░░░░░░ 40% ошибок (начала понимать паттерн)
Эпоха 3: ████░░░░░░░░░░░░░░░░░░░░░ 15% ошибок (почти выучила)
Эпоха 4: ██░░░░░░░░░░░░░░░░░░░░░░░ 5% ошибок (готово)
Аналогия. Как ребёнок учит таблицу умножения. Первый раз — много ошибок. После 10 повторений — ошибается реже. После 50 — отвечает автоматически. Fine-tuning — это те же повторения, только для языковой модели.
JSONL (JSON Lines) — формат файла, где каждая строка — отдельный JSON-объект. Это стандартный формат для обучающих данных.
Почему именно JSONL, а не обычный JSON? Обычный JSON — это один большой объект. Если в нём миллион строк, нужно загрузить весь файл в память. JSONL позволяет читать по одной строке — это быстрее и экономнее.
Обычный JSON (один объект):
[
{"input": "...", "output": "..."},
{"input": "...", "output": "..."}
]
JSONL (каждая строка — отдельный объект):
{"input": "...", "output": "..."}
{"input": "...", "output": "..."}
Для OpenAI fine-tuning каждая строка — это диалог в формате messages (тот же формат, что и при обычном вызове API из урока 2.3):
{"messages": [{"role": "system", "content": "Classify the message."}, {"role": "user", "content": "Товар сломан"}, {"role": "assistant", "content": "{\"category\": \"return\"}"}]}
{"messages": [{"role": "system", "content": "Classify the message."}, {"role": "user", "content": "Спасибо!"}, {"role": "assistant", "content": "{\"category\": \"feedback\"}"}]}
Модель учится: «когда system и user говорят вот это — assistant должен ответить вот это».
Есть два основных подхода к дообучению. Различие — в том, какую часть модели мы меняем.
Меняются все параметры модели. У GPT-4 — сотни миллиардов параметров. Менять каждый из них — как перекрашивать каждый кирпич в многоэтажном доме.
Модель: ████████████████████████████████ (все параметры)
Меняем: ████████████████████████████████ (все — каждый подстраивается)
Требования: мощные GPU (A100, H100 — стоят $10 000+)
Время: часы — дни
Стоимость: $100 — $10 000+
Кто делает: крупные компании с ML-командами
LoRA — метод, который не трогает основную модель. Вместо этого он добавляет маленький «адаптер» — дополнительный слой параметров, который учится новому навыку.
Это как надеть на модель «очки специалиста»: базовое зрение (базовая модель) остаётся, а очки (адаптер) добавляют фокус на конкретную область.
Модель: ████████████████████████████████ (все параметры)
Меняем: ██ (только адаптер — 1-5%)
Требования: обычная GPU (RTX 3090/4090) или облако
Время: минуты — часы
Стоимость: $1 — $100
Кто делает: разработчики, стартапы, исследователи
QLoRA — ещё более экономичная версия LoRA. Буква Q означает Quantization (квантизация) — сжатие модели, чтобы она занимала меньше памяти. С QLoRA можно дообучить модель с 7 миллиардами параметров на GPU с 8 ГБ памяти — например, на обычной игровой видеокарте.
┌────────────────────────────────────────────────────────┐
│ │
│ Full fine-tuning LoRA / QLoRA │
│ ───────────────── ────────────── │
│ Меняет всю модель Добавляет адаптер │
│ Нужны мощные GPU Хватает обычной GPU │
│ Стоит $100-10 000 Стоит $1-100 │
│ Часы — дни Минуты — часы │
│ Немного лучше качество Почти такое же качество │
│ Для компаний с ML- Для всех остальных │
│ командами │
│ │
│ Аналогия: Аналогия: │
│ Перекрасить весь дом Повесить новые шторы │
│ │
└────────────────────────────────────────────────────────┘
Для большинства задач LoRA достаточно. Full fine-tuning оправдан, только когда нужен максимально точный результат и есть ресурсы.
Источник: Hu et al. — "LoRA: Low-Rank Adaptation of Large Language Models" (2021)
https://arxiv.org/abs/2106.09685
Провайдер берёт на себя всё: GPU, обучение, хостинг. Ты загружаешь данные → получаешь модель.
| Провайдер | Что можно дообучить | Метод | Стоимость обучения |
|---|---|---|---|
| OpenAI | GPT-4o, GPT-4o-mini | Managed | От $0.30 за 500 примеров |
| Gemini | Managed | Зависит от модели | |
| Together AI | Llama, Mistral, Qwen | LoRA в облаке | От $0.50 |
Anthropic (создатели Claude) пока не предлагают публичный API для fine-tuning. Поэтому для практики в этом уроке используется OpenAI — у них самый простой и доступный процесс.
Если данные нельзя отправлять на серверы OpenAI (конфиденциальность) или нужен полный контроль — можно дообучить open-source модель (Llama от Meta, Mistral, Qwen от Alibaba).
Что тебе нужно?
│
├── Быстро попробовать LoRA на бесплатном GPU
│ → Unsloth (Python-библиотека, оптимизирована для скорости)
│ → Google Colab с бесплатным GPU (T4)
│
├── Полноценный fine-tuning pipeline
│ → Hugging Face Transformers + PEFT
│ → Стандарт индустрии, много документации
│
├── Облачный fine-tuning без своего GPU
│ → Together AI, Modal, Anyscale
│ → Загружаешь данные → получаешь модель
│
└── Локально на своём Mac
→ MLX (фреймворк от Apple для Apple Silicon)
→ Ollama + LoRA-адаптеры
Для этого курса достаточно знать, что эти варианты существуют. На практике — OpenAI fine-tuning API покрывает большинство задач и не требует своих GPU.
Источники:
OpenAI Fine-tuning: https://platform.openai.com/docs/guides/fine-tuning
Unsloth: https://github.com/unslothai/unsloth
Hugging Face PEFT: https://huggingface.co/docs/peft
Качество данных — самое важное в fine-tuning. Плохие данные → плохая модель. Никакое количество эпох не исправит ошибки в обучающих примерах.
Количество:
Минимум: 50 примеров (результат будет слабый)
Хорошо: 200-500 примеров
Отлично: 500-5000 примеров
Максимум: до 50 000 (OpenAI)
Качество важнее количества:
100 чистых, правильных примеров > 1000 грязных с ошибками
Ошибка 1: Противоречивые примеры
"Товар сломан" → category: "feedback" ← НЕПРАВИЛЬНО
"Товар сломан" → category: "return" ← правильно
Одинаковый вход — разный выход. Модель получает противоречивый сигнал.
Она не знает, какой ответ правильный, и учится "усреднённому" —
который неправильный в обоих случаях.
Ошибка 2: Несбалансированные категории
Данные:
300 примеров → category: "return"
50 примеров → category: "delivery"
20 примеров → category: "payment"
10 примеров → category: "feedback"
Результат: модель будет всё подряд классифицировать как "return",
потому что видела эту категорию в 79% примеров.
Решение: примерно одинаковое количество примеров на каждую категорию.
Ошибка 3: Ответы не такие, какие нужны
В данных: ассистент пишет по 500 слов с объяснениями
В реальности: нужен короткий JSON без объяснений
Модель выучит писать длинно — потому что так в примерах.
Правило: ответ в обучающих данных должен быть ТОЧНО таким,
какой ты хочешь получать от модели.
pip install openai python-dotenv
Нужен API-ключ OpenAI (не Anthropic — у Anthropic нет публичного fine-tuning).
Получить ключ: https://platform.openai.com/api-keys
В файле .env:
OPENAI_API_KEY=sk-...
Классификатор обращений клиентов. На входе — сообщение клиента. На выходе — JSON с категорией, тональностью и приоритетом.
┌──────────────────────────────────────────────────────────┐
│ │
│ Вход: "Товар пришёл сломанным, хочу вернуть деньги" │
│ │ │
│ ▼ │
│ ┌────────────────────┐ │
│ │ Дообученная модель │ │
│ │ (ft:gpt-4o-mini) │ │
│ └─────────┬──────────┘ │
│ │ │
│ ▼ │
│ Выход: {"category": "return", │
│ "sentiment": "negative", │
│ "priority": "high"} │
│ │
└──────────────────────────────────────────────────────────┘
# prepare_data.py — создаёт файл с обучающими данными для fine-tuning
import json
# === ОБУЧАЮЩИЕ ПРИМЕРЫ ===
# Каждый пример: текст обращения клиента → правильная классификация
# В реальном проекте таких примеров нужно 200-500
# Для демонстрации используем 25
training_examples = [
# --- ВОЗВРАТ (return) ---
{"input": "Товар пришёл сломанным, хочу вернуть деньги",
"output": {"category": "return", "sentiment": "negative", "priority": "high"}},
{"input": "Можно ли обменять на другой размер?",
"output": {"category": "return", "sentiment": "neutral", "priority": "medium"}},
{"input": "Хочу отменить заказ и получить возврат",
"output": {"category": "return", "sentiment": "negative", "priority": "high"}},
{"input": "Товар не соответствует описанию на сайте",
"output": {"category": "return", "sentiment": "negative", "priority": "high"}},
{"input": "Как оформить возврат? Не подошёл цвет",
"output": {"category": "return", "sentiment": "neutral", "priority": "medium"}},
# --- ДОСТАВКА (delivery) ---
{"input": "Когда будет доставка заказа #4521?",
"output": {"category": "delivery", "sentiment": "neutral", "priority": "medium"}},
{"input": "Курьер не приехал в назначенное время",
"output": {"category": "delivery", "sentiment": "negative", "priority": "high"}},
{"input": "Можно ли изменить адрес доставки?",
"output": {"category": "delivery", "sentiment": "neutral", "priority": "medium"}},
{"input": "Заказ показывает статус 'в пути' уже неделю",
"output": {"category": "delivery", "sentiment": "negative", "priority": "high"}},
{"input": "Доставка пришла вовремя, всё отлично",
"output": {"category": "delivery", "sentiment": "positive", "priority": "low"}},
# --- ОПЛАТА (payment) ---
{"input": "Деньги списались, но заказ не оформлен",
"output": {"category": "payment", "sentiment": "negative", "priority": "high"}},
{"input": "Какие способы оплаты доступны?",
"output": {"category": "payment", "sentiment": "neutral", "priority": "low"}},
{"input": "Не проходит оплата картой",
"output": {"category": "payment", "sentiment": "negative", "priority": "high"}},
{"input": "Можно ли оплатить при получении?",
"output": {"category": "payment", "sentiment": "neutral", "priority": "low"}},
{"input": "Пришёл двойной чек за один заказ",
"output": {"category": "payment", "sentiment": "negative", "priority": "high"}},
# --- ОТЗЫВ (feedback) ---
{"input": "Отличный магазин, всё понравилось!",
"output": {"category": "feedback", "sentiment": "positive", "priority": "low"}},
{"input": "Качество товара превзошло ожидания",
"output": {"category": "feedback", "sentiment": "positive", "priority": "low"}},
{"input": "Обслуживание ужасное, больше не приду",
"output": {"category": "feedback", "sentiment": "negative", "priority": "medium"}},
{"input": "Нормально, но ничего особенного",
"output": {"category": "feedback", "sentiment": "neutral", "priority": "low"}},
{"input": "Рекомендую друзьям, очень довольна покупкой",
"output": {"category": "feedback", "sentiment": "positive", "priority": "low"}},
# --- ВОПРОС (question) ---
{"input": "Есть ли у вас доставка в Казахстан?",
"output": {"category": "question", "sentiment": "neutral", "priority": "low"}},
{"input": "Какой срок гарантии на электронику?",
"output": {"category": "question", "sentiment": "neutral", "priority": "low"}},
{"input": "Работает ли магазин в праздники?",
"output": {"category": "question", "sentiment": "neutral", "priority": "low"}},
{"input": "Есть ли скидки для постоянных клиентов?",
"output": {"category": "question", "sentiment": "neutral", "priority": "low"}},
{"input": "Можно ли заказать товар оптом?",
"output": {"category": "question", "sentiment": "neutral", "priority": "low"}},
]
# === КОНВЕРТАЦИЯ В ФОРМАТ OPENAI (JSONL) ===
# Системный промпт — одинаковый для всех примеров.
# Он короткий, потому что после fine-tuning модель
# уже "знает" формат и категории.
system_prompt = "Classify the customer message. Respond with JSON only."
# Открываем файл для записи
with open("training_data.jsonl", "w", encoding="utf-8") as f:
for example in training_examples:
# Каждая строка JSONL — диалог в формате messages
# Тот же формат, что и при обычном вызове API (урок 2.3)
line = {
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": example["input"]},
{"role": "assistant", "content": json.dumps(example["output"])}
# json.dumps превращает словарь Python в строку JSON
# {"category": "return"} → '{"category": "return"}'
]
}
# Записываем одну строку в файл
# ensure_ascii=False — чтобы кириллица сохранялась как есть
f.write(json.dumps(line, ensure_ascii=False) + "\n")
print(f"Создано {len(training_examples)} примеров в training_data.jsonl")
После запуска появится файл training_data.jsonl. Каждая строка — один пример. Открой его в текстовом редакторе и убедись, что формат правильный: system → user → assistant.
# fine_tune.py — загружает данные в OpenAI и запускает дообучение
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv() # загружает OPENAI_API_KEY из .env
client = OpenAI() # клиент OpenAI API (ключ берёт из переменной окружения)
# === ШАГ 1: ЗАГРУЗКА ФАЙЛА ===
# OpenAI нужно сначала загрузить файл на их сервер.
# purpose="fine-tune" говорит: "этот файл — для дообучения"
print("Загружаю файл с данными на сервер OpenAI...")
with open("training_data.jsonl", "rb") as f: # "rb" = read binary (требование API)
training_file = client.files.create(
file=f,
purpose="fine-tune"
)
print(f" Файл загружен. ID: {training_file.id}")
# Пример ID: file-abc123
# === ШАГ 2: ЗАПУСК FINE-TUNING ===
# Создаём задачу на дообучение.
# model — какую базовую модель дообучать.
# gpt-4o-mini — самая дешёвая модель OpenAI для fine-tuning.
print("\nЗапускаю fine-tuning...")
job = client.fine_tuning.jobs.create(
training_file=training_file.id,
model="gpt-4o-mini-2024-07-18",
hyperparameters={
"n_epochs": 3 # сколько раз пройти по всем примерам
# 3 эпохи — хороший дефолт для большинства задач
# Больше эпох = модель лучше запоминает, но может "переучиться"
}
)
print(f" Job создан. ID: {job.id}")
print(f" Статус: {job.status}")
# Статус "validating_files" → "queued" → "running" → "succeeded"
print(f"\n Дообучение займёт 10-30 минут.")
print(f" Проверить статус:")
print(f" python check_status.py {job.id}")
# check_status.py — проверяет, готово ли дообучение
import sys
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI()
# ID задачи — передаём аргументом при запуске:
# python check_status.py ftjob-abc123
job_id = sys.argv[1] if len(sys.argv) > 1 else "ftjob-xxxxxxxxxx"
# sys.argv — список аргументов командной строки
# sys.argv[0] = "check_status.py" (имя скрипта)
# sys.argv[1] = "ftjob-abc123" (первый аргумент — ID задачи)
# Запрашиваем статус задачи
job = client.fine_tuning.jobs.retrieve(job_id)
print(f"Статус: {job.status}")
# validating_files — проверяет формат данных
# queued — в очереди на обучение
# running — идёт обучение
# succeeded — готово!
# failed — ошибка
if job.status == "succeeded":
print(f"\nГотово! Имя модели: {job.fine_tuned_model}")
print(f"Используй это имя в параметре model= при вызове API.")
# Пример имени: ft:gpt-4o-mini-2024-07-18:personal::abc123
elif job.status == "failed":
print(f"\nОшибка: {job.error}")
else:
print(f"\nЕщё в процессе. Подожди и проверь снова.")
# Показать последние события (что происходит внутри)
print("\nПоследние события:")
events = client.fine_tuning.jobs.list_events(
fine_tuning_job_id=job_id,
limit=5 # последние 5 событий
)
for event in events.data:
print(f" {event.message}")
# use_model.py — тестируем дообученную модель
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI()
# Имя дообученной модели — из check_status.py после "succeeded"
# Замени на своё имя модели:
FINE_TUNED_MODEL = "ft:gpt-4o-mini-2024-07-18:personal::abc123"
def classify(message):
"""
Классифицирует обращение клиента.
Использует дообученную модель вместо базовой.
"""
response = client.chat.completions.create(
model=FINE_TUNED_MODEL, # ← наша дообученная модель
messages=[
# Промпт короткий — модель уже знает формат и категории
{"role": "system", "content": "Classify the customer message. Respond with JSON only."},
{"role": "user", "content": message}
],
max_tokens=100 # ответ короткий — JSON в одну строку
)
return response.choices[0].message.content
# === ТЕСТИРУЕМ НА НОВЫХ ОБРАЩЕНИЯХ ===
# Эти сообщения НЕ были в обучающих данных.
# Модель должна обобщить паттерн и правильно классифицировать.
test_messages = [
"Посылка потерялась где-то в пути",
"Вы лучший магазин, буду заказывать ещё!",
"Сколько стоит экспресс-доставка?",
"Верните деньги немедленно, товар бракованный!",
"Не могу войти в личный кабинет",
]
print("=== Тестирование дообученной модели ===\n")
for msg in test_messages:
result = classify(msg)
print(f" Вход: {msg}")
print(f" Выход: {result}")
print()
=== Тестирование дообученной модели ===
Вход: Посылка потерялась где-то в пути
Выход: {"category": "delivery", "sentiment": "negative", "priority": "high"}
Вход: Вы лучший магазин, буду заказывать ещё!
Выход: {"category": "feedback", "sentiment": "positive", "priority": "low"}
Вход: Сколько стоит экспресс-доставка?
Выход: {"category": "question", "sentiment": "neutral", "priority": "low"}
Вход: Верните деньги немедленно, товар бракованный!
Выход: {"category": "return", "sentiment": "negative", "priority": "high"}
Вход: Не могу войти в личный кабинет
Выход: {"category": "question", "sentiment": "negative", "priority": "medium"}
Обрати внимание: промпт — одна строка. Никаких длинных инструкций, списков категорий, примеров формата. Модель уже всё знает после дообучения.
prepare_data.py)training_examples = [
{"input": "Товар сломан", "output": {"category": "return", ...}},
...
]
Список словарей Python. Каждый словарь — один пример: input (что говорит клиент) и output (правильный ответ). Это человекочитаемый формат — удобно редактировать и добавлять примеры.
json.dumps(example["output"])
json.dumps() превращает словарь Python в строку JSON. Это нужно, потому что в поле content API ожидает строку, а не словарь.
f.write(json.dumps(line, ensure_ascii=False) + "\n")
Записывает одну строку в файл и добавляет перенос строки (\n). Так получается формат JSONL — одна строка = один пример.
fine_tune.py)client.files.create(file=f, purpose="fine-tune")
Загружает файл на серверы OpenAI. purpose="fine-tune" говорит серверу, что файл предназначен для дообучения, а не для другой задачи.
client.fine_tuning.jobs.create(
training_file=training_file.id,
model="gpt-4o-mini-2024-07-18",
hyperparameters={"n_epochs": 3}
)
Создаёт задачу на дообучение. Три параметра:
- training_file — ID загруженного файла
- model — какую базовую модель дообучать
- n_epochs — сколько раз пройти по всем примерам (3 — хороший дефолт)
use_model.py)client.chat.completions.create(
model=FINE_TUNED_MODEL, # ft:gpt-4o-mini:personal::abc123
messages=[...]
)
Точно тот же API, что и для обычной модели. Единственное отличие — в model указывается имя дообученной модели (начинается с ft:). Всё остальное — идентично.
OpenAI считает стоимость по количеству токенов в обучающих данных:
Формула:
токены в данных × цена за токен × количество эпох
Пример с gpt-4o-mini:
25 примеров × ~100 токенов = 2 500 токенов
2 500 × $0.003 (за 1K) × 3 эпохи = ~$0.02
500 примеров × ~100 токенов = 50 000 токенов
50 000 × $0.003 × 3 = ~$0.45
Для gpt-4o (более мощная модель):
500 примеров × ~100 токенов = 50 000 токенов
50 000 × $0.025 × 3 = ~$3.75
Дообученная модель чуть дороже базовой:
gpt-4o-mini (базовая): $0.15 / 1M input $0.60 / 1M output
gpt-4o-mini (fine-tuned): $0.30 / 1M input $1.20 / 1M output
(2x дороже за токен)
НО промпты после fine-tuning короче (не нужны инструкции),
поэтому реальная стоимость за запрос может быть НИЖЕ.
┌──────────────────────────────────────────────────────┐
│ │
│ Обучение модели: $0.50 — $5.00 │
│ Использование: зависит от объёма │
│ │
│ Главная стоимость: ВРЕМЯ НА ПОДГОТОВКУ ДАННЫХ │
│ │
│ Собрать 500 примеров, │
│ проверить каждый на правильность, │
│ сбалансировать категории, │
│ привести к единому формату — │
│ это часы или дни работы человека. │
│ │
└──────────────────────────────────────────────────────┘
Источник: OpenAI — Pricing
https://openai.com/api/pricing/
Overfitting (переобучение) — ситуация, когда модель слишком хорошо запомнила обучающие примеры, но не может обобщить на новые данные.
На обучающих данных:
"Товар пришёл сломанным" → {"category": "return"} ← правильно
На новых данных:
"Заказ повреждён при доставке" → {"category": "delivery"} ← ОШИБКА
(правильно: "return" — это тоже возврат, но модель не обобщила)
Студент зазубрил ответы на 50 конкретных вопросов из билетов. На экзамене попался вопрос с той же темой, но другой формулировкой — студент не смог ответить. Он запомнил конкретные вопросы вместо того, чтобы понять тему.
✓ На обучающих примерах — идеальные результаты
✗ На новых примерах — ошибки
✗ Модель повторяет фразы из обучающих данных дословно
✗ Модель не справляется с формулировками, которых не было в данных
1. Больше данных (200-500, не 25)
Чем больше разнообразных примеров — тем лучше обобщение.
2. Меньше эпох (2-4, не 10)
Слишком много эпох = модель начинает зубрить.
3. Validation data (проверочные данные)
Отложить 20% примеров и не использовать их для обучения.
Проверять качество на них — если на проверочных ошибки растут,
а на обучающих падают — это переобучение.
4. Разнообразие формулировок
Разные способы сказать одно и то же для каждой категории.
"Товар сломан", "Пришёл бракованный", "Не работает" —
всё это "return", но сказано по-разному.
┌──────────────────────────────────────────────────────────┐
│ КТО И КАК ИСПОЛЬЗУЕТ FINE-TUNING │
│ │
│ Служба поддержки │
│ Модель классифицирует обращения по категориям │
│ и приоритетам. 100 000 обращений/день — промпт │
│ был бы слишком дорогим. Fine-tuning экономит 10x. │
│ │
│ Юридические компании │
│ Модель генерирует документы в точном формате: │
│ структура параграфов, юридические термины, ссылки │
│ на статьи закона. Промпт не даёт такой стабильности. │
│ │
│ Медицина │
│ Модель заполняет клинические записи в формате │
│ МКБ-10. Специфическая терминология + строгий формат │
│ = идеальная задача для fine-tuning. │
│ │
│ E-commerce │
│ Автоматическая категоризация товаров. │
│ "Синяя хлопковая футболка XL" → │
│ {category: "одежда/футболки", size: "XL", │
│ material: "хлопок", color: "синий"} │
│ │
│ Контент и маркетинг │
│ Модель пишет посты, письма, описания в фирменном │
│ стиле компании. 500 примеров текстов компании → │
│ модель воспроизводит тон и структуру. │
│ │
└──────────────────────────────────────────────────────────┘
Запусти prepare_data.py. Открой файл training_data.jsonl в текстовом редакторе. Найди в каждой строке три роли: system, user, assistant. Добавь 5 своих примеров в training_examples (придумай обращения клиентов) и пересоздай файл.
Если есть API-ключ OpenAI — запусти полный цикл: загрузка данных → обучение → проверка статуса → тестирование. Стоимость для 25 примеров на gpt-4o-mini — меньше $0.05. Протестируй модель на обращениях, которых не было в данных.
Отправь те же тестовые обращения в обычную (не дообученную) модель с подробным промптом: - Опиши категории, формат JSON, примеры - Сравни: стабильность формата, длину промпта, качество классификации - Подсчитай разницу в токенах (длинный промпт vs. короткий после fine-tuning)
Это поможет на практике увидеть, когда fine-tuning даёт преимущество, а когда достаточно хорошего промпта.
Задача 1: Что такое fine-tuning простыми словами?
Задача 2: Когда лучше RAG, а когда fine-tuning?
Задача 3: Что такое LoRA и зачем она нужна?
Задача 4: Почему 100 чистых примеров лучше, чем 1000 грязных?
Задача 5: Что такое overfitting?
| Термин | Что значит |
|---|---|
| Fine-tuning | Дообучение готовой модели на своих примерах — модель получает новый навык (стиль, формат, терминологию) |
| JSONL | JSON Lines — формат файла, где каждая строка — отдельный JSON-объект. Стандарт для обучающих данных |
| Эпоха (epoch) | Один полный проход модели по всем обучающим примерам. 3 эпохи = модель прошла по данным 3 раза |
| LoRA | Low-Rank Adaptation — метод частичного дообучения. Добавляет маленький адаптер (~1-5% параметров) вместо изменения всей модели |
| QLoRA | LoRA + квантизация (сжатие модели). Позволяет дообучать на обычной GPU с 8 ГБ памяти |
| Full fine-tuning | Полное дообучение — меняются все параметры модели. Дорого, но максимально точно |
| Адаптер | Маленький набор дополнительных параметров при LoRA. Как «очки специалиста» для модели |
| Гиперпараметры | Настройки процесса обучения: количество эпох, learning rate, batch size |
| Training data | Обучающие данные — примеры «вход → правильный выход», на которых модель учится |
| Validation data | Проверочные данные — модель на них НЕ учится, но по ним измеряется качество |
| Overfitting | Переобучение — модель зазубрила примеры, но не обобщает на новые данные |
| Base model | Базовая модель до дообучения (GPT-4o-mini, Llama, Mistral) |
| Managed fine-tuning | Дообучение через API провайдера (OpenAI, Google) — без своих GPU |
| Open-source модель | Модель с открытым кодом (Llama, Mistral, Qwen) — можно скачать и дообучить самостоятельно |
| Inference | Использование обученной модели для генерации ответов (в отличие от training — обучения) |
| Unsloth | Python-библиотека для быстрого LoRA fine-tuning open-source моделей |
Fine-tuning = дообучение готовой модели на своих примерах
Модель не учится с нуля — она получает специализацию.
Когда нужен:
• Стабильный формат вывода (JSON, структура)
• Специфический стиль или тон
• Экономия токенов на масштабе (короче промпты)
• Специализированная терминология
Когда НЕ нужен:
• Нужны актуальные данные → RAG
• Задача решается промптом → промпт-инженерия
• Мало данных (< 50 примеров) → few-shot в промпте
Порядок: промпт → RAG → fine-tuning
Начинай с простого. Усложняй только когда простое не работает.
Как работает:
1. Собрать 200-500 примеров "вход → правильный выход" (JSONL)
2. Загрузить в OpenAI → запустить обучение (10-30 минут)
3. Получить модель → использовать через тот же API
Типы:
Full fine-tuning — дорого, все параметры, для больших компаний
LoRA — дёшево, маленький адаптер, для всех остальных
Стоимость:
Обучение: $0.02-5.00 (зависит от данных и модели)
Главная цена: время на подготовку качественных данных
Ловушка — overfitting:
Модель зазубрила примеры, но не обобщает на новые.
Решение: больше данных, меньше эпох, разнообразие, validation.
Fine-tuning делает модель точнее для конкретных задач. Но AI-продукт — это не только точность. Это ещё и стоимость, скорость и масштаб. Как выбрать правильную модель для задачи? Как кешировать ответы? Как сократить промпты без потери качества? В следующем уроке — оптимизация и стоимость: экономика AI-продуктов.