Jared Palmer

Kev

Uma família de modelos de decisão sobre o Qwen3.5 / Qwen3.8, de um 0.8B que cabe num notebook a um 27B. Probabilidades tipadas numa passada, atrás de uma API compatível com o System One.

Verificado em 2026-10-05

Pequenos modelos de decisão semelhantes ao Jev que você mesmo pode treinar e executar.

CI Weights: Kev-0.8B · 4B · 9B · 27B Demo on Hugging Face Spaces Frozen eval suites License: Apache-2.0

O Kev é uma família de pequenos modelos de decisão construídos sobre o Qwen3.5 e o Qwen3.8 e baseados na arquitetura descrita em Jev’s Architecture Unmasked. Você pode usar os pesos pré-treinados ou treinar os seus próprios. A API corresponde ao System One da TypeSafe, então você pode apontar o SDK de Python deles para o seu servidor local.

Destaques

  • Perguntas de sim/não (noul), de múltipla escolha (choice) e de avaliação (score) em uma única requisição. As perguntas compartilham o texto mas não conseguem ler umas às outras.
  • Probabilidades calibradas por padrão: cada checkpoint vem com uma temperatura ajustada.
  • Substituto direto do Jev: o SDK de Python da TypeSafe funciona contra um servidor Kev sem alterações.
  • Quatro tamanhos, versionados juntos como Kev 1.0: de um 0.8B que roda em um laptop a um 27B para uma única GPU de data centre.
  • Documentos de até 65,536 tokens, em CUDA e no Apple Silicon através do MLX. Cada ficha de modelo diz até que comprimento um documento pode chegar antes de a acurácia cair.
  • Ajuste fino nos seus próprios exemplos rotulados. Uma skill de agente de código executa todo o ciclo no Modal, de encontrar as suas perguntas a servir o resultado.
  • Implante o seu próprio endpoint HTTPS com um único comando. Ele reduz a zero quando ocioso.
  • Experimente primeiro no navegador: huggingface.co/spaces/jaredpalmer/kev.

Modelos

Comece com o Kev-4B. Migre para o Kev-9B se tiver uma GPU maior, ou para o Kev-27B se tiver uma GPU de 80 GB e quiser o Kev mais acurado. Use o Kev-0.8B quando o tamanho importar mais que a acurácia.

Modelo Base (licença) Roda em: CUDA Roda em: Mac (MLX) Contexto validado Conjuntos de dados reservados: índice Ficha
Kev-0.8B Qwen3.5-0.8B-Base (Apache-2.0) L4, qualquer GPU de 4 GB Qualquer Mac Apple Silicon; medido até 65k tokens 8,192 23.3 Detalhes
Kev-4B Qwen3.5-4B-Base (Apache-2.0) L40S, H100 Mac de 32 GB; medido até 65k tokens 8,192 38.0 Detalhes
Kev-9B Qwen3.5-9B-Base (Apache-2.0) L40S, H100 Mac de 32 GB ou maior (esperado, não medido) 8,192 41.0 Detalhes
Kev-27B Qwen3.8-27B, pós-treinado (Apache-2.0) B200, H200, H100 80 GB Mac de 96–128 GB (esperado, não medido) 65,536 52.3 Detalhes
Jev Hospedado API da TypeSafe – – 54.0 –

“Conjuntos de dados reservados” é o índice corrigido pelo acaso do Decision Index da comunidade, pontuado na partição de teste do breadth-v1: 14 conjuntos de dados públicos em cinco áreas em que nenhum Kev treinou. “Contexto validado” é o documento mais longo, em tokens, para o qual a acurácia em contratos reais (CUAD) fica dentro de 3 pontos da acurácia do mesmo modelo em 8k tokens, no limite inferior de 95%; cada ficha de modelo tem a medição por comprimento.

Modelo Acurácia: fontes novas Acurácia: fontes treinadas Brier: fontes novas
Kev-0.8B 0.648 / 0.697 0.827 / 0.838 0.481 / 0.416
Kev-4B 0.817 / 0.838 0.873 / 0.865 0.269 / 0.242
Kev-9B 0.820 / 0.852 0.874 / 0.873 0.289 / 0.217
Kev-27B 0.851 / 0.889 0.865 / 0.866 0.225 / 0.156
Jev 0.857 / – 0.845 / – 0.211 / –

Cada célula é desenvolvimento / teste. “Fontes novas” significa conjuntos de dados e regras de política que o Kev nunca viu durante o treinamento. É a coisa mais próxima aqui das suas próprias perguntas. “Fontes treinadas” significa exemplos reservados dos conjuntos de dados em que o Kev foi treinado. Escolhemos os checkpoints usando os conjuntos de desenvolvimento e lemos cada conjunto de teste apenas uma vez por modelo publicado. O Jev só foi executado nos conjuntos de desenvolvimento destas duas suítes. O Brier pontua a distribuição de probabilidade inteira, não apenas a resposta do topo; menor é melhor.

Em fontes novas, o Kev-27B está a um ponto do Jev (0.851 vs 0.857), e o Kev-4B e o Kev-9B estão a quatro pontos. Não sabemos em que o Jev foi treinado, então isto não é uma comparação controlada das duas arquiteturas. O que esperar diz onde o Kev é tão bom quanto o Jev e onde não é.

O Kev-0.8B, o 4B e o 9B partem de modelos base do Qwen e compartilham uma receita de treinamento: um pequeno adaptador sobre uma base congelada. O Kev-27B parte do release pós-treinado do Qwen, e não sabemos em que ele foi treinado; cada um dos seus pesos é ajustado, então ele é entregue como 51 GB de pesos completos em vez de um adaptador. Cada ficha de modelo tem a receita completa, todos os resultados, e as versões anteriores mantidas como tags do Hub.

Kev 1.0

