Percée de décomposition de requête : DecomposeRAG gère les questions complexes 50% mieux

Les chercheurs d'UC Berkeley introduisent DecomposeRAG, un framework de décomposition de requête automatisé qui améliore significativement les réponses aux questions multi-sauts.

Auteur
Équipe de Recherche Ailog
Date de publication
Temps de lecture
4 min de lecture

Aperçu de la recherche

Le laboratoire NLP d'UC Berkeley a publié DecomposeRAG, un framework qui décompose automatiquement les requêtes complexes en sous-requêtes plus simples, atteignant des résultats state-of-the-art sur les benchmarks de QA multi-sauts.

Le problème

Les questions complexes nécessitent un raisonnement multi-sauts :

Exemple : "Quelle est la population de la capitale du pays où se trouve la Tour Eiffel ?"

Nécessite : Où se trouve la Tour Eiffel ? → France Quelle est la capitale de la France ? → Paris Quelle est la population de Paris ? → 2,1 millions

Le RAG traditionnel récupère du contexte pour la question complète, manquant souvent les étapes intermédiaires.

Approche DecomposeRAG

Décomposition automatique

Utilise GPT-4 pour décomposer les requêtes en sous-questions :

``python def decompose_query(complex_query): prompt = f"""Break this question into simple sub-questions that must be answered in order.

Question: {complex_query}

Sub-questions (in order): 1."""

response = gpt4.generate(prompt) sub_questions = parse_questions(response)

return sub_questions `

Récupération séquentielle

Répondre aux sous-questions dans l'ordre, en utilisant les réponses précédentes comme contexte :

`python def sequential_rag(sub_questions): context = ""

for i, sub_q in enumerate(sub_questions): Retrieve for this sub-question docs = retrieve(sub_q + " " + context, k=5)

Generate answer answer = llm.generate( query=sub_q, context=docs, previous_answers=context )

Add to cumulative context context += f"\nQ{i+1}: {sub_q}\nA{i+1}: {answer}\n"

return answer Answer to final sub-question `

Validation des réponses

Valide chaque réponse intermédiaire avant de continuer :

`python def validate_answer(question, answer, retrieved_docs): prompt = f"""Is this answer supported by the documents?

Question: {question} Answer: {answer}

Documents: {retrieved_docs}

Supported? (yes/no):"""

validation = llm.generate(prompt)

return "yes" in validation.lower() `

Si la validation échoue, réessayer avec plus de contexte ou une stratégie de récupération alternative.

Résultats de benchmark

Testé sur quatre datasets de QA multi-sauts :

| Dataset | RAG Baseline | DecomposeRAG | Amélioration | |---------|--------------|--------------|-------------| | HotpotQA | 45.3% | 68.7% | +51.7% | | 2WikiMultihopQA | 38.2% | 57.9% | +51.6% | | MuSiQue | 32.1% | 49.8% | +55.1% | | IIRC | 41.7% | 62.3% | +49.4% |

Amélioration moyenne : +52%

Comparaison avec d'autres méthodes

| Méthode | F1 moy | Coût (relatif) | |--------|--------|-----------------| | RAG Standard | 39.3% | 1x | | Chain-of-Thought | 43.8% | 2x | | ReACT | 48.2% | 3x | | DecomposeRAG | 59.7% | 2.5x |

DecomposeRAG atteint la meilleure précision à un coût modéré.

Insights clés

Quand la décomposition aide

L'efficacité varie selon la complexité de la requête :

| Sauts | Baseline | DecomposeRAG | Gain | |------|----------|--------------|------| | 1 (simple) | 68.2% | 69.1% | +1.3% | | 2 (moyen) | 51.3% | 67.4% | +31.4% | | 3 (complexe) | 28.7% | 52.3% | +82.2% | | 4+ (très complexe) | 15.2% | 38.9% | +156.3% |

Constat : Plus de sauts = gains plus importants de la décomposition.

Qualité de la décomposition

Analyse de la qualité des décompositions générées par LLM : • Décomposition correcte : 87.3% • Étapes manquantes : 8.2% • Ordre incorrect : 3.1% • Logique circulaire : 1.4%

Même des décompositions imparfaites améliorent les résultats.

Analyse d'erreurs

Où DecomposeRAG échoue-t-il ? Erreurs de décomposition (23%) : Mauvaises sous-questions Échecs de récupération (34%) : Impossible de trouver des docs pertinents pour la sous-question Erreurs de réponse (28%) : Mauvaise réponse intermédiaire qui se propage Échecs d'intégration (15%) : Impossible de combiner les sous-réponses

Le plus courant : La récupération échoue toujours pour les sous-questions.

Implémentation

Version basique

`python class DecomposeRAG: def __init__(self, retriever, llm): self.retriever = retriever self.llm = llm

