Como usar o Jev para decidir o que arquivar ou apagar na sua política de retenção de dados?

fluxo do Jev decidindo entre manter, arquivar ou apagar dados numa política de retenção
Resposta rápida

O Jev é o modelo System One da TypeSafe: você manda um state (metadados e trecho do registro) mais perguntas tipadas e ele devolve decisão com probabilidade por opção e confidence, sem prosa. Para retenção de dados, o padrão é um Choice de destino (manter, arquivar ou apagar) junto de um Noul para dado pessoal e um Score de relevância, tudo na mesma chamada. O código faz a aritmética de prazo, aplica o roteamento por confiança e grava a trilha. Preço: US$ 0,042 por 1 milhão de tokens de entrada, saída zero.

Toda empresa tem aquele diretório que ninguém abre há três anos

Backup de sistema antigo, planilha de RH de 2019, log de aplicação que alguém jurou que ia limpar, contrato escaneado em duplicata

O problema quase nunca é técnica de storage, é decisão: alguém precisa olhar item por item e dizer se aquilo fica, vai pro storage frio ou some de vez

E é exatamente aí que o Jev entra diferente do que você está acostumado. Ele é o primeiro modelo System One da TypeSafe: em vez de escrever um textão explicando o que acha, ele avalia um state e devolve resposta tipada com probabilidades, que seu software consome direto (doc de System One)

Sem prosa, sem parsear markdown, sem rezar pro JSON vir fechado 🙂

Neste post a gente monta um pipeline de retenção do zero: modela o state com os metadados do registro, escreve o Choice de destino, fecha a decisão de UM registro ponta a ponta e só então escala esse mesmo loop pro lote, gravando a trilha de auditoria de cada escolha

Bora?

O que você precisa antes de começar

Duas frentes aqui: a técnica e a de negócio. A segunda é a que mais gente pula (e depois reclama do resultado)

Do lado técnico:

  • Chave de API criada no console da TypeSafe em https://console.typesafe.ai/, exportada na variável de ambiente TYPESAFE_API_KEY, que é o que o cliente lê
  • SDK Python, instalado com pip install typesafe-sdk, exigindo Python 3.10 ou superior
  • Ou o SDK oficial de JavaScript/TypeScript, via npm, pra Node.js 20 ou mais novo, com ESM, CommonJS e declarações TypeScript inclusas
  • Se você não informar modelo nenhum, o cliente chama o alias jev-latest, que hoje resolve pra versão 1.13
pip install typesafe-sdk
export TYPESAFE_API_KEY="sua_chave_do_console"

Do lado do negócio:

A política de retenção escrita

Prazos definidos, categorias definidas, quem responde por cada tipo de documento

O modelo aplica critério, ele não inventa critério. Se a sua regra é "nota fiscal a gente guarda X anos", isso precisa estar no texto da pergunta, não na cabeça do jurídico

E se você usa Claude Code, a TypeSafe publica uma agent skill que dá ao agente contexto sobre a API, os três tipos de pergunta e os padrões recomendados. A instalação é por marketplace de plugins:

claude plugin marketplace add typesafe-ai/skills
claude plugin install typesafe@typesafe-ai

Depois é só invocar com /typesafe:typesafe-ai dentro da sessão

Repara que o identificador aparece escrito de três jeitos diferentes, e isso não é erro de digitação: typesafe-ai/skills é o marketplace que você adiciona, typesafe@typesafe-ai é o plugin dentro desse marketplace e /typesafe:typesafe-ai é o comando que passa a existir na sessão. Copia e cola exatamente como está na doc da agent skill, sem tentar "padronizar" na mão 🙂

Passo a passo: montando a decisão de retenção com o Jev

Antes do código, o mapa das peças

Uma requisição ao Jev tem duas partes: um bloco de state (string pra texto, objeto ou array pra dado estruturado, tipo registros e logs) e uma ou mais perguntas tipadas. A resposta volta indexada por ID de pergunta

E existem exatamente três tipos de pergunta, nem um a mais:

Primitiva O que ela faz No pipeline de retenção
Choice Escolhe uma opção de um conjunto definido, devolve a opção, uma probabilidade por opção e confidence O destino do registro: manter, arquivar ou apagar
Score Avalia contra níveis ordenados e descritivos, devolve a nota, probabilidade por nível e confidence Relevância operacional do documento hoje
Noul Pergunta sim/não, devolve a probabilidade de ser sim e não tem confidence separado, porque a distribuição só tem dois resultados "Contém dado pessoal?"

Sacou a lógica? Agora vamos montar

1. Modelar o state com os metadados do registro

O state é o que o Jev enxerga. Coloque o tipo de documento, a área dona, marcadores de dado pessoal já conhecidos e um trecho do conteúdo

state = {
    "id_registro": "fin-2021-08841",
    "tipo_documento": "nota fiscal de servico",
    "area": "financeiro",
    "origem": "/mnt/arquivos/financeiro/2021/",
    "data_criacao": "2021-08-14",
    "ultimo_acesso": "2023-02-02",
    "marcadores": ["cnpj_fornecedor"],
    "trecho": "Prestacao de servico de manutencao predial referente a..."
}

O erro comum deste passo: despejar o documento inteiro achando que "quanto mais contexto, melhor". A doc de jaggedness é direta sobre isso: o modelo sofre de context rot e material irrelevante custa acurácia. State enxuto, só o que a pergunta exige

2. Escrever o Choice de destino com critérios explícitos

Aqui mora o resultado do post. As opções precisam ser mutuamente exclusivas e o critério precisa estar escrito:

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

client = TypeSafeClient()

questions = {
    "destino": Choice(
        question=(
            "Segundo a politica de retencao da empresa, qual o destino deste registro? "
            "manter: documento ainda em uso operacional ou com obrigacao legal vigente. "
            "arquivar: sem uso operacional, mas precisa continuar recuperavel para auditoria. "
            "apagar: sem uso operacional, sem obrigacao legal e sem valor historico."
        ),
        options=["manter", "arquivar", "apagar"],
    ),
}

Os nomes exatos dos campos de cada primitiva estão na doc de primitivas, confere lá antes de colar direto

O erro comum deste passo: escrever opção sem definição ("arquivar" sozinho não diz nada). Critério explícito não é firula, é o que separa uma classificação estável de um chute caro

3. Somar as perguntas de apoio na MESMA chamada

Essa é a parte que mais gente faz errado, e dói no bolso

Juntar todas as perguntas de um mesmo documento numa única chamada sai 12,2x mais barato e 10,0x mais rápido do que uma chamada por pergunta, sem mudança nas respostas. O motivo é bobo e óbvio: chamadas de pergunta única reenviam o documento inteiro várias vezes

E como as perguntas são avaliadas em paralelo numa única passada, mandar muitas leva tempo parecido com mandar uma

questions["dado_pessoal"] = Noul(
    question="O registro contem dado pessoal identificavel de pessoa fisica?"
)

questions["relevancia"] = Score(
    question="Qual a relevancia operacional deste registro para a area hoje?",
    levels=[
        "nenhuma: nao seria consultado em nenhum cenario previsivel",
        "baixa: consultado apenas em auditoria ou disputa",
        "media: consultado esporadicamente pela area",
        "alta: usado em processo ativo",
    ],
)

response = client.system_one(state=state, questions=questions)

O erro comum deste passo: fazer três requisições "pra separar bem as responsabilidades". Separa no código, não na rede

4. Ler a resposta por ID e gravar o que veio

A resposta volta por ID de pergunta. Do Choice você tem a opção escolhida, a probabilidade por opção e o confidence. Do Score, a nota, a probabilidade por nível e o confidence. Do Noul, só a probabilidade de sim

destino = response["destino"]

linha = {
    "id_registro": state["id_registro"],
    "destino": destino.selected,
    "probabilidades": destino.probabilities,
    "confidence": destino.confidence,
    "dado_pessoal_p": response["dado_pessoal"].probability,
    "relevancia": response["relevancia"].level,
}

O erro comum deste passo: salvar só a opção vencedora e jogar fora a distribuição. Daqui a seis meses, quando alguém perguntar por que aquele arquivo sumiu, a distribuição é metade da sua resposta

Onde o Jev erra numa política de retenção (e como contornar)

Todo modelo tem terreno irregular, e a TypeSafe documenta o do Jev 1.13 abertamente na página de jaggedness. Três dessas limitações batem em cheio em retenção de dados

Sintoma: o prazo de retenção calculado pelo modelo sai errado

Causa: o Jev 1.13 lê datas como texto, não como quantidades ordenadas. Perguntar qual data vem primeiro, a distância entre duas datas ou se uma cai dentro de uma janela é inconfiável

Solução: dividir o trabalho, que é a recomendação da própria doc. O modelo extrai e classifica, o código faz a aritmética

from datetime import date

PRAZOS_ANOS = {"nota fiscal de servico": 5, "contrato": 10, "log de acesso": 1}

def prazo_vencido(tipo, data_criacao, hoje=None):
    hoje = hoje or date.today()
    anos = PRAZOS_ANOS[tipo]
    return (hoje - data_criacao).days > anos * 365

Como prevenir: nenhuma pergunta enviada ao Jev deve conter a palavra "vencido", "antes de" ou "dentro do prazo". Se você escreveu isso na question, apaga e move pro Python

Sintoma: a contagem do lote não bate

Causa: o Jev 1.13 não conta de forma confiável, e isso inclui ocorrências de um termo num trecho e itens de uma lista longa

Solução: contagem é coisa de len(). Se você precisa saber quantos CPFs aparecem num documento, use regex ou um extrator; use o Noul só pra perguntar se existe dado pessoal, que é um julgamento, não uma contagem

Como prevenir: trate qualquer pergunta que comece com "quantos" como sinal vermelho na revisão de código

Sintoma: o documento convence o modelo a se preservar

Causa: o state é tratado como dado e o Jev 1.13 não o trata como hostil por padrão. Instrução injetada, enquadramento enganoso ou texto que argumenta pela própria classificação podem mover a resposta

Parece paranoia até você lembrar que arquivo corporativo é cheio de "DOCUMENTO CRÍTICO, NÃO EXCLUIR" colado no cabeçalho por alguém em 2017

Solução: critérios explícitos na pergunta e teste da integração antes de liberar, que é exatamente o que a doc orienta. Vale também separar no state o que é metadado confiável (vindo do seu sistema) do que é conteúdo bruto do arquivo

Como prevenir: esse cuidado com texto que tenta dirigir a decisão é o mesmo de qualquer pipeline que recebe material de fora, e ele aparece com força quando você usa o Jev para moderar conteúdo de usuários. Vale trazer a mesma disciplina pra cá

Rodando em lote sobre um volume grande

Até aqui a gente decidiu UM registro, e foi de propósito: primeiro você acerta a decisão em cima de um caso que consegue conferir com o olho, depois multiplica

Um registro é fácil. O diretório inteiro é onde o projeto vive ou morre

A boa notícia é que nada do que veio antes muda: a função avaliar_registro dos próximos passos é exatamente o state do passo 1 mais as perguntas dos passos 2 e 3, chamando client.system_one uma vez por registro

5. Uma chamada por registro, com todas as perguntas juntas

A unidade de trabalho é o registro, não a pergunta. Isso já está resolvido no passo 3, mas na hora do lote vira regra de arquitetura: o loop itera sobre registros, nunca sobre perguntas

O erro comum deste passo: montar fila por pergunta "pra paralelizar melhor". Você paraleliza e paga 12,2x mais, parabéns 😛

6. Subir o pool de workers devagar

A doc do cookbook de perguntas em paralelo é clara: oito workers concorrentes já bastam pra bater o rate limit numa chave compartilhada

Então comece baixo e vá medindo:

from concurrent.futures import ThreadPoolExecutor

WORKERS = 4  # sobe de pouco em pouco, medindo 429

with ThreadPoolExecutor(max_workers=WORKERS) as pool:
    resultados = list(pool.map(avaliar_registro, registros))

O erro comum deste passo: abrir com 64 threads porque "a máquina aguenta". A sua aguenta, o rate limit não

7. Tratar 429 como parte do fluxo normal

Os limites são medidos em tokens por segundo e requisições por minuto. Quem estoura recebe HTTP 429

A boa notícia: os SDKs oficiais já fazem retry com backoff, honrando o header retry-after quando ele existe. Se você está falando direto com a API, o endpoint é uma chamada POST única:

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

O erro comum deste passo: escrever retry próprio por cima do retry do SDK e dobrar a pressão em cima do limite

8. Respeitar os tetos de contexto quando o registro é grande

O orçamento de contexto é dividido em dois tetos: 64k tokens pra state mais todas as perguntas somadas, e 32k tokens pra state mais a pergunta mais longa

Na prática isso quer dizer que documento grandão não vai inteiro. Mande metadados estruturados e um trecho representativo, que é justamente o que o cuidado com context rot já pedia

O erro comum deste passo: olhar só o teto de 64k e esquecer do segundo. Sua pergunta mais verbosa é quem manda no limite apertado

9. Custo: contas antes do lote

O Jev cobra só por token de entrada, a US$ 0,042 por 1 milhão de tokens. Saída sai US$ 0,00

Isso muda o jeito de otimizar: você não ganha nada cortando o tamanho da resposta, ganha cortando state inchado. Que, de novo, é a mesma coisa que melhora a acurácia. Raro um trade-off alinhado assim 🙂

Roteando por confiança e registrando o motivo de cada escolha

Apagar arquivo é irreversível. Arquivar não é. Então os dois não podem ter o mesmo nível de exigência, e é aqui que entra o padrão de confidence-gated routing

A doc descreve três faixas: agir automaticamente, agir com cautela pedindo confirmação ou revisão, e mandar pra humano ou outro sistema. O threshold muda por ação, conforme a consequência do erro. A faixa sugerida usa piso de 0,6 e exige acima de 0,85 pra ações de alto impacto

10. Mapear cada destino na sua faixa

PISO = 0.6
ALTO_IMPACTO = 0.85

def rotear(destino):
    if destino.confidence < PISO:
        return "revisao_humana"
    if destino.selected == "apagar":
        return "executar" if destino.confidence > ALTO_IMPACTO else "revisao_humana"
    if destino.selected == "arquivar":
        return "executar"
    return "manter"

O erro comum deste passo: tratar esses números como verdade universal. A própria doc alerta que a banda não é garantia calibrada: os limites de produção devem sair de exemplos rotulados e do custo de decidir errado e de revisar

11. Persistir a trilha de auditoria

O Jev devolve saída tipada com probabilidades, sem prosa. Ou seja: o "motivo" que você vai mostrar pro auditor é montado pelo seu código, juntando o que veio do modelo com a regra que você aplicou

Grave tudo:

trilha = {
    "id_registro": state["id_registro"],
    "destino": destino.selected,
    "probabilidades": destino.probabilities,
    "confidence": destino.confidence,
    "prazo_vencido": prazo_vencido(state["tipo_documento"], criado_em),
    "regra_aplicada": "apagar exige confidence > 0.85",
    "acao": rotear(destino),
    "model": "jev-1.13.0",
    "avaliado_em": datetime.now(timezone.utc).isoformat(),
}

Repara no campo model: IDs versionados como jev-1.13.0 são aceitos direto, e fixar a versão na trilha é o que permite explicar, daqui a um ano, por que a decisão de hoje foi aquela

O erro comum deste passo: deixar jev-latest no registro de auditoria. Alias é ótimo pra desenvolver, péssimo pra dizer o que exatamente julgou aquele arquivo

Variações do padrão para outros cenários de retenção

O esqueleto acima aguenta um monte de variação. Três que valem o teste:

Classificação hierárquica pra mapear pastas. O cookbook de classificação hierárquica cobre dados organizados em hierarquias, incluindo taxonomias e hierarquias de filesystem, percorrendo a árvore até o nó folha, e aponta o Choice como a primitiva adequada. Se a sua política é organizada por categoria e subcategoria, você faz Choice de nível em nível em vez de um Choice gigante com quarenta opções

Recuo pra categoria mais ampla quando a confiança cai. O cookbook de classificação por confiança mostra esse padrão aplicado a relatórios anuais da SEC, com uma pergunta Choice por documento e 75 industry groups: quando a confiança é baixa, o sistema reporta a divisão mais ampla em vez da classe fina. Traduzindo pra retenção: em vez de mandar pro humano, você pode reportar só "não descartável" e seguir

Fila de revisão priorizada com Score. Se sobraram cinco mil itens pra revisão humana, um Score de risco ordena por onde começar. Essa mecânica de ordenar uma fila por nota é a mesma que aparece quando você usa o Jev para priorizar leads, só muda o que está sendo pontuado

E vale lembrar dos casos fortes que a documentação cita explicitamente: classificação, rotulagem, priorização e reranking de candidatos, esse último no esquema de recuperar com um algoritmo barato e pontuar relevância com o Jev. Se você quiser o panorama de como esse formato de modelo surgiu, o Simon Willison escreveu sobre o anúncio de 15/09/2026

Vídeo: contexto sobre IA no dia a dia

Pra quem quer começar do zero no universo de ferramentas de IA antes de meter a mão num pipeline desses, esse vídeo do canal mostra as visualizações interativas que o Claude ganhou dentro do chat, e como usar isso sem pagar nada

Próximo passo

A ideia central do post cabe numa linha: o modelo julga, o código calcula e executa

Prazo de retenção é aritmética de data, e a doc é explícita que isso não é terreno do Jev 1.13. Contagem é len(). Exclusão de arquivo é uma função sua, com log, com rollback quando dá, com dono

O que sobra pro Jev é o que ele faz bem: olhar um state enxuto e devolver uma decisão tipada com probabilidade e confidence, em lote, barato, no formato que seu software já consome

E o próximo passo concreto, antes de deixar qualquer exclusão rodar sozinha: monte um conjunto de exemplos rotulados da sua política, com o destino que o seu time daria pra cada um

Roda o pipeline em cima deles, compara, e só então define os thresholds de produção a partir do custo real de errar e do custo de revisar

Sem esse conjunto, qualquer número que você colocar no if é achismo

Até o próximo post!

Perguntas frequentes

O Jev consegue calcular se um documento passou do prazo de retenção baseado na data de criação?

Não confie nisso direto no modelo. O Jev 1.13 lê datas como texto, não como quantidade ordenada, então calcular distância entre datas ou checar se uma data caiu dentro de uma janela é inconfiável. O certo é extrair a data com o modelo e fazer a conta do prazo no seu código.

Dá pra usar o Jev pra contar quantos documentos de um lote têm um determinado marcador?

Não é recomendado. O Jev 1.13 não conta de forma confiável, isso inclui ocorrências de um termo num trecho e itens de uma lista longa. Contagem agregada desse tipo deve ficar no seu código, depois de já ter as classificações de cada registro.

Quanto custa rodar um lote grande de registros pela política de retenção no Jev?

A cobrança é só sobre token de entrada, US$ 0,042 por 1 milhão de tokens, e a saída sai a US$ 0,00. Como o preço é por entrada, agrupar as perguntas de um mesmo documento numa única chamada reduz bastante o custo total do lote.

É seguro colocar o conteúdo de um documento direto no state sem revisar antes?

O state é tratado como dado e o Jev 1.13 não trata ele como hostil por padrão. Isso quer dizer que instrução injetada, enquadramento enganoso ou texto que argumenta pela própria classificação pode mover a resposta, então o critério da pergunta precisa ser explícito e a integração precisa ser testada antes de ir pra produção.

Quantos workers eu posso rodar em paralelo pra processar muitos registros de uma vez?

Depende da chave, mas a documentação orienta subir o pool devagar. Em chave compartilhada, 8 workers concorrentes já são suficientes pra bater o rate limit, que é medido em tokens por segundo e requisições por minuto, com erro 429 pra quem estoura.

Qual a diferença entre usar Choice e Score pra decidir arquivar ou apagar um registro?

Choice serve pra escolher entre opções de um conjunto fechado, como manter, arquivar ou apagar, e devolve a opção mais uma probabilidade por opção com confidence. Score já avalia contra níveis ordenados e descritivos, então funciona melhor pra medir relevância operacional do documento, não pra decidir o destino final dele.




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