跳到正文
原文
Google AI:DEV 作者专属(RSS)· Tiago Vilas Boas (Montanha)·· 5 小时前AI 评分53

Jev 与 Laya 实测:决策模型和 LLM 各自擅长什么

Jev e Laya além do hype: o que modelos de decisão fazem que o LLM não faz

AI 导读

作者分享在个人 Agent 工作流中用 TypeSafe 的决策模型 Jev 和开源引擎 Laya 做任务分类、再用 LLM 写作的路由实践。Jev 输出有限标签加校准置信度,托管价 $0.042/百万输入 token,Laya 可本地离线运行但阈值需单独调校;作者估计决策评估比 GPT-4 便宜约 50 到 100 倍,并强调这只是 POC 结论,未上生产。

正文

No meu setup de agentes, eu fiz o que todo dev faz no começo: cada subagente acordava com o melhor modelo do SWE-bench por padrão. Typo no README, rename de variável, tudo rodando no topo do ranking. Com 5 spawns por dia, parecia produtividade. Quando o volume cresceu, veio a fatura e a inconsistência: a mesma tarefa simples consumia o modelo caro, e o custo por tarefa só subia. Traduzindo para produto: cada pedido simples pagava preço de especialista, e ninguém sabia dizer por quê.

A saída foi o Downshift: separar quem decide de quem resolve. Antes de qualquer modelo caro rodar, uma camada fina olha e despacha. Tarefa corporativa vai para um lado, dev pessoal para outro, admin para outro. Resposta curta, sempre igual: um destino. O modelo que resolve entra depois, com contexto. Produto lê assim: triagem antes do especialista. Dev lê assim: gateway antes do serviço. O erro era pedir para o serviço fazer o trabalho do gateway o dia inteiro.

A virada para mim foi separar as duas funções no desenho: Jev e Laya para decidir, LLM para escrever quando precisa. O Jev é o decision model da TypeSafe e a Laya é o engine open-source que fala o mesmo protocolo. Nenhum dos dois gera texto. Eles escolhem entre opções finitas. E essa separação deixa o resultado mais determinístico e a conta mais barata. Até o fim, você sai com as três respostas sem hype: o que cada um faz, quando cada um vence e quanto custa decidir.

Transparência de escopo, antes de continuar: com Jev e Laya eu só fiz POCs até aqui, nada em produção. Os números de preço e protocolo são reais e verificados, mas as conclusões de operação vêm de experimento local, não de tráfego pagante. O que já roda de verdade no meu dia a dia é o Downshift, e é de lá que vêm os exemplos da seção 8.

Índice


1. LLM adivinha a próxima palavra, Jev escolhe uma porta

LLM é um modelo generativo. Ele prevê a próxima palavra dada a sequência anterior. Por isso ele escreve, resume, traduz e explica bem. E por isso a mesma pergunta pode gerar três respostas diferentes, com temperatura, ordem e contexto mudando o resultado.

Jev é o oposto: um modelo classificador e de decisão. Ele é produto real, o System One decision model da TypeSafe, disponível como typesafe/jev-1.13 no OpenRouter. Ele recebe um estado e devolve uma entre N classes que você definiu antes, com probabilidade calibrada e tipos nativos como noul, choice e score. Exemplos reais que vejo no dia a dia:

entrada: "minha fatura veio dobrada, quero estorno"
Jev -> { label: "reembolso", confidence: 0.94 }
entrada: "onde acompanho minha entrega?"
Jev -> { label: "rastreio", confidence: 0.91 }
entrada: "quero falar do plano anual para 40 pessoas"
Jev -> { label: "comercial", confidence: 0.88 }

Nada de parágrafo. Só etiqueta mais confiança. E Laya também não é apelido: é um engine System One open-source que expõe o mesmo protocolo /v1/systemone do Jev, com modelos english, multilingual e typed-decisions (ver guia de uso), para decidir local sem API key. Quem redige a resposta final para o cliente é um LLM comum, que entra depois que a rota já foi decidida.

A diferença que importa para um mid-level recontar em uma frase: LLM escreve texto aberto e varia; Jev aponta uma porta entre poucas portas e repete.

2. Jev na prática: saída finita, confiança e log

Um classificador simples resolve sem GPU, sem prompt de 2 mil tokens, sem retry criativo. Exemplo mínimo em Python, que qualquer dev roda local:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression

texts = [
  "quero reembolso da fatura",
  "cobrança duplicada no cartão",
  "onde está minha entrega",
  "rastrear meu pedido",
  "orçamento para empresa",
  "plano anual para time",
]
labels = ["reembolso", "reembolso", "rastreio", "rastreio", "comercial", "comercial"]

vec = TfidfVectorizer()
X = vec.fit_transform(texts)
jev = LogisticRegression().fit(X, labels)

def jev_decide(frase: str) -> dict:
    proba = jev.predict_proba(vec.transform([frase]))[0]
    idx = proba.argmax()
    return {"label": jev.classes_[idx], "confidence": round(float(proba[idx]), 2)}

print(jev_decide("fui cobrado duas vezes"))
# {"label": "reembolso", "confidence": 0.81}

Três propriedades que o LLM não te dá de graça:

  • Saída finita: só existem reembolso, rastreio, comercial. Dá para validar com enum, testar com tabela, auditar no Grafana.
  • Confiança calibrável: abaixo de 0.70 você manda para revisão humana ou para o LLM com contexto extra. Acima, segue o fluxo automático.
  • Determinismo: mesma entrada, mesma saída. Sem temperatura para tunar, sem prompt que quebra porque alguém mudou uma vírgula.

É por isso que time de suporte e pagamento gosta de decisor: dá para escrever teste unitário em cima. Com LLM puro, cada teste vira aproximação semântica.

Isso não é opinião. Em intenção com rótulo fixo, pequeno fine-tuned ainda vence grande generativo: em Banking-77 e CLINC-150, DistilBERT superou Phi-2 e Llama-3-8B com PEFT, com F1 em torno de 0.92 contra 0.88 e 0.83, treinando e inferindo mais rápido. Em CLINC-150 com 151 intenções, DistilBERT marcou 0.889 de acurácia com 5.3ms contra 0.888 da RoBERTa. Para tabular, CatBoost, LightGBM e XGBoost seguem no topo do benchmark amplo com 20 modelos, à frente de MLP e ResNet na maioria dos datasets.

3. Quando texto livre vence: o LLM entra depois da decisão

Seria desonesto dizer que Jev resolve tudo. Quando a resposta precisa de nuance, contexto longo ou empatia, texto livre vence.

Cena que o classificador não resolve sozinho:

cliente: "assinei o anual ontem, mas meu sócio saiu hoje
e vamos reduzir de 40 para 6 pessoas. Consigo ajustar
sem multa? Estou preocupado com o orçamento."

Jev -> { label: "comercial", confidence: 0.83 }
LLM -> redige proposta com 2 opções, cita cláusula
de redução, sugere data de vigência e pergunta qual prefere.

O Jev acertou a rota em milissegundos. Mas só o modelo generativo monta a resposta com tom, condição e alternativa. Tentar fazer isso com regra e template vira um ninho de if que ninguém mantém depois de três meses.

Regra prática que uso: Jev e Laya decidem o quê fazer; o LLM decide como dizer.

4. A dupla que economiza token: Jev filtra, LLM só entra quando precisa

O ganho de token não vem de mágica. Vem de não chamar o modelo caro para o trabalho barato. Em uma frase: o roteador tira do LLM a triagem, a classificação e o gate de confiança, e deixa para ele só a redação final. O resto desta seção mostra como isso fica em código.

Padrão que tenho aplicado, roteador antes do gerador:

type Rota = "reembolso" | "rastreio" | "comercial" | "revisao_humana";

async function atender(ticket: string): Promise<string> {
  const decisao = await jevDecide(ticket); // Jev via API ou Laya local: milissegundos, custo quase zero

  if (decisao.confidence < 0.7) {
    return filaRevisao(ticket, decisao); // humano decide, sem gastar LLM
  }

  if (decisao.label === "rastreio") {
    return respostaTemplateRastreio(ticket); // nem chama LLM
  }

  // só aqui o LLM entra, já com rota e contexto enxuto
  return llmResponder(ticket, decisao.label);
}

