Salut la famille tech ! Nina Torres de nouveau ici, provenant de agntbox.com. Aujourd’hui, nous explorons quelque chose qui suscite beaucoup d’intérêt dans la communauté IA, en particulier pour ceux d’entre nous qui s’essaient à créer des expériences IA plus personnalisées et conscientes du contexte. Je parle de LlamaIndex, et plus spécifiquement, de la façon dont son moteur de requête a évolué pour gérer des interactions de données de plus en plus complexes. Oubliez simplement le fait de balancer un PDF et d’espérer le meilleur ; nous allons voir comment le rendre véritablement intelligent à travers plusieurs sources de données différentes.
Ma boîte de réception, comme beaucoup d’entre vous, a été inondée de questions sur comment aller au-delà des configurations RAG (Retrieval-Augmented Generation) de base. Les gens construisent des applications incroyables, mais ils se heurtent à un mur lorsque leur IA doit répondre à des questions qui nécessitent la synthèse d’informations provenant d’une base de données, d’un ensemble de documents, et d’une API en direct. Ce n’est plus un simple problème de “trouver ce texte”. C’est un problème de “comprendre quoi demander où, puis combiner les réponses”. Et honnêtement, c’est un problème avec lequel j’ai dû me battre dans un projet personnel pour un client qui gère un site e-commerce de niche – imaginez un assistant IA qui doit vérifier l’inventaire des produits (base de données), consulter des avis d’utilisateurs (documents) et suggérer des articles connexes en fonction des prix en direct (API). Ma configuration initiale de LlamaIndex, bien que convenable pour la partie avis, a complètement échoué sur la synthèse multi-sources.
Aujourd’hui, nous allons explorer les capacités avancées du moteur de requête de LlamaIndex pour la synthèse de données multi-sources. Il ne s’agit pas seulement d’indexer différents types de données ; il s’agit de construire un moteur de requête qui orchestre intelligemment la récupération d’informations à travers ces diverses sources pour répondre à des questions complexes et multipartites. Nous parlons de passer d’un simple récupérateur à un système d’acheminement et de planification sophistiqué.
L’évolution de “Poser une Question” dans LlamaIndex
Vous vous souvenez de la première apparition de LlamaIndex ? C’était incroyable pour transformer les données non structurées en quelque chose avec lequel un LLM pouvait discuter. Vous téléchargez des documents, construisez un index et posez vos questions. Simple, efficace. Mais la vie n’est pas toujours simple. Nos données ne se trouvent pas toujours dans des fichiers texte bien rangés. Elles sont éparpillées dans des bases de données SQL, des magasins noSQL, des API et une multitude de PDFs.
L’approche initiale consistait souvent à créer des index séparés pour chaque source de données. Vous aviez votre index de documents, votre index SQL, peut-être un outil API. Ensuite, vous décidiez manuellement lequel interroger en fonction de l’entrée de l’utilisateur. Cela fonctionne pour des cas simples, mais que dire d’une question comme, “Quelles sont les évaluations moyennes des produits lancés au dernier trimestre, et y a-t-il des tickets de support ouverts pour l’un d’eux ?”
Cette question nécessite :
- Interroger une base de données pour les dates de lancement des produits et les évaluations moyennes.
- Interroger un autre système (peut-être un magasin de documents séparé ou une API) pour les tickets de support ouverts liés à ces produits.
- Synthétiser les deux morceaux d’information pour fournir une réponse cohérente.
C’est ici que LlamaIndex a vraiment amélioré son jeu, en passant de récupérateurs isolés à des moteurs de requête intégrés capables de comprendre et d’agir sur des requêtes aussi multiformes.
Au-delà de la Récupération de Base : Planification et Acheminement des Requêtes
La magie se produit avec ce que LlamaIndex appelle “planification de requête” et “acheminement”. Au lieu de simplement récupérer des morceaux de texte, le moteur de requête, souvent piloté par un LLM lui-même, essaie d’abord de comprendre l’intention de l’utilisateur puis décide de la meilleure stratégie pour y répondre. Cela implique :
- Identifier les Sous-Questions : Décomposer une question complexe en petites questions indépendantes.
- Associer les Sous-Questions aux Outils/Index : Déterminer quelle source de données spécifique (par exemple, une base de données SQL, un index vectoriel de documents, un point de terminaison API) est le mieux adaptée pour répondre à chaque sous-question.
- Exécuter les Requêtes : Lancer ces sous-requêtes contre les outils choisis.
- Synthétiser les Résultats : Prendre les réponses individuelles et les combiner en une seule réponse complète.
Ce n’est pas simplement un concept théorique ; il est pratiquement mis en œuvre à travers des choses comme `QueryPipeline` de LlamaIndex, `RouterQueryEngine`, et la capacité de définir des `Tools` personnalisés.
Configuration pour la Synthèse Multi-Sources : Un Exemple Pratique
Passons en revue une version simplifiée du problème de mon client e-commerce. Imaginez que nous avons trois sources de données :
- Base de Données des Produits : Une base de données SQL avec des IDs de produits, des noms, des prix et des dates de lancement.
- Documents d’Avis : Une collection d’avis d’utilisateurs (PDF, fichiers texte) pour chaque produit.
- API d’Inventaire : Une API simple qui renvoie les niveaux de stock actuels pour un ID de produit donné.
Notre objectif est de répondre à une question comme : “Parlez-moi de ‘Fancy Widget Pro’ – quel est son prix, que disent les utilisateurs à son sujet, et est-il actuellement en stock ?”
Étape 1 : Préparer Vos Sources de Données et Outils
Tout d’abord, nous devons rendre chaque source de données accessible à LlamaIndex en tant qu’outil.
A. Outil Base de Données SQL
Nous allons utiliser `SQLTableRetrieverTool` de LlamaIndex pour cela. Supposons que vous ayez une simple base de données SQLite nommée `products.db` avec une table `products`.
from llama_index.core import SQLDatabase
from sqlalchemy import create_engine, text
from llama_index.core.tools import SQLTableRetrieverTool
# Créer une base de données et une table fictives pour la démonstration
engine = create_engine("sqlite:///products.db")
with engine.connect() as connection:
connection.execute(text("""
CREATE TABLE IF NOT EXISTS products (
product_id TEXT PRIMARY KEY,
name TEXT,
price REAL,
launch_date TEXT
);
"""))
connection.execute(text("""
INSERT OR IGNORE INTO products (product_id, name, price, launch_date) VALUES
('FWP001', 'Fancy Widget Pro', 129.99, '2025-01-15'),
('MGS002', 'Mega Gadget Super', 249.00, '2024-11-01');
"""))
connection.commit()
sql_database = SQLDatabase(engine=engine)
sql_tool = SQLTableRetrieverTool.from_instances(
sql_database=sql_database,
table_names=["products"],
description=(
"Utile pour interroger des informations sur les produits telles que le nom, le prix et la date de lancement. "
"L'entrée doit être une requête SQL pour la table 'products'."
)
)
Mon Avis : Cet outil `SQLTableRetrieverTool` est un sauveur. Avant cela, j’écrivais des fonctions personnalisées pour interagir avec les bases de données, et j’avais l’impression de réinventer la roue à chaque fois. Cet outil rend tout cela beaucoup plus clair, même si vous devez toujours être conscient de l’ingénierie des invites pour vous assurer que le LLM génère de bonnes requêtes SQL.
B. Outil Index des Documents d’Avis
Pour les avis, nous allons créer un index vectoriel à partir de quelques documents d’avis fictifs.
import os
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.tools import QueryEngineTool
# Créer un répertoire et des fichiers d'avis fictifs
os.makedirs("reviews", exist_ok=True)
with open("reviews/FWP001_reviews.txt", "w") as f:
f.write("Avis sur Fancy Widget Pro :\n")
f.write("1. 'J'adore absolument le Fancy Widget Pro ! Si rapide et fiable.' - Utilisateur A\n")
f.write("2. 'Un peu cher, mais ça vaut le coup pour la qualité.' - Utilisateur B\n")
f.write("3. 'A considérablement amélioré mon flux de travail.' - Utilisateur C\n")
with open("reviews/MGS002_reviews.txt", "w") as f:
f.write("Avis sur Mega Gadget Super :\n")
f.write("1. 'L'autonomie de la batterie est incroyable !' - Utilisateur X\n")
f.write("2. 'Processus de configuration déroutant.' - Utilisateur Y\n")
# Charger les documents et créer un index
documents = SimpleDirectoryReader("reviews").load_data()
review_index = VectorStoreIndex.from_documents(documents)
review_query_engine = review_index.as_query_engine()
review_tool = QueryEngineTool(
query_engine=review_query_engine,
metadata={"name": "review_tool",
"description": "Utile pour répondre à des questions sur les avis de produits issus des documents de retours d'utilisateurs. "
"L'entrée doit être un nom de produit spécifique ou un ID."}
)
Mon Avis : Le `QueryEngineTool` est votre référence pour envelopper tout moteur de requête LlamaIndex existant dans un outil. Il est incroyablement flexible. Assurez-vous juste que votre `description` soit très claire pour que le LLM sache quand l’utiliser.
C. Outil API d’Inventaire
Pour l’API, nous allons simuler une simple fonction Python comme un appel API en utilisant `FunctionTool`.
from llama_index.core.tools import FunctionTool
# Simuler une API d'inventaire
def get_stock_level(product_id: str) -> str:
"""
Renvoie le niveau de stock actuel pour un ID de produit donné.
Args:
product_id (str): L'ID du produit.
Returns:
str: Une chaîne indiquant le niveau de stock, par exemple, "En Stock", "Stock Faible", "Rupture de Stock".
"""
if product_id == "FWP001":
return "En Stock"
elif product_id == "MGS002":
return "Stock Faible"
else:
return "Rupture de Stock"
inventory_tool = FunctionTool.from_defaults(fn=get_stock_level,
description=(
"Utile pour vérifier le niveau de stock actuel d'un produit. "
"L'entrée doit être un ID de produit (par exemple, 'FWP001')."
))
Mon Avis : `FunctionTool` est une vraie génialité. Vous pouvez envelopper presque n’importe quelle fonction Python et l’exposer à votre LLM. C’est ainsi que vous vous connectez à de véritables APIs, à des services internes ou même que vous exécutez des scripts locaux. C’est un changement significatif pour intégrer des actions externes dans les capacités de votre IA.
Étape 2 : Construire le Moteur de Requête Router
Maintenant que nous avons nos outils individuels, nous avons besoin d’un moyen pour que LlamaIndex choisisse et utilise intelligemment ceux-ci. C’est ici que le `RouterQueryEngine` entre en jeu. Il utilise un LLM pour décider quel outil (ou séquence d’outils) utiliser en fonction de la requête de l’utilisateur.
from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.selectors import LLMSingleSelector
from llama_index.llms.openai import OpenAI # Supposons que vous ayez configuré la clé API OpenAI
# Initialiser LLM (par exemple, OpenAI) pour le routage et la synthèse
llm = OpenAI(model="gpt-3.5-turbo") # Ou gpt-4, cela dépend de vos besoins et de votre budget
# Combiner tous les outils
all_tools = [sql_tool, review_tool, inventory_tool]
# Créer le RouterQueryEngine
router_query_engine = RouterQueryEngine(
selector=LLMSingleSelector.from_defaults(llm=llm),
query_engine_tools=all_tools,
verbose=True # Mettez sur True pour voir les décisions de routage
)
Point de vue de Nina : Le `LLMSingleSelector` est la méthode par défaut, souvent suffisante, pour dire au routeur quel outil utiliser. Pour des scénarios plus complexes, LlamaIndex propose d’autres sélecteurs ou vous pouvez même en construire un sur mesure. Le `verbose=True` est absolument essentiel pendant le développement – il vous montre ce que le LLM « pense » lorsqu’il essaie de router votre requête, ce qui est précieux pour le débogage.
Étape 3 : Interroger le moteur multi-sources
Prenons notre question complexe :
response = router_query_engine.query("Parlez-moi de 'Fancy Widget Pro' – quel est son prix, que disent les utilisateurs à son sujet, et est-il actuellement en stock ?")
print(response)
Lorsque vous exécutez cela, vous verrez les sorties `verbose` montrant le processus de réflexion du LLM :
- Il identifiera que « prix » nécessite le `sql_tool`.
- « Que disent les utilisateurs » nécessite le `review_tool`.
- « Actuellement en stock » nécessite le `inventory_tool`.
Le LLM exécutera alors chacun de ces outils, obtiendra leurs réponses respectives, et enfin les synthétisera en une seule réponse cohérente. C’est comme avoir un mini-directeur d’orchestre pour vos données !
Une sortie typique pourrait ressembler à :
> Sélection de l'outil moteur de requête : sql_tool
> Sélection de l'outil moteur de requête : review_tool
> Sélection de l'outil moteur de requête : inventory_tool
Le Fancy Widget Pro (ID produit FWP001) coûte 129,99 $. Les utilisateurs l'adorent généralement, le décrivant comme « rapide et fiable » et affirmant qu'il « a considérablement amélioré leur flux de travail », bien que certains mentionnent qu'il est « un peu cher ». Il est actuellement en stock.
C’est une amélioration considérable par rapport à l’interrogation manuelle de chaque source. Le LLM gère l’orchestration, rendant l’interaction beaucoup plus naturelle et puissante.
Scénarios avancés : Pipelines de requêtes et routage récursif
Le `RouterQueryEngine` est fantastique pour choisir un seul outil pour répondre à une sous-question. Mais que faire si la sortie d’un outil doit être utilisée comme entrée d’un autre ? Ou si vous avez besoin d’une séquence spécifique d’opérations qui ne peuvent pas être gérées par une simple sélection d’un seul outil ?
C’est là que le `QueryPipeline` devient incroyablement puissant. Il vous permet de chaîner plusieurs composants, y compris des outils, des récupérateurs, des LLM et même d’autres moteurs de requête, sous la forme d’un graphe acyclique orienté (DAG).
Imaginez un scénario : « Trouver tous les produits lancés au cours des 6 derniers mois qui ont un faible stock et des avis positifs. »
- Interroger la base de données SQL pour les produits lancés au cours des 6 derniers mois.
- Pour chaque ID produit de l’étape 1, vérifier le niveau de stock via l’API. Filtrer pour « faible stock ».
- Pour les produits restants, interroger les documents d’avis pour le sentiment. Filtrer pour « avis positifs ».
- Synthétiser la liste finale.
Il s’agit d’un processus conditionnel en plusieurs étapes. Vous pourriez construire un `QueryPipeline` pour cela, où la sortie d’une étape devient l’entrée de la suivante, éventuellement avec un LLM entre les deux pour traiter les résultats intermédiaires ou décider de l’étape suivante.
Bien que nous ne construisions pas un exemple complet de `QueryPipeline` ici (c’est un sujet à part entière !), sachez qu’il offre la flexibilité nécessaire pour une véritable automatisation des flux de travail complexes au sein de votre application LlamaIndex. Vous pouvez même intégrer un `RouterQueryEngine` dans un `QueryPipeline` pour une prise de décision récursive.
Leçons applicables pour votre prochain projet d’IA
- Cartographiez vos sources de données : Avant d’écrire une seule ligne de code, identifiez clairement toutes les sources de données avec lesquelles votre IA doit interagir. Comprenez leur structure (structurée, non structurée, axée sur l’API).
- Définissez des outils clairs : Pour chaque source de données, créez un outil LlamaIndex spécifique (par exemple, `SQLTableRetrieverTool`, `QueryEngineTool`, `FunctionTool`). Écrivez des `metadata` claires et descriptives pour chaque outil. Cette description est ce que le LLM utilise pour décider quand l’invoquer. Accordez du temps à cela ; c’est l’ingénierie des invites pour vos outils !
- Commencez avec `RouterQueryEngine` : Pour les projets initiaux multi-sources, `RouterQueryEngine` est souvent le point d’entrée le plus simple. Il gère la prise de décision basée sur LLM pour vous.
- Utilisez `verbose=True` largement : Sérieusement, c’est votre meilleur allié. Cela vous donne un aperçu du raisonnement du LLM et vous aide à peaufiner vos descriptions d’outils lorsque le routeur fait des choix inattendus.
- Envisagez `QueryPipeline` pour les flux de travail : Si vos questions impliquent des étapes séquentielles, une logique conditionnelle, ou si la sortie d’un outil alimente directement un autre, commencez à penser à `QueryPipeline`. C’est plus complexe à mettre en place, mais cela offre un contrôle sans précédent sur les interactions en plusieurs étapes.
- Faites évoluer les descriptions d’outils : La capacité du LLM à choisir le bon outil dépend fortement de la façon dont vous avez décrit le but de chaque outil ainsi que les entrées/sorties attendues. N’hésitez pas à expérimenter avec différentes formulations.
La capacité de LlamaIndex à orchestrer intelligemment des requêtes à travers différentes sources de données représente une avancée majeure pour la construction d’agents véritablement intelligents. Cela nous éloigne de la logique rigide et codée en dur vers des systèmes capables de raisonner sur les besoins en information et d’extraire dynamiquement des données des endroits les plus appropriés. L’assistant e-commerce de mon client est désormais beaucoup plus intelligent, capable de récupérer des prix de la base de données, des sentiments utilisateurs d’avis, et des niveaux de stock depuis l’API, le tout à partir d’une seule requête en langage naturel. C’est vraiment impressionnant !
C’est tout pour aujourd’hui, les amis ! Allez-y et construisez des agents IA incroyablement intelligents et multi-sources. Faites-moi savoir ce que vous êtes en train de construire dans les commentaires !
Articles connexes
- **TITRE : Les outils CLI que j’adore et pourquoi vous devriez aussi**
- Comment intégrer des SDK IA
- Meilleures pratiques pour le développement d’agents IA
🕒 Published: