\n\n\n\n A minha escolha de framework para agentes: Construir além do PoC - AgntDev \n

A minha escolha de framework para agentes: Construir além do PoC

📖 12 min read2,324 wordsUpdated Apr 5, 2026

Olá a todos, Leo aqui do agntdev.com! Hoje quero falar sobre algo que tem me intrigado nas últimas semanas, desde que comecei a trabalhar com o último lote de frameworks para agentes. Mais especificamente, estou pensando no aspecto da “construção” – não só na criação de um agente, mas como os construímos, e as implicações frequentemente negligenciadas de escolher um enfoque fundamental em vez de outro. Superamos a fase de “prova de conceito” com os agentes, e agora se trata de torná-los confiáveis, facilmente manuteníveis e realmente úteis.

O foco específico no qual me concentro hoje é Os Custos Ocultos dos Componentes de Agentes Prontos para Uso: Por Que Criar o Seu Próprio Pode Às Vezes Ser Menos Caro.

Agora, sei o que alguns de vocês estão pensando: “Leo, você está serio? Acabamos de obter todas essas ferramentas e frameworks incríveis que nos oferecem módulos de memória pré-construídos, componentes de planejamento e executores de ferramentas. Por que diabos eu deveria criar o meu?” E acreditem, eu me fiz exatamente essa pergunta muitas vezes. Durante muito tempo, fui um defensor convicto do mantra “use o framework”. Por que reinventar a roda, certo?

Minha perspectiva começou a mudar durante um projeto recente para um cliente. Estávamos construindo um agente de suporte interno para uma empresa SaaS de médio porte. A ideia era simples: um agente capaz de responder a perguntas comuns dos clientes explorando a documentação, verificando o status do banco de dados e até abrindo tickets se necessário. Começamos com um dos frameworks para agentes em Python mais populares – vocês sabem, aqueles que prometem um agente em poucos minutos. E nos primeiros dias, parecia magia.

Montamos alguns componentes pré-construídos para a memória (uma integração com um banco de dados vetorial), o planejamento (uma cadeia LLM básica) e a execução de ferramentas (chamando algumas APIs internas). A demonstração parecia incrível. O cliente ficou impressionado. Abrimos uma kombucha para comemorar. Mas então veio a fase de teste em condições reais.

A Ilusão da Velocidade: Quando “Início Rápido” se Torna “Depuração Lenta”

Os problemas começaram de forma sutil. O agente às vezes alucinado, o que é comum com os LLM, mas a forma como ele alucinava era peculiar. Não era justificável dizer qualquer coisa; ele enunciava fatos que eram quase corretos, mas ligeiramente errados, utilizando uma mistura de interações históricas e contexto atual. Começamos a examinar o componente de memória.

O módulo de memória desse framework em particular foi projetado para o histórico de conversas de uso geral. Ele registrava os turnos, os resumia e recuperava pedaços relevantes com base na similaridade semântica. Parece tudo bonito no papel, certo? Mas nosso agente precisava distinguir entre a solicitação atual de um usuário, o contexto histórico do mesmo usuário, e o conhecimento geral da documentação. O componente pré-construído tratava tudo como um grande saco de palavras.

Minha equipe passou dias tentando ajustar os parâmetros desse componente de memória “caixa-preta”. Mudamos os tamanhos dos pedaços, brincamos com diferentes modelos de integração, até tentamos pré-filtrar as entradas antes que chegassem à memória. Nada parecia funcionar. O problema não era a *funcionalidade* do componente; era a sua *filosofia de design* que não se alinhava com o nosso problema específico.

Finalmente percebemos que, para obter o comportamento de que precisávamos, teríamos que escrever um wrapper elaborado em torno da memória pré-construída (algo que parecia uma batalha contra o framework), ou nos aprofundar em seu código-fonte e modificá-lo (algo que parecia como se inscrever em um pesadelo de manutenção). É aqui que o “custo oculto” começou a se revelar.

O Peso do Abstrato: Quando a Generalidade Se Torna um Fardo

Os frameworks, por sua natureza, visam à generalidade. Eles querem servir a um vasto público com necessidades diversas. Isso significa que seus componentes são frequentemente projetados para serem flexíveis, configuráveis e um pouco teimosos sobre como as coisas *deveriam* funcionar. E para 80% dos casos de uso, isso é ótimo! Isso realmente acelera o desenvolvimento.

Mas e quanto ao restante 20%? O que fazer quando seu agente precisa de um tipo de memória muito específica que diferencia o contexto da conversa efêmera, as preferências do usuário a longo prazo e os conhecimentos estáticos? Ou quando sua lógica de planejamento precisa estar estritamente integrada ao estado de um sistema externo complexo, em vez de simplesmente entreter chamadas a ferramentas genéricas?

