Construí o Downshift porque mandar toda tarefa do agente de código para o modelo mais caro é pagar sênior para carimbar envelope. É um hook open-source: quando o Claude Code cria um subagente, ele lê a tarefa e escolhe o modelo. Renomear variável vai pro Haiku; desenhar algoritmo fica no Opus (README).
O difícil foi provar o valor que ele entrega. Meus primeiros números vieram de um dia de uso pessoal. Com um braço de controle e um conjunto de testes separado, o resultado foi mais modesto: em trabalho mecânico delegado, 12 de 12 tarefas passaram nos dois braços e o custo caiu 12%; em correções reais, o roteador rebaixou 3 de 34 subagentes e a diferença de custo não é dele (A/B de 15/10/2026).
A pergunta deixou de ser "qual modelo?" e virou "o que o código garante, e como provo?": o modelo pensa, o código governa, a avaliação prova. O texto reúne decisões e critérios para levar uma feature com LLM à produção. O Downshift é o caso real; o delivery, um exemplo didático. Meus harness e modelos estão neste post.
Índice: 1. Simples primeiro · 2. Provedor isolado · 3. Roteamento · 4. Prompt · 5. RAG · 6. Agentes · 7. Checklist
1. Comece pela solução mais simples
Antes de escolher um modelo, pergunte qual é a solução mais simples que atende aos requisitos de qualidade e segurança. Avance só quando a opção anterior não resolver.
Da esquerda para a direita: regras → classificador → LLM. Encerre o caminho assim que houver uma solução suficiente.
No Downshift, sinais determinísticos definem o tier, e um reforço local por hash FNV pode elevá-lo. O MiniLM externo saiu no PR #142. Um LLM classificador reconheceria vocabulário novo, mas acrescentaria custo e latência a cada spawn.
2. Isole o provedor e valide a saída
Adoto a distinção da Birgitta Böckeler: o harness combina guias, que orientam antes da ação, e sensores, que conferem depois. Teste e schema são sensores computacionais; juiz-LLM é inferencial, mais caro e menos determinístico.
O provedor fica atrás de um adaptador; seu código valida e decide o destino da falha:
package triage
import (
"encoding/json"
"errors"
"fmt"
)
type Triage struct {
Intent *string `json:"intent"`
NeedsHuman *bool `json:"needs_human"`
}
func Validate(raw []byte) (Triage, error) {
var result Triage
if err := json.Unmarshal(raw, &result); err != nil {
return Triage{}, err
}
if result.Intent == nil || result.NeedsHuman == nil {
return Triage{}, errors.New("required field missing")
}
switch *result.Intent {
case "status", "delay", "refund", "other":
return result, nil
default:
return Triage{}, fmt.Errorf("invalid intent: %q", *result.Intent)
}
}
-
Valide sempre. Modo JSON garante JSON válido, não o seu schema. Structured Outputs com
strictrestringe a saída ao schema suportado (OpenAI); o código ainda precisa tratar recusas e respostas incompletas e verificar o conteúdo. - Fixe o snapshot. Alias aponta pro snapshot mais novo e muda quando o provedor atualiza (Anthropic). Avalie antes de trocar e teste o fallback com os mesmos casos.
Guia e sensor. O schema no prompt é guia; a validação é sensor computacional, roda em toda chamada. Falha do roteador: o Downshift é fail-open: se o roteador quebra, o subagente roda com o modelo pedido. Essa escolha preserva a execução; autorização e limites de orçamento continuam obrigatórios no sistema que executa a tarefa. Trade-off: adaptador próprio com um ou dois provedores, gateway (LiteLLM, OpenRouter) quando vários times reinventarem retry e log.
3. Roteie por tarefa, com piso de risco
As regras do Downshift:
- Sem confiança, preserve o modelo solicitado: a abstenção evita uma troca sem evidência suficiente.
- Piso de risco: tarefa simples que toca auth, segredo, pagamento, PII ou concorrência sobe no mínimo pro tier intermediário (complexity-weights).
Números (benchmark/report.md):
- Rede de regressão, 200 tarefas: 69,0% de acerto de tier (IC 95% de 62,5% a 75,5%), 0 de 50 complexas no pequeno, 49 de 100 simples no intermediário: errar para cima foi escolha. É conjunto de ajuste, não prova generalização.
- Splits só de avaliação (#123): 53,0% (n=100) e 41,7% (n=120, cego). A maioria dos erros é abstenção; confiante, acerta 35 de 37 e 22 de 28.
- 40 tarefas Go com teste: com modelo fixo, 40/40 (fronteira), 31/40 (intermediário), 27/40 (pequeno). No tier escolhido pelo classificador, 37/40; era 38/40 e caiu de propósito quando o boost semântico parou de inflar prompt sem sinal (#125).
O hook pede, o harness decide. Reescrita observada no Claude Code e no Antigravity; inferida no Codex; não confirmada no Cursor; no KiroCrew o hook só bloqueia e pede retry (harness support).
4. Prompt é contrato, não pedido
Prompt bom diz o que entra, o que sai, o que é proibido e como saber se deu certo. Para conhecimento externo, avalie recuperação antes de fine-tuning. No estudo de Ovadia et al., RAG teve resultado superior para injeção de conhecimento nas condições avaliadas. Isso não estabelece uma regra para toda tarefa: recuperar fontes, ajustar comportamento e executar ferramentas resolvem necessidades diferentes.
Caso (post completo). "Audite a segurança" devolveu 23 alertas, 22 descartáveis. Reescrito como contrato:
- Achado sem arquivo:linha é descartado.
- CWE ou CVE inventado encerra a sessão.
- Denominador obrigatório: "1 de 174 rotas", não "achei um bug".
- Uma invariante falsificável por rodada: "toda rota que devolve pedido filtra pelo user_id da sessão?"
- Silêncio é resultado válido.
Resultado: 1 IDOR real em 174 rotas, corrigido antes de produção. No mesmo formato, dois reports meus de hardening viraram correção dos mantenedores: Formbricks (issue, PR) e Dub (issue, PR).
Guia e sensor. O contrato é guia; descartar achado sem arquivo:linha é sensor computacional.
5. RAG: consultar a base antes de responder
Pense em um atendente que consulta o manual da empresa antes de orientar o cliente. Ele precisa encontrar a regra certa e explicar como ela se aplica àquela situação.
RAG significa Retrieval-Augmented Generation, ou geração aumentada por recuperação. É um padrão de arquitetura que combina busca com geração de respostas. O sistema consulta uma base de conhecimento — manuais, políticas ou FAQs — e entrega os trechos encontrados ao modelo junto da pergunta. Isso fornece contexto sem treinar o modelo de novo (IBM, AWS).
Exemplo didático: um cliente pergunta sobre cancelamento no delivery. O sistema busca a política vigente na região dele e o modelo explica a regra, citando a fonte. Buscar a política de outra região produz uma orientação errada; mesmo com o trecho certo, o modelo pode distorcê-lo.
Para produto: quem mantém a fonte, quando a busca recebe uma atualização e quem pode consultar cada documento? Meça dúvidas resolvidas corretamente, tempo de resposta e custo por atendimento. RAG ajuda a responder com informação específica e verificável, mas não elimina erros (IBM).
Acima: preparar trechos → filtrar região, vigência e acesso → buscar → ordenar → responder com fontes. Abaixo: conferir a busca à esquerda e a resposta à direita.
Neste desenho, BM25 busca palavras; embeddings representam o texto em números para buscar por significado; RRF combina as listas; o reranker reordena os candidatos conforme a pergunta (Anthropic). São escolhas de implementação: RAG também pode usar busca por palavras, sem banco vetorial (Microsoft).
O reranker deste desenho avalia 20 candidatos. Se faltar evidência, diga que não sabe ou encaminhe a dúvida. Ajuste esse critério na validação; reserve perguntas inéditas, o holdout, para a medição final.
Duas avaliações, separadas:
- Busca: encontrou a informação certa? Hit rate@k mede se há ao menos um trecho relevante entre os k primeiros; recall@k mede quantos dos relevantes vieram; MRR considera a posição do primeiro acerto (IR book).
- Resposta: usou bem o que encontrou? Meça fidelidade às fontes (faithfulness), se a citação sustenta aquela frase e se o sistema admite quando falta informação, sem recusar perguntas que poderia responder (RAGAS).
Caso: um laboratório medido. Central de ajuda de um delivery fictício (25 seções com região e vigência), 44 perguntas rotuladas e 18 novas como holdout. Neste artigo, R@3 é a proporção de buscas que encontram ao menos um trecho relevante entre os três primeiros resultados. No holdout:
| Configuração | Embedding leve (R@3) | Embedding multilíngue (R@3) |
|---|---|---|
| Por palavras (BM25) | 0,69 | 0,69 |
| Por significado (embeddings) | 0,62 | 0,75 |
| Palavras + significado | 0,69 | 0,94 |
- O embedding decide se a híbrida vale: com o leve, ela não passou do BM25.
- Metadado decide o 1º lugar. SP e RJ têm políticas quase iguais; sem filtro de região, o acerto regional cai de 100% para 50%.
- Quase publiquei número inflado. Um glossário escrito olhando as falhas levou o recall@1 de 0,65 para 0,88 no ajuste, e no holdout só de 0,56 para 0,62. Overfitting, a mesma lição do Downshift: 69% no conjunto de ajuste, 53% no cego.
- Semelhança não garante resposta. O score de cosseno mede proximidade entre as representações dos textos. O limiar que recusa todas as sem resposta recusa 47% das respondíveis.
Geração, medida em 17/10/2026. Busca fixa, 62 perguntas, 174 casos por prompt, prompt ingênuo contra prompt de contrato. Gerador gemini-2.5-flash-lite, juiz gpt-4o-mini, ambos com ZDR.
- Citação correta, nos 112 casos avaliados para esse critério: 0/112 no ingênuo, 112/112 no contrato, sem ID inventado.
- Abstenção, nos 62 casos sem evidência: 59/62 (95,2%) nos dois prompts, com 0 recusa indevida nas perguntas respondíveis.
- A fidelidade às fontes não separou os prompts, por efeito teto. E o juiz concordou com o rótulo humano em só 78,8%: dos 9 "infiel" que ele marcou, 2 eram reais. Juiz sozinho é piso, não medida.
- Custo: US$ 0,03 por rodada.
Limites. Busca: amostra pequena (uma pergunta muda 6 pontos), sem reranker. Geração: corpus fictício, 1 gerador, 1 juiz, 1 rodada, busca não medida nesta rodada. As 62 perguntas e os 174 casos são unidades diferentes; os resultados de citação e abstenção usam subconjuntos próprios. Para reproduzir a rodada, ainda falta publicar a composição dos casos e o critério operacional de citação correta. Um ID existente, sozinho, não comprova que a fonte sustenta a afirmação.
Quando vale a complexidade? Comece com arquivos organizados e busca textual; para uma base pequena, o conteúdo direto no contexto pode bastar (Anthropic). Busca híbrida e reranking acrescentam preparação, manutenção, custo e latência. Adote quando as avaliações mostrarem ganho suficiente. Compare com as mesmas perguntas; mantenha vigência e controle de acesso em qualquer opção.
6. Agente precisa de parada, humano e segurança fora do prompt
Num workflow, o código decide o próximo passo; num agente, o modelo decide e chama tools em loop (Anthropic). Passo conhecido é código; agente só com ambiguidade real e parada explícita (passos, orçamento, timeout, humano).
Um jeito simples de explicar esse ciclo é o BDI. Aqui, ele é um recurso visual, não uma arquitetura que todo agente segue: crenças são o que o agente sabe sobre a situação; desejos, o que quer alcançar; intenções, o plano que escolheu. Quando a ferramenta responde, o agente atualiza o contexto e decide o próximo passo.
Em produção, esse ciclo precisa de permissão, schema, orçamento, aprovação humana conforme o risco e sensores.
Evite uma ferramenta genérica como execute_sql(query). A ferramenta deve obter o usuário da sessão, validar os argumentos e pedir aprovação humana para escritas de alto risco.
- Argumento passa por schema antes de executar.
- Escrita exige idempotência e, conforme o risco, humano (reembolso acima de R$ X).
- Segurança fora do prompt. "Não revele dados" no system prompt não é controle. Injeção pode vir indireta, num documento do RAG ou e-mail (OWASP LLM01). Autorização no código, segredo fora do contexto.
No Downshift, o hook lê a tarefa só em memória, não guarda prompt, e a telemetria registra o tipo de subagente sem o nome de agente customizado (#124).
Caso. O Agentic Code Review segue isso com sensores computacionais: IDOR alto ou segredo é BLOCK, o diff é dado não confiável e achado sem path:line não sai.
Trade-off. Aprovação frequente, sozinha, não justifica automatizar. Mova a decisão pro código quando houver uma regra verificável, cobertura das exceções e um destino definido para os casos que exigem julgamento humano.
7. Checklist antes de produção
HTTP 200 com resposta inventada é normal em LLM; qualidade se prova com casos fixos e checagem executável a cada troca. Juiz-LLM só onde não há checagem determinística, calibrado contra rótulo humano: ele tem viés de posição e verbosidade (Zheng et al.), e na seção 5 bateu com o humano em só 78,8%.
Checklist copiável: gist.
[ ] Existe uma versão sem LLM para o caso mais frequente?
[ ] Saída validada por schema; falha tem destino (subir modelo ou humano)
[ ] Snapshot do modelo fixado; fallback testado com os mesmos casos
[ ] Timeout, retry com backoff em 429/5xx, idempotência em toda escrita
[ ] Orçamento por chamada e por conversa; limite de passos no agente
[ ] Tools com menor privilégio; user_id da sessão; humano no irreversível
[ ] RAG: busca medida (hit rate@k, MRR) e geração medida (faithfulness, citação, abstenção), em holdout
[ ] Conjunto de avaliação roda num comando, no CI, antes de cada troca
[ ] Trace por execução: modelo, versão do prompt, tokens, latência, resultado
[ ] Métrica de produção: custo por tarefa resolvida, não por token
Da avaliação ao lançamento. Defina os limites antes de avaliar. Exemplo didático para um assistente de FAQ: nenhuma exposição indevida nos casos de segurança, pelo menos 95% de respostas corretas no conjunto acordado e latência p95 de até 5 segundos. Os valores dependem do produto e não foram validados neste laboratório. Regressão bloqueia o lançamento. Comece com uma parcela pequena do tráfego e compare qualidade, latência e custo por tarefa; se os limites forem violados, reverta modelo e prompt para a versão anterior. Quem opera o serviço precisa ser dono desse acompanhamento e do rollback.
Do protótipo ao produto, o que mudou não foi o modelo: foi dar a cada risco uma guia e um sensor, e medir. No RAG, a geração agora tem número; no Downshift, a economia em uso geral ainda não. Gaps abertos: medir busca e geração na mesma rodada, testar outro gerador e calibrar o juiz. A próxima experiência proposta compara geradores com as mesmas perguntas, busca e critérios, registrando qualidade, latência, falhas e custo por tarefa. Para testes de programação no OpenCode, pretendo experimentar MiMo-V2.6-Flash Free, Ling 3.1 Flash Free, Nemotron 3.5 Lightning Free e Big Pickle, conforme a disponibilidade em /models (OpenCode Zen). São candidatos a testar; os resultados acima continuam sendo do Gemini 2.5 Flash Lite como gerador e GPT-4o Mini como juiz.
Para os comentários: no sistema com LLM que você mantém, qual sensor diz que ele funciona? E se você já calibrou juiz-LLM contra rótulo humano, quanto deu a concordância?



Top comments (0)