Comparamos o desempenho de 5 frameworks RAG: LangChain, LangGraph, LlamaIndex, Haystack e DSPy, construindo o mesmo fluxo de trabalho RAG agentivo com componentes padronizados: modelos idênticos (GPT-4.1-mini), embeddings (BGE-small), retriever (Qdrant) e ferramentas (busca na web Tavily). Isso isola a sobrecarga real e a eficiência de tokens de cada framework.
Resultados de referência dos frameworks RAG
O teste de desempenho consistiu em 100 consultas, com cada framework executando o conjunto completo 100 vezes para fornecer médias estáveis.
- Tokens médios : Total de tokens consumidos em todas as chamadas LLM (roteador, avaliador de documentos, avaliador de respostas e gerador), incluindo prompts (com contexto recuperado) e conclusões. Quanto menor, menor o custo da API.
- Sobrecarga do framework : Tempo de orquestração pura (ms), o processamento interno do framework (lógica de roteamento, gerenciamento de estado, etc.), excluindo a API do LLM e chamadas de ferramentas. Menor = framework mais enxuto.
Todas as implementações alcançaram 100% de precisão no conjunto de testes. Foram utilizados os mesmos modelos, temperaturas, provedor de recuperação de dados, ferramenta de busca na web e um limite de tokens de contexto compartilhado.
Principais conclusões
- Nosso foco é controlar o que é controlável : mesma família de modelos e temperaturas, max_tokens em nível de nó, retriever (Qdrant + BGE-small, k=5, normalização ativada), provedor web (somente Tavily), política de roteamento (heurística + modelo), retorno antecipado da calculadora, limite de tokens de contexto compartilhado, rubrica de avaliação idêntica e instrumentação unificada. Isso reduz substancialmente os principais fatores de confusão em nossas medições.
- A sobrecarga do framework é mensurável, mas pequena : observamos um tempo de resposta de aproximadamente 3 a 14 ms por consulta proveniente da lógica de orquestração. Essas diferenças são reais, mas não são a principal fonte das lacunas de latência superiores a 1 segundo; a maior parte do tempo é gasto em operações de entrada/saída com modelos/ferramentas externas.
- O rastreamento de desempenho utiliza tokens (sob essas restrições) : o DSPy apresenta a menor sobrecarga de framework (~3,53 ms). Em seguida, vêm o Haystack (~5,9 ms) e o LlamaIndex (~6 ms), enquanto o LangChain (~10 ms) e o LangGraph (~14 ms) apresentam sobrecargas maiores. O uso de tokens é menor para o Haystack (~1,57 mil), seguido pelo LlamaIndex (~1,60 mil); o DSPy e o LangGraph registram ~2,03 mil tokens, e o LangChain, ~2,40 mil.
- Questões de roteamento/caminho da ferramenta : Pequenas alterações no roteamento inicial (recuperador vs. web vs. calculadora) e no comportamento de fallback afetam tanto os tokens quanto o tempo, mesmo quando os prompts e os orçamentos estão alinhados.
Por que as diferenças persistem? O “DNA da Estrutura”
Apesar da padronização, pequenas variações na contagem de tokens e na latência ainda persistem. Essas variações são atribuíveis aos comportamentos inerentes e de baixo nível de cada framework, ao seu "DNA".
- Serialização de prompts e mensagens: Cada framework encapsula o mesmo conteúdo lógico com formatação ligeiramente diferente antes de enviá-lo ao LLM, criando pequenas, porém consistentes, variações nos tokens.
- Montagem do contexto: A ordem e inclusão precisas dos metadados dentro do contexto concatenado podem variar ligeiramente de acordo com a estrutura, afetando a contagem final de tokens.
- Critérios de desempate de roteamento: Em casos limítrofes, diferenças sutis na forma como uma estrutura analisa a saída JSON do roteador podem levar a uma escolha inicial diferente da ferramenta.
Nessa configuração, o tamanho do token parece ser o principal fator determinante, mais do que o tempo de execução do framework.
A arquitetura RAG compartilhada e agencial
Para garantir uma comparação justa, todas as cinco implementações foram construídas com base no mesmo fluxo de controle:
- Roteador: Um nó híbrido, que combina modelo e heurística, e que escolhe entre o recuperador, a pesquisa na web ou a calculadora.
- Recuperar documentos: Obtém os 5 principais documentos de Qdrant usando embeddings BGE-small normalizados.
- Classificação de Documentos: Um avaliador do LLM analisa a relevância do documento. Se for irrelevante, o sistema realiza uma busca na internet como alternativa.
- Gerar resposta: Utiliza um LLM de temperatura=0,0 com um limite de token de contexto compartilhado para gerar uma resposta preliminar.
- Resposta da avaliação: Um segundo avaliador do LLM avalia a minuta quanto à fundamentação, contradições (alucinações) e completude.
- Recurso alternativo e retorno antecipado: Uma pesquisa na web é acionada se a nota da resposta for insuficiente. Os resultados da calculadora, no entanto, são retornados diretamente, ignorando as etapas de geração e avaliação.
Exemplos de fluxo de trabalho
Cenário A — Acesso direto do banco de dados:
Cenário B — Evento recente aciona ferramenta web:
Cenário C — A calculadora proporciona um retorno antecipado:
Cenário D — Banco de dados vetorial insuficiente, recorre à pesquisa na web:
Metodologia de estruturas RAG
Todas as cinco implementações alcançaram 100% de precisão em nosso conjunto de testes com 100 consultas, correspondendo às respostas reais. Esse era o requisito fundamental, garantindo que cada framework pudesse executar com sucesso o mesmo fluxo de trabalho RAG (Account-Request for Agency) antes de medirmos as diferenças de desempenho.
1. Componentes principais e configuração
As ferramentas fundamentais foram padronizadas para eliminar as variáveis de desempenho na origem.
- Mestrados em Direito (LLMs):
- Modelo: Todos os nós (roteador, gerador, avaliador) usaram o modelo openai/gpt-4.1-mini através da API OpenRouter.
- Determinismo: a temperatura foi definida como 0,0 para todas as chamadas LLM para garantir a máxima consistência no roteamento, geração e classificação.
- Limites de tokens: Foram aplicados limites rígidos para o número máximo de tokens (max_tokens): 256 para o roteador e os avaliadores, e 512 para o gerador. Isso evita diferenças de latência causadas por uma das estruturas que gera respostas excessivamente longas.
- Modelo de incorporação e recuperação:
- Modelo: Todas as estruturas utilizadas são BAAI/bge-small-en-v1.5 da HuggingFace.
- Normalização: Uma etapa crítica para o desempenho, o parâmetro `normalize_embeddings` foi definido como `True` em todas as cinco estruturas. (LangChain/LangGraph via `encode_kwargs`; LlamaIndex via `normalize=True`; Haystack via `normalize_embeddings`; recuperador DSPy normalizado.)
- Recuperação: O armazenamento de vetores Qdrant foi consultado para ak=5 (5 documentos principais) em todas as implementações.
- Ferramentas:
- Pesquisa na Web: O teste de desempenho foi restrito apenas ao Tavily (max_results=3).
- Calculadora: Todas as cinco implementações utilizaram a biblioteca sympy para análise e avaliação de expressões matemáticas, garantindo funcionalidades idênticas.
2. Fluxo de controle RAG e política
O processo de "tomada de decisão" do agente foi explicitamente reproduzido em todos os aspectos.
- Lógica de roteamento: Uma estratégia de roteamento híbrida foi implementada em todos os cinco scripts para equilibrar a inteligência do modelo com regras determinísticas:
- Uma rota heurística baseada em expressões regulares primeiro verifica padrões óbvios em calculadoras ou pesquisas na web (por exemplo, símbolos matemáticos, anos como "2024").
- Um nó roteador LLM então toma sua própria decisão.
- A decisão final prioriza a heurística para calculadoras, caso contrário, a decisão é tomada pelo especialista em Direito (LLM).
- Orçamento de contexto: Esta é uma das padronizações mais críticas. Antes da chamada do nó `generate_answer`, todo o contexto do documento recuperado e os resultados da pesquisa na web são concatenados e, em seguida , truncados para um limite comum de 2000 tokens usando um utilitário comum `truncate_to_token_budget`. Isso garante que o gerador LLM em cada framework receba uma entrada exatamente do mesmo tamanho, evitando que qualquer framework seja beneficiado ou prejudicado pela verbosidade do contexto recuperado.
- Política de avaliação das respostas:
- Critério flexível: O nó grade_answer usa um enunciado idêntico e flexível em todas as estruturas, instruindo o avaliador do LLM a aceitar respostas semanticamente semelhantes e razoavelmente completas.
- Tratamento de falhas: A lógica para lidar com uma análise JSON falha do avaliador foi padronizada. Se a saída do avaliador não for um JSON válido, o sistema assume uma nota permissiva (grounded=True, complete=True), simulando um cenário real onde não se deseja que um analisador frágil falhe em uma resposta que, de outra forma, seria válida. Os campos estruturados do DSPy retornam (nenhuma análise JSON), o que é registrado como uma diferença de robustez, não como uma vantagem de desempenho.
- Retorno antecipado da calculadora: Como pode ser visto no código, uma chamada bem-sucedida ao nó `calculator_node` define diretamente a resposta final (`final_answer`) e encerra o fluxo de trabalho antecipadamente. Essa é uma otimização significativa que é aplicada de forma consistente, impedindo que o caminho da calculadora invoque desnecessariamente as funções de lógica de linha de comando `generate` e `grade_answer`.
- Alinhamento com DSPy. Para manter a equidade com as linhas de base não-CoT, o DSPy usa dspy.Predict (sem CoT) para o Router e o AnswerGenerator. As assinaturas espelham os contratos de nó de outras estruturas; quando disponíveis, as contagens de tokens usam o uso relatado pelo modelo; caso contrário, usam o fallback do tiktoken.
3. Instrumentação e métricas
O processo de medição foi idêntico, utilizando ferramentas e princípios comuns.
- Latência: A função time.perf_counter() de alta precisão foi usada para todas as medições de tempo. A sobrecarga do framework é calculada consistentemente como Latência Total – Latência das Chamadas Externas.
- Tokenização: Todas as contagens de tokens para prompts e conclusões foram calculadas usando o tiktoken, com a codificação cl100k_base, garantindo uma única fonte de verdade para as métricas de tokens. A métrica "Média de Tokens" apresentada nos resultados representa a soma cumulativa de todos os tokens de entrada (prompt) e saída (conclusão) para cada chamada LLM (por exemplo, roteador, avaliadores, gerador) dentro de um único fluxo de trabalho de consulta.
- Gerenciamento de estado: Embora a sintaxe de implementação varie (TypedDict do LangGraph, classe do LlamaIndex, dicionário do LangChain), a estrutura de estado é funcionalmente idêntica. Cada framework passa o mesmo conjunto de chaves (pergunta, documentos, resultados da web, etc.) entre os nós, garantindo que a lógica de fluxo de controle opere com as mesmas informações.
Ao impor essas padronizações rigorosas em nível de código, este benchmark visa ir além de comparações superficiais e oferecer uma análise replicável do desempenho da estrutura sob uma política RAG fixa.
Interpretação dos resultados:
- Em conclusão, podemos afirmar que, nessa configuração específica e altamente controlada, a sobrecarga de orquestração tende a ser mínima; as diferenças são impulsionadas principalmente pela quantidade de tokens e pelos caminhos das ferramentas.
- Nessa configuração específica e altamente controlada, a sobrecarga do framework é insignificante.
- As diferenças de desempenho foram impulsionadas pela contagem de tokens e variações no percurso da ferramenta.
- Não é possível generalizar: os resultados são específicos para esta arquitetura, modelos, prompts, mecanismo de recuperação e provedor web; alterar esses elementos pode modificar as classificações.
Experiência do desenvolvedor: uma comparação qualitativa
O desempenho não é o único fator; a experiência de desenvolvimento com um framework é igualmente importante.
- LangGraph: O grafo declarativo
Utiliza um paradigma de grafo em primeiro lugar. Você define os nós e os conecta com arestas (incluindo add_conditional_edges), de modo que o fluxo de controle faz parte da arquitetura. O estado é tipado por meio de um TypedDict com atualizações no estilo de reducer (Annotated[…, add]).- Escolha o LangGraph para: fluxos de trabalho complexos com múltiplas ramificações, tentativas e ciclos; sua estrutura se torna mais robusta e fácil de manter à medida que o número de agentes aumenta.
- LlamaIndex: Orquestração imperativa
Um script procedural onde o fluxo de controle é o padrão if/else do Python; o "gráfico" reside no seu código. O estado é uma classe PipelineState dedicada, e o framework fornece primitivas de recuperação limpas (VectorStoreIndex → .as_retriever(k=5)).- Escolha o LlamaIndex para: fluxos de trabalho legíveis em arquivo único, onde você valoriza lógica procedural clara e depuração fácil.
- LangChain: Imperativo com componentes declarativos
A orquestração continua sendo um script Python, mas as tarefas individuais são pequenas cadeias composíveis usando o operador | (por exemplo, prompt | llm | parser). O estado é um dicionário Python flexível e sem tipos definidos.- Escolha o LangChain para: Prototipagem rápida ou equipes já integradas ao ecossistema LangChain que preferem compor pequenas unidades declarativas dentro de um driver imperativo maior.
- Haystack: Orquestração manual baseada em componentes. Componentes tipados e reutilizáveis (@component) com E/S explícita, enquanto o fluxo de controle permanece em Python puro (if/else). Fácil troca de backends LLM/retriever/web, além de instrumentação de primeira classe por etapa (tempo externo versus tempo de framework).
- Escolha a Haystack para: pipelines prontos para produção e testáveis, com contratos claros e controle preciso.
- DSPy: Programas que priorizam a assinatura (menos linhas de código)
Defina uma tarefa por meio de uma assinatura (entradas/saídas + intenção) e, em seguida, implemente-a com módulos que encapsulam o envio de prompts e as chamadas LLM. Isso centraliza o tratamento de prompts/uso e remove o código de integração; a troca de componentes internos (por exemplo, Predict ↔ CoT ) não altera o contrato.- Escolha o DSPy para: código repetitivo mínimo, fluxos de arquivo único legíveis, desenvolvimento orientado a contratos (com otimizadores opcionais).
Trocar desempenho ideal por comparabilidade
- O LangGraph pode se destacar com suas otimizações de grafo nativas quando permitido usar execução paralela, cache de estado e seu sistema de arestas condicionais para lógica de ramificação complexa.
- O DSPy pode apresentar resultados drasticamente diferentes ao usar seus otimizadores exclusivos (como o MIPROv2) e o recurso de prompt Chain-of-Thought, que pode melhorar significativamente a qualidade das respostas.
- O Haystack pode aproveitar seus recursos de cache e processamento em lote, prontos para produção, e otimizações em nível de componente, que desativamos para garantir a imparcialidade.
- O LlamaIndex poderia se beneficiar de suas estratégias avançadas de indexação, mecanismos de consulta e recursos multimodais que não foram utilizados neste teste comparativo.
- O LangChain pode se destacar com seu extenso ecossistema de ferramentas e otimizações LCEL (LangChain Expression Language) quando não estiver limitado ao nosso conjunto de ferramentas padronizado.
A "melhor" estrutura depende de se você está otimizando para: velocidade de desenvolvimento, facilidade de manutenção, desempenho ou padrões arquitetônicos específicos.
Conclusão
Em um pipeline RAG altamente otimizado, a sobrecarga de orquestração geralmente representa uma pequena parcela. O que realmente faz a diferença é a quantidade de tokens processados e as ferramentas invocadas, ambos influenciados por prompts, recuperação e roteamento. A estrutura "certa" depende, em última análise, do estilo de orquestração preferido da sua equipe: grafos declarativos (LangGraph), scripts imperativos (LlamaIndex), cadeias composáveis (LangChain), componentes modulares (Haystack) ou programas com assinatura inicial (DSPy) que minimizam o código repetitivo.
Leitura complementar
Explore outros benchmarks RAG, como:
- Modelos de incorporação: OpenAI vs Gemini vs Cohere
- Banco de dados de vetores principais para RAG: Qdrant vs Weaviate vs Pinecone
- Benchmark RAG agenic: roteamento em múltiplos bancos de dados e geração de consultas
- RAG Híbrido: Aumentando a Precisão do RAG
Seja o primeiro a comentar
Seu endereço de e-mail não será publicado. Todos os campos são obrigatórios.