Post

Modelos mais baratos e um harness robusto: construindo sistemas distribuídos em Rust com agentes de IA

Como a evolução dos LLMs permite usar modelos menores e mais baratos com um harness rigoroso para criar microsserviços de produção em Rust e Kubernetes.

Modelos mais baratos e um harness robusto: construindo sistemas distribuídos em Rust com agentes de IA

Nos primórdios dos agentes de programação autônomos, o senso comum da indústria parecia óbvio: para obter software de alto padrão, era obrigatório usar o maior e mais caro modelo de fronteira disponível. Engenheiros colocavam repositórios inteiros dentro de janelas de contexto gigantescas, torcendo para que a inteligência bruta do LLM deduzisse magicamente casos de borda distribuídos, concorrência complexa e manifestos de infraestrutura.

A realidade, porém, foi decepcionante. Modelos de fronteira sem restrições frequentemente alucinavam métodos de bibliotecas inexistentes, introduziam condições de corrida sutis, desviavam dos padrões arquiteturais do time e acumulavam faturas astronômicas de API em loops de depuração manuais.

Ao longo do último ano, contudo, uma transformação silenciosa aconteceu em duas frentes:

  1. Evolução dos Modelos de Custo Acessível: Modelos menores, ultrarrápidos e econômicos (como as categorias Flash e modelos compactos ajustados para instruções) tornaram-se extremamente competentes em chamadas de ferramentas (tool calling), saídas estruturadas e raciocínio pontual.
  2. A Consolidação do Harness Robusto: Percebemos que a qualidade de um software gerado por IA não decorre da contagem de parâmetros do LLM. Ela é uma propriedade emergente do ambiente, dos ciclos de feedback e dos verificadores determinísticos que limitam e direcionam o agente.

Ao combinar modelos rápidos e baratos com um harness de engenharia rigoroso e automatizado, é possível alcançar resultados idênticos ou superiores aos dos modelos de fronteira desregulados — gastando uma fração mínima em tokens e latência.

Para testar essa hipótese no limite prático, adotei uma abordagem AI-first para construir cinco arquiteturas distribuídas complexas inspiradas no Byte Byte Go:

Cada um desses sistemas foi construído sobre uma base padronizada via Microservices Template em Rust, executando no Kubernetes, com interfaces criadas via OpenDesign, validação estrita no SonarQube e pontuação de qualidade dos jobs do agente com o Jev (modelo System One da TypeSafe AI).

[!NOTE] Uma ressalva sobre velocidade e pragmatismo: Esses cinco projetos de referência foram desenvolvidos muito rapidamente como provas de conceito. Pela alta velocidade de implementação, eles certamente contêm bugs em casos de borda e pontos a serem aprimorados. Ainda assim, constituem uma prova incontestável de que a IA é extremamente útil para alavancar e apoiar o desenvolvimento de software no mundo real.

A seguir, compartilho os princípios e aprendizados práticos dessa jornada.


A Tese Central: O Harness Supera a Força Bruta

Em nossos artigos anteriores sobre Harness Engineering e Loop Engineering, definimos o harness do agente como a camada de fronteira: o runtime, as ferramentas, os sandboxes de execução e os sensores de verificação pelos quais o modelo interage com o código-fonte.

Quando você depende apenas da inteligência do modelo sem um harness bem projetado, você exige perfeição probabilística. Quando você envolve o agente em um harness robusto, o modelo precisa apenas gerar propostas localmente plausíveis. O harness se encarrega de capturar falhas de forma determinística, expor os erros do compilador, validar limites de segurança e guiar a autocorreção.

flowchart TD
    accTitle: Ciclo de verificação em um harness robusto
    accDescr: Um agente de IA usando um modelo barato propõe alterações em um template de microsserviço. O código passa por verificação do compilador Rust, análise estática no SonarQube, testes no Kubernetes e pontuação semântica com Jev antes de ser submetido à revisão humana.
    A["Especificação de Requisitos e Restrições"] --> B["Modelo Rápido / Barato (Geração de Proposta)"]
    B --> C["Scaffolding Padronizado (microservices-template)"]
    C --> D["Compilador Rust & Clippy (Oráculo de Tipos e Memória)"]
    D -- "Erros de Compilação" --> B
    D -- "Build com Sucesso" --> E["Quality Gate do SonarQube (Segurança e Code Smells)"]
    E -- "Quality Gate Reprovado" --> B
    E -- "Quality Gate Aprovado" --> F["Smoke Tests e Health Probes no Kubernetes (/healthz)"]
    F -- "Falha em Runtime" --> B
    F -- "Probes Saudáveis" --> G["Jev (TypeSafe AI) Avaliação Semântica de Qualidade"]
    G -- "Nota Abaixo do Threshold" --> B
    G -- "Nota Aprovada" --> H["PR Verificado Pronto para Revisão Humana"]

Essa arquitetura transfere a responsabilidade da corretude dos pesos neurais do modelo para uma esteira externa e determinística. Um modelo que custa US$ 0,10 por milhão de tokens consegue iterar com agilidade em cima dos erros do compilador até atingir um código matematicamente seguro, superando modelos caros de US$ 15,00 que falham silenciosamente em produção.


Pilar 1: Por que Rust é a Linguagem Perfeita para Agentes de IA

Muitos times optam por linguagens dinâmicas ou permissivas (como Python ou JavaScript) para assistentes de programação, acreditando que elas são “mais fáceis” para os modelos. Na prática, ocorre exatamente o oposto. Linguagens dinâmicas mascaram erros até o momento da execução, forçando o agente a decifrar stack traces imprecisos ou a lidar com debuggers complexos.

Rust é uma linguagem de sistemas estaticamente tipada, com semântica de posse (ownership), gerenciamento de memória sem garbage collector e um sistema expressivo de tipos algébricos. Para um agente de IA operando dentro de um harness, Rust é o parceiro ideal:

  1. O Compilador como Oráculo Determinístico: Se um código compila em Rust, classes inteiras de bugs distribuídos — como referências nulas (null pointers), condições de corrida em threads (data races), uso após liberação de memória (use-after-free) e variantes de enum não tratadas — deixam de existir matematicamente.
  2. Diagnósticos Acionáveis: O rustc e o cargo clippy não apenas apontam erros; eles fornecem explicações detalhadas sobre por que um borrow falhou e sugerem a correção exata (help: consider borrowing here: '&'). Modelos mais baratos leem esses diagnósticos estruturados e corrigem o código em uma ou duas iterações rápidas.
  3. Concorrência Segura por Construção: Implementar estruturas de dados lock-free, canais de comunicação com Tokio e I/O assíncrono em sistemas distribuídos requer extrema disciplina. Rust assegura thread safety em tempo de compilação por meio das traits Send e Sync.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Exemplo: Modelagem estrita de domínio no Encurtador de URLs
// Invariantes em tempo de compilação impedem estados inválidos de chegarem ao storage
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ShortUrl {
    id: UrlId,
    original_url: Url,
    created_at: DateTime<Utc>,
    expires_at: Option<DateTime<Utc>>,
}

impl ShortUrl {
    pub fn new(raw_url: &str, ttl: Option<Duration>) -> Result<Self, DomainError> {
        let original_url = Url::parse(raw_url).map_err(|_| DomainError::InvalidUrl)?;
        let created_at = Utc::now();
        let expires_at = ttl.map(|d| created_at + chrono::Duration::from_std(d).unwrap());

        Ok(Self {
            id: UrlId::generate(),
            original_url,
            created_at,
            expires_at,
        })
    }
}

Quando o agente propõe uma alteração na lógica de negócio, o sistema de tipos impede regressões invisíveis.


Pilar 2: Fundações Padronizadas com o microservices-template

Um agente colocado em um repositório vazio consome dezenas de milhares de tokens discutindo consigo mesmo sobre estrutura de pastas, bibliotecas de log e carregamento de variáveis de ambiente.

Para garantir produtividade imediata, cada serviço foi iniciado a partir do microservices-template. Esse template estabelece a arquitetura hexagonal (portas e adaptadores):

  • Domain Core: Entidades de domínio e regras de negócio puras, sem dependências externas.
  • Ports: Definição de traits para repositórios, mensageria, chamadas HTTP e cache.
  • Adapters: Implementações concretas (PostgreSQL via SQLx, Redis via redis-rs, Kafka via rdkafka, gRPC via Tonic e HTTP via Axum).
  • Observabilidade e Métricas: Telemetria estruturada em JSON com tracing, propagação de traces com OpenTelemetry e métricas para Prometheus expostas em /metrics.
  • Manifestos para Kubernetes: Builds multi-stage distroless em Dockerfile e manifests declarativos com Readiness e Liveness probes (/readyz, /healthz), ConfigMaps e limites de recursos.

Como a fundação já é previsível, o prompt enviado ao modelo econômico não precisa gastar contexto explicando como configurar logs ou conexões com bancos. O raciocínio do modelo fica 100% concentrado nas regras distribuídas da aplicação.


Pilar 3: Verificação Cloud-Native com Kubernetes

Um microsserviço que responde perfeitamente em localhost:8080 frequentemente quebra ao lidar com resolução de DNS interna de pods, injeção de secrets, escalonamento automático ou restrições de rede.

No nosso harness, o agente valida as soluções diretamente em clusters locais do Kubernetes (via kind):

  • Manifestos Declarativos: O agente gera e valida Deployments, Services, ConfigMaps e Horizontal Pod Autoscalers (HPAs).
  • Probes de Saúde e Prontidão: O harness consulta as rotas /healthz e /readyz para validar a sequência correta de inicialização e a tolerância a dependências indisponíveis.
  • Comunicação Inter-Serviços: Os serviços se comunicam por meio de domínios internos do CoreDNS (como http://storage-service.default.svc.cluster.local:8080), obrigando o agente a estruturar o roteamento de rede corretamente.

Pilar 4: Auditoria Estática Rigorosa com SonarQube

O fato de um código compilar em Rust não significa que ele esteja livre de duplicação excessiva, complexidade ciclomática elevada ou problemas de manutenibilidade futura.

Nosso harness integra o SonarQube como uma barreira de qualidade obrigatória. Assim que o código passa pelo cargo clippy e pelos testes unitários, uma análise estática é disparada. O agente só conclui a tarefa se atingir o Quality Gate configurado:

  • Zero Security Hotspots e Zero Vulnerabilidades de segurança.
  • Zero Bugs em caminhos estáticos de execução.
  • Densidade de Linhas Duplicadas estritamente inferior a 3%.
  • Classificação de Manutenibilidade A, mantendo funções curtas e modularizadas.

Se o SonarQube detectar uma função excessivamente complexa ou repetição desnecessária de código entre adaptadores, o harness envia a violação exata da regra para o agente efetuar a refatoração.


Pilar 5: Criação Rápida de Interfaces com OpenDesign

Sistemas distribuídos precisam de interfaces claras para administração e interação dos usuários. Em vez de delegar ao agente a invenção desordenada de CSS e componentes do zero, utilizamos o OpenDesign (integrado via Model Context Protocol).

O agente reúne os requisitos da tela, utiliza as ferramentas do OpenDesign para instanciar componentes coesos do design system e entrega frontends modernos, responsivos e acessíveis perfeitamente integrados às APIs em Rust. Isso elimina o distanciamento entre o contrato OpenAPI do backend e a tela do usuário.


Pilar 6: Avaliação Objetiva com o Jev (TypeSafe AI)

Um dos maiores desafios da engenharia com agentes de IA é avaliar se a entrega final está realmente pronta ou se apenas disfarçou erros. Pedir para outro LLM generativo fazer uma revisão costuma resultar em respostas elogiosas, prolixas e vagas (“O código está excelente e bem formatado!”).

Para contornar esse problema, integramos o Jev, o modelo pioneiro da categoria System One da TypeSafe AI. Diferente de modelos que geram parágrafos livres de texto, o Jev funciona como uma primitiva tipada de software: ele processa o contexto em linguagem natural, o diff do Git e o estado dos testes, retornando julgamentos tipados e probabilidades calibradas de sucesso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Integração conceitual do harness com o TypeSafe JEV
// Retorna notas tipadas e probabilidades em vez de texto opinativo
let evaluation = jev_client.evaluate_agent_run(AgentRunContext {
    specification_id: "SPEC-003",
    git_diff: &diff_summary,
    test_results: &test_run_output,
    sonarqube_metrics: &sonar_report,
}).await?;

if evaluation.adherence_to_spec.score < 0.85 {
    return Err(HarnessError::SpecDivergence(evaluation.adherence_to_spec.reason));
}

if evaluation.production_readiness.probability < 0.90 {
    return Err(HarnessError::ReadinessRisk(evaluation.production_readiness.factors));
}

Ao pontuar dimensões cruciais — como aderência aos requisitos funcionais, completude do tratamento de erros e ergonomia das APIs — o harness decide programaticamente se um pull request pode avançar ou se deve voltar para o agente com instruções precisas de correção.


O Campo de Testes: Cinco Sistemas Distribuídos do Byte Byte Go

Para colocar a metodologia à prova em cenários diversificados, implementamos cinco problemas clássicos de arquitetura inspirados no Byte Byte Go:

Projeto Principais Desafios de Arquitetura Validações Executadas pelo Harness
URL Shortener Codificação Base62 em alto throughput, geração de IDs distribuídos (Snowflake), cache em Redis e persistência em Cassandra/PostgreSQL. Testes de carga no rate limiter, benchmarks de redirecionamento abaixo de 2ms e proteção contra cache stampede.
Web Crawler Fila de rastreamento distribuída (crawl frontier), workers concorrentes com Tokio, parser de robots.txt com politeness delay e deduplicação com SimHash. Cumprimento de intervalos de requisição por domínio, testes de particionamento e backoff exponencial em HTTP 429/503.
Notification System Fan-out multicanal (E-mail, SMS, Notificações Push), filas com priorização, rate limiting por usuário e garantia de entrega idempotente. Deduplicação por chave de idempotência, tolerância a falhas na fila de mensagens e simulação de gateways externos.
OpenTube Pipeline assíncrono de transcodificação de vídeo em HLS, URLs pré-assinadas de object storage, simulação de cache em CDN e player reativo. Validação de checksum dos segmentos de vídeo (.ts), retomada de uploads em partes e integração de interface com OpenDesign.
Search Autocomplete Trie em memória com classificação de termos por frequência, cache top-K, atualizações dinâmicas e indexação por n-grams. Benchmarks de consulta de prefixos em sub-milissegundos, perfil de consumo de memória e concorrência sob locks de escrita.

Destaque Prático: A Trie de Autocompletar em Rust

No sistema de autocompletar buscas, o agente precisava implementar uma árvore Trie com suporte a leituras concorrentes em altíssima velocidade, enquanto uma fila assíncrona atualizava os rankings de frequência de buscas populares.

Um modelo mais barato, em sua primeira tentativa, tropeçou na semântica de Arc<RwLock<TrieNode>> do Rust, gerando erros de borrow checker ao tentar segurar referências através de pontos de suspensão assíncronos (await).

Como o harness devolveu o erro exato do compilador:

1
2
3
4
5
error[E0277]: `RwLockReadGuard<'_, TrieNode>` cannot be sent between threads safely
   --> src/trie/engine.rs:42:13
    |
42  |     tokio::spawn(async move {
    |     ^^^^^^^^^^^^ `RwLockReadGuard` cannot be sent across await boundaries

O modelo compreendeu instantaneamente que travar um std::sync::RwLockReadGuard durante um await bloquearia as threads do runtime do Tokio. Em uma única iteração subsequente, o agente reescreveu a rotina para copiar os resultados top-K antes de emitir a chamada de I/O, resolvendo o erro do compilador e garantindo a ausência de deadlocks assíncronos.

Sem um compilador rigoroso como sensor, um modelo de fronteira geraria uma implementação aparentemente bonita que travaria silenciosamente em produção sob carga concorrente.


Comparativo Econômico e de Eficiência

A comparação empírica entre o modelo tradicional focado apenas em inteligência de ponta e a abordagem orientada a harness demonstra vantagens indiscutíveis:

Dimensão Modelo de Fronteira (Sem Harness) Modelo Barato (Harness Fraco) Modelo Barato (Harness Robusto)
Custo por 1M Tokens de Entrada US$ 3,00 – US$ 15,00+ US$ 0,05 – US$ 0,20 US$ 0,05 – US$ 0,20
Custo por 1M Tokens de Saída US$ 15,00 – US$ 75,00+ US$ 0,20 – US$ 0,80 US$ 0,20 – US$ 0,80
Estratégia de Depuração Raciocínio discursivo prolixo Tentativa e erro às cegas Feedback determinístico de compilador e testes
Validação da Qualidade Autoavaliação do próprio modelo Fé / Revisão humana manual Compilador Rust + SonarQube + Jev
Desvio Arquitetural Alto (reinventa padrões a cada tarefa) Alto (código despadronizado) Baixo (ancorado pelo microservices-template)
Confiabilidade da Entrega Variável (alucinações com alta convicção) Muito baixa (quebras em runtime) Alta (matematicamente verificado e testado)

Ao utilizar modelos mais rápidos e acessíveis, podemos executar de 5 a 10 vezes mais iterações dentro do ciclo de autocorreção, mantendo o custo total de APIs mais de 80% inferior. A combinação de velocidade de iteração e verificação automatizada inflexível entrega um software final mais confiável do que a tentativa única de qualquer modelo de fronteira.


Como Implementar um Harness AI-First no Seu Time

Para aplicar essa metodologia nos projetos da sua equipe:

  1. Escolha um Compilador Rigoroso: Favoreça linguagens com sistemas de tipos estritos (Rust, Go com linters avançados ou TypeScript em modo strict). Deixe que o compilador assuma a responsabilidade primária de detecção de erros.
  2. Crie Templates de Fundação: Mantenha templates consistentes (como o nosso microservices-template) contendo métricas, logs estruturados, tratamento de erros e manifests de container pré-configurados.
  3. Automatize Barreiras Externas de Qualidade: Empregue SonarQube para análise estática de vulnerabilidades e code smells, clusters locais de Kubernetes para testes de infraestrutura e ferramentas visuais para inspeção de telas.
  4. Adote Modelos System One para Avaliação: Substitua avaliações conversacionais genéricas por julgamentos tipados e calibrados com o Jev. Meça aderência a especificações com números objetivos.
  5. Invista em Iteração Barata e Contínua: Direcione seus recursos para ciclos de feedback rápidos e econômicos. Permita que o agente depure proativamente até que todas as validações determinísticas fiquem verdes.

Conclusão

O futuro da engenharia de software na era da IA não depende de esperar por um modelo perfeito que nunca cometa deslizes. O verdadeiro diferencial está em criar sistemas de engenharia resilientes capazes de transformar modelos acessíveis, rápidos e imperfeitos em construtores de software extraordinários.

Embora esses projetos tenham sido construídos em um ritmo extremamente acelerado e certamente abriguem bugs e detalhes a polir, eles são uma demonstração indiscutível do poder da IA para ajudar de maneira prática e transformadora no desenvolvimento de software.

Integrando a clareza arquitetural do microservices-template, a disciplina do Rust, a orquestração do Kubernetes, a vigilância do SonarQube, o design com OpenDesign e a pontuação precisa do Jev, demonstramos que é possível construir sistemas distribuídos de nível industrial hoje mesmo, com eficiência e baixo custo.

Explore os repositórios, avalie os manifests do Kubernetes e clone os projetos no GitHub:

Esta postagem está licenciada sob CC BY 4.0 pelo autor.