async def query(self, complex_question): Step 1: Decompose sub_questions = await self.decompose(complex_question)

Step 2: Sequential RAG context = "" for sub_q in sub_questions: Retrieve docs = await self.retriever.retrieve( sub_q + " " + context, k=5 )

Generate answer = await self.llm.generate( query=sub_q, context=docs, previous=context )

context += f"\n{sub_q} -> {answer}"

Return final answer return answer

async def decompose(self, query): Use LLM to decompose return await self.llm.decompose(query) `

Avancé : Avec validation

`python class ValidatedDecomposeRAG(DecomposeRAG): async def query(self, complex_question, max_retries=2): sub_questions = await self.decompose(complex_question)

context = "" for sub_q in sub_questions: for attempt in range(max_retries): docs = await self.retriever.retrieve(sub_q + " " + context) answer = await self.llm.generate(sub_q, docs, context)

Validate if await self.validate(sub_q, answer, docs): context += f"\n{sub_q} -> {answer}" break elif attempt == max_retries - 1: Failed validation, use best-effort answer context += f"\n{sub_q} -> {answer} (unverified)"

return answer `

Optimisations

Sous-requêtes parallèles

Quand les sous-questions sont indépendantes :

`python Identify independent sub-questions dependencies = analyze_dependencies(sub_questions)

Group independent questions independent_groups = group_by_dependencies(sub_questions, dependencies)

Process groups in parallel for group in independent_groups: Parallel retrieval for group results = await asyncio.gather(*[ self.retrieve_and_answer(q, context) for q in group ])

Add all to context for q, answer in zip(group, results): context += f"\n{q} -> {answer}" `

Cache des résultats intermédiaires

`python class CachedDecomposeRAG(DecomposeRAG): def __init__(self, retriever, llm): super().__init__(retriever, llm) self.cache = {}

async def retrieve_and_answer(self, sub_q, context): cache_key = hash(sub_q + context)

if cache_key in self.cache: return self.cache[cache_key]

result = await super().retrieve_and_answer(sub_q, context) self.cache[cache_key] = result

return result ``

Considérations pratiques

Latence

DecomposeRAG est 2-3x plus lent : • Requête 2-sauts : +2-3 secondes • Requête 3-sauts : +4-6 secondes • Requête 4-sauts : +6-10 secondes

Atténuation : • Sous-requêtes parallèles quand possible • Cache des décompositions courantes • Utiliser des LLMs plus rapides pour les étapes intermédiaires

Coût

Plus d'appels LLM = coût plus élevé : • Décomposition : 1 appel LLM • Chaque sous-question : 1 appel LLM • Validation (optionnelle) : 1 appel par sous-question

Exemple : • 3 sous-questions + validation = 7 appels LLM • vs. 1 appel pour RAG standard

Multiplicateur de coût : 2-5x selon la complexité

Quand utiliser

Utiliser DecomposeRAG quand : • Les questions sont complexes (multi-sauts) • La précision est plus importante que la vitesse • Le budget permet des coûts plus élevés

Utiliser RAG standard quand : • Recherches simples • Vitesse critique • Sensible au coût

Directions futures

Améliorations prévues : Meilleure décomposition : Affiner des modèles plus petits Stratégie adaptive : Détecter automatiquement quand décomposer Raffinement itératif : Réessayer les sous-questions échouées Multimodal : Décomposer à travers modalités

Ressources • Article : "DecomposeRAG: Automatic Query Decomposition for Multi-Hop Question Answering" • Code : github.com/berkeley-nlp/decomposerag • Démo : decomposerag.demo.berkeley.edu

Conclusion

DecomposeRAG démontre qu'une décomposition explicite des requêtes améliore significativement les réponses aux questions multi-sauts. Bien que plus coûteux et plus lent que le RAG standard, les gains de précision justifient le surcoût pour les requêtes complexes où l'exactitude est critique.

Tags

  • query optimization
  • multi-hop
  • research
  • decomposition
