- A estrutura central de um assistente de programação com IA não é uma mágica complexa, mas cerca de 200 linhas de código Python simples
- O sistema é baseado em um loop de conversa com o LLM; quando o LLM solicita uma chamada de ferramenta, o código local a executa e devolve o resultado
- As três ferramentas básicas necessárias são leitura de arquivo (
read), listagem de arquivos (list) e edição de arquivo (edit), o que permite explorar o projeto e modificar código
- Com base na assinatura e na descrição (docstring) das ferramentas, o LLM decide por conta própria qual ferramenta chamar e quando
- Essa estrutura é a mesma essência de produtos comerciais como o Claude Code, e mesmo uma estrutura simples pode implementar um agente de programação poderoso
Conceito básico de agente de programação
- Um agente de programação é um sistema baseado em conversa com um LLM que recebe comandos do usuário e realiza operações reais em arquivos por meio de chamadas de ferramentas
- O usuário digita uma solicitação como “crie um novo arquivo com uma função hello world”
- O LLM responde com as chamadas de ferramenta necessárias em formato JSON
- O programa executa a ferramenta e envia o resultado de volta ao LLM
- O LLM não acessa diretamente o sistema de arquivos; ele apenas faz solicitações, e o trabalho real é tratado pelo código local
As três ferramentas necessárias
- read_file: lê e retorna todo o conteúdo do arquivo especificado
- list_files: retorna a lista de arquivos e pastas em um diretório
- edit_file: substitui uma string existente por uma nova string ou, se
old_str estiver vazio, cria um novo arquivo
- Se a string a ser substituída não existir, retorna “old_str not found”
- Mesmo só com essas três ferramentas, já é possível criar, modificar e explorar arquivos
Registro das ferramentas e integração com o LLM
- Todas as ferramentas são registradas no TOOL_REGISTRY com nome e função, para que o LLM possa chamá-las
- A docstring e a assinatura de cada ferramenta são extraídas e enviadas ao LLM
- O prompt de sistema informa claramente ao LLM a “lista de ferramentas disponíveis” e o “formato de chamada”
- As chamadas de ferramenta ficam restritas ao formato
'tool: TOOL_NAME({JSON_ARGS})'
- Os resultados da execução das ferramentas são enviados ao LLM no formato
tool_result(...)
Parsing das chamadas de ferramenta e tratamento das respostas do LLM
- Nas respostas do LLM, procura-se por linhas que comecem com
tool: para extrair o nome da ferramenta e os argumentos (JSON)
- Após executar cada ferramenta, o resultado é serializado em JSON e adicionado ao histórico da conversa
- A função execute_llm_call chama a API do LLM e retorna o texto da resposta
- run_coding_agent_loop recebe a entrada do usuário e mantém o loop de conversa com o LLM
- O loop interno se repete até que o LLM não solicite mais chamadas de ferramenta
Exemplos de execução e possibilidades de expansão
- Exemplo de conversa:
- “Crie o arquivo hello.py e implemente hello world” → cria um novo arquivo com uma chamada a
edit_file
- “Adicione uma função que multiplica dois números em hello.py” → chama
read_file e depois edit_file
- É possível implementar um assistente de programação completo com cerca de 200 linhas de código
- Produtos comerciais acrescentam a isso tratamento de erros, respostas em streaming, gerenciamento de contexto, ferramentas adicionais e fluxo de aprovação
- A estrutura central continua a mesma: um loop simples em que o LLM decide e o código executa
Prática e expansão
- O código-fonte completo tem cerca de 200 linhas e pode ser expandido com troca por outro provedor de LLM ou adição de ferramentas
- Mesmo com uma estrutura simples, é possível implementar diretamente um protótipo poderoso de agente de programação com IA
1 comentários
Comentários do Hacker News
O que eu acrescentaria é planning
A chave para usar ferramentas de forma eficaz é perceber que elas operam sobre uma lista de TODOs dinâmica
O modo Plan serve para inicializar como essa lista é semeada e quando cada item é executado
A interação do usuário funciona como uma forma de reordenar essa lista
No mês passado, experimentei o quão bem o Claude Code resolve problemas de CTF, e quando desliguei a ferramenta TodoList e o planning, o desempenho caiu de 1 a 2 níveis
Para um vídeo relacionado, veja Breaking Bots: Cheating at Blue Team CTFs with AI Speed Runs
O interessante é que muita gente se concentra apenas em “usar ou não o modo plan”, mas a lista de TODOs está sempre ativa
Também acho engraçado ver textos que tratam “gerenciamento inteligente de contexto” como se fosse apenas um item de TODO
Muita gente acaba tentando implementar isso por conta própria e perde um ano por causa de resultados de avaliação que quebram em produção
Dá para adicionar isso simplesmente como tokens de reasoning, mas na prática é muito mais previsível e eficaz implementar como uma ferramenta explícita de armazenamento de chave única
Parece que essa abordagem simples também pode funcionar para outras ideias de ferramentas que armazenam estrutura de linguagem
Ao testar o Codex, eu passava uns 10 minutos organizando a especificação, dividindo em uma lista de mudanças, mandando salvar isso em um arquivo e depois instruindo a revisar e ajustar o plano após cada mudança
Isso permite que o LLM se concentre em tarefas curtas e orientadas a objetivos sem precisar de entrada contínua de prompt
Na prática, produz um efeito parecido com ter subagentes
Às vezes também coloco como último TODO: “revise todo o trabalho novamente e verifique a qualidade com linter etc.”
Durante a compressão de contexto, ela também é usada como uma representação concisa da sessão
O núcleo de um agente de código é, na verdade, uma simples estrutura de loop e chamadas de ferramentas
Mas se você vai escrever algo como “The Emperor Has No Clothes: How to Code Claude Code in 200 Lines of Code”, precisa mesmo consultar How to Build an Agent do Thorsten Ball
Foi esse texto que apresentou primeiro a ideia de que “a essência do agente é simples”
Claro que, na prática, são necessários TODOs e vários tipos de scaffolding, e o próprio Claude Code também tem configurações complexas, plugins e muitos recursos de UI
Ainda assim, só com o loop mínimo já dá para inicializar um processo que expanda as próprias funcionalidades
Se quiser ver o funcionamento interno, dá para usar claude-trace para rastrear a interação entre o LLM e as chamadas de ferramenta
Além do loop simples, há muitos elementos complexos, como encadeamento de UUID, processamento de fila de mensagens, snapshots de mudanças em arquivos e sidechains de subagentes
Então, “200 linhas” faz sentido conceitualmente, mas em nível real de produção é muito mais complexo
O Codex ainda não tem recurso de enfileiramento, mas continua poderoso
Eu criei um app para macOS chamado Contextify para monitorar em tempo real as transcrições de CLI do Claude Code e do Codex, e permitir consultar o histórico da conversa com o recurso Total Recall
Os modelos Claude são treinados com seu próprio schema de ferramenta str replace
Reescrever o arquivo inteiro é ineficiente, então o essencial é fazer edições parciais
Na prática, há mais elementos
Por exemplo, às vezes o agente entra em early stopping e encerra a tarefa antes da hora
Isso não se resolve nem com os modelos de reasoning mais recentes
O Claude Code contorna isso injetando TODOs em cada prompt para relembrar o trabalho restante
O repositório público do HolmesGPT tem vários benchmarks experimentais
No começo, foi chocante para mim a ideia de que “basta informar ao LLM a lista de ferramentas e o formato de chamada”
Eu pensava: como um LLM, que só gera texto, poderia chamar ferramentas? Mas quando percebi que era só isso, pareceu magia
Durante o feriado, tentei criar com o Opus um agente de código baseado em DSL de Prolog (passou de 200 linhas)
E, surpreendentemente, funcionou bem quase de imediato
Parece que os modelos da geração mais recente chegaram a um ponto em que a importância do harness do agente diminuiu
Para um experimento relacionado, veja este post
Há um ano, este texto era bem preciso, mas agora os harnesses evoluíram muito, então o modelo de loop simples já não explica bem o funcionamento real do Claude Code
Mesmo agentes simples, usando o mesmo modelo, não ficam tão atrás em desempenho
É parecido com um tutorial de “crie seu próprio banco de dados” mostrando o B-tree básico
Subagent, MCP e Skills ficam em um nível intermediário, e otimização de contexto só é realmente significativa em execuções longas
Eu mesmo construo diretamente loops de agentes para uso corporativo e processo mais de 1 bilhão de tokens por mês
O loop simples é o núcleo, mas em ambiente real inúmeros detalhes fazem a complexidade explodir
Por exemplo, como tratar o loop quando o usuário manda uma mensagem no meio, como sincronizar entradas por webhook de algo como Slack,
além de aprovação, guardrails, tratamento assíncrono de tasks etc.
Estou pensando em organizar essa experiência em um post de blog
Como leitura útil, há You Should Write An Agent e How To Build An Agent
Nossa equipe do SWE-bench publicou um agente open source de 100 linhas
É o mini-swe-agent, e ele é popular tanto na academia quanto na indústria
É um bom ponto de partida para aprender sobre o mundo dos agentes
Em 2023, houve um texto chamado “Reimplementando o LangChain em 100 linhas”
Vi esse texto, implementei de fato e usei em vários projetos