É aqui que a abstração começa a pesar. Você não está apenas usando um componente; você herda suas suposições, suas limitações e seus preconceitos intrínsecos. E tentar forçar um pedaço quadrado em um buraco redondo, mesmo batendo muito, geralmente resulta em um pedaço quebrado ou em um buraco malformado.

Na nossa situação com o agente de suporte, o componente de memória pré-construído foi projetado para um fluxo de conversa onde todo o contexto histórico é mais ou menos igual. No entanto, nosso agente precisava priorizar um novo pedido em relação a um banco de dados de FAQs, incorporando o histórico das conversas apenas se o pedido fosse ambíguo ou fizesse claramente referência a uma interação anterior. O componente do framework simplesmente não foi projetado para essa distinção sutil sem uma personalização pesada.

Quando Criar o Seu Próprio Faz Sentido: Controle e Clareza

Após muitas deliberações (e algumas noites de pizza tardias), decidimos abandonar o módulo de memória pré-construído e implementar o nosso. Isso inicialmente pareceu um retrocesso, mas a clareza que trouxe foi imediata.

Projetamos um sistema de memória especificamente para nossas necessidades:

  1. Elemento de conversa efêmera: Uma simples deque (fila de duas extremidades) para os últimos N turnos da conversa atual. Eliminada após X minutos de inatividade ou quando chega um novo pedido distinto.
  2. Armazenamento do perfil do usuário: Um banco de dados leve (Redis, no nosso caso) que armazena as preferências específicas do usuário, os tickets recentes e as perguntas frequentes para aquele usuário. Isso persiste entre as sessões.
  3. Índice da base de conhecimentos: Nossa loja vetorial de escolha, especificamente para a documentação e as FAQs.

A lógica de recuperação foi então personalizada:

  • Em primeiro lugar, tentar corresponder diretamente o pedido com a Base de Conhecimento.
  • Se a confiança não for suficiente, verificar o Armazenamento do Perfil do Usuário para interações passadas ou preferências relevantes.
  • Em última instância, ou para adicionar fluidez à conversa, derivar o contexto do Elemento Efêmero.

Abaixo está um esboço simplificado em Python de como poderia parecer nossa recuperação de memória personalizada, só para dar uma ideia:

“`html


class CustomAgentMemory:
 def __init__(self, user_id, knowledge_base_client, user_profile_store):
 self.user_id = user_id
 self.kb_client = knowledge_base_client
 self.profile_store = user_profile_store
 self.conversation_history = collections.deque(maxlen=10) # Elemento efimero

 def add_to_history(self, role, message):
 self.conversation_history.append({"role": role, "content": message})

 def get_context(self, current_query: str) -> list[str]:
 context_chunks = []

 # 1. Dar prioridade à Base de Conhecimento para respostas diretas
 kb_results = self.kb_client.search(current_query, top_k=3)
 if kb_results:
 context_chunks.extend([res["text"] for res in kb_results])
 # Se houver uma correspondência muito forte, talvez não precisemos de muitas outras informações por enquanto
 if any(res["score"] > 0.8 for res in kb_results): 
 return context_chunks

 # 2. Verificar o Perfil do Usuário para um contexto personalizado
 user_prefs = self.profile_store.get_user_preferences(self.user_id)
 if user_prefs:
 context_chunks.append(f"Preferências do usuário: {user_prefs}")
 
 recent_user_issues = self.profile_store.get_recent_issues(self.user_id, current_query)
 if recent_user_issues:
 context_chunks.extend(recent_user_issues)

 # 3. Adicionar o histórico de conversas recentes para fluidez, mas com prioridade mais baixa
 # Podemos resumir isso ou filtrar sua relevância para evitar ruído
 if self.conversation_history:
 # Abordagem simples: adicionar simplesmente as trocas recentes. Abordagem mais avançada: LLM resumir ou filtrar.
 for item in list(self.conversation_history):
 context_chunks.append(f"{item['role']}: {item['content']}")

 return context_chunks

# Exemplo de uso (simplificado por brevidade)
# kb_client = MyVectorDBClient()
# profile_store = MyRedisProfileStore()
# memory = CustomAgentMemory("user123", kb_client, profile_store)
# memory.add_to_history("user", "Minha impressora não funciona.")
# memory.add_to_history("agent", "Qual modelo é?")
# context = memory.get_context("Como resolver um atolamento de papel na minha HP OfficeJet 3000?")
# print(context)

Essa abordagem nos deu controle total. O LLM recebeu exatamente o contexto que queríamos, na ordem que desejávamos, com o nível certo de persistência. O debugging se tornou simples, pois conhecíamos cada linha de código. Não precisávamos adivinhar o que a caixa-preta interna do framework estava fazendo.

Quando os Componentes Prontos para Uso Se Destacam: A Regra dos 80%

Agora, não digo para jogar fora todos os frameworks e componentes pré-fabricados. Ao contrário! Para muitos, muitos projetos de agentes, são absolutamente a escolha certa. Se as necessidades do seu agente se alinham bem com as suposições do framework, você economizará um tempo considerável.

Por exemplo, se você está construindo um chatbot simples que só precisa responder a perguntas de uma única fonte de conhecimento e manter um fluxo conversacional básico, os componentes de memória pré-fabricados de um framework e de geração aumentada do recuperação (RAG) são perfeitos. Você obtém rapidez, valores padrão razoáveis e uma base bem testada.

Outro campo onde os frameworks se destacam é na orquestração de ferramentas. Ter uma maneira padronizada de definir ferramentas, passar argumentos e gerenciar suas saídas é de um valor inestimável. Mesmo no nosso cenário de memória personalizada, sempre usamos o componente de execução de ferramentas do framework, pois seu design atendia perfeitamente às nossas necessidades. Não precisávamos reinventar como um LLM decide qual API chamar; apenas precisávamos fornecer o contexto certo para ele tomar essa decisão.

A chave é entender os compromissos. É a clássica decisão “comprar versus construir”, mas com um toque de agente. Comprar (usar um componente pré-fabricado) lhe dá rapidez e muitas vezes um custo de desenvolvimento inicial mais baixo. Construir (criar o seu próprio) lhe dá controle, especificidade e muitas vezes custos de manutenção a longo prazo mais baixos para agentes altamente especializados.

Pontos de Ação para o Seu Próximo Projeto de Agente

  1. Compreender Profundamente o Problema Central do Seu Agente: Antes mesmo de olhar para os frameworks, defina exatamente o que seu agente precisa fazer. Que tipo de informações ele deve reter? Como toma decisões? Com quais sistemas externos ele interage? Quanto mais específico você for, melhor será.

  2. Avaliar os Componentes do Framework de Forma Crítica: Não escolha um framework simplesmente porque é popular. Para cada componente crítico (memória, planejamento, execução de ferramentas), pergunte-se:

    “`

    • A filosofia de design deste componente se alinha com as necessidades únicas do meu agente?
    • Quanta configuração ou encapsulamento terei que fazer para adaptá-lo?
    • Quais são suas suposições subjacentes? (por exemplo, sua memória trata todos os contextos da mesma forma?)
    • Qual é a facilidade de depuração se algo der errado neste componente? Posso inspecionar facilmente seu estado interno?
  3. Não Tema em Combinar: Não é necessário se comprometer completamente com um único framework ou criar tudo do zero. Você pode utilizar um framework por sua excelente orquestração de ferramentas, mas implementar sua memória personalizada. Ou usar seu módulo de agendamento, mas fornecer a ele ferramentas sob medida. A modularidade é sua aliada.

  4. Priorize a Clareza em vez da Habilidade (Especialmente para a Lógica Central): Ao construir um sistema que se baseia em um LLM para interpretar o contexto e tomar decisões, a ambiguidade é seu inimigo. Se a criação do seu componente lhe dá um controle perfeitamente claro sobre as entradas do LLM ou sobre o estado do seu agente, essa clareza frequentemente compensa o tempo de desenvolvimento adicional.

  5. Considere o Sobrecarga de Manutenção: Se você personaliza fortemente um componente pré-confeccionado ou o encapsula em camadas de abstração, pode acabar enfrentando mais dores de cabeça relacionadas à manutenção do que se o tivesse simplesmente construído do zero desde o começo. As atualizações do framework subjacente podem quebrar sua lógica personalizada, levando a mais refatorações.

Meu percurso com o projeto de agente de suporte realmente destacou a ideia de que “mais rápido” nem sempre é “mais barato” a longo prazo. Às vezes, reservar um tempo para construir de forma autônoma um elemento central do seu sistema de agente, perfeitamente adaptado às suas necessidades únicas, pode economizar horas de depuração, frustração e refatoração futura. Isso lhe dá um senso de propriedade e uma compreensão mais profunda do cérebro do seu agente.

Portanto, da próxima vez que você iniciar um projeto de agente, faça uma pausa antes de pegar cegamente o componente pré-confeccionado mais prático. Reflita sobre o que realmente diferencia seu agente e considere se uma solução personalizada pode, no final, ser a escolha mais econômica. Boa construção!

Artigos Relacionados

🕒 Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

Learn more →
Browse Topics: Agent Frameworks | Architecture | Dev Tools | Performance | Tutorials
Scroll to Top