2

Como estou pensando em usar o Jev para orquestrar seis agentes no meu app de notícias

Landing do projeto: camaleao.dev. Tô tocando isso em público, postando avanço, número e tombo no X, no TikTok e no Instagram. Se quiser acompanhar de perto, é por lá.

O Camaleão é um app de notícias que muda de cara conforme o momento do dia. No busão você pega um resumo de três linhas, andando na rua vira áudio de uns 90 segundos, e antes de dormir é uma frase só e acabou. Pra isso funcionar, todo dia tem que coletar, agrupar, apurar, escrever, revisar e ranquear matéria, sem ninguém sentado olhando.

A primeira ideia que eu tive foi a preguiçosa: uma chamada de LLM bem grande, com as fontes dentro do prompt, devolvendo a matéria pronta em JSON. Desenhei e já não gostei. Quando isso quebra, você não faz ideia do que quebrou. O modelo inventou uma data, colou um parágrafo da fonte, estourou o formato, gastou o dobro, tanto faz: o que chega pra você é "deu ruim" e uma matéria perdida. Fora que eu ia ter que escolher um modelo bom o bastante pra fazer tudo, o que na prática é pagar modelo caro pra tarefa burra.

Aí virou uma redação, no sentido de redação de jornal mesmo. Cada função é um agente separado, com prompt, modelo e formato próprios, e se um cair os outros seguem.

Arquitetura do Camaleão: etapa do dia com triagem e agrupamento, redação por matéria com apurador, checagem, redator, revisor e os quatro agentes de interface, ranking por usuário e o loop de tempo real no app

O terceiro tipo de chamada

O que mudou minha cabeça foi parar de achar que só existem duas opções, ou código ou LLM.

O terceiro é o Jev, da TypeSafe, que eles chamam de System One. Ele não conversa e não escreve nada. Você manda um state e faz pergunta tipada em cima: escolhe uma dessas opções, dá uma nota de 0 a 4, sim ou não. A resposta volta com probabilidade e confiança junto.

Custa US$ 0,042 por milhão de token de entrada, saída é de graça, e responde em uns 100 ms. É barato e rápido o bastante pra mudar o que você se permite perguntar. Triagem de 500 itens por dia dá centavos. Ranquear o feed de mil usuários sai por uns 21 centavos de dólar por dia. Reordenar a fila depois que a pessoa descarta um card custa US$ 0,0001 e cabe dentro da animação do card saindo da tela.

Ele tem uns defeitos bem documentados e, sendo sincero, foi isso que me deixou tranquilo, porque dá pra desenhar em volta. É mais forte em inglês, então todo state que eu mando vai em inglês mesmo o app sendo em português. É ruim com número e data, então contagem, comparação e janela de tempo ficam no código. Perde precisão quando o state fica grande e cheio de coisa inútil, então cada pergunta leva o mínimo. E ele não trata o state como hostil, que é a parte que me tira o sono de verdade, já que o meu state é texto vindo da internet.

No fim sobrou uma regra que vale pro sistema inteiro: o código controla o fluxo, o LLM escreve, o Jev responde pergunta estreita, e quem junta as respostas é o código de novo.

A redação

A linha de produção de uma matéria ficou assim:

apurador → checagem → redator → revisor → agentes de interface → publicador
  (LLM)   (código+Jev)  (LLM)  (código+Jev)        (LLM)           (código)

O apurador lê todas as fontes daquele assunto e não escreve matéria nenhuma. Ele monta uma ficha de fatos em inglês, cada fato com o id da fonte e uma citação literal, mais onde as fontes se contradizem e o que ainda não se sabe. Separar apurar de escrever foi a decisão que mais rendeu aqui, porque é o que deixa verificar antes de redigir.

A checagem é a parte que eu mais gosto. O código confere se a citação existe literalmente na fonte que eu guardei, e confere se todo número, data e versão que aparecem no fato estão dentro da citação. Depois o Jev entra com um sim ou não de state mínimo, fato mais citação, uns 300 tokens: essa citação sustenta essa afirmação? Fato que não passa sai da ficha. Se sobrar pouco, a matéria é cancelada e paciência.

Ou seja, o que LLM erra mais (número e data) fica com o código, e o que o código não consegue fazer (essa citação sustenta isso de verdade?) sai por um centésimo de centavo.

O redator escreve a matéria canônica em português só a partir da ficha já verificada, marcando qual fato sustenta cada frase. O revisor pergunta pro Jev, parágrafo por parágrafo, se tudo ali tá nos fatos citados, enquanto o código checa número, tamanho e cópia de fonte, rejeitando qualquer trecho de mais de oito palavras igual ao original. Se falhar, volta uma vez pro redator com o motivo. Se falhar de novo, para tudo e vai pra revisão humana.

Depois disso a canônica abre em quatro agentes de interface que rodam em paralelo: resumo, roteiro de áudio, revista e digest. Eles são por layout e não por momento do dia, porque o usuário pode trocar o layout de cada momento nas configurações, e aí amarrar agente a momento seria amarrar conteúdo numa config que muda.

Cada um desses tem fallback escrito antes mesmo de existir. Resumo falhou, entra a linha fina. Revista falhou, entra a matéria completa. Áudio falhou, a matéria só não aparece na playlist do dia. Nada disso segura a publicação, e é essa a diferença prática entre ter seis agentes e ter uma chamada só: eu consigo perder um pedaço e seguir.

O que segura a publicação de propósito é revisão humana. Fato que acusa pessoa ou empresa com nome e sobrenome vai sempre pra um humano. Sai um e-mail com link assinado de aprovar ou rejeitar, sem painel nenhum por enquanto, e o que não foi revisado não publica. Falha fechada.

Última coisa dessa parte: nenhum modelo tá cravado. Cada agente é uma config versionada no repositório, com modelo principal, modelo reserva e suíte de avaliação, e a camada que chama modelo não sabe de fornecedor. O passo zero do projeto é rodar de três a cinco modelos por agente nas mesmas vinte pautas, medindo formato válido, aprovação na checagem, aprovação na revisão, custo e latência, mais um ranking cego feito por mim numa amostra. Ganha o mais barato que fica dentro da margem de qualidade. Meu chute é que os agentes vão terminar em fornecedores diferentes, e o desenho existe justamente pra isso não virar problema.

Ranquear é outro trabalho

Publicada a matéria, começa a segunda metade, que é decidir o que cada pessoa vê. Aqui o Jev faz quase tudo e o LLM não entra.

É uma chamada por usuário. O state é o perfil da pessoa mais as últimas dez leituras, e cada pergunta leva uma matéria candidata: nota de relevância de 0 a 4, já leu algo igual a isso, bate com o interesse X, bate com "lê a fundo sobre Y". O perfil vai em faixas com nome ("reads deeply: agents, open models", "discards fast: funding rounds") em vez de número, porque é o formato que o modelo lê melhor e, de quebra, é menos dado cru saindo do meu banco.

Aí o código pega essas probabilidades e mistura com frescor, diversidade de tópico e uns 10 a 15% de exploração, que tá ali pro feed não fechar em bolha e pra eu continuar aprendendo sobre a pessoa. Tudo fica logado com as probabilidades desde o primeiro dia, então lá na frente dá pra trocar os pesos que eu chutei por um combinador aprendido sem mexer no modelo.

Dentro do app, o Jev aparece em três lugares.

O primeiro é um feed que escuta. Quando chega um sinal forte (descarte com motivo, "menos disso", leitura até o fim, salvar), o servidor pergunta sobre os dez próximos candidatos se a pessoa quer aquilo agora e se aquilo parece com o que ela acabou de rejeitar, e a fila se reordena. O app mantém dois cards à frente, então a tela nunca fica esperando resposta. Se passar de 800 ms ou o serviço cair, uma regra em código rebaixa o tópico e a vida continua.

O segundo é o onboarding. A cada "leria isso? sim ou não", o modelo reavalia as manchetes que eu ainda não mostrei contra o perfil parcial, e a próxima manchete é a que estiver com probabilidade mais perto de 50%, que é onde eu ainda sei menos sobre a pessoa. Dá pra aprender com uns oito swipes o que levaria uns vinte, e custa menos de um centavo por pessoa.

O terceiro é o motivo visível. A faceta que mais pesou no ranking vira um chip no card ("porque você lê sobre agentes"), e tocar nele aplica "menos disso" naquela faceta específica, não no tópico inteiro. Isso só dá pra fazer porque a decisão já nasceu fatiada em perguntas, então eu sei qual pergunta puxou a matéria pra cima.

Onde eu decidi não usar

Foi essa lista que impediu o projeto de virar IA em tudo.

Detectar o momento do dia não passa por modelo nenhum. É regra no celular, com sensor ganhando de estado do sistema, que ganha de faixa de horário. Funciona offline, responde na hora, não sai do aparelho e segue uma prioridade que eu escrevi. Comportamento numérico de leitura, tipo velocidade de rolagem e tempo de pausa, é código. Nada que rode a cada scroll toca a rede. Número e data são código, sempre. E escrever texto continua sendo papel do LLM, porque o Jev não escreve uma linha.

O que ainda me preocupa

O benchmark nem rodou ainda, então tem bastante coisa em aberto. Três me incomodam mais.

A injeção pelo state é a que eu não sei resolver, só amenizar. O texto que eu mando pro modelo decidir vem de site de terceiro, e state curto com resposta tipada é higiene, não garantia.

Depender de um fornecedor só na camada de decisão também pesa. Tem circuit breaker, e se a TypeSafe cair o ranking continua rodando só com código, mas o app fica visivelmente mais burro naquele dia.

E tem o português. O modelo é mais forte em inglês, por isso a primeira versão só consome fonte em inglês e traduz o state. É limitação assumida, não resolvida.

O que vocês acham?

Isso tudo ainda tá no papel, então crítica agora vale bem mais do que daqui a três meses. Se você já rodou pipeline de agentes em produção, ou acha frágil checar fato com citação literal mais pergunta tipada, comenta aí. E se achar que a ideia inteira tá errada, melhor ainda.

Carregando publicação patrocinada...
1

Já pensou em usar RSS como input desse processo? Não ficou claro como captura as notícias exatamente, mas pela citação de robots.txt, imagino que seja com crawlers.

2

É RSS mesmo. Testei 108 feeds e APIs oficiais. O que mais pesa é se o feed traz o
texto completo ou não. Se traz, eu nem entro no site. Se vem só resumo ou título,
uso o feed pra achar a matéria e busco só aquela URL. Citei robots.txt porque tem
fonte que bloqueia, e tem umas que nem feed têm, tipo Anthropic e Meta AI, então
não tem jeito, tem que ficar de olho na página mesmo.

Tô pensando em escrever um post só sobre a coleta. Tem bastante coisa pra contar,
desde o levantamento das 108 fontes até termos de uso e paywall. Mas nesse projeto to tentando dar um foco diferente pra começar a documentar o processo antes mesmo de construir ou ter algo concreto em si. Valeu demais pelo comentário!
Tenho esse outro post que conta um pouco sobre o projeto e o motivo de eu estar fazendo ele:
https://www.tabnews.com.br/ticolls/vou-juntar-alguns-hypes-da-bolha-dev-e-coisas-que-quero-aprender-em-um-unico-projeto