CMF: решения за миллисекунды без генерации токенов (аналог Jev) с открытыми весами

Сейчас очень много обсуждают модель Jev от Typesafe, я решил выложить модель в своем CMF формате для личного использования (License:apache-2.0) которая давно работает на шлюзе
Как это работает? Например пользователь пишет, что карта так и не пришла. Приложению нужно выбрать card_arrival и передать обращение в нужный обработчик, или напиши функцию на go, принять решения нужно максимально быстро. Таких развилок много: выбрать инструмент агента, определить тему заявки, сложность, направить документ на проверку, определить сложность и тип задачи.
Для этих задач я опубликовал CMF Decision: модель, которая принимает решения по ошибке реконструкции. Энкодер, обученные навыки и правила уверенности лежат в одном .cmf-файле. Новые навыки можно добавлять по своим примерам, а незнакомые случаи — передавать подключаемому оракулу-модели которая выступает в роли учителя.
В Cortiq 0.8.0 один и тот же файл работает на CPU, Apple Metal и Vulkan. На RTX PRO 4000 Blackwell полный локальный путь занял 1,10–1,24 мс.
Ниже — как устроен этот механизм, что получилось в сравнении с Jev и Laya и как запустить модель или добавить свою задачу.
Сначала — решение, а не текст ответа
В привычной схеме мы просим генеративную модель написать название категории, затем разбираем ответ. Здесь локальный путь устроен иначе:
Энкодер переводит текст в вектор признаков.
Каждая обученная топология пытается восстановить этот вектор.
Сравниваются ошибки восстановления. Лучше всего подошедшая топология определяет класс.
Пороги уверенности и новизны решают, можно ли принять ответ или следует отказаться.

Резонанс здесь — соответствие входного сигнала обученной топологии: чем меньше ошибка реконструкции, тем лучше соответствие. Отдельной обучаемой сети, предсказывающей номер нужной топологии, нет.
В текущем CMF Decision топология класса — его средний вектор и набор направлений в пространстве признаков. Мы вычитаем среднее, последовательно убираем из остатка составляющие вдоль этих направлений и считаем квадрат нормы остатка. Побеждает наименьшая ошибка. Это тот же принцип выбора, который я использую в патенте Resonance Routing — US 19/452,440;.
Практическое следствие: для нового навыка не обязательно переобучать весь энкодер. Можно обучить отдельные топологии на своих примерах и упаковать их вместе с существующими навыками.
Зачем для этого отдельный формат
CMF здесь — не просто другое расширение файла с весами. В контейнере согласованно хранятся:
энкодер и токенизатор;
описание навыков и допустимых ответов;
параметры топологий;
калибровка и правила принятия решения;
данные для проверки целостности и обучения навыков.
Не нужно отдельно переносить словарь категорий, скрипт классификации и файл порогов, надеясь, что их версии совпадут. Файл открывается движком Cortiq и через CLI, и через HTTP API. Для GPU не нужна конвертация в другой формат.
Готовая модель занимает 304,5 МБ и содержит три навыка для BANKING77, CLINC150 и MASSIVE. Это стартовый набор, а не ограничение формата тремя задачами.
Модель даже можно запустить на мобильном телефоне и использовать телефон как API шлюз, скорость решений высокая около 20мс. на решение (зависит от модели телефона) Приложение для Android
Что получилось против Jev
Jev 1.13 тоже возвращает типизированные решения, а не сгенерированный текст. Поэтому сравнивать с ним уместнее, чем доказывать, что небольшой маршрутизатор быстрее длинного ответа чат-модели.
Мы проверяли выбор класса на трёх открытых наборах: BANKING77 — банковские обращения, CLINC150 — 150 пользовательских намерений, MASSIVE — команды ассистенту. В этом эксперименте использовались англоязычные данные.

Набор | Примеров | CMF Decision | Jev 1.13 |
|---|---|---|---|
BANKING77 | 3 080 | 93,34% | 85,58% |
CLINC150 | 4 500 | 96,18% | 96,76% |
MASSIVE | 2 974 | 86,15% | 85,78% |
Это точность лучшего класса на всех примерах, до порога отказа, без помощи оракула. На BANKING77 разница составила 7,76 процентного пункта в пользу CMF. На CLINC150 немного выше результат Jev; на MASSIVE результаты близки.
Условия подготовки различались: CMF обучался на train + dev, Jev получал по два примера на класс. Публичные тесты использовались и раньше в разработке — это не новый слепой holdout. Поэтому вывод относится к этим системам и этому эксперименту, а не к универсальному превосходству одной архитектуры. Полная методика и исходные числа.
Высокая уверенность не означает ответ на каждый запрос
В рабочей системе полезно уметь отказаться. Например, на BANKING77 модель приняла 90,62% запросов; среди принятых ответов 97,24% оказались правильными.
Это другой показатель, не замена 93,34% в таблице. Если сложные случаи уходят на проверку или к оракулу, нужно одновременно смотреть и на точность принятых ответов, и на долю локально обслуженных запросов.
А если сравнить с локальной Laya?
Laya тоже принимает решения без генерации ответа. Здесь можно убрать сеть из сравнения: обе модели запущены на одном Apple M4. CMF использует Metal, Laya — MPS. Оракул выключен. Сравниваем готовый обученный навык CMF с базовой English-моделью Laya, которой передаём все 77 вариантов сразу.

