6 pontos por GN⁺ 2 시간 전 | Ainda não há comentários. | Compartilhar no WhatsApp
  • Desenvolvedores da Anthropic migraram, no último mês, 10 pacotes com dezenas a centenas de milhares de linhas usando Claude Fable 5, Claude Opus 4.8 e workflows dinâmicos; em vez de corrigir código individualmente, melhoraram o processo iterativo que gera o código
  • A migração Zig→Rust do Bun gerou 1 milhão de linhas em menos de 2 semanas e passou em 100% dos testes existentes antes do merge; um projeto Python→TypeScript moveu 165.000 linhas ao longo de um fim de semana, usando centenas de agentes, 8 gates de etapas e 3 revisões adversariais
  • Migrações em grande escala são adequadas para criar um loop de validação objetivo, pois o trabalho pode ser paralelizado, o código existente serve como especificação e resposta correta, e falhas de compilação/teste geram automaticamente a próxima fila de tarefas
  • O processo avança em etapas: preparar critérios de julgamento, criar rulebook, mapa de dependências e inventário de lacunas, fazer teste de estresse das regras, traduzir tudo, compilar, executar e comparar comportamento; erros recorrentes não são corrigidos arquivo por arquivo, mas sim por ajuste das regras superiores e regeneração
  • O custo ainda fica na casa de dezenas a centenas de milhares de dólares ou mais, mas é possível descartar branches fracassadas e tentar novamente; a migração do Bun consumiu cerca de US$ 165.000 a preços de API e resultou em menor uso de memória, binários 19% menores e melhoria de 2–5% em workloads reais

Melhorando o loop de geração, não o código

  • Migração de código com IA é a abordagem em que agentes movem uma base de código de produção para uma nova linguagem ou framework
    • Em vez de engenheiros traduzirem arquivos diretamente, eles escrevem regras de migração e loops de validação
    • Os agentes repetem tradução, compilação e testes até que o comportamento do novo código corresponda ao original
    • Projetos que antes levavam vários anos podem ser reduzidos para uma escala de semanas
  • Na Anthropic, Claude Fable 5, Claude Opus 4.8 e workflows dinâmicos foram usados para migrar, em um mês, 10 pacotes com dezenas a centenas de milhares de linhas de código
  • O princípio operacional central é não remendar diretamente o código gerado, mas corrigir o loop que criou esse código

Casos reais de migração

  • Migração Zig→Rust do Bun

    • Jarred Sumner migrou o Bun de Zig para Rust com Claude Code
    • Gerou 1 milhão de linhas de código em menos de 2 semanas
    • Antes do merge, passou em 100% da suíte de testes existente do Bun no CI
    • As 19 regressões encontradas depois do merge foram todas corrigidas
    • O port para Rust entrou no Claude Code em junho
    • O Bun tem mais de 10 milhões de downloads mensais e também é usado amplamente dentro do Claude Code
  • Migração Python→TypeScript

    • Mike Krieger migrou uma base de código Python para 165.000 linhas de TypeScript durante um fim de semana
    • Usou centenas de agentes, 8 gates de etapas e 3 revisões adversariais
    • Realizou uma verificação final de equivalência comparando a saída de todos os comandos com a versão original em Python
    • Repetiu o processo de descartar todo o resultado da migração e ajustar regras e workflow; adotou o resultado da terceira execução

Quando reavaliar uma migração de linguagem

  • Vale considerar uma migração se, desde o desenvolvimento inicial, o ambiente técnico mudou a ponto de compromissos antigos virarem limitações, abordagens melhores surgirem ou o ecossistema original encolher
  • Zig oferecia desempenho no nível de C e simplicidade, o que era adequado ao contexto inicial em que Bun era desenvolvido por uma pessoa só, mas essa simplicidade tinha trade-offs conhecidos
  • No passado, migrar de linguagem exigia interromper o roadmap e alocar recursos por vários trimestres
    • Podia ser necessário manter duas bases de código em paralelo por vários trimestres ou anos
    • Se a equivalência final de comportamento ficasse em 90%, o problema de manutenção poderia ser maior do que antes de começar
    • Agora existe a opção de apagar uma branch fracassada e executar novamente
  • Migrar 1 milhão de linhas já não exige necessariamente US$ 3 milhões a US$ 4 milhões em custo de engenharia ao longo de 4 anos, mas ainda pode custar de dezenas a centenas de milhares de dólares ou mais
    • A migração do Bun consumiu 5,9 bilhões de tokens de entrada não cacheados e 690 milhões de tokens de saída
    • A custo de API, o valor foi de cerca de US$ 165.000
    • No port de Mike, o trecho central usou 27 milhões de tokens
  • A justificativa de negócio para a migração já não precisa necessariamente ser existencial; um ano corrigindo bugs recorrentes de memória ou um único gargalo crônico pode bastar
  • Remoção do gargalo de build em Python

    • A ferramenta interna de Mike era entregue aos usuários como um único binário, mas criar binários por plataforma com a toolchain Python levava cerca de 8 minutos
    • Na matriz completa de build, era preciso esperar cerca de 30 minutos a cada release
    • Depois da migração para TypeScript, a compilação caiu para cerca de 2 segundos, a inicialização do binário ficou 6 vezes mais rápida e uma pipeline de distribuição separada foi descartada

