Como monitorar as decisões do Jev em produção sem virar caixa-preta?

Dashboard mostrando como monitorar decisões do Jev em produção com gráficos de confiança e roteamento
Resposta rápida

Monitorar decisões do Jev em produção é diferente de logar resposta de modelo de texto: o retorno vem tipado, com distribuição de probabilidades. Grave sempre o campo model, os answers, o usage, a confiança (0 a 1), o campo probabilities e a faixa de roteamento que disparou a ação. Com isso você monta quatro gráficos: opções escolhidas por pergunta, histograma de confiança, proporção por faixa e volume por ID de modelo. E sai barato: a saída não é cobrada e a entrada custa US$ 0,042 por milhão de tokens

Decisão automatizada que ninguém consegue auditar depois não é automação, é aposta

Fala aí, beleza? O Jev é o primeiro modelo System One da TypeSafe AI, e ele não gera texto: recebe um estado e uma lista de perguntas tipadas, devolve respostas tipadas com probabilidades

Isso muda TUDO no que você precisa logar

Não tem mais "a resposta do modelo" pra colar num log e ler depois com calma

Tem uma opção escolhida, uma confiança entre 0 e 1, uma distribuição sobre as alternativas e um caminho que o seu código tomou por causa disso

E aqui vai o problema real: quando o comportamento muda, quem costuma te avisar é o usuário reclamando

Alias de modelo se move, entrada muda de formato, uma categoria nova aparece e não tem opção pra ela

Se o seu log guarda só o valor escolhido, você fica sabendo que a decisão mudou, mas não POR QUE mudou

O que você precisa antes de instrumentar:

Antes de sair plugando painel, o básico

  • Acesso ao Jev: o acesso direto pela TypeSafe está em early access, com waitlist, e a empresa vai tirando gente da lista aos poucos. Quando a sua vez chega, as chaves de API ficam no console em console.typesafe.ai. E se você ainda está na fila, calma: dá pra chegar no Jev pelas rotas alternativas logo abaixo, e todo o desenho de log deste post vale igual nos dois casos
  • O endpoint de avaliação: as chamadas vão em POST https://api.typesafe.ai/v1/systemone, com Authorization: Bearer <API_KEY> e Content-Type: application/json. O corpo leva state, model e um mapa nomeado de questions
  • Ou uma rota alternativa: o Jev também está no Vercel AI Gateway (model ID typesafe-ai/jev, pela API experimental experimental_evaluate, que exige AI SDK 7 ou superior), na Cloudflare via binding do Workers AI com env.AI.run('typesafe/jev', {...}) e no OpenRouter com o ID typesafe/jev-1.13. Cada plataforma nomeia do seu jeito, e nenhum desses formatos é igual ao ID versionado que volta no campo model da API direta (jev-1.13.0, que você vai ver mais pra frente): não confunda o que você MANDA com o que você LOGA
  • Atenção no OpenRouter: ele não aparece na lista padrão de modelos porque aquela lista cobre modelos que produzem texto. E não é pra chamar em /api/v1/chat/completions, e sim na rota de decisões
  • Pra quem vai usar auto instrumentação: existe o pacote openinference-instrumentation-typesafe, que pede typesafe-sdk >= 0.6.0

Uma nota de dimensionamento: o Jev 1.13 está listado com janela de contexto de 32.000 tokens

Se o seu state é um documento gordo, isso entra na conta antes de qualquer discussão sobre log 🙂

Formação Claude Code
Formação Recomendada

Formação Claude Code

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

  • 120 aulas
  • 4 projetos
  • 9h 45min

Como montar o log de decisões do Jev passo a passo:

A regra que eu seguiria é simples: o log tem que permitir reconstruir a decisão sem precisar chamar a API de novo

  1. Mapeie os campos que a resposta realmente entrega

A resposta traz três coisas que você vai querer pra sempre: o campo model (o ID versionado que de fato respondeu), os answers nomeados e um usage com input_tokens e output_tokens

Com a chave do console na mão, ou seja, depois que você saiu da waitlist, a chamada direta fica assim:

curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json

O payload.json é o seu state, o model e o mapa de questions

O que sai de lá é o que vira log

O erro comum deste passo: tratar o retorno como se fosse texto e serializar tudo num campo só de string. Aí ninguém agrega nada depois, porque agregação precisa de coluna, não de parágrafo

  1. Grave a confiança E a distribuição, não só a opção vencedora

Respostas de Choice e Score carregam uma confiança entre 0 e 1, derivada da distribuição de probabilidades da própria resposta. A Noul devolve um valor de 0 (não) a 1 (sim)

E toda resposta de Choice e Score inclui a propriedade probabilities, com a distribuição completa sobre as opções ou níveis (floats que somam 1)

Essa distribuição é o ouro do seu log

Distribuição concentrada significa resposta certa

Distribuição espalhada significa incerteza

É a diferença entre "ele escolheu A" e "ele escolheu A com 0,34 contra 0,31 de B", que é praticamente um cara ou coroa disfarçado de decisão

O erro comum deste passo: logar só a opção escolhida. Você perde justamente o sinal que antecipa a degradação, porque a opção vencedora pode continuar a mesma enquanto a distribuição vai achatando semana após semana

  1. Registre a faixa de confiança e a ação que o sistema tomou depois

A documentação recomenda dividir a confiança em três faixas com comportamentos diferentes: alta segue automático, média pede confirmação ou revisão, baixa vai pra humano, pede esclarecimento ou cai em outro sistema

Seu log precisa dizer em qual faixa aquela decisão caiu e o que aconteceu em seguida

Sem isso você tem a decisão do modelo, mas não tem a decisão do SISTEMA, que é a que o usuário sentiu

{
  "request_id": "tkt-88213",
  "question": "categoria_ticket",
  "input_digest": "ticket:88213 len:412 lang:pt",
  "model": "jev-1.13.0",
  "choice": "faturamento",
  "confidence": 0.91,
  "probabilities": {"faturamento": 0.91, "tecnico": 0.05, "outro": 0.04},
  "band": "alta",
  "action": "auto_route",
  "input_tokens": 613,
  "output_tokens": 0
}

Repare no input_digest: um resumo curto da entrada (tamanho, idioma, tipo, um hash), não o conteúdo inteiro

Dá pra correlacionar mudança de comportamento com mudança de entrada sem transformar o log numa cópia da sua base

O erro comum deste passo: usar um limiar único pro sistema todo. A própria documentação afirma que o limiar não é um número único: ações diferentes dentro do mesmo sistema devem ser liberadas em níveis diferentes conforme a consequência do erro, e os limiares devem ser escolhidos com exemplos rotulados

  1. Logue o campo model em TODA resposta, sempre

Esse é o passo que mais gente pula e mais dói depois

Aliases como jev-latest se movem quando sai uma versão nova

Ou seja: as respostas podem mudar sem nenhuma alteração no seu código

A orientação é logar o campo model da resposta e, se os seus limiares foram ajustados numa versão específica, fixar o ID versionado, tipo jev-1.13.0

Quer saber o que a sua conta pode mandar no campo model? Tem o GET /v1/models, que lista os nomes com descrição e data de lançamento de cada um. IDs versionados são aceitos mesmo sem aparecer na lista

O erro comum deste passo: chamar com alias e gravar no log o alias que você mandou, em vez do model que voltou. Você acha que tem rastreabilidade, mas na prática todo o histórico diz "jev-latest" e não dá pra separar antes e depois da troca de versão

  1. Plugue a auto instrumentação e pare de reescrever log na mão

Quem está em Python tem o pacote openinference-instrumentation-typesafe

pip install openinference-instrumentation-typesafe

Ele aplica patch direto em TypeSafeClient.system_one e AsyncTypeSafeClient.system_one, sem wrapper de cliente, e traça as chamadas como spans LLM do OpenInference. No Langfuse os spans chegam por OpenTelemetry

No span gerado, o input.value guarda o corpo da requisição (state, model e questions) e o output.value guarda o corpo da resposta (model, answers e usage)

Vem junto llm.request.model_name, llm.response.model_name e as contagens llm.token_count.prompt, llm.token_count.completion e llm.token_count.total

A lógica é a mesma de monitorar o GPT-6 Astra em produção: trace pra investigar caso a caso, log estruturado pra agregar

O erro comum deste passo: achar que o trace substitui o log de negócio. O span te dá requisição e resposta, mas a faixa de roteamento e a ação tomada depois são decisão do SEU código, e só o seu código pode registrar

O painel mínimo: quais quatro gráficos revelam mudança de comportamento?

Não precisa de painel bonito