На всех 3 080 примерах BANKING77 обученный навык CMF получил 93,34% при медиане 3,10 мс. Laya, получившая описания всех 77 меток без дообучения, — 35,65% и 917,59 мс.
У CMF задача уже сохранена в навыке; Laya читает варианты вместе с каждым запросом. Практический смысл здесь в том, чтобы один раз обучить постоянную развилку, а затем многократно использовать её локально.
Это стресс-тест с большим числом вариантов, а не предел возможностей Laya. Её автор рекомендует предварительно сокращать большой список кандидатов; для длинных входов предусмотрена multilingual-модель. Эти режимы здесь не проверялись. Разное обучение тоже не позволяет объявлять универсальную победу одной архитектуры. Новый замер не подменяет отдельные CPU/GPU-серии ниже.
Чтобы не ограничиться короткими названиями меток, заранее выделили по три тестовых запроса каждого класса — 231 всего — и дали Laya по два обучающих примера на метку. Эта конфигурация не заработала надёжно: 206 из 231 ответа пришлись на одну метку, точность упала до 1,73% против 35,50% с коротким описанием на тех же запросах. Это не «обычная точность Laya», а неудачный режим с длинным списком примеров. Повышение лимита токенов само по себе не делает модель пригодной для такого входа.
Это повторно используемый публичный тест, не новый слепой эксперимент. Чисто локальная серия не заменяет предыдущий тест Jev через API. Методика, память, p95 и ответы по каждому запросу.
Что дал перенос на GPU
Я ускорял не только резонансное ядро, но и весь локальный путь от текста до решения: подготовку признаков, энкодер, реконструкцию и финальный выбор. В таблицах ниже нет загрузки модели, сети и внешнего оракула.

На Apple M4 медиана уменьшилась на 14–26%: до 2,28–2,58 мс в зависимости от набора. CPU и GPU проверялись по очереди на одних и тех же текстах; Mac при этом оставался обычным рабочим компьютером.
На RTX PRO 4000 Blackwell в непрерывной серии получилось 1,10–1,24 мс: в 14–20 раз быстрее нативного CPU-пути на том же сервере с Xeon E5-2690 v4. Сначала считались CPU-эталоны, затем — серия прогретых GPU-запросов.
У панелей графика разные масштабы и разные режимы подачи запросов. Это сравнения CPU/GPU внутри каждого стенда, не рейтинг M4 против RTX и не измерение производительности сервера под параллельной нагрузкой.
Самое неожиданное: паузы тоже влияют на скорость
Если между запросами на RTX считать CPU-эталон, видеокарта успевает простаивать и снижать частоту памяти. В отдельной диагностике на 400 примерах каждого набора медиана Vulkan была уже 3,40–8,57 мс, а не около 1,2 мс. В журнале этому соответствовали пониженные частоты памяти. Частоты и лимиты питания мы принудительно не меняли.
На M4 другая особенность: Metal делит GPU с рабочим столом. Медиана может улучшиться, а редкие задержки — ухудшиться. В одной из дополнительных непрерывных серий на MASSIVE Metal оказался медленнее CPU.
Поэтому CPU остаётся вариантом по умолчанию, а GPU включается явно. Для конкретного приложения стоит проверить не только средний поток, но и редкие запросы после пауз. Все режимы, p95/p99 и измерения памяти.
Что именно оптимизировано
Главный выигрыш дал не перевод каждой маленькой операции на GPU по отдельности, а организация всего вычисления:
веса и промежуточные данные остаются на устройстве;
энкодер и реконструкция выполняются в одной отправке команд, без ожидания CPU между слоями;
часть операций объединена, чтобы не записывать и не читать лишние промежуточные массивы;
последовательное обновление остатка при реконструкции сохраняется, в том числе для неортогональных базисов.
Вычисления остались FP32: без переобучения и перехода на FP16. На всех 10 554 примерах каждого полного прогона совпали выбранные классы и решения об отказе. Это сохранение качества после оптимизации, а не новое улучшение точности модели.
За ускорение приходится платить памятью. В HTTP-проверке опубликованной 0.8.0 процесс занимал около 808 МиБ RAM на M4/Metal и 648 МиБ RAM плюс 522 МиБ VRAM на RTX/Vulkan. Это снимки после запросов с тремя загруженными навыками, не пиковое потребление. Сопоставимых данных о памяти серверов Jev у нас нет.
А скорость через API?
В прежнем клиентском замере Cortiq через HTTPS давал медиану 70–79 мс, Jev через OpenRouter — 346–392 мс. В эти числа входит сеть; серверы, параллельность и объём выборки различались. Их нельзя делить на локальные 1,2 мс и объявлять получившееся число ускорением модели.
Полезный практический вывод проще: быстрый локальный выбор можно разместить рядом с приложением и не добавлять сетевой вызов на каждую освоенную задачу.
Как попробовать
Для первого знакомства есть интерактивное демо в Hugging Face Spaces. Введите запрос, выберите навык и посмотрите решение, уверенность и ошибки реконструкции трёх лучших кандидатов. Установка и API-ключ не нужны; демо работает на CPU, без оракула.
Готовый сервис без установки
Если не хочется разворачивать модель самостоятельно, можно воспользоваться allaigate Routing API — готовым сервисом маршрутизации на основе формата CMF. Получите API-ключ на сайте и подключите сервис к своему приложению по документации. Скачивать модель и настраивать сервер для этого не нужно.
Локальный запуск: одна установка, один файл
Нужен Rust 1.88 или новее. Установка актуальной версии из crates.io:
cargo install cortiq-cli --locked
Скачиваем модель и выполняем первый запрос:
curl -fL -o cortiq-decision.cmf \
https://huggingface.co/infosave/cmf-decision/resolve/main/cortiq-decision.cmf
cortiq decide cortiq-decision.cmf --skill banking77 \
-p "I still have not received my new card"
В этом контрольном примере модель локально выбирает card_arrival. Для локального решения ключ облачного API не нужен.
GPU-поддержка уже входит в обычную установку. На Apple Silicon:
CORTIQ_DECISION_DEVICE=metal cortiq decide cortiq-decision.cmf \
--skill banking77 -p "I still have not received my new card"
На машине с аппаратным Vulkan-драйвером:
CORTIQ_DECISION_DEVICE=vulkan cortiq decide cortiq-decision.cmf \
--skill banking77 -p "I still have not received my new card"
Если видеокарт несколько, добавьте CORTIQ_DECISION_VULKAN_ADAPTER с уникальной частью имени нужной карты. Тот же выбор устройства работает для cortiq serve; /healthz показывает фактический адаптер. Ошибка GPU не маскируется незаметным переходом на CPU.
Добавляем свой навык
Допустим, теперь нужно различать доставку, документы об оплате и отмену подписки. Подготовим train.jsonl: одна фраза и её метка на строку. Вот фрагмент формата, не полный обучающий набор:
{"text":"My parcel has not arrived yet.","label":"delivery"}
{"text":"Where can I download my invoice?","label":"billing"}
{"text":"I want to cancel my subscription.","label":"cancellation"}
Для каждой метки нужны разные примеры. Одна строка на метку не создаёт рабочую топологию. Ниже — небольшой полный набор, на котором проверены команды этого раздела; он нужен для знакомства с инструментом, не для оценки качества на реальных обращениях.
Учебный train.jsonl: 27 фраз, три отдела
{"text":"My parcel has not arrived yet.","label":"delivery"}
{"text":"Where is my delivery?","label":"delivery"}
{"text":"The courier did not bring my package.","label":"delivery"}
{"text":"I am still waiting for my order.","label":"delivery"}
{"text":"When will my parcel arrive?","label":"delivery"}
{"text":"Can you track my shipment?","label":"delivery"}
{"text":"My delivery is delayed.","label":"delivery"}
{"text":"The package is late again.","label":"delivery"}
{"text":"Please tell me the status of my shipment.","label":"delivery"}
{"text":"Where can I download my invoice?","label":"billing"}
{"text":"Please send me the receipt for my payment.","label":"billing"}
{"text":"I need an invoice for this purchase.","label":"billing"}
{"text":"Can I get a copy of my receipt?","label":"billing"}
{"text":"The total on my invoice looks wrong.","label":"billing"}
{"text":"I need a payment receipt for my records.","label":"billing"}
{"text":"Please email me the invoice.","label":"billing"}
{"text":"How do I get a receipt for my order?","label":"billing"}
{"text":"The invoice is missing from my account.","label":"billing"}
{"text":"I want to cancel my subscription.","label":"cancellation"}
{"text":"Please stop my subscription renewal.","label":"cancellation"}
{"text":"I no longer want this subscription.","label":"cancellation"}
{"text":"How do I cancel my plan?","label":"cancellation"}
{"text":"Please cancel my membership.","label":"cancellation"}
{"text":"Turn off automatic renewal for my plan.","label":"cancellation"}
{"text":"I would like to end my subscription.","label":"cancellation"}
{"text":"Stop renewing my membership.","label":"cancellation"}
{"text":"I need to unsubscribe from this service.","label":"cancellation"}
В question.json описываем смысл вариантов:
{
"instructions": "Choose the support department for this customer request.",
"criteria": {
"delivery": "Delivery, shipment tracking and missing parcels",
"billing": "Invoices, receipts and billing documents",
"cancellation": "Cancelling subscriptions and membership renewals"
}
}
Добавляем навык, проверяем новый файл и используем его:
cortiq decision add-skill cortiq-decision.cmf --skill support \
--train train.jsonl --question question.json -o support.cmf
cortiq decision verify support.cmf
cortiq decide support.cmf --skill support \
-p "Please send me a copy of the invoice for my last payment."
Проверенный результат этого примера — billing. Старые навыки остаются в support.cmf; исходный файл не перезаписывается. На маленьком учебном наборе у навыка certified: false: статистическую надёжность нельзя получить из нескольких удачных запросов.
Если нужна отдельная модель только со своим навыком, вместо add-skill используйте:
cortiq decision train --encoder cortiq-decision.cmf --skill support \
--train train.jsonl --question question.json -o support-only.cmf
Настраивать можно и данные, и размер топологии: --k задаёт число направлений на класс, --calibration — отдельную калибровочную выборку. Итог проверяйте на данных, которые не участвовали ни в обучении, ни в подборе параметров. Для JSONL-файла test.jsonl с полями text и label:
cortiq decide support.cmf --skill support \
--input test.jsonl --bench --out predictions.jsonl
API и оракул для незнакомых случаев
Локальный сервер запускается одной командой:
cortiq serve cortiq-decision.cmf
По умолчанию он слушает только 127.0.0.1:8080. Пока ключи не созданы, локальный контрольный запрос выглядит так:
curl -s http://127.0.0.1:8080/v1/route \
-H 'Content-Type: application/json' \
-d '{"input":{"text":"I still have not received my new card"},"taxonomy_id":"banking77"}'
Есть и типизированный протокол state + questions, знакомый по Jev/OpenRouter: /v1/decisions и /api/alpha/decisions. Навыки отвечают локально, а для неизвестного контракта можно явно разрешить обращение к оракулу. Примеры запросов и настройки API.
В качестве оракула можно подключить, например, MiMo-V2.6-Flash. Остановите предыдущий сервер и запустите вариант с лимитом расходов:
export OPENROUTER_API_KEY="<ваш ключ OpenRouter>"
cortiq serve cortiq-decision.cmf --state ./decision.state \
--oracle xiaomi/mimo-v2.6-flash --oracle-budget 1
Освоенные запросы по-прежнему решаются локально. Только неопределённые случаи могут уйти в облако; ответы оракула кешируются. Показанные выше качество и GPU-задержки измерены без оракула — результаты MiMo им не приписываются.
Для обучения через сервер нужен ключ с соответствующим разрешением. Создать его можно до запуска сервера:
cortiq decision keys create --state ./decision.state \
--account demo --plan developer --learning-allowed
После создания ключа передавайте его в Authorization: Bearer <ключ Cortiq>. В режиме без ключей на loopback ответы оракула кешируются, но не обучают модель.
Самообучение — не немедленная замена весов ответом LLM. Накапливаются примеры, обучается отдельный кандидат топологии, он сравнивается с текущей версией на контрольных данных. Принятое обновление можно сохранить новой версией CMF или откатить. Неизменность чужих весов проверяется отдельно от качества: новый кандидат всё равно может начать выигрывать у старых классов на части запросов. Механизм обучения и отката.
Что в итоге
Для меня главный результат — не одна красивая цифра задержки. Обученный навык стал переносимым артефактом: его можно добавить в CMF, проверить, запустить рядом с приложением и перенести с CPU на GPU без переупаковки модели.
На освоенных задачах — короткий локальный путь без генерации ответа и без платы за облачный API. Для новых задач — собственные примеры и обучаемые топологии. Для неопределённых случаев — явный отказ или оракул с заданным бюджетом.
Это и есть направление CMF Decision: не заставлять универсальную генеративную модель каждый раз заново решать уже освоенную развилку, а сохранять такие решения в навыках, которыми управляет разработчик.
Попробовать: демо в Spaces · готовый API · модель CMF Decision · исходный код и релиз 0.8.0 · cortiq-cli на crates.io.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.