Данные, которые нельзя выдумать: как мы собираем трейсы для тренировки агентских навыков Cotype. agents.. agents. GRPO.. agents. GRPO. harness.. agents. GRPO. harness. llm.. agents. GRPO. harness. llm. RLVR.. agents. GRPO. harness. llm. RLVR. synthetic data.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы. Блог компании MWS AI.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы. Блог компании MWS AI. Блог компании МТС.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы. Блог компании MWS AI. Блог компании МТС. ии-агенты.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы. Блог компании MWS AI. Блог компании МТС. ии-агенты. ИИ-агенты для бизнеса.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы. Блог компании MWS AI. Блог компании МТС. ии-агенты. ИИ-агенты для бизнеса. искусственный интеллект.. agents. GRPO. harness. llm. RLVR. synthetic data. агентский режим. Алгоритмы. Блог компании MWS AI. Блог компании МТС. ии-агенты. ИИ-агенты для бизнеса. искусственный интеллект. Машинное обучение.
Данные, которые нельзя выдумать: как мы собираем трейсы для тренировки агентских навыков Cotype - 1

На днях мы выкатили третье поколение языковых моделей Cotype — флагманскую Cotype Pro 3 и ее облегченную версию Cotype Light 3 (к слову, лайт мы выкатили чутка раньше, но это не имеет значения). Почитать о характеристиках моделей можно вот в этом посте. Тут же мы расскажем вам о нюансах обучения — точнее о том, как мы учим наши модели выполнять многошаговые сценарии без запинок, что совершенно необходимо, так как они выступают ключевым компонентом наших корпоративных ИИ-агентов и мультиагентных систем.

Давайте сначала проблему опишу, для наглядности

Представим, что клиент просит изменить заказ и называет свой e-mail. ИИ-агент, подключенный к каналу обслуживания, ищет по нему клиента и получает «не найдено» — адрес устарел. Дальше есть три варианта развития событий:

  • можно повторить тот же запрос и снова получить ту же ошибку

  • можно сообщить, что клиент не найден, и закрыть диалог; 

  • можно изменить признак поиска — найти клиента по имени и индексу — и продолжить.

Получить довольного клиента можно, только если пойти по третьему пути. 

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

Эта проблема — не проблема для компаний, которые могут позволить себе LLM на сотни миллиардов параметров. Нашим же клиентам нужны модели, которые можно установить в контур и которые не разорят бизнес на инференсе. Поэтому даже наша флагманская модель Cotype содержит всего лишь 27 млрд параметров, и это меньше, чем у предыдущего поколения. А облегченная версия — и вовсе 9 млрд. 

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

TL;DR

Наш пайплайн собран на τ²-bench (tau2) — открытом фреймворке для оценки tool-calling-агентов в режиме dual-control, где роли агента и клиента играют отдельные модели. Под свою задачу мы его существенно доработали: добавили генерацию доменов, сбор трейсов с исполнением вызовов в базе и тренировочный контур. RL-обучение (GRPO) идет поверх verl-agent gym.

На отложенном тесте (телеком, финансы, HR) дообучение модели на 9 млрд параметров через GRPO поднимает основную метрику с 0,794 до 0,856; причем основной прирост — на автономных задачах: ST 0,727 → 0,821.

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

1. Карта типичных ошибок

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

Класс ситуации

Что требуется от агента

Доля в корпусе

Перенос данных через контекст

Удерживать и переносить значения — идентификаторы, суммы, статусы — из ответов инструментов и реплик клиента в аргументы следующих вызовов

40%

Ветвление по состоянию

Перед действием свериться с состоянием сущности и выбрать ветку: операция допустима или нет

25%

Действие без лишних уточнений

Если нужное уже сказано — действовать, а не переспрашивать по второму кругу

20%

Восстановление после ошибки инструмента

После неудачного вызова сменить стратегию, а не повторять то же действие

