Abbiamo confrontato 5 RAG frameworks: LangChain, LangGraph, LlamaIndex, Haystack e DSPy, costruendo lo stesso workflow RAG agentic con componenti standardizzati: modelli identici (GPT-4.1-mini), embedding (BGE-small), retriever (Qdrant) e strumenti (ricerca web Tavily). Questo isola il vero overhead e l'efficienza dei token di ciascun framework.
Risultati del benchmark dei framework RAG
Il benchmark è consistito in 100 query, con ogni framework che ha eseguito l'intero set 100 volte per fornire medie stabili.
- Token medi: Totale dei token consumati in tutte le chiamate LLM (router, document grader, answer grader e generator), inclusi sia i prompt (con contesto recuperato) che le completions. Valori più bassi = costi API inferiori.
- Overhead del framework: Tempo di orchestrazione puro (ms), l'elaborazione interna del framework (logica di routing, gestione dello stato, ecc.), escludendo le chiamate LLM API e agli strumenti. Valori più bassi = framework più snello.
Tutte le implementazioni hanno raggiunto il 100% di accuratezza sul set di test. Sono stati utilizzati gli stessi modelli, temperature, provider di retrieval, strumento di ricerca web e un limite condiviso di token di contesto.
Principali risultati
- Concentriamoci sul controllo di ciò che è controllabile: Stessa famiglia di modelli e temperature, max_tokens a livello di nodo, retriever (Qdrant + BGE-small, k=5, normalizzazione attiva), provider web (solo Tavily), politica di routing (euristica + modello), ritorno anticipato della calcolatrice, limite condiviso di token di contesto, griglia di valutazione identica, strumentazione unificata. Questo riduce sostanzialmente i principali fattori di confusione nelle nostre misurazioni.
- L'overhead del framework è misurabile ma piccolo: Abbiamo osservato ~3–14 ms per query dalla logica di orchestrazione. Queste differenze sono reali, ma non sono la principale fonte dei gap di latenza >1 s; la maggior parte del tempo è spesa per l'I/O con modelli/strumenti esterni.
- Le prestazioni seguono i token (in queste condizioni): DSPy mostra l'overhead del framework più basso (~3,53 ms). Haystack (~5,9 ms) e LlamaIndex (~6 ms) seguono, mentre LangChain (~10 ms) e LangGraph (~14 ms) sono più alti. L'utilizzo dei token è più basso per Haystack (~1,57k), poi LlamaIndex (~1,60k); DSPy e LangGraph sono ~2,03k e LangChain ~2,40k.
- Il percorso di routing/strumento conta: Leggere variazioni nel routing iniziale (retriever vs web vs calcolatrice) e nel comportamento di fallback influenzano sia i token che il tempo, anche quando prompt e budget sono allineati.
Perché le differenze persistono? Il "DNA del framework"
Nonostante la standardizzazione, rimangono piccole variazioni nei conteggi dei token e nella latenza. Queste sono attribuibili ai comportamenti intrinseci e di basso livello di ciascun framework, il loro "DNA".
- Serialeizzazione di prompt e messaggi: Ogni framework incapsula lo stesso contenuto logico con una formattazione leggermente diversa prima di inviarlo all'LLM, creando delta di token piccoli ma costanti.
- Assemblaggio del contesto: L'ordinamento preciso e l'inclusione dei metadati all'interno del contesto concatenato possono differire leggermente da framework a framework, influenzando il conteggio finale dei token.
- Tie-break del routing: In casi borderline, sottili differenze nel modo in cui un framework analizza l'output JSON del router possono portare a una scelta iniziale dello strumento diversa.
In questa configurazione, l'impronta dei token sembra essere il principale motore, più del tempo di esecuzione del framework.
L'architettura RAG agentic condivisa
Per ottenere un confronto equo, tutte e cinque le implementazioni sono state costruite sullo stesso flusso di controllo:
- Router: Un nodo ibrido modello-ed euristica che sceglie retriever, web_search o calcolatrice.
- Recupera documenti: Recupera i primi 5 documenti da Qdrant utilizzando embedding BGE-small normalizzati.
- Valuta documenti: Un giudice LLM valuta la rilevanza del documento. Se irrilevante, attiva un fallback di ricerca web.
- Genera risposta: Utilizza un LLM con temperature=0.0 e un limite condiviso di token di contesto per generare una bozza di risposta.
- Valuta risposta: Un secondo giudice LLM valuta la bozza per groundedness, contraddizioni (allucinazioni) e completezza.
- Fallback e ritorno anticipato: Viene attivata una ricerca web se il grado della risposta è insufficiente. I risultati della calcolatrice, tuttavia, vengono restituiti direttamente, saltando i passaggi di generazione e valutazione.
Esempi di workflow
Scenario A — Colpo diretto dal database:
Scenario B — Un evento recente attiva lo strumento web:
Scenario C — La calcolatrice fornisce un ritorno anticipato:
Scenario D — Vector DB insufficiente, fallback alla ricerca web:
Metodologia dei framework RAG
Tutte e cinque le implementazioni hanno raggiunto il 100% di accuratezza sul nostro set di test di 100 query, corrispondendo alle risposte ground truth. Questo è stato il requisito fondamentale, garantendo che ogni framework potesse eseguire con successo lo stesso workflow RAG agentic prima di misurare le differenze di prestazioni.
1. Componenti principali e configurazione
Gli strumenti fondamentali sono stati standardizzati per eliminare le variabili di prestazioni alla fonte.
- LLMs:
- Modello: Tutti i nodi (router, generator, grader) hanno utilizzato il modello openai/gpt-4.1-mini tramite l'OpenRouter API.
- Determinismo: la temperatura è stata impostata su 0.0 per tutte le chiamate LLM per garantire la massima coerenza nel routing, nella generazione e nella valutazione.
- Limiti dei token: Sono stati impostati limiti rigorosi di max_tokens: 256 per il router e i graders, e 512 per il generator. Questo previene differenze di latenza causate da un framework che genera risposte eccessivamente lunghe.
- Modello di embedding e retrieval:
- Modello: Tutti i framework hanno utilizzato BAAI/bge-small-en-v1.5 da HuggingFace.
- Normalizzazione: Un passaggio critico per le prestazioni, normalize_embeddings è stato impostato su True in tutti e cinque i framework. (LangChain/LangGraph tramite encode_kwargs; LlamaIndex tramite normalize=True; Haystack tramite normalize_embeddings; retriever DSPy normalizzato.)
- Retrieval: Lo store vettoriale Qdrant è stato interrogato per un k=5 (primi 5 documenti) in tutte le implementazioni.
- Strumentazione:
- Ricerca web: Il benchmark è stato limitato a Tavily-only (max_results=3).
- Calcolatrice: Tutte e cinque le implementazioni hanno utilizzato la libreria sympy per l'analisi e la valutazione delle espressioni matematiche, garantendo capacità identiche.
2. Flusso di controllo e politica RAG
Il processo di "presa di decisioni" dell'agente è stato esplicitamente riflesso in tutti i casi.
- Logica di routing: Una strategia di routing ibrida è stata implementata in tutti e cinque gli script per bilanciare l'intelligenza del modello con regole deterministiche:
- Un heuristic_route basato su regex controlla prima i pattern ovvi della calcolatrice o della ricerca web (ad esempio simboli matematici, anni come "2024").
- Un router_node LLM prende poi la sua decisione.
- La decisione finale dà priorità all'euristica per le calcolatrici, altrimenti deferendo alla scelta dell'LLM.
- Budgeting del contesto: Questa è una delle standardizzazioni più critiche. Prima che il nodo generate_answer venga chiamato, tutto il contesto del documento recuperato e i risultati della ricerca web vengono concatenati e poi troncati a un limite condiviso di 2000 token utilizzando un'utilità comune truncate_to_token_budget. Questo garantisce che il generator LLM in ogni framework riceva un input delle stesse dimensioni esatte, impedendo a un singolo framework di essere avvantaggiato o svantaggiato dalla verbosità del suo contesto recuperato.
- Politica di valutazione della risposta:
- Griglia di valutazione permissiva: Il nodo grade_answer utilizza un prompt identico e permissivo in tutti i framework, istruendo il giudice LLM ad accettare risposte semanticamente simili e ragionevolmente complete.
- Gestione degli errori: La logica per la gestione di un fallimento del parse JSON dal grader è stata standardizzata. Se l'output del grader non è un JSON valido, il sistema passa a un grado permissivo (grounded=True, complete=True), imitando uno scenario reale in cui non si vorrebbe che un parser fragile fallisse una risposta altrimenti buona. I campi strutturati di DSPy restituiscono (nessun parse JSON), questo viene registrato come una differenza di robustezza, non come un vantaggio di prestazioni.
- Ritorno anticipato della calcolatrice: Come visto nel codice, una chiamata riuscita al calculator_node imposta direttamente final_answer e termina il workflow in anticipo. Questa è un'ottimizzazione significativa che viene applicata in modo coerente, impedendo al percorso della calcolatrice di invocare inutilmente i generator e grade_answer LLMs.
- Allineamento DSPy. Per mantenere l'equità con i baseline non-CoT, DSPy utilizza dspy.Predict (nessun CoT) per Router e AnswerGenerator. Le firme rispecchiano i contratti dei nodi degli altri framework; dove disponibili, i conteggi dei token utilizzano l'utilizzo riportato dal modello, altrimenti fallback tiktoken.
3. Strumentazione e metriche
Il processo di misurazione è stato identico, utilizzando utility e principi condivisi.
- Latenza: time.perf_counter() ad alta precisione è stato utilizzato per tutti i tempi. L'Overhead del Framework è calcolato in modo coerente come Latenza Totale – Latenza Chiamate Esterne.
- Tokenizzazione: Tutti i conteggi dei token per prompt e completions sono stati calcolati utilizzando tiktoken, la codifica cl100k_base, garantendo un'unica fonte di verità per le metriche dei token. La metrica "Token medi" riportata nei risultati rappresenta la somma cumulativa di tutti i token di input (prompt) e output (completion) per ogni chiamata LLM (ad esempio, router, graders, generator) all'interno di un singolo workflow di query.
- Gestione dello stato: Sebbene la sintassi di implementazione vari (TypedDict di LangGraph, classe di LlamaIndex, dizionario di LangChain), la struttura dello stato è funzionalmente identica. Ogni framework passa lo stesso insieme di chiavi (question, documents, web_results, ecc.) tra i nodi, garantendo che la logica del flusso di controllo operi sulle stesse informazioni.
Imponendo queste standardizzazioni rigorose a livello di codice, questo benchmark mira ad andare oltre i confronti superficiali e offrire un'analisi replicabile delle prestazioni del framework in una politica RAG fissa.
Interpretazione dei risultati:
- Puoi concludere: In questa configurazione specifica e altamente controllata, l'overhead di orchestrazione tende a essere minimo; le differenze sono guidate principalmente dai conteggi dei token e dai percorsi degli strumenti.
- In questa configurazione specifica e altamente controllata, l'overhead del framework è trascurabile.
- Le differenze di prestazioni sono state guidate dal conteggio dei token e dalle variazioni del percorso degli strumenti.
- Non puoi generalizzare: I risultati sono specifici di questa architettura, modelli, prompt, retriever e provider web; modificarli può alterare le classifiche.
Esperienza dello sviluppatore: un confronto qualitativo
Le prestazioni non sono l'unico fattore; quanto un framework si sente facile da costruire è ugualmente importante.
- LangGraph: Il grafo dichiarativo
Utilizza un paradigma first-graph. Definisci i nodi e li colleghi con gli edge (inclusi add_conditional_edges), quindi il flusso di controllo fa parte dell'architettura. Lo stato è tipizzato tramite un TypedDict con aggiornamenti in stile reducer (Annotated[…, add]).- Scegli LangGraph per: workflow complessi con più rami, retry e cicli; la sua struttura scala in robustezza e manutenibilità man mano che gli agenti crescono.
- LlamaIndex: Orchestrazione imperativa
Uno script procedurale in cui il flusso di controllo è un if/else Python standard; il "grafo" vive nel tuo codice. Lo stato è una classe PipelineState dedicata e il framework fornisce primitive di retrieval pulite (VectorStoreIndex → .as_retriever(k=5)).- Scegli LlamaIndex per: workflow leggibili in un singolo file in cui apprezzi una logica procedurale chiara e un facile debugging.
- LangChain: Imperativo con componenti dichiarativi
L'orchestrazione rimane uno script Python, ma i singoli compiti sono piccole catene componibili utilizzando l'operatore | (ad esempio, prompt | llm | parser). Lo stato è un dizionario Python flessibile e non tipizzato.- Scegli LangChain per: prototipazione rapida o team già nell'ecosistema LangChain che preferiscono comporre piccole unità dichiarative all'interno di un driver imperativo più ampio.
- Haystack: Basato su componenti, orchestrazione manuale Componenti tipizzati e riutilizzabili (@component) con I/O esplicito, mentre il flusso di controllo rimane Python semplice (if/else). Facile sostituire i backend LLM/retriever/web, oltre a strumentazione di primo livello per passaggio (tempo esterno vs framework).
- Scegli Haystack per: pipeline pronte per la produzione e testabili con contratti chiari e controllo granulare.
- DSPy: Programmi first-signature (meno righe di codice)
Definisci un compito tramite una signature (input/output + intento), quindi implementalo con Moduli che incapsulano il prompting e le chiamate LLM. Centralizza la gestione dei prompt/uso e rimuove il codice di collaudo; sostituire gli interni (ad esempio, Predict ↔ CoT) non cambia il contratto.- Scegli DSPy per: boilerplate minimo, flussi leggibili in un singolo file, sviluppo guidato dai contratti (con ottimizzatori opzionali).
Scambiare prestazioni ottimali per confrontabilità
- LangGraph potrebbe eccellere con le sue ottimizzazioni native del grafo quando gli è consentito utilizzare l'esecuzione parallela, la cache dello stato e il suo sistema di conditional edge per una logica di branching complessa.
- DSPy potrebbe mostrare risultati drasticamente diversi quando utilizza i suoi ottimizzatori di signature (come MIPROv2) e il prompting Chain-of-Thought, che possono migliorare significativamente la qualità della risposta.
- Haystack potrebbe sfruttare la sua cache pronta per la produzione, le funzionalità di batching e le ottimizzazioni a livello di componente che abbiamo disabilitato per equità.
- LlamaIndex potrebbe beneficiare delle sue strategie di indicizzazione avanzate, motori di query e capacità multi-modali che non sono state esercitate in questo benchmark.
- LangChain potrebbe brillare con il suo esteso ecosistema di strumenti e le ottimizzazioni LCEL (LangChain Expression Language) quando non vincolato al nostro set di strumenti standardizzato.
Il framework "migliore" dipende da ciò che si ottimizza: velocità di sviluppo, manutenibilità, prestazioni o modelli architetturali specifici.
Conclusione
In una pipeline RAG agentic strettamente abbinata, l'overhead di orchestrazione è solitamente una piccola fetta. Ciò che fa la differenza è quanti token elabori e quali strumenti invochi, entrambi plasmati da prompt, retrieval e routing. Il framework "giusto" dipende infine dallo stile di orchestrazione preferito dal tuo team: grafi dichiarativi (LangGraph), script imperativi (LlamaIndex), catene componibili (LangChain), componenti modulari (Haystack) o programmi first-signature (DSPy) che minimizzano il boilerplate.
Ulteriori letture
Esplora altri benchmark RAG, come:
- Modelli di Embedding: OpenAI vs Gemini vs Cohere
- Miglior Database Vettoriale per RAG: Qdrant vs Weaviate vs Pinecone
- Benchmark RAG agentic: routing multi-database e generazione di query
- RAG Ibrido: Aumentare l'accuratezza RAG
Cita questo benchmark
Scegli il formato adatto a dove pubblicherai. Incollare la versione con link nel tuo CMS preserva il backlink.
@misc{dilmegani2026,
author = {Dilmegani, Cem and Sarı, Ekrem},
title = {{RAG Frameworks: LangChain vs LangGraph vs LlamaIndex}},
year = {2026},
month = jun,
howpublished = {\url{https://aimultiple.com/rag-frameworks}},
note = {AIMultiple. Consultato il 3 Giugno 2026}
}
Sii il primo a commentare
Il tuo indirizzo email non verrà pubblicato. Tutti i campi sono obbligatori. I commenti vengono lasciati nella loro lingua originale.