Os quatro modelos acima são lançados juntos como Kev 1.0. Cada repositório do Hub tem uma tag v1.0, então --run jaredpalmer/kev-4b@v1.0 sempre carrega os mesmos pesos, e o release do GitHub kev-1.0 tem os checkpoints 0.8B, 4B e 9B com checksums SHA-256. Os 51 GB de pesos do Kev-27B são grandes demais para um asset de release e estão apenas no Hub.

Modelo Revisão dos pesos no Hub Temperatura Treinado em estados de até
Kev-0.8B 9a45d25e 2.35 7,552 tokens
Kev-4B 139fdd94 2.41 7,552 tokens
Kev-9B b5d8c18e (v2) 2.19 7,552 tokens
Kev-27B 28be62e9 (v2, pesos completos) 1.32 32,768 tokens

O Kev 1.0 não treina nada novo. Ele fixa os checkpoints, as fichas, as suítes de avaliação e o código de serviço com que a próxima geração do Kev será comparada. As notas de release listam o que mudou desde o release anterior da família e o que se sabe que não funciona bem.

Início rápido

Experimente no navegador

O Hugging Face Space executa o Kev-4B e o Kev-0.8B, sem nada para instalar.

Rode localmente

Você precisará de Python 3.12 ou 3.13 e do uv. O .python-version do repositório faz o uv sync usar o 3.13; o torch ainda não tem wheels para o 3.14.

git clone https://github.com/jaredpalmer/kev.git && cd kev
uv sync --extra serve
uv run --extra serve python -m kev.serve --run jaredpalmer/kev-4b --port 8009

Isto inicia o Kev-4B na sua máquina: CUDA ou ROCm se você tiver uma GPU, MLX no Apple Silicon. A primeira execução baixa o adaptador e o modelo base. O --run também aceita um diretório de checkpoint local ou uma revisão do Hub como jaredpalmer/kev-4b@qwen3.

Em outro terminal, envie um ticket:

curl -s localhost:8009/v1/systemone -H 'content-type: application/json' -d '{
  "state": "Shoes arrived two weeks late and in the wrong size. Also I see two charges on my card.",
  "model": "kev-latest",
  "questions": {
    "department":  {"type": "choice", "instructions": "Which team should handle this?",
                    "criteria": {"returns": "Exchanges, refunds, wrong or damaged items",
                                 "shipping": "Delivery status, delays, lost packages",
                                 "billing": "Charges, invoices, payment problems"}},
    "escalate":    {"type": "noul",  "instructions": "Does this need urgent human attention?"},
    "frustration": {"type": "score", "instructions": "How frustrated is the customer?",
                    "criteria": ["Calm", "Frustrated", "Very angry"]}
  }}'

Resposta de exemplo do Kev-4B, rodando em bf16 em um Apple M5:

{
  "model": "kev-latest",
  "answers": {
    "department":  { "type": "choice", "choice": "returns", "confidence": 0.21,
                     "probabilities": { "returns": 0.47, "shipping": 0.28, "billing": 0.25 } },
    "escalate":    { "type": "noul", "noul": 0.93 },
    "frustration": { "type": "score", "score": 1.44, "confidence": 0.34,
                     "legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
                     "probabilities": { "0": 0.00, "1": 0.56, "2": 0.44 } }
  },
  "usage": { "input_tokens": 101, "output_tokens": 161 },
  "latency_ms": 495
}

O ticket menciona uma devolução, uma entrega atrasada e um problema de cobrança, e as probabilidades do departamento dizem isso. É por isso que o Kev devolve probabilidades em vez de um único rótulo: o seu código pode encaminhar os casos confiantes e enviar o resto para uma pessoa.

Use a partir do Python

Se você já chama o Jev, aponte o seu cliente para o Kev e mantenha o resto do seu código. O SDK da TypeSafe está incluído em uv sync --extra serve:

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

client = TypeSafeClient(
    api_key="local",
    base_url="http://127.0.0.1:8009",
    model="kev-latest",
)
response = client.system_one(
    state="I was charged twice. Please fix this ASAP.",
    questions={
        "billing": Noul(instructions="Is this ticket about billing?"),
        "tone": Choice(
            instructions="What is the customer's tone?",
            criteria={"calm": None, "frustrated": None, "angry": None},
        ),
        "urgency": Score(
            instructions="How urgent is this ticket?",
            criteria=["can wait", "this week", "today"],
        ),
    },
)
print(response.nouls["billing"].noul)
print(response.choices["tone"].choice)
print(response.scores["urgency"].score)

Ajuste fino com os seus próprios dados

Os modelos publicados foram treinados em conjuntos de dados públicos e exemplos de política gerados. Se as suas perguntas forem diferentes, como as suas próprias categorias de roteamento, as suas próprias regras de escalonamento ou outro idioma, um ajuste fino curto costuma ajudar mais que qualquer mudança de prompt. Ele também ajusta a temperatura aos seus dados, então a confiança sobre a qual você define limiares é medida nos seus próprios rótulos.

O que esperar: em uma carga de trabalho de suporte de exemplo (três perguntas, 1,050 registros gerados, 15 minutos em uma H100), o ajuste fino levou o Kev-4B de 67.7% para 73.6% de acurácia, e de automatizar 34% das decisões com um orçamento de erro de 5% para 48% (detalhes). Em dados reais, uma época em 5,219 reclamações rotuladas de finanças do consumidor levou o Kev-4B de 0.804 para 0.904 de acurácia em reclamações que ele nunca tinha visto. Ganhos como estes são dentro da distribuição: eles dizem quão bem o Kev aprende a sua tarefa, não como ele se sai em todo o resto. Dimensione o seu conjunto de dados primeiro. Com 400 registros, o ganho na carga de trabalho de exemplo ficou dentro do ruído.

Com um agente de código