10%

Корректное завершение диалога

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

5%

Таблица 1. Типичные ошибки ИИ-агентов на примере сценариев клиентской поддержки

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

2. Подход к созданию обучающих трейсов

Обучающие трейсы можно получать двумя путями:

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

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

  • Ошибка инструмента не постановочная — база отвергает неверный аргумент, и агент сам ищет обходной путь.

  • Развилка — это статус сущности, который агент прочитал из базы и на который отреагировал.

  • Разные варианты прохождения задачи возникают сами: на разные данные база отвечает по-разному.

  • Идентификаторы и суммы переходят из шага в шаг, потому что их вернул вызов. Другого источника у них нет.

Это то, что называется grounding — когда диалог не просто выглядит правдоподобно, а подтвержден реальным действием. 

Мы пошли по второму пути. Но давайте опишу пайплайн целиком. 

3. Пайплайн целиком

Вся работа по созданию трейсов у нас разделена на два этапа:

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

  • Собственно генерация трейсов. Диалог разыгрывают две LLM — одна за агента, другая за клиента. Каждый предложенный агентом вызов уходит в исполнитель инструментов, тот загружает состояние диалога, исполняет вызов со всеми проверками и изменениями в базе и возвращает фактический результат. Сценарий при этом лишь расставляет ловушку — подставляет устаревший e-mail, переводит заказ в статус «доставлен», а проходит ее LLM-агент сам. Его попытки, ошибки и развилки попадают в трейс как есть.

Смотрите Схему 1 с комментариями для наглядности.

Схема 1. Пайплайн подготовки обучающих трейсов для ИИ-агентовГлавный узел на схеме — исполнитель инструментов справа. К нему сходятся три стадии генерации (сценарии, диалоги, проверка), через него все вызовы инструментов идут в базу. Домен здесь — маленький самодостаточный мир под одну предметную область. В нем три части: записи в базе (клиенты, заказы, карты и т. п.); системные промпты с политикой — что агенту можно и в каком порядке; и набор инструментов — обычных Python-функций со своей логикой, проверками и предсказуемыми ошибками-фолбэками на недопустимый ввод. Вызовы агента исполняются именно на этих функциях, взаимодействуя с настоящей БД.

Схема 1. Пайплайн подготовки обучающих трейсов для ИИ-агентов
Главный узел на схеме — исполнитель инструментов справа. К нему сходятся три стадии генерации (сценарии, диалоги, проверка), через него все вызовы инструментов идут в базу. Домен здесь — маленький самодостаточный мир под одну предметную область. В нем три части: записи в базе (клиенты, заказы, карты и т. п.); системные промпты с политикой — что агенту можно и в каком порядке; и набор инструментов — обычных Python-функций со своей логикой, проверками и предсказуемыми ошибками-фолбэками на недопустимый ввод. Вызовы агента исполняются именно на этих функциях, взаимодействуя с настоящей БД.

Собственно, всего в рамках этих двух этапов выполняется 6 шагов: 

Подготовка среды

① ARCHITECT (/architect-train-domains) проектирует набор доменов — спецификации, не код — по нескольким предметным темам. Каждый домен сконструирован так, чтобы провоцировать целевые классы ошибок: инструменты, возвращающие идентификаторы; операции, завязанные на состояние; вызовы, которые умеют падать.

② BUILD (/build-mini-domain) компилирует каждую спецификацию в исполняемый домен: модель данных, инструменты, база, политика. Отрапортовать об успехе субагент может только после самотестирования — домен регистрируется, инструменты загружаются, проверяется реакция на недопустимое состояние.

③ ROUTE (/route-corpus) раскладывает целевые диалоги по слотам вида «домен × класс ситуации» и выдает каждому слоту непересекающийся пул сущностей, чтобы параллельные генераторы не конфликтовали за одни и те же данные.

Генерация трейсов

④ SCENARIO (/gen-scenario) пишет по сценарию на слот: задача, первое сообщение клиента, что он знает и сообщит, что «не помнит» (последнее заставляет агента искать данные, а не получать их готовыми), и эталонная цепочка действий. Цепочку прогоняют в базе от начала до конца — провалов нет.

⑤ РОЗЫГРЫШ — диалог разыгрывают две LLM, одна агентом, другая клиентом. Каждый предложенный агентом вызов уходит в базу, фактический результат возвращается в реплику.

⑥ ПРОВЕРКА (verify_grounding.py) переисполняет каждый вызов из готового диалога и сверяет с записанным результатом. Разошлось — диалог в брак. Часть диалогов так отсеивается.

На выходе — сырые проверенные трейсы. Приведение к конкретному формату обучения — отдельный технический шаг SFT/DPO, в сам конвейер он не входит.

Стадии сборки и написания сценариев (2 и 4) идут волнами субагентов (это когда кодовый агент вызывает других агентов самостоятельно). Каждый работает в своем пуле сущностей, так что волны не конфликтуют за данные.

Покажу, как все это выглядит, на примерах.

4. ПримерыПример 1. Простой перенос данных

В основе — простой контур. Состояние каждого диалога живет в отдельном файле: перед вызовом оно загружается, инструмент отрабатывает на нем, измененное состояние сохраняется обратно. Так значение, которое вернул один вызов — например, свежий идентификатор, — становится доступно следующему. Вот тот же диалог по шагам (реплики клиента и агента, а между ними — вызовы инструментов и фактические ответы базы):

# Клиент: зачислить карту GC-000001 на заказ ORD-10001, списать весь баланс.

lookup_gift_card(“GC-000001”)

  → {“balance”: 25.0, “status”: “active”}

# сумму 25.0 агент берет из ответа базы и подставляет в следующий вызов

apply_gift_card_to_order(“GC-000001”, “ORD-10001”, amount=25.0)

  → {“redemption_id”: “RED-001”, “remaining_balance”: 0.0}

# идентификатор RED-001 уходит клиенту дословно

# Агент: готово, списано 25 EUR, операция RED-001, остаток 0.

Суммы и идентификаторы агент не выдумывает, а переносит из ответа базы в следующий вызов и в финальную реплику. Каждый диалог стартует со своей копии базы: это независимые сессии, а не один общий мир.

Ниже еще три трейса по разных классам ошибок: ветвление по состоянию, более сложный перенос и восстановление после ошибки.

Пример 2. Ветвление по состоянию: перенос экзамена

Студент просит: «Перенесите мой экзамен EX-0024 на попозже». Сценарий заранее перевел экзамен в статус «уже сдан»:

lookup_exam(exam_id=”EX-0024″)  →  {“status”: “taken”, “reschedule_count”: 1, …}

# status == “taken”  →  ветка отказа, в базе ничего не меняем

“Экзамен EX-0024 уже сдан, перенести его нельзя.”

Агент сначала читает статус и только потом решает: переносить нечего.

Пример 3. Перенос данных через контекст: диспут по банкомату

Проверенный трейс из четырех вызовов, где каждый аргумент берется из предыдущего ответа:

lookup_transaction(“TXN-000001″)        → amount=100.0, atm_id=”ATM-001″, status=”posted”

lookup_atm_log(“ATM-001”, “10:59:00”)   → dispensed=false        # по политике диспут допустим

file_dispute(“TXN-000001″, reason)      → dispute_id=”DSP-0001”

issue_provisional_credit(“DSP-0001″, amount=100.0) → credit_id=”CR-0001”

Здесь два переноса сразу: dispute_id из третьего вызова в четвертый и сумма 100.0 из первого. Ветвление по состоянию зашито в политику.

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

Тот самый случай из начала статьи, теперь в виде трейса. Клиент назвал неактуальный e-mail, первый поиск падает, агент меняет признак поиска:

find_user_by_email(“john.smith@unknown.com“)   → ошибка: пользователь не найден

# вместо повтора того же вызова — другой признак поиска:

find_user_by_name_zip(“John”, “Smith”, “10024”)  → user_id=”U-7829″   # продолжаем

5. Эксперименты и результаты

5.1. Подход

Мы дообучили на сгенерированных по вышеописанному пайплайну трейсах модель Qwen3.5-9B,  и прогнали ее вместе с конкурентами большего размера на отложенном тесте из трех областей: телеком, финансы и HR (кадровые задачи). 

Тест и обучение не пересекаются. Каждая задача идет в двух режимах: MT — диалог с симулятором клиента; и ST — вся информация выдается одним сообщением, дальше агент работает автономно. Итого 90 задач, по 5 прогонов на каждую на русском языке.

  • Роль клиента играет Qwen3.5-9B, следуя структурированному сценарию с персоной и границей знаний.

  • Роль ИИ-агента — Cotype Light 3 (та же Qwen3.5-9B, но уже дообученная).

  • Роль судьи по текстовым утверждениям — GPT-OSS-120B с голосованием по трем прогонам.

Тут возможен вопрос про циркулярность: клиент-симулятор и обучаемая модель — обе из семейства Qwen3.5-9B (клиент — базовая модель, агент под оценкой — обученная; модель не судит сама себя). На скоринг это все равно не влияет. Оси DB и ACTION детерминированы и считаются против эталона, а не через клиента; текстовые требования судит gpt-oss-120B — другое семейство, работа судьи провалидирана и не имеет определенного байеса. Клиент следует фиксированному сценарию с заданной персоной и границей знаний, то есть подыгрывать агенту не волен.

Метрика — мультипликативная тройка, где провал по любой оси обнуляет результат:

primary=DB×ACTION×NL_frac

primary=DB×ACTION×NL_frac

DB — совпадение итогового состояния базы с эталоном, ACTION — совпадение цепочки вызовов без приоритета очереди, NL_frac (NL — natural language) — доля выполненных требований на естественном языке, сюда относим комментирование результатов и общение с пользователем.

5.2. Базовые модели

Модель

Параметры

ALL

MT

ST

Qwen3.5-122B-A10B

122B MoE

0,833

0,844

0,822

Qwen3.5-27B

27B

0,817

0,855

0,779

GPT-OSS-120B

120B MoE

0,802

0,817

0,787

Qwen3.5-9B (база)

9B

0,794

0,861

0,727

Qwen3-VL-32B

32B

0,729

0,724

0,733

Qwen3.5-4B

4B

0,669

0,817

0,520

Qwen3-VL-8B

8B

0,592

0,564

0,620

Из таблицы видно две вещи. Первое: на этих задачах размер сам по себе помогает слабо. Базовая 9B (0,794) идет вплотную к 27B (0,817) и 122B MoE (0,833) — разрыв в десятки раз по параметрам дает единицы процентов по метрике. Второе — и для нас главное: режим ST стабильно тяжелее MT. В диалоге агент может переспросить и неявно исправиться, в автономном режиме такой страховки нет. Резче всего это на 4B — 0,817 в диалоге против 0,520 автономно. Автономные задачи и есть то место, где обучение должно дать максимум.

5.3. SFT против DPO против GRPO

Базовая модель для обучения — Qwen3.5-9B, все методы на LoRA rank 16.

  • SFT — 600 образцовых трасс от учителей (учителя — Qwen3.5-9B и 27B).

  • DPO — тот же корпус, что и в SFT, в паре с трассы с нулевой наградой.

  • GRPO — онлайн-RL в той же среде с исполнением вызовов в базе, с полностью детерминированной наградой, без LLM-судьи: формат, совпадение действий, аргументы, состояние базы. Роллауты генерируются на лету на автономных задачах — это в 5–10 раз быстрее.

Метод

ALL

MT

