Création d’un RAG agentic pour les applications de texte vers SQL

Le mélange de génération augmentée par récupération (RAG) et de modèles d’IA générative a apporté des changements au traitement du langage naturel en améliorant les réponses aux requêtes. Dans le domaine du RAG Agentic, cette méthode conventionnelle de se fier à un modèle monolithique pour les tâches a été améliorée en introduisant la modularité et l’autonomie. En décomposant le processus de résolution de problèmes en outils intégrés au sein d’un agent, le RAG Agentic offre des avantages tels que la précision, la transparence, la scalabilité et les capacités de débogage.

La Vision Derrière le RAG Agentic pour le Texte-vers-SQL

Les systèmes RAG traditionnels récupèrent souvent des documents pertinents et se reposent sur un seul modèle monolithique pour générer des réponses. Bien que cette méthode soit efficace dans certains cas, lorsqu’il s’agit de sorties structurées comme dans le cas de la génération de SQL, cette approche peut ne pas être la plus efficace. C’est là que nous pouvons tirer parti de la puissance du cadre RAG Agentic, où nous :

  1. Divisons les tâches en outils plus petits et plus gérables au sein d’un agent
  2. Améliorons la précision en attribuant des tâches à des outils spécialisés
  3. Améliorons la transparence en suivant le raisonnement et le flux de travail de chaque outil
  4. Simplifions la mise à l’échelle et le débogage grâce à une conception modulaire

Parlons maintenant du fonctionnement de cet outil et du rôle de chaque composant dans la transformation des questions des utilisateurs en requêtes SQL précises.

Vue d’Ensemble de l’Architecture

La structure comprend un agent utilisant des outils dans le flux de travail texte-vers-SQL. Le processus peut être résumé comme suit:

Requête utilisateur → Outil de transformation de requête → Outil de mise en avant à quelques coups → Outil de recherche hybride → Outil de réarrangement → Outil de récupération de table → Outil de construction de prompt → Outil d’exécution LLM → Outil d’exécution SQL → Résultat final

1. Outil de transformation de requête utilisateur

Cet outil consiste à traiter la requête utilisateur pour une meilleure compréhension du LLM. Il traite les ambiguïtés, reformule les questions des utilisateurs, traduit les abréviations dans leur forme complète et fournit du contexte lorsque nécessaire.

Améliorations

  • Gérer les références temporelles. Associer des termes tels que « à ce jour » ou « jusqu’à présent » à des dates explicites.
  • Remplacer les mots ambigus. Par exemple, « récent » pourrait être remplacé par « les 7 derniers jours ».
  • Associer les abréviations ou acronymes à leur signification complète.

Exemple

Entrée : « Afficher les ventes récentes MTD. »

Requête transformée : « Récupérer les données de ventes des 7 derniers jours (Mois à ce jour). »

Python

 

from datetime import date, timedelta

def transform_query(user_query):
    # Gérer les références temporelles ouvertes
    today = date.today()
    transformations = {
        "as of today": f"up to {today}",
        "till now": f"up to {today}",
        "recent": "last 7 days",
        "last week": f"from {today - timedelta(days=7)} to {today}",
    }
    
    for key, value in transformations.items():
        user_query = user_query.replace(key, value)

    # Associer les abréviations courantes
    abbreviations = {
        "MTD": "Month to Date",
        "YTD": "Year to Date",
    }
    for abbr, full_form in abbreviations.items():
        user_query = user_query.replace(abbr, full_form)

    return user_query

query_transform_tool = Tool(
    name="Query Transformer",
    func=transform_query,
    description="Refines user queries for clarity and specificity, handles abbreviations and open-ended terms."
)

2. Outil d’incitation à quelques coups

Cet outil appelle le LLM pour identifier la question d’un type à partir d’un ensemble (nous pouvons également dire correspondant au modèle). La question correspondante améliore le prompt avec un exemple de requête SQL.

Workflow Exemple

1. Question d’entrée : « Montrez-moi les ventes totales par produit pour les 7 jours. »

2. Modèles prédéfinis :

  • « Afficher les ventes regroupées par région. » → Exemple SQL ; SÉLECTIONNER région, SUM(ventes) …
  • « Afficher les ventes totales par produit. » → Exemple SQL; SÉLECTIONNEZ nom_produit, SUM(ventes) …

3. Question la plus similaire : « Afficher les ventes totales par produit. »

4. Exemple de sortie SQL : SÉLECTIONNEZ nom_produit, SUM(ventes) DE …

Python

 

from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model="gpt-4")

predefined_examples = {
    "Show sales grouped by region": "SELECT region, SUM(sales) FROM sales_data GROUP BY region;",
    "Show total sales by product": "SELECT product_name, SUM(sales) FROM sales_data GROUP BY product_name;",
}

def find_similar_question(user_query):
    prompt = "Find the most similar question type for the following user query:\n"
    prompt += f"User Query: {user_query}\n\nOptions:\n"
    for example in predefined_examples.keys():
        prompt += f"- {example}\n"
    prompt += "\nRespond with the closest match."

    response = llm.call_as_function(prompt)
    most_similar = response['content']
    return predefined_examples.get(most_similar, "")

few_shot_tool = Tool(
    name="Few-Shot Prompting",
    func=find_similar_question,
    description="Finds the most similar question type using an additional LLM call and retrieves the corresponding example SQL."
)

3. Outil de Recherche Hybride

Pour une récupération robuste, cet outil combine la recherche sémantique, la recherche par mot-clé basée sur BM25 et la cartographie basée sur des mots-clés. Les résultats de ces méthodes de recherche sont regroupés en utilisant une fusion de rang réciproque.

Comment tout cela se met-il en place ?

Cartographie de Table de Mots-Clés

Cette approche cartographie les tables aux mots-clés contenus dans la requête. Par exemple :

  • La présence de « ventes » entraîne la sélection de la table des ventes.
  • La présence de « produit » entraîne la sélection de la table des produits.

Cartographie de Chevauchement de Mots-Clés (BM25)

Il s’agit d’une méthode de recherche basée sur le chevauchement de mots-clés qui sélectionne les tables en fonction de la pertinence. Pour cela, nous appliquerons la technique BM25. Cela trie les documents par ordre de pertinence par rapport à une recherche utilisateur. Cette technique de recherche prend en compte la saturation des termes ainsi que TF-IDF (Fréquence des Termes-Inverse de la Fréquence des Documents).

La fréquence des termes (TF) permet de mesurer la fréquence d’un terme dans un document donné. L’approche de la fréquence inverse des documents (IDF) souligne les mots qui apparaissent dans chaque document, réduisant leur importance.

La normalisation prend en compte la longueur du document pour éviter tout biais en faveur des documents plus longs.

Étant donné:

  • sales_data: Contient des termes tels que « ventes, » « date, » « produit. »
  • products: Contient des termes tels que « produit, » « catégorie. »
  • orders: Contient des termes tels que « commande, » « date, » « client. »
  • financials: Contient des termes tels que « revenu, » « profit, » « dépense. »

Requête de l’utilisateur : « Afficher les ventes totales par produit. »

  • Identifier les termes dans la requête de l’utilisateur : [« ventes, » « produit »].
  • Trier chaque document (en fonction de la fréquence et de la pertinence de ces termes) dans DataBaseTable.

Pertinence des documents:

  • sales: Haute pertinence en raison à la fois de « ventes » et « produit »
  • products: Haute pertinence en raison de « produit. »
  • orders: Pertinence plus faible en raison de la présence uniquement de « ventes. »
  • financials: Non pertinent.

Sortie:

Liste classée: [products, sales_data, orders, financials]

Recherche sémantique

Dans cette méthode de recherche, comme son nom l’indique, nous trouvons des tables sémantiquement similaires en utilisant des plongements vectoriels. Nous y parvenons en calculant un score de similarité, tel que la similarité cosinus, entre le document (vecteurs de table) et les vecteurs de requête de l’utilisateur.

Fusion du rang réciproque

Combine les résultats de recherche BM25 et sémantique en utilisant la stratégie de fusion de rang réciproque, qui est expliquée un peu plus en détail ci-dessous:

Fusion de rang réciproque (RRF) combinant BM25 et recherche sémantique:

RRF est une méthode pour combiner les résultats de plusieurs algorithmes de classement (par exemple BM25 et recherche sémantique). Il attribue un score à chaque document en fonction de son rang dans les méthodes individuelles, en donnant des scores plus élevés aux documents classés plus haut dans plusieurs méthodes.

Formule RRF:

RRF(d) = Σ(r ∈ R) 1 / (k + r(d))

Où:

  • d est un document
  • R est l’ensemble des classeurs (méthodes de recherche)
  • k est une constante (typiquement 60)
  • r(d) est le rang du document d dans la méthode de recherche r

Exemple étape par étape

Données d’entrée.

1. Résultats de classement BM25:

  • produits (Rang 1)
  • données de vente (Rang 2)
  • commandes (Rang 3)

2. Résultats de classement de recherche sémantique:

  • données de vente (Rang 1)
  • financiers (Rang 2)
  • produits (Rang 3)

Fusion étape par étape

Pour chaque tableau, calculer le score:

1. données de vente

  • Rang BM25 = 2, Rang sémantique = 1
  • Score RRF = (1/60+2 ) + (1/60+1) = 0.03252

2. produits

  • Rang BM25 = 1, Rang sémantique = 3
  • Score RRF = (1/60+1) + (1/60+3)= .03226

3. commandes

  • Classement BM25 = 3, Classement sémantique = Non classé
  • Score RRF = (1/60+3)= 0.01587

4. financiers

  • Classement BM25 = Non classé, Classement sémantique = 2
  • Score RRF = (1/60+2)=0.01613

5. Trier par score RRF

  • sales_data (meilleur score en raison du classement supérieur dans la recherche sémantique).
  • produits (score élevé du BM25).
  • commandes (moindre pertinence globale).
  • financiers (chevauchement limité).

