Como usar o Jev para decidir quando o agente deve parar de iterar?

Diagrama mostrando o Jev recebendo um estado e devolvendo uma decisão tipada para controle de loop de agente
Resposta rápida

O Jev é o primeiro System One Model da TypeSafe AI, anunciado em 15/09/2026: ele não gera texto, recebe um estado e devolve decisões tipadas com probabilidade. Pra controle de loop isso muda tudo: em vez de pedir pro próprio LLM julgar se "já terminou?" e depois parsear a string, você declara as saídas válidas no schema e recebe um Noul (probabilidade de 0 a 1), um Choice ou um Score. A cada iteração você monta o state, faz as perguntas numa única chamada e usa a probabilidade como condição de saída do loop.

Agente que itera pra sempre e agente que para cedo demais têm a mesma causa raiz: quem responde "já terminou?" é o mesmo LLM que acabou de escrever a resposta

E ele quase sempre acha que fez um ótimo trabalho, né? 😅

A TypeSafe AI anunciou em 15/09/2026 o Jev, o primeiro System One Model deles: uma classe de modelo feita pra tomar decisão rápida e estruturada que o software consome direto. Ele não é autorregressivo, não prevê o próximo token e não te devolve uma stringzinha simpática

Tu manda um estado, ele devolve decisão tipada com probabilidade

É exatamente a peça que faltava pra tirar o "parar ou continuar" das mãos de quem tem conflito de interesse

Por que deixar o LLM julgar o próprio "já terminou?" falha

O desenho clássico é esse: o agente executa, produz um resultado, e aí você manda de volta pro mesmo modelo uma pergunta tipo "a tarefa está completa? responda SIM ou NÃO"

Dois problemas nascem juntos aí

O primeiro é o conflito: o gerador é o avaliador. O segundo é mecânico e dói mais no dia a dia: a saída é texto livre. Hoje vem SIM, amanhã vem Sim, a tarefa parece estar completa, embora... e o teu if quebra

E aí entra o gambiarrão de sempre: regex, .lower().startswith("sim"), retry quando não parseia, um JSON mode que às vezes volta com campo a mais

O Jev resolve isso por construção: as saídas válidas são declaradas no schema antes da chamada. Ele só responde dentro desse espaço declarado, sempre com probabilidade associada

Não tem resposta fora do espaço definido, não tem erro de tipo

Que "espaço definido"? É você quem escreve: se a pergunta é sim/não, o retorno é uma probabilidade entre 0 e 1. Se é escolha, o retorno é uma das opções da tua lista. Não existe terceira via inventada no meio do caminho

E não é ideia de maluco isolado: a LangChain publicou o material Building a harness with Jev descrevendo nós de decisão dentro do loop do agente, como roteamento de modelo e gate de tool call avaliado antes da execução

Ou seja: o padrão de "decisão de controle sai do LLM e vira chamada tipada" já tá documentado por terceiro, não é só o fornecedor falando bem de si mesmo

O que você precisa antes de começar

Lista curta, beleza?

  • Conta e chave de API criadas no console da TypeSafe (console.typesafe.ai)
  • A chave exportada na variável de ambiente TYPESAFE_API_KEY
  • SDK oficial, se você for usar: npm install @typesafe-ai/sdk ou pip install typesafe_sdk. Os dois leem a TYPESAFE_API_KEY e usam jev-latest por padrão
  • Um agente com loop já existente, porque o Jev não substitui o LLM que executa a tarefa

Esse último ponto é o que mais confunde gente chegando agora: o Jev não escreve teu código, não redige teu email, não chama tua tool. Ele decide

Sobre acesso: não tem mais waitlist, a TypeSafe abriu pra todo mundo. Conta nova recebe US$ 5,00 de crédito inicial (algo em torno de 120 milhões de tokens)

O preço é US$ 0,042 por milhão de tokens de entrada, e os tokens de saída são gratuitos

Sim, tu consegue prototipar um gate de loop inteiro dentro do crédito de boas-vindas 🙂

export TYPESAFE_API_KEY="sua_chave_aqui"

Tome cuidado: chave em variável de ambiente, não hardcoded no arquivo que você vai commitar. Já viu esse filme antes

Passo a passo: transformando o "parar ou continuar" em decisão tipada

1. Desenhe o state da iteração:

O campo state aceita string, objeto JSON, array ou null. Use isso a teu favor e mande estado estruturado, não prosa

O que costuma entrar: o objetivo original, a última ação executada, o resultado da tool, quantas tentativas já rolaram e o que ainda está pendente

{
  "objetivo": "Corrigir o teste que falha em auth/login_spec.ts",
  "tentativas": 3,
  "ultima_acao": "run_tests",
  "resultado_ultima_acao": "1 failing: expected 200, got 401",
  "arquivos_alterados": ["src/auth/session.ts"],
  "pendencias": ["teste ainda falhando"]
}

O erro comum deste passo: jogar o histórico bruto da conversa inteira dentro do state

Funciona? Provavelmente. Mas você acabou de transformar uma decisão barata numa chamada gorda, e enterrou o sinal relevante (tentativas, resultado da última ação) embaixo de dez mil tokens de "claro! vou analisar isso pra você"

Estado é estado. Transcrição é transcrição

2. Escolha o tipo de pergunta certo:

O Jev aceita exatamente três tipos, e é aqui que a maioria erra o desenho

Tipo O que você pergunta O que volta
Choice Uma opção entre até 255 alternativas A opção de maior probabilidade + a probabilidade de cada uma (somam 1) + confiança
Score Uma rubrica ordenada de 2 a 10 níveis Um valor fracionário no espectro + a distribuição completa + confiança
Noul Uma afirmação sim/não Probabilidade de 0 (não) a 1 (sim)

Noul é o nome que a TypeSafe dá pra pergunta sim/não, e é o tipo natural pro "já terminou?"

O erro comum deste passo: usar Choice com as opções ["parar", "continuar"] quando a pergunta é binária. Dá certo, mas você joga fora a graduação: com Noul você recebe o quanto o modelo acha que terminou, não só o lado vencedor

3. Monte a requisição:

O endpoint do Jev é próprio, não é /chat/completions. É POST https://api.typesafe.ai/v1/systemone

O corpo exige três campos: model, state e questions. O questions é um mapa do nome da pergunta pra um objeto com type e instructions

curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "jev-latest",
    "state": {
      "objetivo": "Corrigir o teste que falha em auth/login_spec.ts",
      "tentativas": 3,
      "ultima_acao": "run_tests",
      "resultado_ultima_acao": "1 failing: expected 200, got 401",
      "pendencias": ["teste ainda falhando"]
    },
    "questions": {
      "esta_completo": {
        "type": "Noul",
        "instructions": "O objetivo foi totalmente atingido e não há pendência aberta no estado?"
      }
    }
  }'

A resposta traz model, answers e usage

O erro comum deste passo: escrever instructions vago tipo "está bom?". Afirmação vaga gera distribuição espalhada, e distribuição espalhada é confiança baixa. Escreva a afirmação como uma frase que dá pra julgar olhando só o state

4. Faça várias perguntas de uma vez só:

As perguntas são avaliadas numa única ida e volta. Então não faz sentido chamar três vezes pra saber completude, qualidade e próxima ação

{
  "model": "jev-latest",
  "state": { "...": "..." },
  "questions": {
    "esta_completo": {
      "type": "Noul",
      "instructions": "O objetivo foi totalmente atingido e não há pendência aberta?"
    },
    "qualidade": {
      "type": "Score",
      "instructions": "Qualidade do resultado atual: 1 inutilizável, 5 pronto pra entregar"
    },
    "proxima_acao": {
      "type": "Choice",
      "instructions": "Qual a próxima ação mais útil dado o estado?",
      "options": ["rodar_testes", "editar_codigo", "ler_arquivo", "encerrar"]
    }
  }
}

O erro comum deste passo: adicionar uma pergunta pedindo pro Jev "explicar por que decidiu isso"

Ele não gera texto. Ponto. Se você precisa de justificativa legível pra humano, isso é trabalho de outro modelo, ou do teu log mostrando o state que entrou e a distribuição que saiu

5. Ligue a resposta ao controle do loop:

Agora a parte que importa: a condição de saída deixa de ser um parse de string e vira comparação numérica

const TYPESAFE_URL = "https://api.typesafe.ai/v1/systemone"

// valores arbitrários deste projeto: calibre com os seus próprios dados,
// não existe limiar oficial recomendado pela TypeSafe
const PARAR_ACIMA_DE = 0.9
const DESISTIR_ABAIXO_DE = 0.2
const MAX_ITERACOES = 12

async function decidir(state) {
  const res = await fetch(TYPESAFE_URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.TYPESAFE_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "jev-latest",
      state,
      questions: {
        esta_completo: {
          type: "Noul",
          instructions: "O objetivo foi totalmente atingido e não há pendência aberta?"
        }
      }
    })
  })
  return res.json()
}

async function rodarAgente(objetivo) {
  let state = { objetivo, tentativas: 0, pendencias: ["concluir o objetivo"] }

  for (let i = 0; i < MAX_ITERACOES; i++) {
    state = await executarUmaIteracao(state) // aqui roda o teu LLM de sempre

    const { answers, usage } = await decidir(state)
    const p = answers.esta_completo

    console.log({ iteracao: i, completude: p, usage })

    if (p >= PARAR_ACIMA_DE) return { status: "concluido", state }
    if (p <= DESISTIR_ABAIXO_DE && state.tentativas >= 3) {
      return { status: "escalar_humano", state }
    }
  }

  return { status: "limite_de_iteracoes", state }
}

O erro comum deste passo: remover o MAX_ITERACOES porque "agora o Jev decide". Não. O gate é semântico, o contador é mecânico, e os dois protegem coisas diferentes

6. Pine a versão do modelo quando precisar de estabilidade:

jev-latest é ótimo pra prototipar e péssimo pra reprodutibilidade, porque o que está por trás dele pode mudar

O jev-latest já foi observado resolvendo para jev-1.13.0, e o identificador typesafe/jev-1.13 aparece listado em provedores

{ "model": "jev-1.13.0" }

O erro comum deste passo: pinar e esquecer. Se tu pinou, anota no README por que pinou e quando revisar, senão daqui a seis meses ninguém lembra

Usando o score de confiança como trava de segurança

Aqui mora a parte mais bonita do desenho, e a mais ignorada

Respostas de Choice e Score carregam um campo de confiança separado, de 0 a 1, derivado do formato da distribuição de probabilidades

Probabilidade concentrada numa opção significa confiança alta. Distribuição espalhada entre as opções significa confiança baixa

A regra prática que a própria documentação resume é linda de simples: a resposta diz o quê, a confiança diz se você deve agir

1. Separe três faixas de tratamento:

  • Confiança alta e decisão "completo": para o loop e entrega
  • Confiança alta e decisão "incompleto": continua iterando, com a próxima ação que o Choice apontou
  • Confiança baixa: não é pra parar nem pra insistir cegamente. É pra escalar, seja pra um humano, seja pra um modelo maior fazer uma passada de revisão

Distribuição espalhada quase sempre quer dizer que o state que você mandou não tem informação suficiente pra decidir. O modelo tá te avisando que a pergunta tá mal servida, não que a tarefa tá mais ou menos

Essa faixa do meio é a mesma discussão de autonomia do agente no Claude Code: o ponto não é dar autonomia total nem zero, é ter um sinal confiável pra saber em qual dos dois modos você está agora

2. Trate o Noul diferente:

Noul não tem campo de confiança separado. A própria probabilidade é o sinal que a aplicação usa

Ou seja: ali você não tem uma trava, você tem duas fronteiras

Perto de 1 é sim com força. Perto de 0 é não com força. E a região do meio, aquele território morno onde o modelo não se compromete, é justamente o teu gatilho de escalação

function faixaNoul(p) {
  if (p >= PARAR_ACIMA_DE) return "parar"
  if (p <= DESISTIR_ABAIXO_DE) return "continuar_iterando"
  return "escalar" // zona morna: ninguém decide por palpite
}

3. Entenda por que dá pra confiar nesse número:

O Jev é treinado com um método de calibração próprio da TypeSafe, o RLCD (Reinforcement Learning for Calibrated Decisions)

A propriedade buscada é essa: grupos de previsões com probabilidade mais alta devem acertar com mais frequência que grupos de probabilidade mais baixa

Parece óbvio, mas não é o comportamento padrão de um LLM cuspindo "tenho certeza absoluta" no meio de um parágrafo. Ali o número é texto. Aqui ele é a saída do modelo

Importante ser honesto: não existe limiar oficial recomendado pela TypeSafe do tipo "abaixo de tanto, continue". Os valores de corte são decisão sua, e a forma certa de achar é logar as probabilidades junto com o desfecho real de cada rodada e olhar os dados depois

Outras decisões de loop que valem tirar do LLM

