Pré-requisitos

Conta, créditos e uma chave.

  1. Entre no painel com o login único e crie a sua organização.
  2. Em Cobrança, compre créditos (a partir de R$ 8,80 = 20 milhões de tokens de entrada; saída não é cobrada).
  3. Em Chaves de API, crie uma chave. O segredo aparece uma única vez: guarde num cofre.
Terminal
export JEVAAAS_API_KEY="jev_sk_..."   # painel → Chaves de API
O exemplo inteiro é um roteador de tickets de suporte. Troque o estado e as perguntas pelo seu caso: o ciclo é o mesmo.

Etapa 1 · Pergunte

Faça a primeira chamada com perguntas soltas.

O fanout julga perguntas tipadas sobre um estado, sem nada publicado antes. É o jeito mais rápido de ver se o JEV entende o seu problema. Três tipos cobrem quase tudo: choice (uma opção de um menu), score (nota numa rubrica) e noul (probabilidade de sim).

cURL
curl https://jev.api.br/v1/decisions/fanout \
  -H "Authorization: Bearer $JEVAAAS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "typesafe/jev-1.13.0",
    "state": { "ticket": { "messages": [
      { "author": "customer", "text": "A fatura veio em dobro. Preciso disso ainda hoje." }
    ] } },
    "questions": {
      "urgente": { "type": "noul", "instructions": "O cliente pede resolução imediata?" },
      "assunto": { "type": "choice", "instructions": "Qual é o assunto principal?",
        "criteria": { "financeiro": "Fatura, cobrança ou pagamento.",
                      "suporte": "Falha de funcionamento ou configuração.",
                      "indeterminado": "Evidência insuficiente para escolher." } }
    }
  }'
TypeScript · @jevaas/sdk
import { Jevaas } from '@jevaas/sdk';

const jevaas = new Jevaas({
  apiKey: process.env.JEVAAAS_API_KEY!,
  baseUrl: 'https://jev.api.br/v1',
});

const r = await jevaas.fanout({
  model: 'typesafe/jev-1.13.0',
  state: { ticket: { messages: [{ author: 'customer', text: 'A fatura veio em dobro.' }] } },
  questions: {
    urgente: { type: 'noul', instructions: 'O cliente pede resolução imediata?' },
  },
});
console.log(r.answers, r.usage); // [{ question_id: 'urgente', type: 'noul', noul: 0.12 }] { input_tokens, output_tokens }
Dica: todo choice precisa de uma saída de escape, como indeterminado. Sem ela, o modelo é obrigado a escolher uma fila mesmo quando nenhuma serve, e você perde o sinal mais útil: "o seu menu não cobre este caso".

Teste sem código no Playground →

Etapa 2 · Contrate

Transforme as perguntas num contrato versionado.

Quando as perguntas funcionam, publique um contrato: as perguntas, as regras de rota e a barra de confiança passam a morar no JEVaaS, com versão. O seu código deixa de interpretar probabilidades e passa a receber uma rota: auto, human_review, collect_evidence ou abstain.

Comece sempre em "mode": "shadow": o julgamento vem completo, mas enforced é false e nenhuma rota autoriza ação.

ticket-router.json
{
  "id": "ticket-router",
  "description": "Roteia o ticket para a fila que deve tratá-lo.",
  "owner": "[email protected]",
  "mode": "shadow",
  "action_class": "internal_write",
  "bar": 0.75,
  "collect_floor": 0.7,
  "primary_question": "fila",
  "default_route": "human_review",
  "escalations": { "human_review": "fila-triagem-humana", "default": "fila-triagem-humana" },
  "state_fields": [{ "path": "ticket.messages", "role": "evidence", "required": true }],
  "questions": {
    "fila": {
      "type": "choice",
      "instructions": "Qual equipe deve tratar a solicitação principal em ticket.messages?",
      "criteria": {
        "financeiro": "Fatura, cobrança ou pagamento.",
        "suporte": "Falha de funcionamento, configuração ou integração.",
        "indeterminado": "Evidência insuficiente ou nenhuma fila adequada."
      }
    }
  },
  "routes": [
    { "when": { "question": "fila", "equals": "indeterminado", "escape_hatch": true },
      "route": "abstain", "reason": "o menu de filas não cobre o caso" },
    { "when": { "question": "fila", "confidence_below": 0.7 },
      "route": "human_review", "reason": "confiança abaixo do piso" },
    { "when": { "question": "fila", "equals": "financeiro", "confidence_at_least": 0.75 },
      "route": "auto", "allow": "ticket:route:financeiro", "reason": "financeiro com confiança" }
  ]
}
cURL · publicar
curl https://jev.api.br/v1/contracts \
  -H "Authorization: Bearer $JEVAAAS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @ticket-router.json          # o JSON acima; volta a versão 1
TypeScript · julgar pelo contrato
const d = await jevaas.judge({
  contract: 'ticket-router',
  decision_id: ticket.id,            // o mesmo id em retries: nunca julga duas vezes
  state: { ticket: { messages: ticket.messages } },
});

switch (d.route) {
  case 'auto':          if (d.enforced) await moverPara(d.selected!.choice!); break;
  case 'human_review':  await filaHumana(ticket, d.escalation); break;
  case 'abstain':       await filaHumana(ticket, 'menu-de-filas-incompleto'); break;
  case 'collect_evidence': await pedirMaisDados(ticket); break;
}
// guarde d.receipt_id junto do ticket: é por ele que você mede e audita
Mudou uma pergunta ou regra? Publique uma versão nova (PUT /contracts/ticket-router). A anterior fica imutável, e cada recibo registra a versão que o julgou.

Etapa 3 · Meça em sombra

Compare o JEV com a sua produção antes de confiar.

Em sombra, a sua operação continua decidindo como hoje. Para cada julgamento, devolva o que a produção de fato fez e, numa amostra, o rótulo de uma pessoa. Com isso a calibração mostra o acerto real em cada faixa de confiança do seu caso, não num benchmark.

TypeScript · desfecho, rótulo e calibração
// o que a produção de fato fez (ex.: a fila em que o atendente pôs o ticket)
await jevaas.receipts.outcome(d.receipt_id, {
  production_answer: 'financeiro',
  action_taken: true,
});

// amostra conferida por uma pessoa: é o que mede acerto × confiança
await jevaas.receipts.label(d.receipt_id, { human_label: 'financeiro', labeled_by: '[email protected]' });

const cal = await jevaas.calibration('ticket-router', { mode: 'shadow' });
console.log(cal); // acerto por faixa de confiança, divergência da produção, taxa de revisão humana
A confiança não equivale à acurácia do seu caso. Uma faixa de 0,9 que acerta 70% nos seus dados pede barra mais alta ou perguntas melhores, não mais tráfego.

Etapa 4 · Promova

Passe a autorizar só quando a medição sustentar.

Rode o golden set do contrato (casos com resposta conhecida) e troque o modo para enforce. A partir daí, auto vem com allow e enforced: true. O resto continua indo para pessoas, como antes.

cURL · escopo contracts
# chave com "pode promover contratos" (escopo contracts): rode o golden set (casos com a resposta esperada da pergunta decisiva)
curl -X POST https://jev.api.br/v1/evals/ticket-router/run \
  -H "Authorization: Bearer $JEVAAAS_PROMOVER_KEY" -H "Content-Type: application/json" \
  -d '[
    { "name": "fatura-dobrada", "expected": "financeiro",
      "state": { "ticket": { "messages": [{ "author": "customer", "text": "A fatura veio em dobro." }] } } },
    { "name": "erro-login", "expected": "suporte",
      "state": { "ticket": { "messages": [{ "author": "customer", "text": "Não consigo entrar, dá erro 500." }] } } }
  ]'

# relatório bom? então autorize
curl -X POST https://jev.api.br/v1/contracts/ticket-router/mode \
  -H "Authorization: Bearer $JEVAAAS_PROMOVER_KEY" -H "Content-Type: application/json" \
  -d '{ "mode": "enforce" }'
Quem promove: avaliar o golden set, trocar o modo e promover versão exigem o escopo contracts. No painel, marque pode promover contratos ao criar a chave, e use essa chave só no processo de publicação, não no serviço que julga.
Reversível: voltar para shadow é a mesma chamada. Faça isso ao primeiro sinal de deriva na calibração.

Opere

Acompanhe consumo, recibos e erros.

TypeScript
const q = await jevaas.quota();   // teto e consumo do período
const u = await jevaas.usage();   // série diária de consumo
const recentes = await jevaas.receipts.list({ contract: 'ticket-router' });
  • 402: sem créditos. Compre no painel; a chamada não foi cobrada.
  • 429: limite de uso ou teto diário. Espere a janela; não repita em laço.
  • Timeout: a decisão pode ter acontecido. Repita com o mesmo decision_id, nunca com um novo.

No painel, Uso mostra a série diária e Cobrança mostra saldo, estoque em tokens, histórico e recibos.

Boas práticas

O que separa um piloto de uma operação.

  • Chave só no servidor, nunca no navegador ou no app. Uma chave por sistema, para revogar sem derrubar os outros.
  • Envie ao estado só o que a decisão precisa. Menos dado pessoal, menos token, julgamento mais estável e menos viés: veja o que medimos.
  • Toda pergunta choice tem saída de escape, e toda saída de escape vai para uma pessoa.
  • A barra de confiança é da consequência (action_class), não do modelo: mexer em dinheiro pede barra maior que mover um ticket.
  • Guarde o receipt_id junto do registro de negócio. É a trilha de auditoria da decisão.
  • Comece em sombra, sempre. Promova por contrato, não por projeto inteiro.
  • Versione o contrato como código: revise a mudança, publique uma versão nova, compare a calibração das duas.

Próximos passos

Aprofunde.