Octolib 0.39.0: к стеку присоединилась модель, которая не может написать ни предложения
С того дня, как мы выделили его из Octocode, каждый вызов модели в нашем стеке был одним из трёх. Сгенерировать текст. Превратить текст в вектор. Отранжировать векторы относительно запроса. Octolib — Rust-библиотека под Octomind, OctoHub, Octocode и Octobrain — содержала по модулю на каждый: llm, embeddings, reranker. Потом у неё появился media.
Сегодня появляется четвёртый, и этот не похож на остальные. octolib::evaluation обращается к модели, которая не может сгенерировать ни одного токена. Вы передаёте ей состояние и набор типизированных вопросов, а она возвращает вероятности. Да или нет, одно из N, позиция на шкале. За 70–500 миллисекунд. По $0.042 за миллион входных токенов, причём вывод бесплатный — потому что выводить нечего, биллинга нет.
Модель — Jev от TypeSafe AI, которая вышла из стелс-режима 15 сентября. TypeSafe называет эту категорию моделями System One. Мы считаем её самым интересным новым примитивом, появившимся в AI-стеке в этом году, и Octolib 0.39.0 — наша ставка на неё: одна строка provider:model, три способа до неё добраться и тот же учёт стоимости, что мы применяем ко всему остальному.
Это главная новость. Релиз также превращает Cloudflare Workers AI в полноценного медиапровайдера, добавляет локальный ONNX-бэкенд эмбеддингов, подключает двух новых LLM-провайдеров и наконец заставляет структурированный вывод валидироваться ровно один раз. Всё, что случилось после 0.36.1, — ниже.
Зачем агенту модель, которая только решает
Разберите агента для кодинга до основания — и останется одна большая модель, делающая работу. Вокруг неё сидит управляющий слой, который выносит маленькие, ограниченные суждения о том, что эта модель делает. Запускать ли эту shell-команду? Какой из сорока навыков подходит этому запросу, если вообще какой-то? Действительно ли релевантна эта извлечённая память? Нужен ли агенту весь этот результат инструмента на 40 КБ, или ни байта из него?
У каждого серьёзного агента для кодинга есть этот второй слой. У нас это супервизор Octomind. У Anthropic — классификатор авторежима в Claude Code. И в обоих случаях модель общего назначения выносит эти суждения, когда её определяющая способность — писать развёрнутое объяснение — выключена именно для этих вызовов. Запрос туда-обратно к frontier-модели, повторяемый на каждое решение, чтобы получить одно слово.
Jev создан для таких решений и больше ни для чего. Три примитива:
- Noul — вопрос «да/нет», на который модель отвечает вероятностью того, что ответ «да».
- Choice — один вариант из заданного вами набора, с вероятностью для каждого варианта и уверенностью, показывающей, насколько «острое» распределение.
- Score — позиция на упорядоченной шкале уровней, описанных словами; может попасть и между уровнями.
Он принимает состояние один раз и оценивает все вопросы по нему за один параллельный проход, так что десятый вопрос почти бесплатен. Его обучали на калибровку, а не на предпочтения, поэтому ответ «90%» должен оказываться верным примерно в 90% случаев на большой выборке предсказаний. И пространство ответов замкнуто по построению: модель может выбрать неверный вариант, но не может выдумать новый — значит, нечего чинить в JSON и нечего нечётко сопоставлять с enum.
Длинную версию — что это, где ломается, что люди построили с ним за первые 72 часа и каждое решение управляющего слоя внутри агента, которое он мог бы взять на себя, с живыми цифрами — мы написали в блоге Octomind: Jev Explained: модель System One от TypeSafe и решения внутри каждого AI-агента. Этот пост — про библиотеку.
API
Модуль называется evaluation, он включён по умолчанию и компилируется сам по себе, если вам нужно только это:
octolib = { version = "0.39", default-features = false, features = ["evaluation"] }
Форма следует остальному Octolib. Один тип запроса, один высокоуровневый хелпер, одна строка provider:model:
use octolib::{evaluate, Answer, EvaluationRequest, Question};
async fn triage() -> octolib::EvaluationResult<()> {
// Требует TYPESAFE_API_KEY; используйте "cloudflare:typesafe/jev", чтобы списывать кредиты AI Gateway.
let request = EvaluationRequest::new("Help! My payouts have been failing for 3 days.")
.with_question("is_urgent", Question::noul("Does this convey urgency?"))
.with_question(
"department",
Question::choice(
"Which team should handle this?",
[("billing", "Payments, refunds"), ("technical", "Bugs, outages")],
),
)
.with_question(
"frustration",
Question::score("How frustrated is the customer?", ["Calm", "Frustrated", "Very angry"]),
);
let response = evaluate("typesafe:jev-latest", request).await?;
if let Answer::Noul { noul } = response.answers["is_urgent"] {
println!("urgent with p={noul:.2}, cost {:?}", response.usage.cost);
}
Ok(())
}
Состоянием может быть строка, JSON-объект или массив. Ответы возвращаются типизированными под теми же id, что и вопросы — Answer::Noul, Answer::Choice с картой вероятностей и уверенностью, Answer::Score с легендой, — так что в Rust вы ветвитесь по числам, а не по распарсенному тексту.
Три маршрута к одной модели:
| Строка модели | Через что доходит до Jev | Ключи |
|---|---|---|
typesafe:jev-latest |
API TypeSafe напрямую (ранний доступ) | TYPESAFE_API_KEY |
cloudflare:typesafe/jev |
Cloudflare AI, биллинг через кредиты AI Gateway | CLOUDFLARE_API_KEY, CLOUDFLARE_ACCOUNT_ID |
octohub:jev |
Ваш собственный прокси OctoHub, стоимость сообщает хаб | OCTOHUB_API_KEY, OCTOHUB_API_URL |
Несколько деталей, которые важны только под серьёзной нагрузкой, — а это как раз та часть, которая нам важна:
- Здесь ретраи безопасны. У оценки нет побочных эффектов, поэтому повтор не может задвоить работу. Клиент повторяет запрос на 429, 529 и 5xx с бэкоффом и уважает
Retry-Afterс потолком в 30 секунд. Генерационные POST-запросы в других местах Octolib намеренно не повторяются; этот — повторяется. - Стоимость считается по опубликованному тарифу, $0.042 за миллион входных токенов, и попадает в
usage.cost, как и любой другой вызов. Через OctoHub побеждает стоимость, сообщённая хабом. - Поле
modelв ответе сообщает версионированную модель, которая ответила.jev-latestсдвигается, когда TypeSafe выпускает новую версию; если вы настраиваете пороги — логируйте её и фиксируйте. - Id моделей валидируются до отправки запроса.
openai:jev-latest— неподдерживаемый провайдер;cloudflare:@cf/zai-org/glm-5.3— чат-модель, а не модель оценки. Оба падают при конструировании, а не при отправке запроса.
У Jev контекст 32k, и собственная документация TypeSafe говорит, что точность падает по мере того, как состояние заполняется материалом, который вопросу не нужен. Урезайте состояние. Задавайте много вопросов; отправляйте мало.
Куда это встраивается: Octomind и OctoHub
Мы не добавляем модули в Octolib ради забавы. Каждый модуль существует потому, что он понадобился продукту, и этот понадобился дважды.
Супервизор Octomind уже работает на инварианте: бесплатные сигналы отсекают лишнее до модели, а вызовы модели редки. Сегодня в main [supervisor.evaluate] добавляет калиброванный третий уровень между «бесплатным» и «frontier» на трёх стыках: фильтр релевантности после извлечения памяти, Choice по реестру, когда все правила активации навыков воздержались, и предварительная проверка, решающая, нужно ли пакету инструментов вообще будить модель-авторизатор. Каждый стык — один переключатель, по умолчанию выключен. Одна попытка на вызов, пятисекундный таймаут, без ретраев; любой сбой сохраняет прежнее поведение для этого хода. И одно правило, которое мы поставили бы во главу любой интеграции с Jev: состояние никогда не несёт результатов инструментов или сообщений ассистента, потому что ревьюер никогда не должен читать то, что, возможно, его уговаривает.
OctoHub получает POST /v1/evaluations. Настройте алиас один раз, в своём прокси, со своими ключами:
[evaluation_models]
"jev" = ["typesafe:jev-latest", "cloudflare:typesafe/jev"]
и каждый клиент на каждом языке — Python-хук, TypeScript-воркер, shell-скрипт — вызывает octohub:jev и получает те же типизированные ответы, ту же строку стоимости на запрос и ту же атрибуцию, что и его чат-комплишены. Поэтому octohub — третий провайдер оценки в Octolib: библиотека вызывает прокси, прокси вызывает Octolib.
Оба попадут в следующие релизы Octomind и OctoHub; библиотека вышла первой, потому что библиотека всегда выходит первой.
Cloudflare Workers AI теперь медиапровайдер
В прошлый раз стек media в Octolib покрывал изображения, видео, речь и транскрипцию через OpenRouter, Replicate, fal, ElevenLabs и Runway. 0.39.0 добавляет Cloudflare Workers AI для изображений, речи и транскрипции через тот же синхронный эндпоинт /ai/run, который использует чат-провайдер.
Зарегистрированные модели с возможностями, опциями и ориентировочными ценами:
- Изображения: FLUX.1 schnell, FLUX.2 dev, Leonardo Lucid Origin и Phoenix 1.0. Цена за выходной тайл и шаг.
- Речь: Deepgram Aura 1 и Aura 2 (английский и испанский), MeloTTS. Цена за символ.
- Транскрипция: Whisper, Whisper large-v3-turbo, Deepgram Nova 3. Цена за минуту аудио; сегменты, слова, языки и метаданные парсятся в типизированную транскрипцию.
Каталог загружается лениво и кеширует страницы, с фолбэком на метаданные для моделей, которые Cloudflare ещё не внесла в список. Там, где апстрим сообщает стоимость в нейронах, она сохраняется как сообщённая, а не заменяется оценкой длительности. Сиды изображений уходят только тем моделям, которые их принимают; типы речи сохраняются, а не приводятся насильно.
Чат-сторона провайдера Cloudflare получила ту же доработку: выбирает и нормализует уровни рассуждения по моделям, применяет схемы только к моделям в формате OpenAI, которые их действительно соблюдают, разрешает перекрывающиеся id моделей по самому длинному совпадению и для неизвестных моделей откатывается к ориентировочным возможностям вместо того, чтобы падать.
Всё остальное после 0.36.1
Десять релизов за двенадцать дней. Сжатая версия.
Два новых LLM-провайдера. Inception Labs предоставляет семейство диффузионных LLM Mercury: inception:mercury-2.5, рядом Mercury 2, вывод по JSON-схеме и вызов инструментов. Tinker от Thinking Machines предоставляет своё семейство Inkling плюс модели с открытыми весами (Nemotron, GLM, Kimi, Qwen, GPT-OSS, DeepSeek) и чекпоинты сэмплеров; id моделей с двоеточиями обрабатываются, а короткие имена вроде tinker:inkling разрешаются в id serverless-инференса. Оба идут с примерами, которые берут спецификацию модели из командной строки.
ONNX-эмбеддинги, локально. Новый провайдер эмбеддингов onnx загружает графы и токенизаторы HuggingFace в ONNX Runtime — onnx:<org>/<repo>, с необязательным #path-to.onnx для конкретного графа, — предпочитает квантованные графы, учитывает метаданные пулинга и статические размерности, группирует запросы в батчи с отслеживанием использования токенов. Он встаёт рядом с FastEmbed и HuggingFace-бэкендом на Candle как третий способ делать эмбеддинги без ключа API. Это единственное нарушение совместимости в раунде: у EmbeddingProviderType появился вариант Onnx, так что исчерпывающим match нужна новая ветка.
Структурированный вывод валидируется один раз. Прежний сценарий мог повторять провалившуюся валидацию схемы и агрегировать usage между попытками. Это было благонамеренно и неправильно: прятало поведение провайдера за циклом. Теперь ровно один вызов схемы к апстриму, один централизованный шаг извлечения и валидации, а ошибка парсинга или валидации возвращается с логированием проблемного ответа и без повтора. Клиентские вызовы инструментов сохраняются после валидации финального вывода. Два провайдера в том же изменении перестали обещать лишнее: Ollama и Cloudflare больше не заявляют гарантированное соблюдение схем, которое не могут обеспечить, а OpenAI падает с ошибкой (fails closed), когда указания схемы игнорируются, вместо того чтобы вернуть что-то, что лишь выглядит правильным.
Уровни усилия рассуждения маппятся по провайдерам. Модели GLM у Alibaba и Z.ai сопоставлены с поддерживаемыми ими уровнями усилия; Fireworks сохраняет максимальный уровень для GLM 5.2. Z.ai теперь принимает сообщения с сохранённым мышлением и оставляет ходы ассистента «только мышление» вместо того, чтобы их выбрасывать.
Список моделей изменился. Снятые модели Cerebras заменены на qwen-3.8-27b с поддержкой видео и лимитом входа 128K. Снятые маршруты V4 у DeepSeek заменены на deepseek-flash, трактуемый как мультимодальный; цены V4.1 Flash исправлены и добавлены на Alibaba. Отозванные модели Hetzner заменены на Qwen. Кеширование BytePlus и сторонние цены обновлены. OctoHub теперь определяет размерности эмбеддингов при конструировании и кеширует их по эндпоинту и модели, из-за чего конструирование провайдера OctoHub стало асинхронным — второе небольшое изменение API, о котором стоит знать. Маппер провайдеров валидирует алиасы моделей, сохраняет квантованные и отклоняет несопоставленные модели при конструировании, а не при первом запросе.
Мелочи, но важные. Аудиоформаты fal маппятся на значения, которые fal принимает (MP3 и PCM; неподдерживаемые форматы используют значение по умолчанию для модели). Пустое содержимое сообщений снова разрешено. rustls на 0.23.45, dirs на 7.0.
Обновление
cargo add [email protected]или поднимите версию. Все фичи включены по умолчанию; новая фичаevaluationне тянет ничего тяжёлого.- Если вы делаете
matchпоEmbeddingProviderType, добавьте веткуOnnx. - Если вы конструируете провайдер эмбеддингов OctoHub напрямую, он теперь
async. - Если вы полагались на то, что структурированный вывод повторяет провалившуюся валидацию, — больше не повторяет. Ошибка несёт то, что вернул провайдер; решайте в своём коде.
- Установите
TYPESAFE_API_KEYилиCLOUDFLARE_API_KEYплюсCLOUDFLARE_ACCOUNT_IDи попробуйте пример выше. Он съедает пару сотен входных токенов: меньше двух тысячных цента.
FAQ
Что такое модель оценки? Модель, которая отвечает на типизированные вопросы о состоянии калиброванными вероятностями вместо генерации текста. Jev от TypeSafe — первая такая модель — возвращает вероятность «да/нет» (Noul), один вариант из набора (Choice) или позицию на шкале (Score) за 70–500 мс. Она не умеет писать код или прозу. Её работа — решения вокруг вашего LLM: маршрутизация, допуск, фильтрация релевантности, выбор навыка.
Нужен ли аккаунт TypeSafe, чтобы ей пользоваться?
Нет. Прямой доступ — по листу ожидания, но cloudflare:typesafe/jev работает уже сегодня с аккаунтом Cloudflare и загруженными кредитами AI Gateway, а octohub:jev работает через ваш собственный OctoHub с любым из ключей за ним.
Octolib 0.39.0 что-нибудь ломает?
Один вариант enum (EmbeddingProviderType::Onnx), один конструктор стал async (эмбеддинги OctoHub), и структурированный вывод больше не ретраит провалы валидации. Чат, медиа, реранжирование и каждая строка модели, которой вы уже пользуетесь, не изменились.
Jev уже внутри Octomind?
Гейты оценки уже в main Octomind, за [supervisor.evaluate], по умолчанию выключены и выйдут в следующем релизе. Этот релиз Octolib — то, на чём они построены.
Какие продукты работают на Octolib?
Octomind (каждый чат-вызов, эмбеддинг и гейт оценки), OctoHub (чат, эмбеддинги, медиа и новый маршрут /v1/evaluations), Octocode (чат, эмбеддинги, реранжирование) и Octobrain (эмбеддинги, реранжирование). Когда провайдер меняет API или цены, правка живёт в одном месте и достаётся каждому продукту.
Суть
Работа Octolib всегда состояла в том, чтобы следующая модель становилась изменением в одну строку для всего, что мы выпускаем. Обычно это значит новый провайдер или исправленная цена. Иногда это значит новый тип модели, и библиотеке приходится решать, как он вписывается.
Модели оценки вписываются как четвёртый модуль, потому что это другая функция: не «напиши мне ответ», а «вот состояние, вот мои вопросы — скажи, что ты думаешь и насколько сильно». Агентам этот примитив был нужен с первого pre-tool-хука. Мы имитировали его одним токеном от рассуждающей модели. Теперь это типизированный вызов, с честной ценой, в одной строке от вас.
github.com/muvon/octolib · Apache-2.0 · crates.io · подробный разбор Jev в блоге Octomind.