ST

База (9B)

0,794

0,861

0,727

SFT

0,819

0,867

0,770

DPO

0,827

0,907

0,748

GRPO (Cotype Light 3)

0,856

0,890

0,821

Qwen3.5-27B (ориентир)

0,817

0,855

0,779

Qwen3.5-122B MoE (ориентир)

0,833

0,844

0,822

Главный результат — на автономных задачах: GRPO поднимает ST с 0,727 до 0,821. Именно там у базовой 9B был провал, и такие данные его закрывают. По агрегату GRPO дает 0,856 против 0,794 у базы.

Навык при этом переносится с ST на MT: GRPO учился только на автономных задачах, но подтянул и диалоговый режим (0,861 → 0,890). После обучения 9B оказывается сопоставима по метрике с 27B и 122B MoE.

Где именно прибавляет, видно по динамике обучения. Какие инструменты звать, модель знает с самого начала — ось действий держится около 0,91 и почти не растет. А вот доводить изменение базы до конца она учится: ось состояния растет с 0,53 до 0,97.

Динамика обучения. SFT и DPO прибавляют меньше — ALL 0,819 и 0,827 против 0,856 у GRPO. DPO делает агента осторожнее: он реже трогает операции записи, что помогает на read-задачах и мешает на write (отсюда лучший MT 0,907 и слабый ST 0,748).

Динамика обучения. SFT и DPO прибавляют меньше — ALL 0,819 и 0,827 против 0,856 у GRPO. DPO делает агента осторожнее: он реже трогает операции записи, что помогает на read-задачах и мешает на write (отсюда лучший MT 0,907 и слабый ST 0,748).

5.4. Устойчивость: pass^k

pass^k — вероятность, что успешны все k случайно выбранных прогонов задачи. Чем больше k, тем строже планка: одной удачной попытки уже недостаточно. Прогон здесь засчитывается по строгому бинарному критерию: NL оценивается бинарно — все утверждения должны быть выполнены, а не дробной долей NL_frac, как в основной метрике. Поэтому абсолютные значения тут ниже, чем primary из § 5.3, — это разные шкалы, и сравнивать pass^k нужно между моделями, а не с primary.

Данные, которые нельзя выдумать: как мы собираем трейсы для тренировки агентских навыков Cotype - 4

GRPO держит первое место во всем диапазоне, и с ростом k отрыв растет: к k = 5 он заметно опережает и базу, и SFT с DPO. RL дает не разовый успех, а воспроизводимый — а в проде задача должна решаться каждый раз, а не в среднем по прогонам.

5.5. Человеческая валидация качества корпуса

Для ручной проверки мы взяли 30 случайных диалогов из тестового набора и отдали их команде из 11 аннотаторов, с перекрестной проверкой.

Метрика

Значение

Качество сценария (среднее)

3,83/5

Доля «отлично» (=5)

47,8%

Доля «непригодно» (=1)

17,4%

Согласие судьи и эксперта

95,6%

Выход симулятора-юзера из роли

4,3%

Ложные срабатывания судьи

1

Пропуски судьи

2

Ключевая цифра — согласие автоматического судьи с экспертами, 95,6%. Ручная проверка подтверждает сразу две вещи: качество собранных данных и согласованность человека и LLM-судьи.

6. Итог

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

На отложенном тесте (телеком, финансы, HR) дообучение через GRPO (в таблицах и графиках мы обозначили так Cotype Light 3) поднимает основную метрику с 0,794 до 0,856. Главный прирост — на автономных задачах, где у компактной модели меньше всего права на ошибку: ST 0,727 → 0,821. Cotype Light 3 выходит на 0,856 — выше базовой 27B (0,817) и 122B MoE (0,833), при заметно меньшем инференсе, чем у 27B. А человеческая валидация (95,6% согласия судьи с экспертами) показывает, что и сами данные качественные.

Автор: sir-timio

Источник