Sortie finale: [‘sales_data’, ‘produits’, ‘financiers’, ‘commandes’]

Tables récupérées en utilisant la cartographie de Tableau de mots-clés sont toujours incluses.

Python

 

from rank_bm25 import BM25Okapi

def hybrid_search(query):
    # Cartographie basée sur les mots-clés
    keyword_to_table = {
        "sales": "sales_data",
        "product": "products",
    }
    keyword_results = [table for keyword, table in keyword_to_table.items() if keyword in query.lower()]

    # Recherche BM25
    bm25 = BM25Okapi(["sales_data", "products", "orders", "financials"])
    bm25_results = bm25.get_top_n(query.split(), bm25.corpus, n=5)

    # Recherche sémantique
    semantic_results = vector_store.similarity_search(query, k=5)

    # Fusion du rang réciproque
    def reciprocal_rank_fusion(results):
        rank_map = {}
        for rank, table in enumerate(results):
            rank_map[table] = rank_map.get(table, 0) + 1 / (1 + rank)
        return sorted(rank_map, key=rank_map.get, reverse=True)

    combined_results = reciprocal_rank_fusion(bm25_results + semantic_results)

    return list(set(keyword_results + combined_results))

hybrid_search_tool = Tool(
    name="Hybrid Search",
    func=hybrid_search,
    description="Combines keyword mapping, BM25, and semantic search with RRF for table retrieval."
)

4. Outil de re-classement

Cet outil garantit que les tables les plus pertinentes sont priorisées.

Exemple

  • Tables d’entrée: [« sales_data », « produits », « financiers »]
  • Logique de re-classement
    • Pour chaque table, calculer un score de pertinence en concaténant la requête et la description de la table.
    • Trier par score de pertinence.
  • Sortie: [« sales_data », « produits »]

Un peu plus sur la logique de Re- classement :

Le crossencoder calcule un score de pertinence en analysant la requête concaténée et la description de la table comme une seule paire d’entrées. Ce processus implique :

  • Entrée par paire. La requête et chaque description de table sont appariées et transmises comme entrée au cross-encoder.
  • Encodage conjoint. Contrairement aux encodeurs séparés (par exemple, bi-encodeurs), le cross-encoder encode conjointement la paire, ce qui lui permet de mieux capturer le contexte et les dépendances entre la requête et la description de la table.
  • Notation. Le modèle produit un score de pertinence pour chaque paire, indiquant dans quelle mesure la table correspond à la requête.
Python

 

from transformers import pipeline

reranker = pipeline("text-classification", model="cross-encoder/ms-marco-TinyBERT-L-2")

def re_rank_context(query, results):
    scores = [(doc, reranker(query + " " + doc)[0]['score']) for doc in results]
    return [doc for doc, score in sorted(scores, key=lambda x: x[1], reverse=True)]

re_rank_tool = Tool(
    name="Re-Ranker",
    func=re_rank_context,
    description="Re-ranks the retrieved tables based on relevance to the query."
)

5. Outil de construction de prompts

Cet outil construit un prompt détaillé pour le modèle de langue, en incorporant la requête affinée de l’utilisateur, le schéma récupéré et des exemples de l’Outil de Few-Shot Prompting.

Supposons que vous soyez quelqu’un de compétent dans la génération de requêtes SQL. Générez une requête SQL pour : Récupérer les ventes totales groupées par produit pour les 7 derniers jours.

Tables pertinentes :

  1. sales_data : Contient les colonnes [sales, date, product_id].
  2. products : Contient les colonnes [product_id, product_name].

Exemple SQL :

Plain Text

 

SELECT product_name, SUM(sales) FROM sales_data JOIN products ON sales_data.product_id = products.product_id GROUP BY product_name;

Perspectives futures

Bien que ce système utilise un agent unique avec plusieurs outils pour simplifier la modularité et réduire la complexité, un cadre multi-agent pourrait être exploré à l’avenir. Nous pourrions éventuellement explorer ce qui suit :

  1. Agents dédiés pour la récupération de contexte. Agents séparés pour les recherches sémantiques et par mots-clés.
  2. Agents spécifiques à la tâche. Agents spécialisés dans la validation ou l’optimisation SQL.
  3. Collaboration entre les agents. Utilisation d’un agent de coordination pour gérer la délégation des tâches.

Cette approche pourrait améliorer la scalabilité et permettre des flux de travail plus sophistiqués, notamment dans les déploiements au niveau de l’entreprise.

Conclusion

Agentic RAG pour les applications de text-to-SQL offre une approche évolutive et modulaire pour résoudre les tâches de requête structurée. En incorporant la recherche hybride, le re-ranking, les prompts few-shot et la construction dynamique de prompts au sein d’un cadre à agent unique, ce système garantit précision, transparence et extensibilité. Ce flux de travail amélioré démontre un puissant modèle pour transformer les questions en langage naturel en requêtes SQL exploitables.

Source:
https://dzone.com/articles/creating-an-agentic-rag-for-text-to-sql-applications