\n\n\n\n Minha Escolha de Framework para Agentes: Construindo Além do PoC - AgntDev \n

Minha Escolha de Framework para Agentes: Construindo Além do PoC

📖 12 min read2,290 wordsUpdated Mar 31, 2026

Olá a todos, Leo aqui do agntdev.com! Hoje, quero falar sobre algo que tem martelado na minha cabeça nas últimas semanas, desde que coloquei a mão na massa com o último lote de frameworks de agentes. Especificamente, estou pensando no aspecto de “construção” – não apenas em construir um agente, mas como os construímos, e as implicações frequentemente negligenciadas de escolher uma abordagem fundamental em vez de outra. Já passamos da fase de “prova de conceito” com os agentes, e agora se trata de torná-los confiáveis, manuteníveis e realmente úteis.

O ângulo específico que estou explorando hoje é Os Custos Ocultos de Componentes de Agente Pré-fabricados: Por que Construir o Seu Pode Ser Mais Barato às Vezes.

Agora, sei o que alguns de vocês estão pensando: “Leo, você está falando sério? Acabamos de conseguir 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 eu iria querer construir o meu próprio?” E acredite em mim, eu me fiz essa mesma pergunta muitas vezes. Durante muito tempo, fui um seguidor devoto do mantra “use o framework”. Por que reinventar a roda, certo?

Minha perspectiva começou a mudar durante um projeto recente com um cliente. Estávamos construindo um agente de suporte interno para uma empresa de SaaS de médio porte. A ideia era simples: um agente que pudesse responder a perguntas comuns de clientes, vasculhando documentação, verificando status de bancos de dados e até escalando tickets quando necessário. Começamos com um dos populares frameworks de agente em Python – você conhece os que prometem que você terá um agente em minutos. E nos primeiros dias, parecia mágica.

Conectamos alguns componentes pré-fabricados para memória (uma integração com banco de dados vetorial), planejamento (uma cadeia básica de LLM) e execução de ferramentas (chamando algumas APIs internas). A demonstração parecia ótima. O cliente ficou impressionado. Abrimos uma kombucha comemorativa. Mas então veio o teste do mundo real.

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

Os problemas começaram de forma sutil. O agente ocasionalmente apresentava alucinações, o que é comum em LLMs, mas a forma como alucina era peculiar. Ele não estava apenas inventando coisas; estava afirmando com segurança fatos que eram quase corretos, mas um pouco errados, puxando de uma mistura do que parecia ser interações históricas e contexto atual. Começamos a investigar o componente de memória.

O módulo de memória desse framework em particular foi projetado para histórico de conversação de uso geral. Ele armazenava interações, as resumia e recuperava partes relevantes com base em similaridade semântica. Parece bom no papel, certo? Mas nosso agente precisava distinguir entre a consulta atual de um usuário, o contexto histórico do mesmo usuário e o conhecimento geral da documentação. O componente pré-fabricado estava tratando tudo como uma grande bolsa 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 incorporação, até tentamos pré-filtrar as entradas antes de chegarem à memória. Nada funcionou muito bem. O problema não era a *funcionalidade* do componente; era a *filosofia de design* dele não estar alinhada com nosso problema específico.

Eventualmente, percebemos que para obter o comportamento que precisávamos, teríamos que ou escrever uma camada elaborada em cima da memória pré-fabricada (o que parecia uma luta contra o framework) ou mergulhar fundo em seu código-fonte e modificá-lo (o que parecia se inscrever em um pesadelo de manutenção). É aqui que o “custo oculto” começou a se mostrar.

O Peso da Abstração: Quando a Generalidade Se Torna um Fardo

Frameworks, por sua natureza, buscam a generalidade. Eles querem atender a um público amplo com necessidades diversas. Isso significa que seus componentes são frequentemente projetados para serem flexíveis, configuráveis e um tanto opinativos sobre como as coisas *deveriam* funcionar. E para 80% dos casos de uso, isso é fantástico! Realmente acelera o desenvolvimento.

Mas e quanto aos outros 20%? E quando seu agente precisa de um tipo muito específico de memória que distingue entre contexto de conversa efêmero, preferências de usuário de longo prazo e conhecimento estático? Ou quando sua lógica de planejamento precisa estar intimamente integrada ao estado de um sistema externo complexo, em vez de apenas encadear chamadas de ferramentas genéricas?

É quando a abstração começa a pesar. Você não está apenas usando um componente; está herdando suas suposições, suas limitações e seus preconceitos inerentes. E tentar forçar um objeto quadrado em um buraco redondo, mesmo com muitos marteladas, geralmente leva a um objeto quebrado ou a um buraco deformado.

No nosso cenário do agente de suporte, o componente de memória pré-fabricado foi projetado para um fluxo conversacional onde todo o contexto histórico é mais ou menos igual. No entanto, nosso agente precisava priorizar uma consulta recente contra um banco de dados de FAQs, puxando o histórico de conversação apenas se a consulta fosse ambígua ou claramente referenciava uma interação anterior. O componente do framework simplesmente não foi construído para essa distinção sutil sem uma customização pesada.

Quando Construir Seu Próprio Faz Sentido: Controle e Clareza