Por que isso corta custo de verdade:

  • Ticket de rastreio nunca acorda o LLM: lookup mais template.
  • Ticket ambíguo vai para humano antes de gastar retries; quando o LLM entra, o prompt já vem curto e com a intenção resolvida.
  • Sem chave de API ou offline, a Laya decide local no mesmo protocolo, sem mudar o request.

Laya no seu dia a dia: o mesmo request, sem API key. Suba o laya-serve local e aponte o cliente para ele. O protocolo é o mesmo do Jev, então o código que você testa na máquina é o que falaria com o gerenciado:

// TYPESAFE_BASE_URL=http://localhost:8002 TYPESAFE_API_KEY=local-test (Laya local)
// TYPESAFE_BASE_URL=https://api.typesafe.ai (Jev gerenciado)
const res = await fetch(`${process.env.TYPESAFE_BASE_URL}/v1/systemone`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.TYPESAFE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "typed-decisions", // na Laya: english, multilingual ou typed-decisions
    state: { ticket: "fui cobrado duas vezes na fatura" },
    questions: {
      rota: {
        type: "choice",
        instructions: "Para qual fila vai este ticket?",
        labels: ["reembolso", "rastreio", "comercial"],
      },
      confianca_baixa: {
        type: "noul",
        instructions: "O pedido está ambíguo ou fora do escopo das filas?",
        labels: { yes: "Ambíguo", no: "Claro" },
      },
    },
  }),
});
const { answers } = await res.json(); // tipado, com probabilidade: sem parsing de texto

Três usos que a POC me pagou:

  • Dev local sem key: testo o roteador no localhost antes de gastar um token sequer.
  • CI: o teste do roteador vira assert em cima de answers.rota, igual teste de enum.
  • Fallback: sem rede ou sem verba de API, a Laya decide local; com chave, o mesmo código fala com o Jev.

Esquema completo de campos no comparativo Laya vs Jev. E re-tune não é conselho vago, é número: para a distribuição {0.91, 0.04, 0.03, 0.02}, a Laya reporta confiança ~0.71, onde a fórmula de probabilidade máxima daria ~0.88. Mesmo request, gate diferente. Calibre o corte por fonte:

const corte = fonte === "laya" ? 0.6 : 0.7; // Laya e Jev não compartilham threshold
if (decisao.confidence < corte) return filaRevisao(ticket, decisao);

Em termos de harness: Jev é guia computacional antes da geração. Ele é barato, testável e roda no PR e CI como qualquer código. O LLM fica como passo inferencial depois do gate, com trilha de auditoria do que o decisor escolheu. Se um dia o decisor errar, você tem label, confiança e entrada no log, não um prompt gigante para adivinhar o que aconteceu.

Quanto custa decidir, em números verificados:

  • Jev gerenciado: $0.042 por milhão de tokens de entrada, saída grátis (preço do Jev 1.13). Cada resposta traz usage.cost em dólar: dá para logar custo por rota junto com label e confiança.
  • Laya local: custo marginal perto de zero. Você paga a máquina que já tem mais o download do modelo, e decide offline quantas vezes quiser.
  • Ordem de grandeza (estimativa da minha POC, não benchmark): avaliação via decisor sai cerca de 50 a 100x mais barata que a mesma avaliação via GPT-4, que custa por token de entrada e de saída a cada retry.

Por isso a conta fecha: o roteador tira do LLM as chamadas baratas e repetidas (triagem, classificação, gate de confiança) e deixa para ele só a redação final. Cada ticket de rastreio que nunca acorda o LLM é token que não aparece na fatura.

O número que sustenta esse desenho vem de roteamento entre modelos: RouteLLM economizou até 3.66x no MT-Bench mantendo 95% da qualidade do GPT-4, e FrugalGPT em cascata economizou de 50% a 98% mantendo a acurácia do melhor modelo isolado. A lógica é a mesma do Jev: não acordar o modelo caro para o trabalho barato.

5. Trade-offs honestos de modelo de decisão contra LLM

Visão Staff, sem hype de mercado. Cada linha abaixo já me mordeu ao menos uma vez.

Dimensão Jev (decisão) LLM generativo
Determinismo Alto, mesma entrada repete Baixo, varia por temperatura e contexto
Custo por chamada Quase zero, roda local Pago por token, cada retry conta
Latência Milissegundos Centenas de ms a segundos
Dados para começar Precisa de exemplos rotulados Funciona com zero ou poucos exemplos
Mudança de escopo Exige retreino ou nova regra Muda com prompt, sem retreino
Texto aberto Não faz Faz bem
Falha típica Erra calado fora da distribuição Inventa com confiança

Três cuidados que o hype esconde:

  1. Decisor apodrece em silêncio. Se surge um produto novo ou um golpe novo, o Jev continua classificando com confiança alta no vocabulário velho. Sem monitoramento de distribuição e re-rotulagem periódica, vira débito técnico.
  2. Rótulo custa gente. LLM aceita 5 exemplos no prompt. Jev pede centenas de exemplos revisados para ficar estável. Esse custo aparece no planejamento, não na demo.
  3. LLM cobre o buraco do decisor. Classe nova, idioma novo, caso raro: o LLM atende no improviso enquanto você coleta dados para treinar o Jev. Arquitetura boa usa os dois, não elege um vencedor.

Deixar claro, porque já vi confusão em review: Jev e Laya não são mini ChatGPTs. Eles não conversam, não resumem, não escrevem. Laya cai na mesma coluna do Jev, com duas diferenças práticas: roda local e open-source, e os thresholds precisam ser re-tunados porque a confiança é calculada de outro jeito. Se você pedir texto para eles, vai receber etiqueta. Se pedir decisão auditável para o LLM puro, vai receber parágrafo bonito que muda amanhã.

6. Antes de mandar pro modelo caro

Antes de colar a tarefa no chat, pergunta o seguinte. Se você não usa roteador nenhum, a pergunta ainda vale: o modelo caro precisa mesmo desta conversa?

- [ ] A resposta cabe numa palavra só? "typo", "bug pequeno", "feature", "arquitetura". Se cabe, não peça um parágrafo para descobrir isso.
- [ ] Você precisa de texto de verdade? Descrição de PR, explicação, plano. Aí sim o modelo escreve, depois que o tipo da tarefa já está claro.
- [ ] Dá para conferir a resposta como você confere um teste? Se a saída certa é sempre a mesma, não deixe o modelo inventar uma versão nova a cada retry.
- [ ] Você ainda não tem exemplos guardados? Usa o modelo caro agora, anota o que ele classificou, e na próxima vez essa nota vira a regra.
- [ ] A tarefa mexe em algo que não dá para desfazer fácil? Push, deploy, migration, pagamento. Na dúvida, você confirma. O modelo não aplica sozinho.
- [ ] Semana que vem você vai lembrar dos erros? Se ninguém olha quando a classificação errou, ela continua errando no mesmo lugar.

É a pausa de dez segundos antes de pedir para o modelo mais caro corrigir um typo.

7. Evidência: o que a pesquisa sustenta

Sem prometer número do seu ticket. Estes são os benchmarks nos datasets deles, que uso como limite do que dá para afirmar:

Onde tenho segurança para recomendar Jev: saída em enum, alto volume, precisa de auditoria e latência baixa. Onde não prometo número: economia exata no seu fluxo. Meça acerto, confiança e custo por rota por um mês antes de cravar.

8. Jev e Laya no seu harness pessoal

Tudo acima usou o cenário de suporte ao cliente. No seu Cursor ou Kiro do dia a dia, o mesmo desenho economiza token de outro jeito, em três pontos:

1. Roteador de modelo. Antes de chamar o modelo caro, o Jev classifica a tarefa: typo e rename vão para o barato, code review vai para o intermediário, gate de PRD vai para o Opus. É o model routing por harness: a decisão custa fração de centavo e evita que tarefa simples acorde o modelo mais caro.

2. Juiz local em vez de LLM-judge. Revisar o próprio draft com outro LLM custa uma segunda chamada cheia de contexto. Com a Laya local, você pontua o rascunho com perguntas noul e score (foi o que a skill humanizar faz com jev_questions.json): determinístico, offline, custo marginal zero. O LLM só volta se a nota ficar abaixo do corte.

3. Gate antes do loop do agente. Classifique o pedido antes de montar o contexto: leitura (grep, git log) libera na hora; escrita (push, deploy) pede confirmação e carrega a skill do domínio. Skill é texto sob demanda, agente com contexto gordo é token queimado. O decisor mantém o prompt magro.

pedido -> Jev/Laya classifica -> barato ou caro? -> leitura ou escrita?
   simples + leitura  -> modelo barato, tools livres
   complexa + escrita -> modelo forte, skill do domínio, confirmação humana

No seu setup, cada linha dessa tabela que vira default economiza um acionamento do modelo caro por dia. Em um mês, é a diferença entre "IA ficou cara" e "IA se paga".

No Downshift, o estudo virou decisão. O roteador aplica exatamente o que este artigo prega: classifica a tarefa e despacha para o tier mais barato que dá conta. Exemplo real, sem mock:

$ downshift try "fix a typo in the README"
Task:       fix a typo in the README
Complexity: TRIVIAL
Needs tier: small
Recommend:  claude-haiku-4-5
→ TRIVIAL task → use claude-haiku-4-5 (small tier)

$ downshift try "rearchitect the payment flow across services"
Task:       rearchitect the payment flow across services
Complexity: COMPLEX
Needs tier: frontier
Recommend:  claude-opus-4-8
→ COMPLEX task → use claude-opus-4-8 (frontier tier)

Typo vai de Haiku, re-arquitetura vai de Opus, e nenhum LLM participou da classificação. E aqui a jornada fecha o círculo: as POCs com Jev e Laya me apresentaram o mundo dos mini-LMs. Estudando eles, a camada de classificação do Downshift ficou plugável: o hook continua igual, o backend de decisão troca sem tocar no resto. Entre as opções, eu optei por um classificador local por similaridade a protótipos, no mesmo desenho do MiniLM. O que o Downshift liga por padrão hoje é um embedding hash determinístico (hash-embed-v1), sem Python e sem GPU. Ele só sobe a classe quando o regex não está confiante, e nunca rebaixa. O MiniLM de verdade entra se você apontar DOWNSHIFT_MINILM_EMBED para um comando. Sem o comando, o hash segura o hook.

O teste do MiniLM de verdade, à parte do binário, foi assim. Peguei o modelo pequeno all-MiniLM-L6-v2 (roda em CPU, formato ONNX, sem GPU) e pedi para ele transformar cada prompt num ponto num espaço. Depois calculei o "endereço médio" de cada classe com 200 exemplos já rotulados: um ponto para TRIVIAL, um para SIMPLE, um para MEDIUM, um para COMPLEX. Na hora de classificar, o prompt novo vai para a classe cujo endereço está mais perto. Isso é o argmax: escolhe o vizinho mais próximo, sem desempate.

Separei 300 prompts que o modelo não viu no treino, todos em inglês, e medi.

  • Acertou 287 de 300, 95,7%.
  • Quando a classe vencedora estava claramente mais perto que a segunda (margem de 0,02), isso aconteceu em 94,7% dos casos, e aí o acerto subiu para 97,9%. A margem é a folga entre o primeiro e o segundo lugar. Folga pequena significa dúvida, e dúvida não deveria trocar o regex.
  • Cada prompt levou 1,87 ms na mediana. 95% deles ficaram abaixo de 2,96 ms.
  • Onde erra: MEDIUM, 85,3%. TRIVIAL 97,3%. SIMPLE e COMPLEX, 100%. O meio é o que se confunde com os vizinhos.

Esse número é desse modelo, não do hash que o binário usa hoje. Quando o dataset tiver português, o teste precisa ser refeito com um MiniLM multilingual. Decisor decide, gerador escreve, humano veta.


Curtiu sair do hype e ver o que Jev, Laya e esses micro-LMs fazem de verdade? Então me conta nos comentários: na sua próxima tarefa, o modelo vai escrever ou só escolher? E o que você vai mudar a partir de amanhã?

来源:Google AI:DEV 作者专属(RSS) · dev.to