npx skills add jaredpalmer/kev@kev-finetune

Depois peça ao seu agente para “fazer ajuste fino do Kev nos meus tickets de suporte”. A skill kev-finetune entrevista você, encontra as perguntas que o seu código já faz ao Jev ou ao TypeSafe, converte os rótulos que você tem ou gera o suficiente com qualquer LLM para medir um ganho, faz o ajuste fino a partir de um checkpoint publicado no Modal, ajusta a temperatura em uma fatia reservada, pontua o resultado contra o modelo intocado, implanta um endpoint e desmonta tudo no final. Você não precisa de uma GPU local nem de um clone deste repositório. Uma execução de treinamento do Kev-4B custa cerca de $1 em uma H100.

Manualmente

O README da skill é a mesma receita para pessoas: seis scripts curtos da biblioteca padrão e um app Modal. Para treinar a partir deste repositório, coloque os seus exemplos em um arquivo JSONL, uma requisição por linha. É o mesmo formato de uma requisição de API, mais um label em cada pergunta:

{"state": {"subject": "Charged twice", "body": "I see two charges for order #4411. Please refund one."},
 "questions": {
   "team":     {"type": "choice", "instructions": "Which team should handle this ticket?",
                "criteria": {"billing": "Payments and refunds", "shipping": "Delivery problems", "access": "Login and account access"}, "label": "billing"},
   "angry":    {"type": "noul",   "instructions": "Is the customer angry?", "label": false},
   "priority": {"type": "score",  "instructions": "How urgent is this ticket?", "criteria": ["low", "normal", "high"], "label": 1}}}

Para choice, o rótulo é o nome da opção; para noul, é true ou false; e para score, é a posição do nível começando em 0. Separe 10–20% do arquivo para avaliação.

Depois parta de um checkpoint publicado com --init_from:

uv run python -m kev.train --data train.jsonl --base Qwen/Qwen3.5-4B-Base --init_from jaredpalmer/kev-4b \
    --epochs 2 --lr 2e-5 --batch 1 --accum 8 --dtype bf16 --checkpointing 1 --device cuda --out runs/mine

uv run python -m kev.benchmark --run runs/mine --data heldout.jsonl --out runs/mine-eval
uv run --extra serve python -m kev.serve --run runs/mine --port 8009

O --init_from carrega o adaptador e a cabeça de ponteiro do modelo publicado antes do treinamento, então você mantém o que o Kev já sabe e adiciona o seu domínio por cima. Partir do modelo base em vez disso joga isso fora: no teste de um usuário em 836 decisões de ferramenta de suporte, um ajuste fino a partir da base marcou 0.33 no próprio conjunto de avaliação do Kev, contra 0.84 do modelo publicado; os mesmos dados com --init_from mantiveram 0.83 ali e chegaram a 0.88 no domínio novo. Use uma taxa de aprendizado menor que a da receita do zero (2e-5 é um bom começo), e escolha o --base para corresponder ao checkpoint de partida; o treinador confere que a base, a revisão, o rank do LoRA e o tamanho da cabeça concordam antes de carregar qualquer coisa.

--batch 1 --accum 8 em bf16 cabe o modelo 0.8B em uma GPU de 4 GB. O benchmark reporta acurácia, Brier e calibração por tipo de pergunta, então você pode ver em quais das suas perguntas o ajuste fino ajudou. O checkpoint de partida é registrado em runs/mine/training_config.json. Em um Mac, rode um trabalho de treinamento por vez; dois trabalhos na mesma GPU Apple são bem mais lentos.

Implante o seu próprio endpoint

Para obter um endpoint HTTPS em vez de um servidor local, você não precisa deste repositório, apenas de uma conta no Modal:

pip install modal && modal setup
curl -LO https://raw.githubusercontent.com/jaredpalmer/kev/main/skills/kev-deploy/scripts/kev_serve.py
KEV_API_KEY=$(openssl rand -hex 24) modal deploy kev_serve.py

Isso serve o Kev-4B em uma L40S em https://<your-workspace>--kev-api.modal.run, com a mesma API acima por trás de Authorization: Bearer <key>. Ele reduz a zero quando ocioso, então um endpoint sem uso não custa nada. A primeira requisição depois da ociosidade espera cerca de 35 segundos por um contêiner iniciar. KEV_MODEL=jaredpalmer/kev-9b serve outro modelo na GPU que lhe convém; o Kev-27B vai para uma B200, com fallback para uma H200 ou H100. Se você usar um agente de código, npx skills add jaredpalmer/kev@kev-deploy faz o mesmo e liga a URL ao seu código. skills/kev-deploy tem a tabela de GPU e custo.

Um modelo que você ajustou com a skill kev-finetune é implantado da mesma forma a partir do seu próprio app Modal (KEV_SERVE_SECRET=kev-serve-key KEV_SERVE_RUN=<run> modal deploy scripts/kev_modal.py; veja o guia de deploy dela). Para hospedar o Kev nas suas próprias máquinas, rode kev.serve de Rode localmente em uma máquina com GPU com --host 0.0.0.0 e coloque-o atrás do seu próprio proxy; Desempenho de serviço diz qual GPU escolher.

O que esperar

Acurácia. O Kev-27B está dentro de três pontos do Jev, ou à frente dele, em 9 das 11 categorias de fontes novas no gráfico abaixo. O Kev-4B e o Kev-9B ficam quase tão próximos em fontes de formato de classificação como roteamento, implicação e perguntas de ciência. As perguntas de conhecimento dependem sobretudo do modelo base: no MMLU o Kev-9B marca 0.73 e o Kev-27B iguala o Jev em 0.90, mas no MMLU-Pro, mais difícil, o Kev-27B marca 0.675 contra 0.840 do Jev. Os modelos menores também ficam atrás na aritmética de datas com precisão de dia.

Acurácia por fonte para Kev e Jev

Confiança. Cada checkpoint vem com uma temperatura ajustada, então as suas probabilidades são calibradas por padrão. Conforme servido, o Kev-9B coloca pelo menos 0.9 de probabilidade em uma resposta errada para 2.4% das perguntas de fontes novas, contra 3.7% do Jev. O Jev ainda ranqueia melhor as suas respostas: com um orçamento de erro de 5%, o Kev-4B, o 9B e o 27B conseguem automatizar 0.52–0.69 das decisões de fontes novas, o Kev-0.8B 0.14 e o Jev 0.70. Confira um limiar nos seus próprios dados antes de confiar nele.

Velocidade. O Kev-4B responde seis perguntas sobre um texto curto novo em 18.1 ms de tempo de modelo em uma H100 e 41.5 ms em uma L40S, e um contêiner serve cerca de 101 requisições por segundo em uma H100. Em um Apple M5, o Kev-4B leva 721 ms para cinco perguntas, ou 136 ms quando o texto se repete e vem do cache. Desempenho de serviço tem toda GPU e tamanho de lote.

Comprimento. O Kev-0.8B, o 4B e o 9B treinaram sobretudo em estados de até 384 tokens, com os mais longos nos seus ajustes finos de documento e habilidade (até 7,552 tokens), e o Kev-27B em estados de até 32,768. O servidor aceita estados de até 65,536 tokens, e 8,192 a mais por pergunta, e recusa um mais longo com um 422 em vez de cortá-lo. Até onde cada modelo se mantém acurado além do seu comprimento de treinamento é a coluna “Contexto validado” em Modelos. Para o Kev-0.8B, o 4B e o 9B isso é 8,192 tokens: em 16k a medição em contratos reais já não consegue descartar uma queda de mais de 3 pontos, e em 32k os três são mensuravelmente menos acurados que em 8k. O Kev-27B se mantém até o limite de 65,536 tokens. Em contratos reais de até 64k tokens (CUAD) o Kev-27B marca 0.874, e a sua confiança ali é menos confiável que em texto curto; a ficha dele tem os números por comprimento.

Playground

Com o servidor rodando, abra outro terminal. Você precisará do Node 20.9+:

cd playground
npm install
npm run dev -- -p 3001

Abra localhost:3001, carregue um preset e edite o texto e as perguntas. Pressione ⌘↵ para executar. “Packed vs separate” compara fazer todas as perguntas de uma vez com fazê-las uma a uma. “Permute” executa uma pergunta Choice com seis ordens de opção. Há também presets para testar o isolamento de perguntas e tokens delimitadores falsos.

Playground do Kev

Há também uma demo de xadrez. O tabuleiro é a entrada, os lances legais são opções de Choice, e uma pergunta Score avalia a posição. Você pode jogar contra o Kev ou deixá-lo jogar sozinho. As partidas são salvas em localStorage.

API

POST /v1/systemone

state é o texto a avaliar. Cada pergunta tem instruções e, quando necessário, um conjunto de respostas para escolher.

{
  "state": "…",                          // string | object | array — the content to evaluate
  "model": "kev-latest",
  "questions": {
    "<id>": {                            // you choose the id; the model never sees it
      "type": "noul" | "choice" | "score",
      "instructions": "…",               // string | object | array, optional
      "criteria": …                      // noul: {true?, false?}  choice: {option: description|null}  score: [level, …]
    }
  }
}
Tipo Critérios Resposta
noul Descrições opcionais para true e false noul: probabilidade de sim
choice 1–255 nomes de opção, cada um com uma descrição ou null choice: opção mais provável; probabilities e confidence
score 1–255 descrições, ordenadas da menor para a maior score: índice do nível médio, começando em 0; legend, probabilities e confidence

Para Choice com K > 1 opções, a confiança é (p_max − 1/K) / (1 − 1/K). Uma única opção tem confiança 1. A confiança de Score é max(0, 1 − E|level − mode| / D): mode é o nível mais provável e D é a distância média de uma distribuição uniforme sobre os níveis em relação ao seu meio (2/3 para três níveis), então toda a probabilidade em um nível dá 1 e uma dispersão uniforme ou mais larga dá 0. As duas fórmulas são as do adaptador de referência da TypeSafe (system-one-adapter 0.2.1). Nenhum dos dois campos é uma taxa de acurácia medida.

Objetos e arrays são convertidos em texto rotulado. Strings semelhantes a delimitadores na entrada do usuário são escapadas antes da tokenização. Requisições inválidas retornam 422, e um estado maior que 65,536 tokens também: o servidor nunca descarta parte de um documento silenciosamente, e o erro dá a contagem de tokens do estado e o limite. usage.output_tokens conta os tokens nas respostas serializadas, não tokens gerados.

Método Caminho Propósito
GET /v1/models Fichas dos modelos (name, description, release_date) mais os detalhes do checkpoint carregado
POST /v1/systemone/permute Executa uma pergunta Choice com ordens de opção diferentes (n_perm de 1 a 64, padrão 6)
POST /v1/systemone/separate Executa cada pergunta na sua própria passada direta

