Como usar o Jev como cérebro de um NPC no seu jogo

O Jev é o primeiro modelo da classe System One da TypeSafe AI: você manda um estado e perguntas tipadas, ele devolve decisões com probabilidades, sem gerar texto livre. Pra usar o Jev como cérebro de NPC o padrão é direto: serializa o estado do jogo (vida, posição, inimigos próximos, munição) no campo state, define a lista fechada de ações numa pergunta Choice, chama POST https://api.typesafe.ai/v1/systemone com model jev-latest e executa o valor que vier em choice. O campo confidence vira o interruptor do fallback determinístico quando a distribuição sai espalhada demais 🙂
Fala aí, beleza? NPC bom não precisa falar bonito, ele precisa escolher a ação certa no momento certo
E é justamente aí que a maioria dos projetos se enrola: joga o estado do jogo num LLM de geração, pede pra ele "responder só com o nome da ação" e reza pra não vir um parágrafo educado no meio do combate
Aí você escreve parser, regex, retry, fallback pra quando a IA inventa uma ação que não existe…
O Jev nasceu justamente pra esse buraco. Ele é o primeiro modelo da classe System One da TypeSafe AI: recebe um estado e perguntas tipadas, devolve decisões com probabilidades e não tem cabeça de geração de texto. É modelo de decisão, ponto
A ideia deste post é essa: encaixar o Jev como camada de decisão tipada dentro do seu game loop, com a lista de ações fechada ANTES da chamada e uma probabilidade pra cada uma
Bora ver na prática?
O que você precisa antes de começar
Antes de sair codando, se liga no checklist:
- Conta na TypeSafe e uma chave de API, que sai do console em
console.typesafe.ai - SDK Python (
pip install typesafe-sdkouuv add typesafe-sdk, exige Python >= 3.10, instala com hífen e importa com underscore, te explico isso lá no passo 3) ou o SDK JavaScript/TypeScript, pacote@typesafe-ai/sdk, que vem com ESM, CommonJS e declarações TS - A variável de ambiente
TYPESAFE_API_KEY, que o client Python lê sozinho do ambiente - Um jogo cujo loop consiga expor o estado em JSON (ou pelo menos montar um dicionário com os campos que importam)
Um aviso honesto sobre acesso: o Jev foi lançado em 15/09/2026 com lista de espera, abriu pra todos em 20/09/2026 (com US$ 5 de crédito em contas novas) e em 22/09/2026 a TypeSafe pausou temporariamente novos cadastros por excesso de demanda, dizendo que trabalha pra reabrir
Contas já criadas seguem funcionando normalmente. Se você ainda não tem a sua, pode ser que precise esperar a reabertura
Tome cuidado com isso aqui: a API do Jev não é compatível com o formato OpenAI
Não existe /chat/completions, não existe array messages, não existe temperature. Apontar um cliente OpenAI pro endpoint da TypeSafe simplesmente não funciona, então nem tente reaproveitar aquele wrapper que você já tinha 😛

Domine o Jev e coloque decisões de IA dentro do seu sistema
Você vai aprender a usar o Jev, o System One Model da TypeSafe AI, pra automatizar decisões com resposta tipada e confiança medida, sem depender de chat nem de alguém revisando cada passo. Entre na lista de espera para garantir a condição de lançamento!
Passo a passo: do estado do jogo à ação do NPC
- Modele o state do NPC
O campo state é o conteúdo a avaliar, e ele aceita string, objeto JSON ou array com contexto relacionado. Ou seja: você não precisa transformar seu mundo numa frase em português, pode mandar estrutura de dados mesmo
{
"npc": {
"id": "guarda_03",
"vida": 34,
"vida_max": 100,
"municao": 2,
"posicao": { "x": 12.5, "y": 0, "z": -4.2 },
"cobertura_proxima": true
},
"inimigos_proximos": [
{ "tipo": "jogador", "distancia": 6.1, "visivel": true, "arma": "shotgun" },
{ "tipo": "drone", "distancia": 14.8, "visivel": false, "arma": null }
],
"aliados_vivos": 1,
"ultima_acao": "atirar"
}
Repare que eu mandei só o que muda a decisão: vida, munição, distância, visibilidade, cobertura
O erro comum deste passo: despejar o dump inteiro do mundo dentro do state. Além de estourar o orçamento de tokens (falo disso lá embaixo), estado demais dilui o sinal e a distribuição de probabilidades sai mais espalhada
- Defina a lista fechada de ações como uma pergunta Choice
Aqui mora o pulo do gato. A primitiva Choice escolhe UMA opção de um conjunto que você definiu antes, então o NPC nunca vai "inventar" uma ação que seu código não sabe executar
O formato tem type igual a "choice", um campo instructions e um campo criteria, que é um mapa de opção para descrição (e aceita null quando a opção dispensa detalhe)
{
"type": "choice",
"instructions": "Escolha a próxima ação tática deste NPC guarda, considerando vida, munição, cobertura e os inimigos próximos.",
"criteria": {
"atacar": "Avançar e atirar no inimigo visível mais próximo. Exige munição e vida em nível seguro.",
"buscar_cobertura": "Mover-se para a cobertura próxima e interromper o fogo. Indicado com vida baixa ou sob fogo direto.",
"recarregar": "Recarregar a arma. Indicado quando a munição está baixa e não há inimigo a curta distância.",
"pedir_ajuda": "Chamar aliados. Indicado quando está em desvantagem numérica e há aliado vivo.",
"patrulhar": null
}
}
O limite é generoso: máximo de 255 opções por Choice. Na prática, se o seu NPC tem 200 ações possíveis, o problema não é o Jev, é o seu design 😀
O erro comum deste passo: opções que se sobrepõem. Se atacar e avancar_atirando significam quase a mesma coisa, a probabilidade se divide entre as duas, o confidence cai e você acha que o modelo ficou burro. Descrição de critério vaga dá no mesmo
- Monte a requisição
A API System One tem um único endpoint HTTP: POST https://api.typesafe.ai/v1/systemone, com os headers Authorization (Bearer) e Content-Type: application/json
O corpo tem exatamente três campos no nível raiz: state, model e questions (um mapa de id da pergunta para o objeto da pergunta). O alias do modelo é jev-latest
curl -X POST https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"state": { "npc": { "vida": 34, "municao": 2 }, "inimigos_proximos": [] },
"model": "jev-latest",
"questions": {
"acao": {
"type": "choice",
"instructions": "Escolha a próxima ação tática deste NPC guarda.",
"criteria": {
"atacar": "Avançar e atirar no inimigo visível mais próximo.",
"buscar_cobertura": "Mover-se para a cobertura e interromper o fogo.",
"recarregar": "Recarregar a arma quando a munição está baixa.",
"patrulhar": null
}
}
}
}'
Em Python, o mesmo payload montado na mão fica assim:
import os
import json
import requests
URL = "https://api.typesafe.ai/v1/systemone"
def decidir(state, questions):
payload = {
"state": state,
"model": "jev-latest",
"questions": questions,
}
resp = requests.post(
URL,
headers={
"Authorization": f"Bearer {os.environ['TYPESAFE_API_KEY']}",
"Content-Type": "application/json",
},
data=json.dumps(payload),
)
resp.raise_for_status()
return resp.json()
Se preferir o SDK oficial, o caminho é importar Choice, Noul, Score e TypeSafeClient de typesafe_sdk. O client lê TYPESAFE_API_KEY do ambiente, chama jev-latest por padrão e a chamada sai por client.system_one(...)
E calma, não são dois pacotes diferentes: você instala como typesafe-sdk (com hífen) e importa como typesafe_sdk (com underscore). É o mesmo bicho, só a convenção normal do Python 😀
O erro comum deste passo: insistir no vício de LLM. Nada de messages, nada de temperature, nada de system prompt. O contexto todo vive no state e a intenção vive no instructions de cada pergunta
- Leia a resposta e execute a ação
A resposta da Choice traz três coisas: choice (a opção escolhida), probabilities (uma probabilidade por opção) e confidence (número de 0 a 1)
# r = objeto de resposta da pergunta "acao", conforme o retorno da API
acao_escolhida = r["choice"]
probs = r["probabilities"]
conf = r["confidence"]
EXECUTORES = {
"atacar": npc.atacar,
"buscar_cobertura": npc.buscar_cobertura,
"recarregar": npc.recarregar,
"pedir_ajuda": npc.pedir_ajuda,
"patrulhar": npc.patrulhar,
}
EXECUTORES[acao_escolhida]()
E olha que massa: como a lista é fechada, esse dicionário de executores NUNCA vai dar KeyError por ação inventada
O probabilities também abre uma porta divertida pra jogo: em vez de sempre pegar o choice, você pode sortear a ação usando as probabilidades como peso, e aí o NPC deixa de ser previsível sem virar aleatório burro
O erro comum deste passo: tratar o retorno como verdade absoluta e jogar fora o probabilities. Essa distribuição é o material mais rico que você tem pra tunar comportamento depois
- Aplique um limiar de confidence com fallback determinístico
O confidence é calculado pelo formato da distribuição: concentrada numa opção significa confiança alta, espalhada significa confiança baixa. Ele existe exatamente pra você aplicar limiar no código
LIMIAR = 0.7
if conf >= LIMIAR:
EXECUTORES[acao_escolhida]()
else:
# árvore de comportamento clássica assume o volante
EXECUTORES[fallback_behavior_tree(npc, mundo)]()
O fallback_behavior_tree aí não tem IA nenhuma, e é esse o ponto: é a sua regra determinística de sempre (o if/else ou a árvore de comportamento que você já tinha), devolvendo o nome de uma ação da MESMA lista fechada do Choice
Tipo: vida baixa e cobertura por perto, vai de buscar_cobertura; sem munição e nenhum inimigo colado, recarregar; nada disso, patrulhar
Como o retorno do fallback vive no mesmo dicionário EXECUTORES, o resto do seu loop nem fica sabendo quem decidiu
Ou seja: a IA decide quando tem opinião formada, e a sua máquina de estados de sempre decide quando o cenário está ambíguo. O melhor dos dois mundos
O erro comum deste passo: chutar o limiar antes de olhar dado. Logue confidence e probabilities em arquivo por algumas sessões e escolha o número olhando a distribuição real do SEU jogo
- Adicione perguntas auxiliares na mesma requisição
O questions é um mapa, então você manda várias perguntas de uma vez sobre o mesmo state. Além da Choice da ação, existem mais duas primitivas:
- Score: nota em níveis ordenados. O
criteriaé um array ordenado de descrições de nível, do extremo baixo pro alto, e a resposta trazscore(que pode até cair entre dois níveis),probabilitiespor nível econfidence. Perfeito pra um medidor de agressividade. O mínimo é 2 níveis e a API aceita até 10 - Noul: sim/não. A resposta é um número entre 0 e 1 com a probabilidade de "sim", e o
criteriaé opcional, trazendo descrições pratrueefalse. Serve redondo pra "esse NPC deve recuar?"
agressividade = r_score["score"] # nível ordenado
deve_recuar = r_noul # probabilidade de "sim", de 0 a 1
if deve_recuar > 0.8:
npc.recuar()
else:
npc.velocidade = base * fator(agressividade)
Agora o detalhe que MUITA gente erra: todas as perguntas da mesma requisição são avaliadas em paralelo e isoladamente contra o mesmo state
O resultado de uma pergunta não vira contexto escondido que altera outra. Não existe "se o Noul der true, então a Choice vai considerar isso"
O erro comum deste passo: escrever instructions encadeando perguntas ("caso a resposta anterior seja sim…"). Não funciona. Se você precisa de encadeamento, ele é seu: lê a primeira resposta, decide no código e faz uma segunda chamada
- Encaixe a chamada no game loop sem travar o frame
Chamada de rede dentro do frame é receita de stutter. Nenhum modelo do mundo salva isso
O padrão que funciona é desacoplar a decisão do render:
- Chame em eventos (o jogador entrou no campo de visão, o NPC levou dano, acabou a munição) ou num tick lento (a cada X segundos por NPC)
- Guarde a última decisão em cache e execute ela enquanto a próxima não chega
- Use o cliente assíncrono: o SDK Python expõe
AsyncTypeSafeClientjustamente pra isso
import asyncio
async def cerebro_do_npc(npc, mundo, intervalo=1.5):
while npc.vivo:
estado = serializar_estado(npc, mundo)
resposta = await pedir_decisao(estado)
npc.decisao_atual = resposta
await asyncio.sleep(intervalo)
O erro comum deste passo: chamar a API todo frame pra cada NPC da cena. Além de derrubar o FPS, você multiplica custo por 60 sem ganhar comportamento nenhum, porque o estado do jogo mal mudou entre um frame e outro
Além do combate: outros usos do Jev em NPCs
Combate é o exemplo óbvio, mas o padrão "estado dentro, decisão tipada fora" vale pra praticamente qualquer NPC:
- Comerciante decidindo aceitar uma troca: pergunta Noul, com
criteriadescrevendo o que é um negócio bom e um negócio ruim pra ele. A resposta vem como probabilidade de "sim", então você pode até usar o valor como margem de negociação em vez de um corte seco - Guarda escalando suspeita: pergunta Score, com os níveis ordenados do "nada notado" até o "alarme geral". Como o
scorepode cair entre dois níveis, dá pra animar a transição em vez de pular de estado de forma seca - Diretor de dificuldade escolhendo o próximo evento: uma Choice com o estado da sessão (tempo jogado, mortes, recursos do jogador) e opções tipo emboscada, item, descanso ou evento narrativo
Esse mesmo desenho de Choice com criteria bem escrito aparece em contextos completamente diferentes de jogo, tipo qualificar leads com o Jev, e vale a leitura pra ver o padrão fora do game loop
E se a ação precisar de argumentos?
Boa pergunta. "Atacar" é fácil, mas e "mover para (x, z)" ou "usar item Y"?
Existe um cookbook oficial de function calling da TypeSafe que resolve exatamente isso: uma Choice escolhe a função, uma descrição por função entra nos critérios, e perguntas extras cuidam dos argumentos, uma pergunta por argumento
Como tudo é avaliado em paralelo, a resposta de todos os argumentos volta junto. Aí o seu código lê apenas as respostas da função escolhida e ignora o resto
É um desperdício pequeno de tokens em troca de uma chamada só. Pra NPC, vale demais
Vídeo: IA lendo seu projeto por dentro
Pra começar do zero com IA analisando código e estrutura de projeto, este vídeo do canal mostra uma skill que faz a IA ler seu código e desenhar a arquitetura sozinha, com o Archify
Custo, limites e alternativas de hospedagem
Orçamento de tokens:
São dois números que você precisa ter na cabeça: 64k cobre o state mais todas as perguntas somadas, e 32k se aplica ao state mais a pergunta mais longa
Na prática isso é MUITA folga pro estado de um NPC, mas é o motivo pra você não mandar o mundo inteiro serializado. Mande o recorte que importa pra decisão
Preço:
O Jev custa US$ 0,042 por 1 milhão de tokens de input, e o output não é cobrado
Como o custo mora no input, o que define sua conta é o tamanho do state vezes o número de chamadas. Estado enxuto e tick lento por NPC fazem mais diferença no boleto do que qualquer micro otimização de prompt
Limites de taxa:
Os rate limits do Jev estão sendo ajustados dinamicamente e podem mudar sem aviso enquanto a demanda segue alta (planos custom/enterprise têm limites maiores)
Traduzindo pro seu jogo: trate erro de limite como caso normal, não como exceção. O fallback determinístico do passo 5 já te cobre aqui também
Onde rodar:
Além da API direta da TypeSafe, o Jev está disponível em mais dois lugares:
- Vercel AI Gateway, com o model id
typesafe-ai/jev, exposto no AI SDK 7 pela APIexperimental_evaluate - Cloudflare Workers AI, via
POST https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run, com modeltypesafe/jeve uminputcontendostateequestions
Se o seu backend de jogo já vive num desses dois, é caminho natural
E aqueles números gigantes de performance?
Aqui vale o cuidado de sempre com número divulgado por fabricante:
| Métrica | Alegação da própria TypeSafe | Teste independente |
|---|---|---|
| Velocidade | 193,6x mais rápido | 2,0x a 3,6x mais rápido na mediana |
| Custo | 444,6x mais barato | 4,7x a 7,5x mais barato que os dois modelos pequenos mais baratos |
Os 193,6x e 444,6x são claim self-reported da TypeSafe em avaliações de workflow, comparando com modelos de fronteira
O teste independente mediu vantagem bem menor. Continua sendo vantagem, e boa, só não é mágica
Um detalhe técnico que explica por que as probabilidades servem de verdade pra tomar decisão: o Jev é treinado com RLCD (Reinforcement Learning for Calibrated Decisions), abordagem da própria TypeSafe que calibra as probabilidades pra refletirem a taxa real de acerto
Conclusão
O padrão é esse e ele cabe em uma linha: estado dentro, decisão tipada fora, confidence como interruptor do fallback
Você deixa de parsear texto livre, deixa de tratar ação inventada e passa a trabalhar com uma lista fechada de opções e uma distribuição de probabilidade em cima delas
Meu próximo passo sugerido pra você: não comece com dez NPCs
Começa com um NPC só e uma única Choice de 3 ou 4 ações, loga probabilities e confidence num arquivo por algumas sessões e ajusta os criteria até a distribuição fazer sentido com o que você esperava
Só depois disso expande pra Score, Noul e argumentos
E se o volume de decisões do seu jogo crescer muito, vale olhar a comparação entre Jev e um classificador próprio antes de escalar
Até o próximo post! 😀
Perguntas frequentes
O Jev serve pra controlar NPC sem gerar texto livre?
Serve, e é exatamente pra isso que ele foi pensado. O Jev é modelo de decisão da classe System One: recebe o state do NPC e perguntas tipadas (Choice, Score ou Noul) e devolve escolha com probabilidade, sem parágrafo educado no meio do combate.
Quantas ações um NPC pode ter numa pergunta Choice do Jev?
O limite é de até 255 opções por Choice, o que cobre praticamente qualquer árvore de decisão de NPC. Se o seu personagem tem 200 ações possíveis o Jev aguenta, o gargalo ali costuma ser o design do próprio jogo.
Dá pra usar um cliente OpenAI pra chamar o Jev no meu NPC?
Não dá. A API do Jev não é compatível com o formato OpenAI: não existe /chat/completions, array messages nem temperature. É preciso usar o endpoint próprio da TypeSafe ou o SDK oficial.
Quanto custa usar o Jev pra decisão de NPC em tempo real?
O input custa US$ 0,042 por 1 milhão de tokens, e o output não é cobrado. Como o state de um NPC costuma ser pequeno e o retorno é só a decisão, o custo por chamada tende a ser baixo.
Ainda dá pra criar conta nova no Jev pra testar em um NPC?
Depende do momento. Em 22/09/2026 a TypeSafe pausou temporariamente novos cadastros por excesso de demanda, mas contas já criadas continuam funcionando normalmente enquanto o acesso não reabre.
Como usar o confidence do Jev pra decidir se confio na ação do NPC?
O confidence é um número de 0 a 1 calculado a partir do formato da distribuição de probabilidades. Distribuição concentrada numa opção indica confiança alta, distribuição espalhada indica confiança baixa, então dá pra aplicar um limiar no código antes de executar a ação escolhida.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 45min
Blog | Mais populares

Como montar um workflow de automação combinando decisões do Jev em código
Aprenda a montar um workflow com Jev: decisões tipadas encadeadas em código, alta confiança agindo sozinha e casos incertos escalando para revisão.

Jev decide, LLM escreve: como dividir os papéis dentro de um agente de IA
Jev é o modelo que decide, não escreve: entenda como dividir papéis entre Jev e LLM dentro de um agente de IA e quando usar cada um.

Para quem o Jev serve (e para quem não serve)?
Jev serve pra roteamento, scoring e guardrails em IA, não pra texto ou código. Veja pra quem o Jev serve e quando evitar.
