Como usar o Jev para escolher qual fonte o seu RAG vai consultar?

Roteador de fonte no RAG não é tarefa de redação, é escolha dentro de uma lista fechada. Usar Jev para RAG significa transformar essa decisão numa pergunta Choice: cada índice ou coleção vira uma opção, você inclui um no_search e um other, manda a pergunta do usuário como state e recebe de volta a opção escolhida, a probabilidade de cada uma e um confidence de 0 a 1. O roteamento em si fica no seu código, com limiar. Entrada custa US$ 0,042 por 1M de tokens e a saída é gratuita, então dá pra rotear toda consulta
Fala aí, beleza? Se o seu RAG dispara busca em todo índice que existe pra depois "ver no que dá", você está pagando contexto pra receber ruído
E o pior: quando a coleção errada entra no prompt, o modelo que responde não te avisa, ele só responde bonito e errado
A decisão de QUAL fonte consultar é uma escolha dentro de uma lista que você já conhece, e é exatamente aí que o Jev entra. Ele é o primeiro modelo público da TypeSafe AI, de uma classe que a empresa chama de System One: não gera texto, recebe um estado não estruturado e devolve decisões tipadas com probabilidades
Ou seja, o roteador de busca vira uma pergunta Choice, e não um prompt torcendo pra IA responder {"index": "faq"} sem inventar aspas no meio 😀
Bora montar isso na prática?
O que você precisa antes de montar o roteador
Do lado da TypeSafe, o setup é curto
- conta no console da TypeSafe (
console.typesafe.ai). O Jev deixou de ter waitlist, o cadastro está aberto pra todo mundo - quem cria conta recebe US$ 5 em crédito gratuito, algo em torno de 120 milhões de tokens de entrada
- a variável de ambiente
TYPESAFE_API_KEY, que os dois SDKs leem sozinhos - o SDK oficial da sua stack
Python:
pip install typesafe-sdk
Exige Python 3.10 ou superior, e o cliente chama jev-latest por padrão. O repositório fica em typesafe-sdk-python
JavaScript/TypeScript:
npm install @typesafe-ai/sdk
O pacote é o @typesafe-ai/sdk, com TypeSafeClient e o método client.systemOne(), também lendo TYPESAFE_API_KEY. Código em typesafe-sdk-js
E do lado do seu RAG, você precisa de duas coisas que provavelmente já tem, só que bagunçadas:
- a lista real de índices ou coleções que o sistema pode consultar
- uma descrição honesta do que cada um cobre, e do que ele NÃO cobre
Essa segunda parte é a que todo mundo pula, e é a que decide a qualidade do roteador. "documentos" não é descrição, beleza? "contratos assinados a partir de 2023, com cláusulas e aditivos, sem proposta comercial" é
Curso de Jev: Sistemas Mais Inteligentes, Rápidos e Robustos
Desenvolva sistemas mais inteligentes, rápidos e robustos com Jev
Passo a passo: montando o roteador de busca com uma pergunta Choice
A primitiva aqui é a Choice: ela seleciona uma opção dentro de um conjunto fixo definido por você e retorna a opção escolhida, a probabilidade de cada opção e um valor de confiança
E tem espaço de sobra: uma Choice aceita até 255 opções, e a própria documentação recomenda passar a lista COMPLETA em vez de uma lista curta, porque cada opção custa poucos tokens
- Liste suas fontes como opções, uma por índice ou coleção
Cada opção pode carregar campos descritivos pra explicar o escopo. Um detalhe que economiza dor de cabeça: os nomes que aparecem nos exemplos da doc (question, focus, what, not_for, examples) não fazem parte da API e não são reservados. Quem escolhe o nome dos campos é você, do mesmo jeito que escolhe o nome das opções
import os
from typesafe import TypeSafeClient, Choice
client = TypeSafeClient() # le TYPESAFE_API_KEY do ambiente
fontes = [
{
"name": "docs_produto",
"what": "documentacao publica do produto, guias de uso, referencia de API",
"not_for": "preco, contrato, dados de cliente especifico",
"examples": ["como configuro webhook?", "quais parametros o endpoint aceita?"],
},
{
"name": "base_contratos",
"what": "contratos assinados, aditivos e clausulas a partir de 2023",
"not_for": "proposta comercial nao assinada, documentacao tecnica",
"examples": ["qual o prazo de rescisao do cliente X?"],
},
{
"name": "tickets_suporte",
"what": "historico de chamados resolvidos, com sintoma e solucao aplicada",
"not_for": "politica oficial, texto normativo",
"examples": ["ja aconteceu esse erro de timeout antes?"],
},
]
O erro comum deste passo: mandar três opções genéricas do tipo interno, externo, outro. Descrição vaga vira probabilidade espalhada, e aí você culpa o modelo por uma lista que ninguém entenderia
- Adicione a opção de não buscar e a opção de escape
Nem toda pergunta merece busca. "bom dia, tudo bem?" não precisa varrer índice nenhum
E a documentação recomenda incluir uma opção do tipo other ou none of the above quando a lista pode não cobrir toda entrada, justamente pro modelo poder dizer que nenhuma das outras serve
fontes += [
{
"name": "no_search",
"what": "saudacao, agradecimento ou pergunta que o assistente responde sem recuperar nada",
"examples": ["oi", "obrigado!", "voce consegue me ajudar?"],
},
{
"name": "other",
"what": "nenhuma das fontes acima cobre essa pergunta",
},
]
roteador_fonte = Choice(
name="fonte_de_busca",
question="Qual fonte deve ser consultada para responder a pergunta do usuario?",
options=fontes,
)
O erro comum deste passo: esquecer o escape e obrigar o modelo a empurrar a pergunta pra alguma fonte à força. Sem other, toda entrada fora do escopo vira falso positivo em cima da opção mais parecida
- Monte o state com contexto mínimo
O state é o conteúdo que você pede pro modelo avaliar, e ele aceita string, objeto JSON ou array. Em Python você passa direto em client.system_one(state=...)
A orientação oficial é dar a cada pergunta apenas o contexto de que ela precisa, e usar o JSON que você já tem (schema, taxonomia, linha de banco) em vez de serializar tudo num template de string
Curso RecomendadoDesenvolva sistemas mais inteligentes, rápidos e robustos com JevConhecer cursostate = {
"pergunta": "qual o prazo de rescisao que fechamos com a Acme?",
"ultimo_turno": "usuario perguntou sobre renovacao do contrato da Acme",
"cliente_logado": True,
}
O erro comum deste passo: despejar a conversa inteira no state "por garantia". Fora o custo, você tem teto: 64k tokens cobrem o state mais todas as perguntas juntas, e 32k se aplicam ao state mais a pergunta mais longa. Histórico longo também dilui o sinal, porque o turno de três mensagens atrás briga com a pergunta atual
- Chame o modelo
Cada requisição avalia um único state contra uma ou mais perguntas. Todas veem o mesmo state, são avaliadas de forma independente e você pode misturar Choice, Score e Noul na mesma chamada
resposta = client.system_one(
state=state,
questions=[roteador_fonte],
)
# para cada pergunta, a resposta traz: opcao escolhida,
# a probabilidade de cada opcao e um confidence de 0 a 1
Em JavaScript, mesma ideia com client.systemOne():
import { TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient(); // le TYPESAFE_API_KEY
const resposta = await client.systemOne({
state: {
pergunta: "qual o prazo de rescisao que fechamos com a Acme?",
ultimoTurno: "usuario perguntou sobre renovacao do contrato da Acme",
clienteLogado: true,
},
questions: [roteador_fonte],
});
O erro comum deste passo: esperar que o modelo execute a busca. Modelos System One não geram código nem escolhem sozinhos a própria próxima ação. Ele te entrega a decisão, quem chama o retriever é você
- Roteie no seu código
A parte mais chata de aceitar e a mais libertadora: fluxo de controle, regras determinísticas e efeitos colaterais ficam do lado do código
RETRIEVERS = {
"docs_produto": buscar_docs,
"base_contratos": buscar_contratos,
"tickets_suporte": buscar_tickets,
}
if fonte_escolhida == "no_search":
passagens = []
elif fonte_escolhida == "other":
passagens = fallback_humano(state)
else:
passagens = RETRIEVERS[fonte_escolhida](state["pergunta"])
Simples assim, e totalmente auditável. Sem parser de string, sem regex torcendo pra IA ter fechado a chave 🙂
Roteamento por confiança: o que fazer quando o Jev fica na dúvida
Tem pergunta ambígua. "quanto tempo isso dura?" pode ser SLA de suporte ou prazo de contrato, e o modelo vai te dizer isso: as probabilidades ficam divididas e o confidence cai
A resposta curta: você não chuta e nem manda buscar em tudo, você define um limiar de confiança e deixa o código decidir o caminho
A TypeSafe calcula e retorna um valor de confiança de 0 a 1 em toda resposta de Choice e de Score, além das probabilidades completas, justamente pra você aplicar limiar sem refazer a conta
E o que é limiar (threshold)? É só um número de corte que VOCÊ escolhe, nada de mágica: acima dele a decisão segue sozinha, abaixo dele ela toma outro caminho. O confidence é o valor que entra nessa comparação, então na prática o seu roteador vira um if comparando dois números
Dá pra ter mais de um corte também: um limiar alto pra seguir direto numa fonte só, um limiar do meio pra buscar nas duas fontes mais prováveis, e abaixo disso escalar. Se liga
O padrão na documentação se chama confidence-gated routing: o código toma caminhos diferentes pra respostas confiantes e pra não confiantes, escalando os casos incertos pra uma pessoa ou pra um modelo de raciocínio mais caro
THRESHOLDS = {
"auto": 0.85,
"multi": 0.55,
}
def rotear(fonte_escolhida, confianca, probabilidades):
if confianca >= THRESHOLDS["auto"]:
return [fonte_escolhida]
if confianca >= THRESHOLDS["multi"]:
# dividida entre duas fontes? busca nas duas mais provaveis
return top_n(probabilidades, 2)
return "escalar"
Repare numa coisa boa: os limiares vivem numa constante e a função de roteamento lê só as respostas já armazenadas. É o mesmo desenho do cookbook de classificação de passagens de RAG, onde os limiares ficam numa constante THRESHOLDS e a função route() lê apenas o que já está salvo
Tradução prática: reavaliar os limiares em cima de mil decisões antigas não custa uma chamada de API. Você guarda a resposta crua, mexe no número, roda de novo e compara. Massa demais pra calibrar sem queimar crédito
Tome cuidado com um detalhe: limiar alto demais no começo joga metade do tráfego no fallback e você conclui que "não funcionou". Comece medindo a distribuição de confiança nas suas perguntas reais, e só depois escolha o corte

Crie sistemas com IA para vender
Prompts, modelos e checklists para criar e publicar seu sistema com IA e preparar a oferta para o primeiro cliente.
Quero o e-book gratuito Receba o livro e os bônus no seu e-mail.Além do roteador: outras decisões do pipeline que o Jev resolve
O roteador é só a primeira porta. Como uma requisição avalia um state contra N perguntas, em paralelo e misturando primitivas, dá pra tomar várias decisões na mesma ida
As três primitivas de pergunta são Choice, Score e Noul:
| Primitiva | O que devolve | Onde encaixa no RAG |
|---|---|---|
| Choice | opção escolhida, probabilidade de cada opção e confiança | escolher índice, coleção ou não buscar |
| Score | valor escalar calibrado de 0.0 a 1.0 | pontuar relevância de passagem recuperada |
| Noul | probabilidade de a resposta ser "sim" | "esta passagem responde a pergunta?" |
Classificar as passagens que voltaram
A documentação tem um cookbook chamado "Classifying RAG passages": você pontua cada passagem recuperada numa requisição e decide no código quais chegam ao modelo que responde
A ideia é separar evidência aceita de evidência conflitante, e descartar passagem com instrução escondida (prompt injection). Isso último é ouro: documento de origem duvidosa com "ignore as instruções anteriores" no meio do texto morre antes de entrar no prompt
Re-ranking com Noul
Tem também um cookbook de re-ranking que usa um Noul por par pergunta/candidato e ordena os candidatos pela probabilidade, sem limiar nenhum. Nada de "nota de 1 a 10" em texto livre, é probabilidade mesmo
No experimento desse cookbook, com shortlists BM25 de 30 passagens para 40 consultas do CLERC:
| Métrica | Antes | Depois do re-ranking |
|---|---|---|
| Acurácia top-1 | 5% | 18% |
| Acurácia top-10 | 38% | 62% |
É o mesmo recall bruto do BM25, só que ordenado direito. Barato de testar
Quando as fontes têm níveis
Se o seu acervo é hierárquico (área, depois subárea, depois coleção), a doc tem um cookbook de classificação hierárquica. Ajuda quando 255 opções numa Choice única viraria uma sopa de nomes parecidos
E olha, esse mesmo desenho de decisão tipada não vive só dentro de RAG: usar o Jev pra qualificar e priorizar leads no funil é literalmente o mesmo padrão, trocando índice por estágio
Por que essa decisão não precisa de texto livre
Aqui está o pulo do gato do post
Escolher fonte é seleção dentro de um conjunto fechado, não redação. Você já sabe todos os resultados possíveis antes de perguntar. Então pra que pedir uma string?
Quando você usa um LLM generativo pra isso, ganha três problemas de brinde:
- precisa parsear a saída, e ela varia de formato quando o modelo resolve ser prestativo
- ele pode devolver uma fonte que não existe, com a maior convicção
- você não recebe probabilidade calibrada, só um texto seguro de si
Com Choice, o conjunto de respostas é o que você definiu, e vem acompanhado da distribuição inteira mais o confidence. Dá pra decidir o que fazer com a dúvida em vez de descobrir a dúvida em produção
Tem outro ponto no guia oficial que fecha o raciocínio: ele manda quebrar julgamentos amplos em perguntas estreitas, tipadas e atômicas. A própria doc cita "Analise esta mensagem e determine o melhor curso de ação" como exemplo de pergunta ruim, sinal de que a tarefa precisa ser fatiada em perguntas menores compostas no código
É o oposto do agente que decide sozinho o que fazer em seguida. Modelos System One não geram código nem escolhem a própria próxima ação, e nesse caso isso é uma feature, não uma limitação. Seu roteador fica determinístico, testável e versionável
Se você está na dúvida entre isso e treinar um modelo próprio pra decidir, vale olhar o comparativo entre Jev e classificador treinado em casa, porque a conta muda bastante conforme o volume
E por falar em conta: tokens de entrada custam US$ 0,042 por 1 milhão, e os tokens de saída são gratuitos. Isso muda o cálculo de "vale a pena rotear?" pra "por que eu não estaria roteando toda consulta?"
Conclusão
Recapitulando o caminho: sua lista de índices vira opções de uma Choice, você acrescenta no_search e other, manda a pergunta do usuário como state com contexto mínimo, chama o modelo e roteia no seu código lendo escolha, probabilidades e confidence
O próximo passo concreto, na ordem que evita retrabalho:
- cria a conta no console e usa o crédito de US$ 5 pra rodar o roteador com as opções REAIS do seu índice, não com exemplo de blog
- monta um conjunto de 30 a 50 perguntas que você já sabe a fonte correta e mede o acerto
- calibra os limiares em cima das respostas salvas, que isso não custa chamada nova
- só depois plugue o re-ranking em cima do que voltar
Último lembrete que já pegou gente desprevenida: aliases de modelo se movem quando sai uma versão nova. Hoje jev-preview aponta pro mesmo modelo de jev-latest, e o campo model da resposta informa o ID versionado que respondeu. Loga esse campo junto com suas métricas, senão você não vai saber se o acerto mudou por causa do seu prompt ou por causa de uma versão nova atrás do alias 😉
Até o próximo post!
Perguntas frequentes
Quantas fontes posso colocar em uma única pergunta Choice do Jev?
Uma pergunta Choice aceita até 255 opções, e a documentação recomenda listar todas as suas fontes reais em vez de resumir em três ou quatro categorias genéricas. Cada opção custa poucos tokens, então não tem motivo pra cortar índice da lista.
O Jev decide sozinho pra qual índice mandar a busca depois de escolher a fonte?
Não. O Jev não gera código nem escolhe sozinho a próxima ação, ele só devolve a opção escolhida, as probabilidades e a confiança. Quem dispara a busca no índice certo é o seu código, lendo essa resposta.
Quanto custa em dólar rodar o roteador de busca com o Jev?
Os tokens de entrada custam US$ 0,042 por 1 milhão e a saída é gratuita, então cada Choice de roteamento fica bem barato. Quem cria conta ainda ganha US$ 5 de crédito, o equivalente a cerca de 120 milhões de tokens de entrada.
Dá pra rotear a busca e checar outra coisa na mesma chamada, tipo se a pergunta precisa de contexto extra?
Dá sim. Uma requisição avalia um único state contra várias perguntas ao mesmo tempo, de forma independente, e você pode misturar Choice, Score e Noul na mesma chamada. Então o roteamento de fonte pode andar junto com um Noul de "precisa de mais contexto?", por exemplo.
O que o Jev faz quando a pergunta do usuário não se encaixa em nenhuma fonte cadastrada?
Se você incluiu a opção other ou none of the above na lista, o modelo pode sinalizar isso em vez de forçar a pergunta pra fonte mais parecida. A documentação recomenda incluir essa opção sempre que a lista pode não cobrir toda entrada.
Como saber se a decisão do roteador é confiável o suficiente pra buscar direto, sem revisão?
Toda resposta de Choice vem com um campo confidence de 0 a 1 e as probabilidades completas de cada opção. É esse valor que alimenta o padrão de confidence-gated routing: o código segue direto quando a confiança é alta e escala pra revisão humana ou pra um modelo mais caro quando não é.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 48min
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.