Precisa de quatro gráficos que quebram quando a realidade muda

  1. Distribuição das opções escolhidas, por pergunta, ao longo do tempo

Um gráfico de área por opção, quebrado pelo nome da pergunta

É o seu detector de mudança de mundo: quando uma categoria que era marginal vira maioria em dois dias, algo mudou na entrada, não no modelo

  1. Histograma de confiança

Empilhe a confiança em buckets e compare a semana atual com a anterior

Uma barra que era concentrada perto do topo e começa a inchar no meio é o aviso mais precoce que existe, porque a opção escolhida ainda nem mudou

  1. Proporção de decisões por faixa de roteamento

Alta, média e baixa, em percentual do volume

Esse é o gráfico que o time de suporte entende: se a faixa média pula, mais gente vai ser incomodada com confirmação, e a fila de revisão humana cresce antes de qualquer reclamação chegar

  1. Volume por ID de modelo

Uma série por valor do campo model

Dois IDs diferentes aparecendo no mesmo dia? O alias virou

Esse gráfico transforma "mudou do nada" em "mudou às 14h de terça, quando a versão trocou", que é exatamente o tipo de correlação que você já persegue quando vai monitorar performance de workflows n8n em produção

Quem está chamando via Vercel AI Gateway ganha um pedaço disso de graça no lado de custo e volume: as chamadas de avaliação do Jev aparecem nos logs e no custom reporting, contam pros budgets e aceitam as demais opções de provider em providerOptions.gateway

Sinais de que a decisão degradou (e o que cada um significa):

Sintoma: a confiança caiu em bloco, do dia pra noite

Causa provável: troca de versão por baixo do alias. Se você chama jev-latest, a resposta muda quando sai versão nova, sem você mexer em nada

Solução: abre o gráfico de volume por ID de modelo e confirma se tem dois valores no mesmo dia. Se tem, fixa o ID versionado (jev-1.13.0) e revalida os limiares antes de voltar pro alias

Como prevenir: nunca deixe o campo model da resposta fora do log, e trate mudança de versão como deploy, não como detalhe de infra

Sintoma: massa enorme numa opção genérica, ou nenhuma opção sobrando pro que é novo

Causa provável: a sua lista de Choice não cobre a entrada real. A documentação recomenda incluir uma opção de escape do tipo "outro" ou "nenhuma das anteriores" quando a lista pode não cobrir tudo, justamente pro modelo poder dizer que nenhuma opção serve

Solução: adiciona o escape e acompanha ele como métrica de primeira classe. Crescimento de "outro" é sinal de categoria faltando, não é lixo

Como prevenir: Choice aceita até 255 opções e Score precisa de 2 a 10 níveis, então espaço pra granularidade existe. O que não existe é adivinhação: sem escape, a resposta vai cair em alguma opção de qualquer jeito

Sintoma: pergunta binária SEMPRE respondida, mesmo em entrada claramente ambígua

Causa provável: o Jev não consegue se abster. O Langfuse aponta isso direto: num binário forçado, sem opção de desconhecido ou needs_review, ele escolhe a resposta menos errada em vez de dizer que não sabe

Solução: se a sua regra de negócio precisa de "não sei", isso tem que ser uma opção explícita na pergunta. Não é um comportamento que aparece sozinho

Como prevenir: toda pergunta em que a ambiguidade é possível nasce com a saída de abstenção desenhada junto com as outras opções

Sintoma: buracos no log e picos de latência

Causa provável: 429 Too Many Requests ou 529 Overloaded. Nesses casos a orientação é repetir com backoff exponencial, e os SDKs clientes já fazem isso na política padrão de retry. Chamando o endpoint HTTP na mão, o backoff é problema seu

Solução: instrumente a tentativa, não só o sucesso. Se você só loga resposta 200, o retry fica invisível e a latência aparece como mistério

Como prevenir: contador de erro por código e por pergunta no mesmo painel, ao lado do volume. Buraco no gráfico de decisões quase nunca é "ninguém usou", é "alguém falhou calado"

Onde esse log te salva na prática:

Moderação com rubrica: várias perguntas independentes sobre o mesmo estado podem ir numa única requisição, avaliadas em paralelo e isoladas umas das outras. O cookbook de autoconsistência da TypeSafe usa uma rubrica de 8 perguntas Choice pra ilustrar isso

Com log por pergunta, você descobre que a rubrica não degradou inteira: degradou UMA pergunta, que é um problema mil vezes mais fácil de resolver

Roteamento de tickets: aqui o valor do log é a faixa. Se a faixa média cresce, o custo não aparece na fatura da API, aparece na fila da equipe que revisa

Jev como avaliador de traces: o Langfuse documenta um fluxo pra pontuar traces com o Jev, puxando observações pela API, decidindo com o modelo e gravando o resultado de volta como score

Bonito porque fecha o ciclo: o log de produção alimenta a avaliação, e a avaliação volta como score no mesmo lugar onde você já olha

Checagem de estabilidade: no estilo do cookbook de autoconsistência, que roda a mesma rubrica 15 vezes sobre o mesmo post pra medir se o rótulo se mantém entre repetições

Vale guardar um punhado de entradas fixas e repetir o exercício de vez em quando

Se o rótulo começa a oscilar num caso que era estável, você tem evidência antes de ter reclamação 😀

Vídeo: automações que rodam sozinhas

Pra começar do zero com processos que rodam sem ninguém olhando, este vídeo do canal mostra prompts virando automações agendadas no Antigravity 2.0

Conclusão:

Observabilidade aqui é barata, e isso é raro

O Jev cobra por token de entrada, US$ 0,042 por milhão, e a saída sai por US$ 0,00 por milhão de tokens

O que você paga mesmo é o trabalho de desenhar o log uma vez: model, answers, usage, confiança, probabilities, faixa e ação tomada

Próximo passo é escolher os limiares POR AÇÃO, com exemplos rotulados, porque consequência de erro diferente pede liberação diferente

E antes de confiar demais em Score numérico, em datas ou em contagem, dá uma passada na página de limitações conhecidas do jev-1.13: ela lista calibração numérica fraca nos níveis de Score, datas lidas como texto e não como quantidades ordenadas, e contagem pouco confiável, com o erro crescendo conforme o tamanho do que se conta

Saber onde o modelo é esquisito é metade do painel…

Até o próximo post!

Perguntas frequentes

Como saber se o alias jev-latest mudou de versão sem eu perceber?

Só olhando o campo model que vem em toda resposta da API. Como o alias se move sozinho quando sai versão nova, o jeito de flagrar a mudança é logar esse campo em cada chamada e comparar ao longo do tempo. Se os seus limiares de confiança foram calibrados numa versão específica, o caminho é fixar o ID versionado, tipo jev-1.13.0, em vez de usar o alias.

Dá pra confiar só na opção escolhida pelo Jev sem olhar a distribuição de probabilidades?

Dá, mas você perde o sinal mais cedo de degradação. A opção vencedora pode continuar igual semana após semana enquanto o campo probabilities vai ficando mais espalhado, indicando que o modelo está cada vez mais em cima do muro. Distribuição concentrada é resposta certa, distribuição espalhada é incerteza, e isso não aparece se você loga só o choice.

Quantas vezes o Jev deveria responder a mesma pergunta pra eu confiar que o resultado é estável?

A TypeSafe publica um cookbook de autoconsistência que roda a mesma rubrica de moderação 15 vezes sobre o mesmo post pra medir se o rótulo se mantém entre repetições. A rubrica usada nesse cookbook tem 8 perguntas Choice. É um jeito de testar estabilidade antes de confiar num limiar de confiança em produção.

O que fazer quando a API do Jev retorna 429 ou 529?

A orientação da documentação da API é repetir a chamada com backoff exponencial, e os SDKs clientes já fazem isso na política padrão de retry. Se você fala direto com o endpoint HTTP, o backoff fica por sua conta, e vale instrumentar a tentativa e não só o sucesso, senão o retry some do log e a latência vira mistério.

O Jev consegue dizer que não sabe responder uma decisão incerta?

Não de forma nativa. O próprio Langfuse documenta que, num binário forçado sem opção de desconhecido ou needs_review, o Jev escolhe a resposta menos errada em vez de admitir incerteza. Pra ter esse comportamento você precisa incluir explicitamente uma opção tipo none ou outro na pergunta Choice.

Quanto custa manter o log de decisões do Jev rodando em produção?

O preço é só por token de entrada: US$ 0,042 por milhão de tokens, com a saída sem cobrança nenhuma. Isso ajuda a decidir o que entra no state, já que o Jev 1.13 tem janela de contexto de 32.000 tokens e cada campo extra no estado pesa na conta de entrada.




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 Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares