Conclusão da Unidade 2
Na Unidade 1 o Alfred consultava uma base que nós mesmos inventamos. Agora ele consulta 23.152.022 processos do TJRJ, e os números que ele devolve abrem no sistema do Tribunal.
Entre uma coisa e outra, o agente não mudou.
O que mudou, exatamente
Vale reler a tabela da introdução agora que a unidade acabou, porque ela é o argumento inteiro do curso:
| Unidade 1 | Unidade 2 | |
|---|---|---|
| Modelo | qwen2:7b no Ollama local |
igual |
| Framework | smolagents, CodeAgent |
igual |
| Ciclo | Thought → Action → Observation | igual |
| Estrutura das Tools | Duas: listar assunto, buscar processo | igual |
| Controle de sigilo | Constante no código, nunca argumento | igual |
| Origem do dado | SQLite sintético | API Pública do DataJud |
| Linguagem de consulta | SQL parametrizado | Elasticsearch Query DSL |
| Dependências novas | — | nenhuma (urllib da biblioteca padrão) |
Três linhas de oito. Foi isso que separou um exercício de um agente que consulta o acervo nacional.
Esse é o ponto a levar para fora do curso: agente não é o dado. Quem entendeu o ciclo, entendeu-o para qualquer origem — e trocar a origem é trabalho de Tool, não de agente.
O que você tem agora
Um cliente de 30 linhas (cnj.py) que fala com o CNJ sem instalar nada, e que preserva o corpo do erro em vez de reduzi-lo a "HTTP 400". Foi essa decisão que transformou uma agregação quebrada numa aula sobre .keyword.
Duas Tools contra dado real (tools_cnj.py), com quatro cuidados que nenhuma delas precisa hoje e todas vão precisar amanhã: teto de sigilo, guarda antes da rede, limite de resultados e máscara aplicada no código.
Query DSL suficiente para o trabalho real: term contra match, bool/filter, range, sort, aggs, track_total_hits. E a noção de por que assuntos.nome e assuntos.nome.keyword são dois campos diferentes com o mesmo conteúdo.
Uma medição que vale como argumento em qualquer conversa sobre o tema: 100% do índice público do TJRJ é nivelSigilo 0, provado por dois caminhos independentes. Quem perguntar "esse agente aí vai ler processo sigiloso?" recebe um número, não uma opinião.
A lição desta unidade
A Unidade 1 terminou com duas frases sobre modelos. Esta termina com uma sobre Tools:
Num Code Agent, a Tool devolve objeto Python — e o erro de tipo não avisa.
Vale desdobrar, porque foi caro. Nas quatro execuções que este curso guardou, três deram errado:
-
A Tool devolvia
json.dumps([...]). O modelo escreveufor assunto in listar_assuntos(...), o laço percorreu caracteres, e cerca de 78 requisições foram ao CNJ perguntar por assuntos chamados'{','"','a'. Nenhuma exceção. Tempo de execução normal. Resultado vazio com aparência de resultado. -
Corrigido o tipo, a Tool passou a devolver
dict. O modelo escreveuprocessos.extend(processos_assunto), eextendsobre um dicionário percorre as chaves. A lista final ficou['assunto', 'quantidade_pedida', 'encontrados', ...]. De novo: nenhuma exceção. -
Corrigidos os tipos, as Tools passaram a funcionar — e o agente não parou. Obteve os seis processos no Step 3 e continuou andando até o
max_steps, gastando 175 segundos e 20 mil tokens no último passo para responder, em inglês, o que já tinha em mãos há três passos.
O padrão dos dois primeiros é o mesmo, e é ele que interessa: em Python quase tudo é iterável, e iterar a coisa errada raramente dá erro — dá um resultado. Num script comum você percebe na hora. Num agente, esse resultado vira Observation, entra no contexto e o modelo escreve o passo seguinte em cima dele.
Daí a regra prática que fecha a unidade: antes de acusar o modelo, confira o tipo que a sua Tool devolve. Nos dois episódios o raciocínio do qwen2:7b estava correto; o contrato da Tool é que estava mal escrito.
E o terceiro episódio acrescenta a outra metade: o CodeAgent só termina quando o código gerado chama final_answer. Modelos pequenos não chamam sozinhos com confiabilidade. Duas frases no pedido — chame final_answer, responda em português — levaram a mesma tarefa de 6 passos para 4, e do inglês para os dados estruturados que se pediu. Prompt orienta; max_steps garante.
O que ficou de fora, de propósito
O DataJud tem um campo que esta unidade nem tocou: movimentos[] — a lista completa de andamentos de cada processo, com código da TPU, nome e data e hora.
É o campo mais rico da API e o mais pesado. Um processo movimentado traz centenas de andamentos — o mais pesado que encontramos tem 613 —, e jogar isso inteiro numa Observation estoura o num_ctx do modelo em um único passo.
Fica como o primeiro exercício de quem quiser ir além agora:
Escreva uma terceira Tool,
ultimos_movimentos(numero_processo, quantidade=5), que busque um processo pelo número, ordenemovimentospordataHorae devolva só os últimos, cada um com nome e data já formatada.
Repare que o enunciado inteiro é sobre reduzir. É esse o ofício de quem escreve Tools para agente — e é o assunto da unidade seguinte.
O que vem pela frente
Unidade 3 — a Tool sai do script. Duas metades ligadas. Primeiro movimentos[] a sério: o problema geral de que ele é um exemplo é como fazer um agente trabalhar com mais texto do que cabe na janela. Depois, essas Tools deixam de morar dentro do seu programa e passam a ser um servidor MCP — o mesmo protocolo que o Claude e outros clientes falam, rodando na sua máquina, servindo o seu agente local.
Unidade 4 — o seu Agent. Você escolhe um tema da sua competência, adapta as Tools e testa localmente. É o projeto final, e é a razão de tudo até aqui.
E há um caminho que este curso não percorre, mas para o qual ele preparou você por inteiro.
A API do CNJ tem metadado público. O sistema do Tribunal tem tudo — nome das partes, peças, sentença — e tem os três níveis de sigilo, sem ninguém tendo filtrado antes.
Todo o código desta unidade vai para lá quase sem mudança: as duas Tools continuam duas, o teto de sigilo continua constante, a máscara continua no código. Muda a função consultar — de POST para SELECT — e muda o fato de que, do outro lado, a sua credencial é nominal e deixa rastro.
O capítulo Sigilo na origem foi escrito pensando nesse dia. Vale relê-lo antes de escrever a primeira consulta contra o banco do Tribunal.
Uma última observação sobre o que foi feito aqui.
Nenhum dado saiu da sua máquina além da consulta — um nome de assunto e um pedido de ordenação. O modelo é local, a chave é pública, a resposta é metadado público, e o conteúdo dos autos continua onde sempre esteve: no sistema do Tribunal, atrás da sua credencial.
Um agente que devolve ponteiros e deixa o acesso acontecer onde há trilha de auditoria não é uma limitação que aceitamos. É o desenho certo — e é o que torna possível mostrar isso a um colega sem precisar pedir desculpa por nada.
Até a Unidade 3.