Depois de muita deliberação (e algumas sessões de pizza até tarde da noite), decidimos descartar o módulo de memória pré-fabricado e implementar o nosso. Inicialmente, isso parecia um retrocesso, mas a clareza que trouxe foi imediata.

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

  1. Buffer de Conversa Efêmera: Uma fila duplamente encadeada simples para as últimas N interações da conversa atual. Limpado após X minutos de inatividade ou quando uma nova consulta distinta chega.
  2. Armazenamento de Perfil de Usuário: Um banco de dados leve (Redis, no nosso caso) armazenando preferências específicas do usuário, tickets recentes e perguntas frequentes para aquele usuário. Isso persiste entre sessões.
  3. Índice de Base de Conhecimento: Nosso banco de dados vetorial de escolha, especificamente para a documentação e FAQs.

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

  • Primeiro, tente corresponder a consulta diretamente contra a Base de Conhecimento.
  • Se não tiver confiança suficiente, verifique o Armazenamento de Perfil de Usuário para interações ou preferências passadas relevantes.
  • Como último recurso, ou para adicionar fluência conversational, puxe contexto do Buffer Efêmero.

Aqui está um esboço simplificado em Python de como nossa recuperação de memória personalizada pode parecer, apenas para lhe dar uma ideia:


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) # Buffer efêmero

 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. Priorizar 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 a correspondência for muito forte, talvez não precisemos de muito mais por enquanto
 if any(res["score"] > 0.8 for res in kb_results): 
 return context_chunks

 # 2. Verificar Perfil de Usuário para 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 histórico recente de conversa para fluência, mas prioridade mais baixa
 # Podemos resumir isso ou filtrá-lo para evitar ruído
 if self.conversation_history:
 # Abordagem simples: apenas adicionar as interações recentes. Mais avançado: LLM resumir ou filtrar.
 for item in list(self.conversation_history):
 context_chunks.append(f"{item['role']}: {item['content']}")

 return context_chunks

# Uso Exemplo (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 está funcionando.")
# memory.add_to_history("agent", "Qual modelo é?")
# context = memory.get_context("Como eu conserto a jambração 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. A depuração se tornou simples porque conhecíamos cada linha de código. Não estávamos adivinhando o que a “caixa preta” interna do framework estava fazendo.

Quando Componentes Pré-Fabricados Ainda Brilham: A Regra dos 80%

Agora, não estou dizendo para descartar todos os frameworks e componentes pré-fabricados. Longe disso! Para muitos, muitos projetos de agente, eles são absolutamente a escolha certa. Se as necessidades do seu agente estão bem alinhadas com as suposições do framework, você economizará uma quantidade tremenda de tempo.

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 e recuperação aumentada de geração (RAG) de um framework são perfeitos. Você obtém velocidade, padrões razoáveis e uma base bem testada.

Outra área onde os frameworks se destacam é na orquestração de ferramentas. Ter uma maneira padronizada de definir ferramentas, passar argumentos e lidar com suas saídas é extremamente valioso. Mesmo em nosso cenário de memória personalizada, ainda usamos o componente executor de ferramentas do framework, porque seu design atendeu perfeitamente às nossas necessidades. Não precisávamos reinventar como um LLM decide qual API chamar; só precisávamos fornecer o contexto correto para que essa decisão fosse tomada.

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

Lições Práticas para a Sua Próxima Construção de Agente

  1. Compreenda Profundamente o Problema Central do Seu Agente: Antes de olhar para frameworks, mapeie exatamente o que seu agente precisa fazer. Que tipo de informação ele precisa lembrar? Como ele toma decisões? Com quais sistemas externos ele interage? Quanto mais específico você puder ser, melhor.

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

    • Essa filosofia de design do componente está alinhada com os requisitos únicos do meu agente?
    • Quanta configuração ou adaptação eu precisaria fazer para fazê-lo se encaixar?
    • Quais são suas suposições subjacentes? (por exemplo, sua memória trata todo o contexto igualmente?)
    • Quão fácil é depurar se algo der errado dentro deste componente? Posso inspecionar facilmente seu estado interno?
  3. Não Tenha Medo de Misturar e Combinar: Você não precisa se comprometer totalmente com um framework ou criar tudo do zero. Você pode usar um framework por sua excelente orquestração de ferramentas, mas implementar sua própria memória personalizada. Ou usar seu módulo de planejamento, mas fornecer ferramentas personalizadas. A modularidade é sua amiga.

  4. Priorize Clareza em vez de Astúcia (Especialmente para a Lógica Central): Quando você está construindo um sistema que depende de um LLM para interpretar contexto e tomar decisões, a ambiguidade é sua inimiga. Se construir seu próprio componente lhe dá controle cristalino sobre a entrada para o LLM ou o estado do seu agente, essa clareza muitas vezes vale o tempo extra de desenvolvimento.

  5. Considere a Sobrecarga de Manutenção: Se você personalizar muito um componente pré-construído ou envolvê-lo em camadas de abstração, pode estar se inscrevendo para mais dores de cabeça de manutenção do que se tivesse construído do zero desde o início. Atualizações no framework subjacente podem quebrar sua lógica personalizada, levando a mais refatorações.

Minha jornada com o projeto do agente de suporte realmente reforçou a ideia de que “mais rápido” nem sempre é “mais barato” a longo prazo. Às vezes, levar tempo para construir uma parte central do seu sistema de agente, adaptada precisamente às suas necessidades únicas, economizará horas infinitas de depuração, frustração e eventual refatoração no futuro. Isso lhe dá propriedade e uma compreensão mais profunda do cérebro do seu agente.

Portanto, da próxima vez que você estiver iniciando um projeto de agente, pare antes de simplesmente pegar o componente pré-construído mais conveniente. Pense sobre o que realmente diferencia seu agente e considere se uma solução personalizada pode ser a escolha mais econômica no final. 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

Partner Projects

AgntlogAgntkitAgntapiAgntai
Scroll to Top