Uma vez que o padrão entra na cabeça, você começa a ver decisão tipada em todo canto do harness

  • Gate de tool call: antes de executar a ferramenta, uma pergunta avalia se aquela chamada faz sentido no estado atual. A LangChain descreve exatamente esse nó avaliado antes da execução. Noul resolve, e é o seu escudo contra os rm -rf da vida
  • Roteamento de modelo: Choice entre o modelo rápido e o modelo caro, decidido pela dificuldade que aparece no state, não por um if com contagem de caracteres do prompt
  • Próxima ação: Choice dentro de um conjunto fechado de ferramentas. Como as opções são declaradas no schema, é impossível o agente inventar uma tool que não existe
  • Qualidade do rascunho antes de entregar: Score com rubrica ordenada, de 2 a 10 níveis. Muito melhor que "o texto está bom? sim/não"
  • Detecção de loop improdutivo: Noul perguntando se o agente está repetindo a mesma tentativa com o mesmo resultado. É o gate que salva você da conta de API surpresa no domingo de manhã 😅

Se você quer ver o modelo aplicado fora do contexto de agente, os casos de uso do Jev dentro do software seguem exatamente a mesma lógica: decisão que o código consome direto, sem parse no meio

Custo e latência: por que essa camada extra compensa

O argumento contra é previsível: "você adicionou mais uma chamada de modelo por iteração"

Verdade. Então vamos olhar os dois eixos

No custo, o preço é US$ 0,042 por milhão de tokens de entrada e os tokens de saída são gratuitos. Como o state estruturado que você manda é pequeno (lembra do passo 1?), o gate custa uma fração do que custa a própria iteração do agente

Na velocidade, a TypeSafe afirma que o Jev é de 40x a 200x mais rápido que LLMs de fronteira em tarefas System One

E aqui eu preciso ser chato: isso é claim do fornecedor, não benchmark independente. Não vou vender esse número como verdade medida por terceiro, porque não é

A boa notícia é que você não depende de acreditar: a resposta traz o campo usage. Loga ele a cada gate, soma no fim do dia e compara com o custo das iterações que o gate evitou

Um agente que parava na iteração 12 por timeout e agora para na 4 porque alguém perguntou direito "já terminou?" se paga sozinho

Conclusão

A ideia central cabe em uma frase: quem decide parar não deve ser quem escreveu a resposta

O Jev encaixa exatamente aí, porque ele não compete com o teu LLM executor. Ele ocupa o espaço que hoje é preenchido por regex, retry e torcida

Próximo passo concreto, sem firula: cria a chave no console, exporta a TYPESAFE_API_KEY e coloca um único Noul de completude no loop que mais te dá dor de cabeça hoje

Roda uma semana logando probabilidade e desfecho

Só depois disso você adiciona o Score de qualidade e o Choice de próxima ação, já com número na mão pra calibrar as faixas em vez de chutar

Começa pequeno, mede, expande

Até o próximo post! 🙂

Perguntas frequentes

Quanto custa usar o Jev pra decidir quando um agente deve parar de iterar?

O Jev cobra US$ 0,042 por milhão de tokens de entrada, e os tokens de saída são gratuitos. Conta nova ganha US$ 5,00 de crédito inicial, o que dá pra rodar bastante gate de decisão antes de gastar nada do bolso.

Qual a diferença entre Noul e Score pra saber se o agente já terminou?

Noul é a pergunta sim/não: devolve só uma probabilidade de 0 a 1, sem campo separado de confiança, porque a própria probabilidade já carrega esse sinal. Score é pra quando ‘terminou’ não é binário: retorna um valor fracionário numa rubrica de 2 a 10 níveis, mais a distribuição completa e um campo de confiança à parte.

Ainda existe lista de espera pra acessar o Jev?

Não. A TypeSafe removeu a waitlist e anunciou que o Jev está disponível pra qualquer pessoa, sem espera. O blog de lançamento de 15/09/2026 ainda menciona ‘early access’, mas esse trecho ficou desatualizado.

O Jev substitui o LLM que executa as tarefas do meu agente?

Não. O Jev só decide, ele não gera texto nem chama tool. Você precisa de um loop de agente já existente, com o LLM de execução separado, e usa o Jev como a camada que julga se continua ou para.

Dá pra fixar uma versão específica do Jev em vez de usar jev-latest?

Dá sim. O identificador jev-latest resolvia para jev-1.13.0 no momento deste post, e o id typesafe/jev-1.13 aparece listado em provedores pra quem quer pinar a versão manualmente.

O endpoint do Jev funciona igual ao /chat/completions de outros LLMs?

Não, o Jev tem endpoint próprio: POST https://api.typesafe.ai/v1/systemone. O corpo da requisição pede model, state e questions, e a resposta vem com model, answers e usage, num formato bem diferente do padrão de chat.



Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 48min

Blog | Mais populares