Por que agentes de IA são adequados para migrações

  • Trabalho paralelo é possível
    • O código pode ser dividido em milhares de unidades independentes, como arquivos e crates, para vários agentes processarem ao mesmo tempo
  • O código existente funciona como uma especificação clara e abrangente
    • Também pode servir como referência central para criar instruções para agentes de tradução
  • A suíte de testes atua como juiz embutido
    • Se a validação é objetiva, o modelo pode iterar por dias com base na resposta correta, sem que humanos arbitrem qualidade continuamente
  • Falhas de compilação ou teste se tornam automaticamente próximos itens de trabalho, reduzindo a necessidade de escrever uma fila de tarefas separada
  • Consistência e tratamento de exceções podem ser incorporados ao loop
    • Revisores associam cada problema à regra violada
    • A forma de resolver uma exceção vira uma regra que todos os agentes passam a seguir
    • Em vez de divergências silenciosas de comportamento, violações de regras viram itens de trabalho explícitos
  • Fable e Opus 4.8 foram usados para delegar, coordenar e verificar o trabalho paralelo de subagentes, além de encontrar múltiplos caminhos até o objetivo
  • O uso de tokens foi otimizado com um padrão consultivo que combina vários níveis de modelos

Pré-requisito: julgar equivalência entre original e port

  • Antes de iniciar a migração, é necessário um juiz forte que avalie o código original e o código-alvo pelos mesmos critérios
    • Sem juiz, não há critério de sucesso nem condição de término
    • Testes que dependem de funções internas da linguagem original podem não rodar sem alterações no código-alvo
  • Classifique os testes existentes entre testes que podem ser expressos como chamadas externas e testes dependentes de implementação interna que não serão portados
  • Reescreva testes de comportamento externo como asserções que possam rodar tanto no original quanto no port
    • Um agente adversarial verifica se as asserções não foram enfraquecidas no processo de reescrita
  • Execute o juiz no código original para confirmar que passa e depois verifique se ele falha em código quebrado intencionalmente
  • Jarred tinha uma grande suíte de testes escrita em uma terceira linguagem, TypeScript
  • Mike criou um harness de equivalência com 7 cenários de uso reais e tratou toda mudança de comportamento como bug a ser corrigido

Etapa 1: rulebook, mapa de dependências e inventário de lacunas

  • Os artefatos de base não são uma simples tradução, mas uma lista de locais a refatorar, um rulebook de como traduzir e um mapa de dependências que define a ordem de trabalho
  • A ordem de criação importa
    • Primeiro é preciso definir os padrões do rulebook para então identificar, no inventário de lacunas, os itens que não podem ser tratados por esses padrões
    • O rulebook e o inventário de lacunas são validados juntos por auditoria conjunta
  • Rulebook

    • A forma do rulebook depende de o novo código preservar a estrutura antiga ou ser completamente redesenhado
    • Ao preservar a estrutura, como Jarred, o centro é uma tabela de correspondência entre tipos e expressões idiomáticas das linguagens, e os componentes difíceis de traduzir remetem ao inventário de lacunas
    • Ao redesenhar, como Mike, o rulebook funciona como documento de design
    • Jarred conversou com Claude para criar políticas para cada área ambígua e configurou 8 subagentes para revisar, cada um, uma das 8 categorias de erro esperadas
  • Mapa de dependências

    • Em migrações paralelas, é necessário entender dependências entre arquivos para decidir quais mover primeiro e quais agrupar no mesmo lote
    • Em código legado sem manifesto explícito e em bases C/C++, Python etc., as dependências precisam ser descobertas e mapeadas diretamente
    • Agentes do Claude Code podem gerar esse mapa em um loop que escreve e executa scripts determinísticos, revisa e corrige os resultados
    • Um exemplo generalizado está no prompt de mapa de dependências
  • Inventário de lacunas entre linguagens e revisor cético

    • O inventário de lacunas registra conhecimentos que existem implicitamente no código atual, mas precisam ser explicitados na linguagem-alvo
    • Em Zig→Rust, a principal lacuna era o modelo de gerenciamento de memória
    • Em Zig, o fato de o chamador precisar liberar um buffer pode existir apenas em comentários; mesmo se a liberação for esquecida, o código compila e o vazamento só aparece em execução
    • Em Rust, a propriedade é transferida para o chamador e a memória é liberada automaticamente; uso após move ou dupla liberação não compila
    • Em Python→TypeScript, interfaces e contratos eram a principal lacuna
    • Python não exige declarar o formato dos objetos recebidos nem dos valores retornados
    • Em TypeScript, é preciso escrever contratos de métodos, argumentos e formas de retorno para compilar
    • Jarred listou as lacunas antes da tradução, enquanto Mike traduziu primeiro e criou a lista durante a auditoria; ambos os enfoques podem ser usados conforme o projeto
    • Um exemplo generalizado está no prompt de criação de inventário de lacunas

Etapa 2: teste de estresse das regras

  • Antes da migração completa, faça uma pequena migração experimental para pressionar o rulebook e encontrar problemas
  • Jarred comparou três trabalhos de agentes
    • O primeiro agente traduziu 3 arquivos seguindo o rulebook
    • O segundo agente traduziu o mesmo escopo como se fosse um engenheiro Rust experiente
    • O terceiro agente escreveu novas regras de tradução com base nas diferenças entre os dois resultados
  • Esse processo encontrou 2 problemas graves antes que se espalhassem por todos os 1.448 arquivos
  • Essa abordagem só funciona em migrações que preservam a estrutura, nas quais é possível comparar linha a linha duas traduções do mesmo arquivo
  • Em redesenhos como o de Mike, revisores adversariais atacam o documento de design, e a validação deve vir de execuções end-to-end descartáveis
  • Todos os arquivos traduzidos no teste devem ser descartados; o objetivo é melhorar as regras, não avançar gradualmente no código
  • Um exemplo generalizado de tarefa está no prompt de teste de estresse

Etapa 3: tradução de todo o código

  • Todas as etapas seguintes usam um loop multiagente de implementar→revisar→corrigir
  • A implementação em massa pode ficar com modelos menores, enquanto a revisão fica com modelos maiores
    • Mike usou 12 subagentes Claude Sonnet ao paralelizar a migração central
  • A fila de trabalho é gerenciada mecanicamente
    • Um script de lote considera uma tarefa concluída pela existência, em disco, do arquivo traduzido
    • Os arquivos restantes são divididos em lotes para agentes de implementação
    • A cada execução, a fila é reconstruída a partir do estado do disco, permitindo retomar após interrupções por padrão
  • Se o agente processar pouco por excesso de cautela, pode-se instruí-lo de forma mais direta, contextualizando que o compilador vai capturar erros na próxima etapa
  • Itens que não puderam ser tratados com confiança são marcados como // TODO(port): <reason> e resolvidos na etapa 4
  • A lista de trabalho posterior é gerada automaticamente a partir de erros de compilação, falhas em smoke tests e falhas de testes
  • Revisão adversarial e atualização de regras

    • Dois revisores adversariais em contextos independentes avaliam o resultado da implementação; se discordarem, um terceiro agente decide
    • Quando o mesmo erro se repete em vários arquivos, os arquivos não são corrigidos individualmente
    • Adiciona-se uma frase ao rulebook e os lotes afetados são regenerados
    • O rulebook continua crescendo também durante a etapa de tradução, e código que contraria as regras não é remendado manualmente
  • Onde colocar o compilador

    • Se a compilação é rápida, ela pode ser incluída no loop de tradução
    • Mike executava a compilação TypeScript em todos os loops, pois cada unidade terminava em segundos
    • Se a compilação demora, deixe-a para a etapa seguinte
    • Jarred proibiu o uso do compilador no loop de tradução porque executar cargo levava minutos
    • A partir desta etapa, os prompts ficam mais curtos; um exemplo está no prompt de início de tradução

Etapas 4–6: compilar, executar e verificar equivalência de comportamento

  • As três etapas compartilham a mesma estrutura de loop, e quanto mais avançam, menos julgamento humano é necessário
  • Dependendo da linguagem e do tamanho do projeto, a etapa de compilação pode ser absorvida pela etapa de tradução completa
  • Etapa 4: compilação

    • Jarred configurou um script orquestrador para executar o compilador uma vez em todo o workspace
    • Agentes de correção processavam a lista de erros em paralelo, passavam por revisão adversarial e então repetiam o build
    • A revisão da lista de erros era usada para identificar problemas sistêmicos, não erros individuais
    • Depois de corrigir imports circulares permitidos pela compilação preguiçosa de Zig, surgiram milhares de erros de módulos Rust
    • A lógica para classificar quais dependências apagar, mover ou quais limites reestruturar foi adicionada ao loop
  • Etapa 5: execução e smoke tests

    • Crashes em smoke tests atuam como a mesma resposta mecanicamente correta das listas de erros de compilação
    • Em vez de tratar problemas individualmente, eles são agrupados por causa raiz e revisados por subagentes adversariais
  • Etapa 6: comparação de comportamento com o original

    • Divida o código que já passou por tradução, compilação e smoke tests, e execute a suíte de testes preparada na etapa preliminar tanto no original quanto no port
    • Agentes de correção analisam juntos os testes falhos e as duas bases de código, enquanto revisores adversariais verificam as correções
    • Restrinja a reconstrução do binário apenas ao daemon de build
    • Agentes de correção escrevem patches, e o daemon agrega os patches e faz uma única recompilação
    • Os testes afetados são reexecutados e os resultados retornados
    • O trabalho é serializado para impedir que vários agentes executem builds caros separadamente
    • Se a mesma falha se repete em vários testes, corrija a regra superior que criou o bug e regenere apenas os arquivos afetados por essa regra
  • Quando não há suíte de testes

    • Mike usou Claude para gerar um pequeno script que executava 7 cenários reais no código Python original e no novo port, comparando resultados
    • Para cada cenário com falha, designou um agente de correção separado e iterou até todos os 7 passarem
    • Claude também projetou uma suíte própria de testes end-to-end e a executou autonomamente durante a noite
    • O ciclo de corrigir erros e executar novamente se repetiu por quatro noites
    • A lista de cenários previamente escrita também encontrou pequenos problemas de usabilidade difíceis de prever
    • Mesmo sem testes existentes, Claude pode criar um juiz usando a base de código original como resposta correta

Princípios operacionais observados em execuções repetidas

  • Em vez de seguir o guia literalmente, planeje a migração com Claude conforme as características do projeto antes de começar
  • Deixe agentes de correção tratarem falhas individuais, enquanto humanos focam em padrões de erro recorrentes
  • Estruture revisão de forma adversarial e validação de forma mecânica
    • Revisão adversarial é útil em trabalhos longos e pode valer o consumo adicional de tokens
    • Use scripts como compilador, diff e suíte de testes como juízes finais
  • Não use o maior modelo em todas as tarefas
    • Modelos menores são úteis para paralelizar implementação em massa
    • O maior modelo deve se concentrar em revisão e na escrita de regras que outros agentes seguirão
  • O tempo humano deve ser investido antecipadamente no rulebook e nos testes de estresse; o restante é, em grande parte, trabalho de esvaziar filas
  • O estado de conclusão deve ser mecanicamente determinável, como “o arquivo de saída existe em disco”, e a fila deve permitir retomada

Resultados e limitações da migração do Bun

  • O port Rust do Bun está rodando em produção, mas cerca de 4% do código Rust fica dentro de blocos unsafe
    • A maior parte são operações de ponteiro de uma linha nas fronteiras C/C++
  • Todos os vazamentos de memória detectáveis por ferramentas foram corrigidos
    • Em um benchmark que repetia o build 2.000 vezes, o uso de memória caiu de 6.745 MB para 609 MB
  • O tamanho dos binários Linux e Windows diminuiu 19%
  • Otimizações entre linguagens melhoraram em 2–5% o desempenho de workloads reais, como serviços HTTP, next build e tsc
  • Em migrações grandes, é preciso revisar os resultados e padrões iterativos criados pelo loop, mais do que cada linha de código gerada

Materiais relacionados

Ainda não há comentários.

Ainda não há comentários.