Actualités

Percée de décomposition de requête : DecomposeRAG gère les questions complexes 50% mieux

5 novembre 2025
4 min de lecture
Équipe de Recherche Ailog

Les chercheurs d'UC Berkeley introduisent DecomposeRAG, un framework de décomposition de requête automatisé qui améliore significativement les réponses aux questions multi-sauts.

Aperçu de la recherche

Le laboratoire NLP d'UC Berkeley a publié DecomposeRAG, un framework qui décompose automatiquement les requêtes complexes en sous-requêtes plus simples, atteignant des résultats state-of-the-art sur les benchmarks de QA multi-sauts.

Le problème

Les questions complexes nécessitent un raisonnement multi-sauts :

Exemple : "Quelle est la population de la capitale du pays où se trouve la Tour Eiffel ?"

Nécessite :

  1. Où se trouve la Tour Eiffel ? → France
  2. Quelle est la capitale de la France ? → Paris
  3. Quelle est la population de Paris ? → 2,1 millions

Le RAG traditionnel récupère du contexte pour la question complète, manquant souvent les étapes intermédiaires.

Approche DecomposeRAG

Décomposition automatique

Utilise GPT-4 pour décomposer les requêtes en sous-questions :

DEVELOPERpython
def decompose_query(complex_query): prompt = f"""Break this question into simple sub-questions that must be answered in order. Question: {complex_query} Sub-questions (in order): 1.""" response = gpt4.generate(prompt) sub_questions = parse_questions(response) return sub_questions

Récupération séquentielle

Répondre aux sous-questions dans l'ordre, en utilisant les réponses précédentes comme contexte :

DEVELOPERpython
def sequential_rag(sub_questions): context = "" for i, sub_q in enumerate(sub_questions): # Retrieve for this sub-question docs = retrieve(sub_q + " " + context, k=5) # Generate answer answer = llm.generate( query=sub_q, context=docs, previous_answers=context ) # Add to cumulative context context += f"\nQ{i+1}: {sub_q}\nA{i+1}: {answer}\n" return answer # Answer to final sub-question

Validation des réponses

Valide chaque réponse intermédiaire avant de continuer :

DEVELOPERpython
def validate_answer(question, answer, retrieved_docs): prompt = f"""Is this answer supported by the documents? Question: {question} Answer: {answer} Documents: {retrieved_docs} Supported? (yes/no):""" validation = llm.generate(prompt) return "yes" in validation.lower()

Si la validation échoue, réessayer avec plus de contexte ou une stratégie de récupération alternative.

Résultats de benchmark

Testé sur quatre datasets de QA multi-sauts :

DatasetRAG BaselineDecomposeRAGAmélioration
HotpotQA45.3%68.7%+51.7%
2WikiMultihopQA38.2%57.9%+51.6%
MuSiQue32.1%49.8%+55.1%
IIRC41.7%62.3%+49.4%

Amélioration moyenne : +52%

Comparaison avec d'autres méthodes

MéthodeF1 moyCoût (relatif)
RAG Standard39.3%1x
Chain-of-Thought43.8%2x
ReACT48.2%3x
DecomposeRAG59.7%2.5x

DecomposeRAG atteint la meilleure précision à un coût modéré.

Insights clés

Quand la décomposition aide

L'efficacité varie selon la complexité de la requête :

SautsBaselineDecomposeRAGGain
1 (simple)68.2%69.1%+1.3%
2 (moyen)51.3%67.4%+31.4%
3 (complexe)28.7%52.3%+82.2%
4+ (très complexe)15.2%38.9%+156.3%

Constat : Plus de sauts = gains plus importants de la décomposition.

Qualité de la décomposition

Analyse de la qualité des décompositions générées par LLM :

  • Décomposition correcte : 87.3%
  • Étapes manquantes : 8.2%
  • Ordre incorrect : 3.1%
  • Logique circulaire : 1.4%

Même des décompositions imparfaites améliorent les résultats.

Analyse d'erreurs

Où DecomposeRAG échoue-t-il ?

  1. Erreurs de décomposition (23%) : Mauvaises sous-questions
  2. Échecs de récupération (34%) : Impossible de trouver des docs pertinents pour la sous-question
  3. Erreurs de réponse (28%) : Mauvaise réponse intermédiaire qui se propage
  4. Échecs d'intégration (15%) : Impossible de combiner les sous-réponses

Le plus courant : La récupération échoue toujours pour les sous-questions.

Implémentation

Version basique

DEVELOPERpython
class DecomposeRAG: def __init__(self, retriever, llm): self.retriever = retriever self.llm = llm async def query(self, complex_question): # Step 1: Decompose sub_questions = await self.decompose(complex_question) # Step 2: Sequential RAG context = "" for sub_q in sub_questions: # Retrieve docs = await self.retriever.retrieve( sub_q + " " + context, k=5 ) # Generate answer = await self.llm.generate( query=sub_q, context=docs, previous=context ) context += f"\n{sub_q} -> {answer}" # Return final answer return answer async def decompose(self, query): # Use LLM to decompose return await self.llm.decompose(query)

Avancé : Avec validation

DEVELOPERpython
class ValidatedDecomposeRAG(DecomposeRAG): async def query(self, complex_question, max_retries=2): sub_questions = await self.decompose(complex_question) context = "" for sub_q in sub_questions: for attempt in range(max_retries): docs = await self.retriever.retrieve(sub_q + " " + context) answer = await self.llm.generate(sub_q, docs, context) # Validate if await self.validate(sub_q, answer, docs): context += f"\n{sub_q} -> {answer}" break elif attempt == max_retries - 1: # Failed validation, use best-effort answer context += f"\n{sub_q} -> {answer} (unverified)" return answer

Optimisations

Sous-requêtes parallèles

Quand les sous-questions sont indépendantes :

DEVELOPERpython
# Identify independent sub-questions dependencies = analyze_dependencies(sub_questions) # Group independent questions independent_groups = group_by_dependencies(sub_questions, dependencies) # Process groups in parallel for group in independent_groups: # Parallel retrieval for group results = await asyncio.gather(*[ self.retrieve_and_answer(q, context) for q in group ]) # Add all to context for q, answer in zip(group, results): context += f"\n{q} -> {answer}"

Cache des résultats intermédiaires

DEVELOPERpython
class CachedDecomposeRAG(DecomposeRAG): def __init__(self, retriever, llm): super().__init__(retriever, llm) self.cache = {} async def retrieve_and_answer(self, sub_q, context): cache_key = hash(sub_q + context) if cache_key in self.cache: return self.cache[cache_key] result = await super().retrieve_and_answer(sub_q, context) self.cache[cache_key] = result return result

Considérations pratiques

Latence

DecomposeRAG est 2-3x plus lent :

  • Requête 2-sauts : +2-3 secondes
  • Requête 3-sauts : +4-6 secondes
  • Requête 4-sauts : +6-10 secondes

Atténuation :

  • Sous-requêtes parallèles quand possible
  • Cache des décompositions courantes
  • Utiliser des LLMs plus rapides pour les étapes intermédiaires

Coût

Plus d'appels LLM = coût plus élevé :

  • Décomposition : 1 appel LLM
  • Chaque sous-question : 1 appel LLM
  • Validation (optionnelle) : 1 appel par sous-question

Exemple :

  • 3 sous-questions + validation = 7 appels LLM
  • vs. 1 appel pour RAG standard

Multiplicateur de coût : 2-5x selon la complexité

Quand utiliser

Utiliser DecomposeRAG quand :

  • Les questions sont complexes (multi-sauts)
  • La précision est plus importante que la vitesse
  • Le budget permet des coûts plus élevés

Utiliser RAG standard quand :

  • Recherches simples
  • Vitesse critique
  • Sensible au coût

Directions futures

Améliorations prévues :

  1. Meilleure décomposition : Affiner des modèles plus petits
  2. Stratégie adaptive : Détecter automatiquement quand décomposer
  3. Raffinement itératif : Réessayer les sous-questions échouées
  4. Multimodal : Décomposer à travers modalités

Ressources

  • Article : "DecomposeRAG: Automatic Query Decomposition for Multi-Hop Question Answering"
  • Code : github.com/berkeley-nlp/decomposerag
  • Démo : decomposerag.demo.berkeley.edu

Conclusion

DecomposeRAG démontre qu'une décomposition explicite des requêtes améliore significativement les réponses aux questions multi-sauts. Bien que plus coûteux et plus lent que le RAG standard, les gains de précision justifient le surcoût pour les requêtes complexes où l'exactitude est critique.

Tags

query optimizationmulti-hopresearchdecomposition

Articles connexes

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !