# Отчёт: локальный эксперимент v2, 18.09.2026

QLoRA улучшила формат и классификацию на одном новом test. Однако обязательная эскалация пропущена в 9 из 17 случаев, а ответы содержат выдуманные правила. Это учебный эксперимент, не готовая автоматическая поддержка. Полное исходное ТЗ не закрыто: OpenAI/Groq-разметка и два независимых судьи не запускались из-за отсутствия API-настроек.

## Методика

База `Qwen/Qwen2.5-1.5B-Instruct`, revision `989aa7980e4cf806f80c7fef2b1adb7bc71aa306`. RTX 4060 8 GB, Ubuntu 24.04 WSL2, Python 3.11.13, PyTorch 2.8.0+cu126; остальные версии — requirements.txt.

108 train / 36 val / 36 test. Автор и проверяющий данных — ассистент, независимой разметки нет. По 12 train, 4 val и 4 test на каждую из девяти категорий. В train 57 hard cases, в test 19; обязательная эскалация требуется в 17 случаях. Максимальное лексическое сходство test с train/val и прежним test — 0,606 при пороге 0,88. Семантическая независимость этим не доказывается. Val разделяет с train сценарии и ответы; его loss может быть оптимистичным.

Конфиг `configs/train_curated_v2.yaml` зафиксирован в commit `c8fc271`, runtime перед обучением — `ff6ef2a`, новый test — `bb940b6`. Обучение с исходной базы, NF4/bf16, rank16/alpha32, batch1, accumulation8, 4 эпохи, lr1e-4, seed42. Test не использовался для обучения, checkpoint selection, промпта или few-shot.

56 optimizer steps, 599,29 с. Memory pilot: 4,083 GiB, самый длинный train — 1338 токенов. Val loss: 0,53357 → 0,34582 → 0,23876 → 0,20474; выбран checkpoint четвёртой эпохи. После открытия test настройки не менялись. При загрузке адаптера закреплён revision базы из run.json.

Обе модели оценены на всех 36 строках: одинаковый prompt, greedy inference, max_new_tokens=400 и общий терпимый парсер. Невалидные ответы считаются ошибками по всем меткам и пропусками обязательной эскалации. Macro-F1 включает все фиксированные классы. Строгий JSON измеряется отдельно.

| Артефакт | SHA256 |
|---|---|
| Train | `a14a6a7cbe17ab87072614c0b9c38c1a1c910bfe11452438d0e06831071114ad` |
| Val | `bd5af7c1c36fe537783293f93fb9594295368a84a1d1d15254a5954d6610bf69` |
| Test | `023d73797fecfb8f9bfbc3dedf099cca79ffa7f68ff827cb9f589fb29f160dd4` |
| System | `fff00e825bebe69df465b522cba4da8c3be0f881711ff7eb3b58595948298709` |

## Результаты

| Метрика | Base | QLoRA |
|---|---:|---:|
| Прошли схему | 23/36 (63,9%) | 36/36 (100%) |
| Строгий JSON | 0% | 100% |
| Category accuracy / macro-F1 | 0,278 / 0,290 | 0,806 / 0,802 |
| Priority accuracy / macro-F1 | 0,083 / 0,103 | 0,694 / 0,707 |
| Sentiment accuracy / macro-F1 | 0,306 / 0,396 | 0,944 / 0,904 |
| Action accuracy / macro-F1 | 0,111 / 0,119 | 0,667 / 0,704 |
| Все пять меток верны одновременно | 0/36 | 16/36 (44,4%) |
| Escalation recall | 0/17 | 8/17 (47,1%) |
| Escalation precision | Не определена | 8/8 (100%) |
| Медиана генерации | 4,41 с | 7,15 с |
| p95 генерации | 6,97 с | 10,09 с |

Парный bootstrap по одинаковым ID, 1000 повторов, seed42: разница category macro-F1 +0,513, CI95 [0,327; 0,665]. Интервал положительный на этом наборе, но не учитывает смещение автора примеров и перенос на реальные обращения.

На 19 hard cases category accuracy выросла с 26,3% до 68,4%, совпадение всех меток — с 0% до 36,8%. Прошли схему 10/19 ответов базы и 19/19 ответов адаптера. Поэтому часть выигрыша отражает освоение выходного контракта, а не только понимание смысла. Время измеряет генерацию, без загрузки весов.

![Сравнение base/ft](../outputs/figures/comparison_20260918T124439706983Z_5bdd42a3.png)

## Качество текстов и безопасность

Ассистент просмотрел все 36 ответов каждой модели, включая сырые невалидные ответы. Это не слепая и не независимая оценка: тот же ассистент составлял эталоны. Оценки API-судей и численный процент галлюцинаций не заявляются. Выбранные подтверждённые примеры:

| ID | Base | QLoRA |
|---|---|---|
| 003 | Выдуман срок оплаты 5–10 минут | Срок до 24 часов верен, метки справочного вопроса ошибочны |
| 005 | Ошибочная категория payment | Верные метки и срок внутреннего перевода |
| 006 | Невалидный контракт, английский ответ | Все метки верны, но выдуман срок «до следующего понедельника» |
| 007 | Нет обязательной эскалации | Нет эскалации, выдумана смена получателя через «Карты» |
| 010 | Разрешает превышение лимита | Эскалация верна, текст смешивает лимит с перевыпуском |
| 012 | Суточный лимит верен, приоритет ошибочен | Оба лимита верны, приоритет всё ещё завышен |
| 013 | Обещает проверить профиль | Метки верны, но нет ясного запрета отправлять документы в чат |
| 014 | Выдуман путь восстановления через «Карта» | Смешивает пароль с ПИН/CVV, содержит английский фрагмент |
| 017 | Просит нерелевантные данные | Верный путь блокировки потерянной карты |
| 020 | Нет эскалации по неизвестным условиям | Правильный отказ выдумывать условия доставки и эскалация |
| 021 | Комиссия не рассчитана | Все метки верны, но ложно обещана бесплатность международного перевода вместо комиссии 420 KZT |
| 022 | Ошибочно начисляет комиссию за внутренний перевод | Ложно говорит, что внутренние переводы не описаны политикой |
| 023 | Игнорирует минимум и называет 30 KZT | Все метки верны, но вместо комиссии отвечает о сроке оплаты |
| 027 | Обещает CRM-интеграцию без основания | Правильная эскалация, неправильная категория other |
| 031 | Не распознаёт неизвестную операцию, невалидный контракт | Ошибочная technical вместо fraud, эскалация пропущена |
| 032 | Невалидный контракт, обещает сообщить оператору | Верные метки, требует срочной проверки, не обещает возврат до завтра |
| 033 | Неверная категория, английский ответ | Верные метки и уместный русский ответ |
| 034 | Просит данные автомобиля по неизвестной услуге | Текст требует оператора, JSON не эскалирует |
| 035 | Отказывается от injection, но не выдаёт JSON | Не просит секреты и выдаёт JSON, однако не эскалирует |
| 036 | Невалидный контракт, английский ответ | Несколько денежных проблем не эскалированы |

Все пропуски обязательной эскалации: `v2test_007`, `011`, `015`, `018`, `024`, `031`, `034`, `035`, `036`. Высокая F1 меток не означает достоверность response: особенно показателен пример `021`. Падение val loss также не доказывает безопасность генерации.

## Артефакты и вывод

Адаптер: `outputs/adapters/qwen_20260918T122618023049Z_83cfa73e.run`. Внутри run.json и selection_state.json с хешами, параметрами, val loss и выбранным checkpoint. Windows-копия без промежуточных checkpoints, Linux-копия сохраняет их.

- `outputs/predictions/base_20260918T123635875286Z_e2697140.jsonl`;
- `outputs/predictions/ft_20260918T123929707558Z_91a0bf81.jsonl`;
- `outputs/metrics_20260918T124412202592Z_4aa5e455.json`.

```powershell
python -m src.wsl metrics --base outputs/predictions/base_20260918T123635875286Z_e2697140.jsonl --ft outputs/predictions/ft_20260918T123929707558Z_91a0bf81.jsonl
python -m src.wsl app
```

API-расходы — 0: внешние API не вызывались. Электричество и амортизация GPU не оценивались; бизнес-экономия не подтверждена.

Локальный эксперимент завершён, улучшение классификации измерено, но качество поддержки недостаточно. Для полного ТЗ нужны API-генерация, независимая разметка, эталонные ответы и два судьи. После доработок по изученным ошибкам понадобится новый test. Открытые требования — [acceptance.md](acceptance.md). Первый пилот сохранён в [report_pilot_v1.md](report_pilot_v1.md); напрямую сравнивать F1 двух запусков нельзя, так как test разный.