Uma requisição pode carregar qualquer número de perguntas. O servidor as executa um orçamento de tokens por vez (uma linha máxima de 16,384 tokens por passada direta, contando o documento em cache uma vez por pergunta naquela passada), então a memória não cresce com o número de perguntas e as respostas não dependem da divisão. Toda resposta carrega um cabeçalho x-typesafe-request-id. O servidor se liga a 127.0.0.1 (--host 0.0.0.0 para aceitar outras máquinas) e é aberto por padrão; defina KEV_API_KEY para exigir Authorization: Bearer <key> em /v1/*, como os clientes da TypeSafe sempre enviam.

Variável Efeito
KEV_TEMPERATURE=1.0 Devolve as probabilidades brutas em vez das calibradas
KEV_DATE_FACTS=1 Anexa o número de dias entre quaisquer duas datas no estado (veja Benchmarks)
KEV_TRUNCATE_STATES=1 Lê os primeiros 65,536 tokens de um estado mais longo em vez de recusá-lo; toda resposta então tem truncated e usage.state_tokens / state_tokens_used
KEV_DTYPE=fp32 Serve o caminho exato em fp32 que as avaliações usam (bf16 é o padrão em GPUs)
KEV_API_KEY Exige uma chave bearer

Como funciona

Cada checkpoint é um adaptador LoRA de rank 16 e uma pequena cabeça de ponteiro sobre um modelo base do Qwen. Em uma base só de atenção (Qwen3), o estado e as perguntas entram em uma única sequência de tokens:

<state> …state…
<q> instructions <opt> option 1 </opt> <opt> option 2 </opt> … <decide>
<q> instructions <opt> option 1 </opt> <opt> option 2 </opt> … <decide>

A máscara de atenção permite que um token leia o estado e a sua própria pergunta, mas não outras perguntas nem tokens futuros. Os ids de posição de cada pergunta reiniciam logo depois do estado. Isso permite que o modelo processe o estado uma vez e responda cada pergunta de forma independente.

O Qwen3.5 e o Qwen3.8 misturam camadas de atenção com camadas Gated DeltaNet, que são recorrentes e ignoram máscaras de atenção. Para esses modelos, que são todo Kev atual, cada pergunta roda como a sua própria linha: o estado seguido por aquela pergunta, com as mesmas posições acima. As linhas são independentes, então o isolamento é exato, e o servidor e o DecisionModel.probs() calculam o estado uma vez e reutilizam o seu cache para cada linha. O forward(), com que o kev.benchmark pontua e do qual todo número publicado vem, mantém as linhas simples e roda o estado uma vez por pergunta; os dois concordam até o arredondamento de fp32. Em modelos só de atenção, as linhas e a máscara acima dão probabilidades idênticas (tests/test_model.py).

O Kev-27B usa o mesmo projeto sobre Qwen/Qwen3.8-27B, com duas diferenças. A sua base é o release pós-treinado do Qwen, e não um checkpoint -Base, e não sabemos em que ele foi pós-treinado. E todo peso do backbone é treinado, não apenas um adaptador, e mantido em bf16, então o checkpoint é o modelo inteiro: 51 GB de pesos bf16 mais a cabeça de ponteiro. Ele serve apenas em bf16 (cerca de 66 GB residentes com os buffers de serviço), que é por isso que precisa de uma placa de 80 GB. No Apple Silicon o backend MLX carrega esses pesos como estão, sem mesclagem (veja Desempenho de serviço); esperamos que isso caiba em um Mac de 96–128 GB, mas não o medimos. As suas probabilidades servidas ficam dentro de 0.022 do caminho de avaliação em uma H200 (runs/serving-27b-r23).

A cabeça de ponteiro pontua o estado oculto </opt> de cada opção contra o estado oculto <decide> da pergunta. Um softmax transforma essas pontuações em probabilidades. Como o <decide> vem por último, ele pode atender à lista completa de opções.

O treinamento usa entropia cruzada sobre a resposta correta. O adaptador e a cabeça são treinados juntos; o resto dos pesos da base permanece fixo (o Kev-27B treina todos eles). Os exemplos de treinamento e as requisições de API usam o mesmo formato de texto. Nenhuma saída de Jev foi usada para treinamento.

Fazer as perguntas juntas ou separadas produz probabilidades dentro de 4e-6 nos testes em fp32. Isto não significa que a ordem das opções é irrelevante: opções dentro de uma pergunta ainda podem afetar umas às outras. Veja o código do modelo e testes de paridade.

Treinamento

Os modelos publicados compartilham um conjunto de treinamento base, decision-v7: 10,000 exemplos de dez conjuntos de dados públicos, 896 exemplos de política gerados, e 1,680 exemplos de 60 estruturas de regra geradas. O Kev-0.8B, o 4B e o 9B treinam nele por duas épocas com LoRA rank 16 e entropia cruzada. A taxa de aprendizado é 1e-4 para o 0.8B e 5e-5 para o 4B e o 9B. Nessas bases híbridas o adaptador cobre as projeções de atenção, MLP e DeltaNet; o kev.train escolhe os alvos certos a partir da configuração do modelo.

O Kev-0.8B, o 4B e o 9B recebem então ajustes finos de acompanhamento curtos a partir dos seus checkpoints publicados, pelo mesmo caminho --init_from que você usaria para os seus próprios dados: casos gerados que declaram contagens de dias ou têm a evidência decisiva removida (os três), depois documentos reais e dados de habilidade gerados (os três; o Kev-9B desde a v2, 2026-09-30). O Kev-27B é treinado de forma diferente. Todo peso da base é ajustado por uma época em oito H200s (--full_ft 1, taxa de aprendizado 2e-6) em um corpus de 145,840 registros: os próprios dados do Kev, as suítes de documento, habilidade e ferramentas de desenvolvimento, conjuntos de dados públicos, famílias de tarefa licenciadas e registros gerados de documento longo, roteamento de ferramentas, log de agente e guardrail, com estados de até 32,768 tokens. O resultado é então promediado com o Kev-27B anterior, treinado por adaptador, 0.85 a 0.15. As fichas dos modelos listam cada estágio com os seus dados e custo.

# sanity run, ~1 minute
uv run python -m kev.train --n_per_source 40 --accum 4 --out runs/smoke

# the first stage of Kev-0.8B (~20 min on one H100; the Mac path works but is slow for Qwen3.5 bases)
uv run python -m kev.train --suite evals/v7/decision-v7 --base Qwen/Qwen3.5-0.8B-Base --base_revision dc7cdfe2ee4154fa7e30f5b51ca41bfa40174e68 \
    --epochs 2 --lr 1e-4 --batch 8 --dtype bf16 --p_none_pair 0.25 --device cuda --out runs/kev-0.8b

# the first stage of Kev-4B (one H100 via Modal, ~1 h; see below). Swap in Qwen/Qwen3-4B-Base for the previous generation.
uv run python -m kev.train --suite evals/v7/decision-v7 --base Qwen/Qwen3.5-4B-Base --base_revision 1001bb4d826a52d1f399e183466143f4da7b741b \
    --epochs 2 --lr 5e-5 --batch 4 --accum 2 --dtype bf16 --checkpointing 1 --p_none_pair 0.25 --device cuda --out runs/kev-4b

Use uv run python -m kev.train --help para todas as opções de treinamento. Os modelos publicados não usam as perdas opcionais --perm_kl ou --ord_w. O PLAN.md registra o que foi tentado, o que ajudou e o que não ajudou.

Cada tentativa recebe a sua própria H100. O estudo continua rodando se você se desconectar, e você pode baixar os resultados quando ele terminar:

uv run modal token new                                    # once; opens the browser
KEV_GPU=T4 uv run modal run modal_app.py::smoke           # end-to-end check, ~1 minute of GPU

uv run modal deploy modal_app.py                          # once; studies run on the deployed app and survive disconnects
uv run modal run modal_app.py::study \
    --suite evals/v7/decision-v7 --plan experiments/v7-final.json \
    --name my-study --transfer evals/v4/transfer-v4 --budget 30 --timeout 7200
uv run modal run modal_app.py::pull --name my-study       # results -> runs/my-study, ranked

Os planos de estudo listam configurações de treinamento. Cada tentativa salva as configurações, os hashes do código, os hashes do conjunto de dados e os resultados. Escolha modelos usando os resultados de desenvolvimento, não o teste bloqueado. Depois de escolher um candidato final, você pode ler os seus resultados de teste uma vez:

uv run modal run modal_app.py::locked_test --trial my-study/00-trial-0 --name my-candidate   # one read, ever

Benchmarks

Os dados de avaliação em evals/ são congelados: versões de conjunto de dados e checksums de arquivo são registrados em cada manifesto. Arquivos grandes são baixados do espelho do Hub e conferidos contra esses hashes. Todo modelo nas tabelas acima é pontuado nos mesmos itens. Os números neste README e nas fichas dos modelos são conferidos na CI contra os relatórios versionados de que vêm (docs/claims.json, uv run python scripts/verify_claims.py).

Suíte O que mede
decision-v7 Exemplos reservados dos dez conjuntos de dados de treinamento, das políticas geradas e das estruturas de regra (“fontes treinadas”)
transfer-v4 764 registros de conjuntos de dados e de tipos de política e regra em que o Kev nunca treinou: QNLI, SciQ, PAWS, MMLU, Emotion, TweetEval, políticas e regras reservadas (“fontes novas”)
transfer-v9 O transfer-v4 mais MMLU-Pro de 10 vias, registros enterrados em texto não relacionado, e registros “impossíveis de saber” cuja evidência decisiva foi removida
uv run python -m kev.benchmark --run jaredpalmer/kev-4b --suite evals/v4/transfer-v4 --out runs/my-eval      # new sources
uv run python -m kev.benchmark --run jaredpalmer/kev-4b --suite evals/v9/transfer-v9 --out runs/my-eval-v9   # + MMLU-Pro, buried states, unknowable items
uv run python -m kev.benchmark --run jaredpalmer/kev-4b --suite evals/v7/decision-v7 --out runs/my-eval-id   # trained sources
uv run python -m kev.benchmark --remote http://127.0.0.1:8009 --suite evals/v4/transfer-v4 --out runs/my-remote   # any System One endpoint, Jev included

Estes comandos usam dados de desenvolvimento. Dados de teste exigem --allow-test. O benchmark reporta acurácia, Brier, erro de calibração, a fatia de decisões que você poderia automatizar com um orçamento de erro de 5%, mudanças de ordem de opções e isolamento de perguntas. Nos registros impossíveis de saber, ele reporta com que frequência o modelo ainda responde com pelo menos 0.9 de confiança (Kev-9B 0%, Jev 9%). Os números de acurácia publicados usam avaliação em fp32, não o caminho de serviço em bf16. O kev.jev roda as mesmas perguntas contra o Jev através do Vercel AI Gateway, e o kev.compare compara duas execuções salvas com intervalos de confiança bootstrap pareados.

Calibração. Cada checkpoint guarda uma temperatura, e a cabeça de ponteiro a aplica quando o modelo é carregado. O Kev-4B (2.41) e o Kev-0.8B (2.35) ajustaram as suas nos seus próprios conjuntos de desenvolvimento dentro da distribuição; o Kev-27B (1.32) e o Kev-9B (2.19) ajustaram as suas em conjuntos de dados reservados em que nunca treinaram. Um reajuste dos dois modelos menores nesses conjuntos de dados reservados foi testado e não manteve nenhum dos dois: não melhorou o Kev-4B e deixou o Kev-0.8B pior calibrado nas suas suítes de documento e habilidade (as fichas dos modelos têm os números). Uma temperatura nunca muda qual resposta vence. Em fontes novas, ela leva o erro de calibração do Kev-9B de 0.103 para 0.041 e os seus erros confiantes (respostas erradas com probabilidade ≥ 0.9) de 8.2% para 2.4%, abaixo dos 3.7% do Jev. Os números de acurácia acima são os mesmos dos dois jeitos; os números de Brier são para as probabilidades brutas. O scripts/calibrate_checkpoint.py também reporta uma estimativa fora do fold, para que o ajuste amostral possa ser conferido contra registros que ele não viu.

Datas. O Kev não consegue subtrair datas de forma confiável, mas consegue usar uma contagem de dias que recebe. KEV_DATE_FACTS=1 anexa uma frase por par de datas no estado (“26 de junho de 2026 fica 8 dias antes de 4 de julho de 2026”). Nas perguntas de política de prazo, isso leva o Kev-9B de 0.80 para 0.90 (Jev 0.93). Nenhuma das tabelas usa isso.

Conjuntos de teste de outras pessoas. evals/external/ contém conjuntos de teste de outros projetos, convertidos para este formato, com os seus resultados publicados de Jev ao vivo. Alguns foram pontuados em versões anteriores dos pesos do Kev, que a coluna Kev nomeia. Três foram removidos porque não conseguem servir de portão, e as fichas dos modelos mantêm os números com que os seus releases foram decididos: os tickets de suporte sintéticos do scienthoon em 2026-09-27 (texto templated; uma das suas três perguntas depende de uma regra que o texto não declara), e em 2026-09-30 o WANLI (wanli-v1, wanli-v2: um quarto dos pares são pares que os dois anotadores do WANLI rotularam de forma diferente, com o gabarito fixado em um deles) e as avaliações públicas da TypeSafe (typesafe-v1: o gabarito é a resposta média de dois modelos de fronteira fechados, e em 89 perguntas ele não consegue distinguir checkpoints).

Suíte O que é Jev Kev
SemIf 144 decisões autorais 0.965 0.917 (Kev-9B em v7-base)

Os rótulos do SemIf se sustentam, mas ele está perto da saturação: todo checkpoint do Kev-27B responde corretamente 130 das 144, então é uma verificação de sanidade, não uma forma de ranquear modelos.

Desempenho de serviço

Escolha a GPU pelo modelo:

Modelo GPU ($/h) 6 perguntas, texto curto 5 perguntas, texto de 2,200 tokens Requisições/s, 64 clientes
Kev-0.8B L4 (0.80) 22.7 / 16.1 ms 108.6 / 32.3 ms 62.8
Kev-4B L40S (1.95) 41.5 / 27.7 ms 145.2 / 43.0 ms 51.4
Kev-4B H100 (3.95) 18.1 / 12.9 ms 89.4 / 22.5 ms 100.8
Kev-9B L40S (1.95) 66.4 / 42.7 ms 235.6 / 57.5 ms 32.7
Kev-9B H100 (3.95) 24.0 / 16.6 ms 88.5 / 26.4 ms 79.5
Kev-27B B200 (6.25) 46.5 / 32.2 ms 178.0 / 52.1 ms 44.2
Kev-27B H200 (4.54) 67.2 / 50.0 ms 274.8 / 73.8 ms 28.6
Kev-27B H100 (3.95) 75.0 / 52.0 ms 277.5 / 79.3 ms 28.9

Os tempos são tempo de modelo por requisição (o latency_ms que a API devolve), mediana de 20, para um texto novo / o mesmo texto de novo. O servidor faz cache do texto, então fazer mais perguntas sobre um documento que você já enviou paga apenas pelas perguntas. As requisições por segundo são para 64 clientes concorrentes enviando seis perguntas sobre um texto curto novo cada; o servidor os agrupa. As linhas B200 e H100 do Kev-27B foram medidas na sua versão anterior, a mesma arquitetura servida em bf16 (runs/fused-27b-*); a linha H200 é o checkpoint atual (runs/serving-27b-r23). O tempo de rede é extra: cerca de 65 ms por ida e volta através de um endpoint web do Modal na mesma região.

Uma L4 basta para o Kev-0.8B mas é lenta demais para o Kev-4B. A A100 é mais lenta que a L40S aqui e custa mais. O Kev-9B precisa de cerca de 17 GB de memória de GPU e o Kev-27B de 51 GB de pesos (cerca de 66 GB com os buffers de batching); sob carga o Kev-27B é limitado pela computação, e uma B200, H200 ou H100 custa mais ou menos o mesmo por requisição. Em CUDA, instale o flash-linear-attention para os modelos Qwen3.5 (o kev_serve.py e as imagens do Modal já o fazem).

No Apple Silicon, o uv sync --extra serve instala o MLX e o servidor o usa automaticamente. Cinco perguntas sobre um texto de ~270 tokens em um M5 (32 GB):

Modelo Texto novo O mesmo texto de novo
Kev-0.8B 149 ms 28 ms
Kev-4B 721 ms 136 ms

Documentos longos são lidos para o cache 1,024 tokens por vez, então a memória fica próxima dos pesos. Com um documento de 65,000 tokens, o Kev-0.8B leva 21.2 s na primeira vez e 202 ms depois disso, com um pico de 3.8 GB, e o Kev-4B 84.5 s e 716 ms com 13.0 GB (runs/mlx-long-states; as fichas dos modelos têm cada comprimento). O Kev-9B ainda não foi medido deste jeito.

Checkpoints de adaptador são dobrados na base conforme carregam, o que mantém brevemente uma segunda cópia dos pesos. Checkpoints de pesos completos como o Kev-27B carregam como salvos, sem nada mesclado, então o carregamento precisa apenas dos pesos. Conferimos isso no Kev-4B escrito como pesos bf16 completos: o carregamento teve um pico de 8.4 GB para 8.4 GB de pesos, contra 15.9 GB no caminho do adaptador. As suas respostas coincidiram exatamente com o caminho do adaptador assim que ambos passam a ter os mesmos valores bf16, e ficaram dentro de 0.015 do caminho em fp32 em 60 perguntas (runs/mlx-full-4b). Os pesos do Kev-27B são 51 GB. Pelas mesmas medições ele precisa de cerca de 51 GB mais memória de trabalho, então um Mac de 64 GB é limítrofe e um Mac de 96–128 GB deve caber. Ainda não o executamos em um Mac tão grande. A primeira versão do Kev-27B, um adaptador, rodou deste jeito em um M5 Max de 128 GB, igualando a acurácia publicada (graças a Sean Connelly, #175).

O servidor roda em bf16 em GPUs e Macs. As suas probabilidades diferem do caminho em fp32 que as avaliações publicadas usam em no máximo cerca de 0.03 em uma GPU e 0.05 em um Mac, e a resposta do topo muda em cerca de uma pergunta em 300. Defina KEV_DTYPE=fp32 para o caminho exato. O /v1/models reporta o backend e a precisão em uso. uv run modal run modal_app.py::serving --run jaredpalmer/kev-4b --gpu L40S --name <name> mede uma linha da tabela na sua própria conta (as linhas acima: runs/serve-*, runs/grouping-4b-h100, runs/fused-27b-*, runs/serving-27b-r23).

Limitações

  • A calibração é uma única temperatura. Ela não consegue reordenar confianças, então a fatia de decisões de fontes novas que você consegue automatizar com um orçamento de erro de 5% (0.52–0.69 para o Kev-4B, o 9B e o 27B) ainda está abaixo dos 0.70 do Jev. Teste um limiar de probabilidade nos seus próprios dados antes de confiar nele.
  • As perguntas de conhecimento são definidas pelo modelo base. O MMLU é 0.73 para o Kev-9B contra 0.90 do Jev, e o MMLU-Pro 0.59 contra 0.84.
  • O ajuste fino pode piorar o modelo base em tarefas individuais. A aritmética de datas foi o caso mais claro (issue #8); treinar em contagens de dias declaradas mais KEV_DATE_FACTS=1 a recupera.
  • Mudar a ordem das opções pode mudar uma resposta. O isolamento de perguntas não impede isso.
  • O Kev-0.8B, o 4B e o 9B treinaram sobretudo em no máximo 384 tokens de estado e 1,024 tokens para o estado mais uma pergunta (os seus ajustes finos de documento e habilidade em estados de até 7,552 tokens), e o Kev-27B em estados de até 32,768 tokens. O serviço permite um estado de 65,536 tokens; o comprimento de contexto validado de cada modelo está em Modelos.
  • Em um Mac, as respostas levam centenas de milissegundos, não dezenas. O Kev-27B precisa de uma GPU de 80 GB. Em um Mac ele precisa de cerca de 51 GB mais memória de trabalho; esperamos que um Mac de 96–128 GB o comporte, mas não medimos nenhum.
  • O Kev-27B parte de um modelo pós-treinado cujos dados de treinamento desconhecemos.

Desenvolvimento

uv run --extra serve python -m pytest tests/test_unit.py tests/test_research.py tests/test_generators.py tests/test_conventions.py \
    tests/test_documents_tools.py tests/test_hard_v1.py tests/test_devtools_v1.py tests/test_breadth_v1.py tests/test_rounds.py tests/test_skill_scripts.py -q   # no weights, no server; what CI runs
KEV_BASE_URL=http://127.0.0.1:8009 uv run --extra serve python -m pytest tests/test_api.py -q   # against a running server
cd playground && npm run lint && npx next typegen && npx tsc --noEmit -p .

Os testes da API rodam as requisições de exemplo da TypeSafe e o SDK oficial contra o seu servidor local. O PLAN.md é o plano de pesquisa: o que aprendemos, as regras que todo experimento segue, e uma linha por rodada. O log completo (todo experimento, os critérios definidos antes de ele rodar, e como ele saiu) está na tag git research-archive-2026-09-24.

Geração anterior (Qwen3) e o protótipo

A primeira família Kev usou bases Qwen3 com os mesmos dados e configurações. Esses pesos continuam publicados e rodam em PyTorch comum em um Mac, mas não são mais desenvolvidos.

Modelo Base Acurácia: fontes treinadas Acurácia: fontes novas Brier: fontes novas Ficha do modelo
Kev-0.6B (Qwen3) — jaredpalmer/kev-0.6b Qwen3-0.6B-Base 0.801 / 0.808 0.620 / 0.642 0.536 / 0.483 Detalhes
Kev-4B (Qwen3) — jaredpalmer/kev-4b@qwen3 Qwen3-4B-Base 0.854 / 0.856 0.790 / 0.806 0.328 / 0.294 Detalhes
Kev-8B (Qwen3) — jaredpalmer/kev-8b Qwen3-8B-Base 0.863 / 0.870 0.796 / 0.780 0.337 / 0.327 Detalhes

O Kev-0.5B original usou o Qwen2.5-0.5B e é mantido como referência; veja a sua ficha de modelo.

Solução de problemas
  • Se o MPS ficar sem memória durante o treinamento, verifique se você está rodando apenas um trabalho. Não ative output_hidden_states nem adicione tokens com o trainable_token_indices do peft; ambos já causaram problemas de memória aqui.
  • Se o playground carregar mas os botões não funcionarem, use localhost:3001. O Next.js verifica os hostnames de desenvolvimento. Outros hosts precisam de uma entrada em allowedDevOrigins no playground/next.config.ts.
  • Se o carregamento do conjunto de dados reportar Dataset scripts are no longer supported, use legacy-datasets/banking77. Este repositório já o usa.

Autores

Construído com o Devin. Agradecimentos a Archer Hume pelo texto sobre a arquitetura, à TypeSafe pelo projeto da API, e ao Qwen pelos modelos base.

Trabalhos relacionados: Hydragen, DeFT, FIRST.

Licença

Apache-2.0. Os modelos base Qwen3, Qwen3.5 e Qwen3.8 também são Apache-2.0. Os conjuntos de dados de treinamento têm as suas próprias licenças; veja as fichas dos modelos.