Hallo, Technikfamilie! Nina Torres ist zurück auf agntbox.com. Heute werden wir etwas erkunden, das in der KI-Community für Aufsehen sorgt, besonders für diejenigen von uns, die versuchen, personalisierte und kontextbewusste KI-Erlebnisse zu schaffen. Ich spreche von LlamaIndex und genauer gesagt darüber, wie sich sein Abfrage-Engine entwickelt hat, um zunehmend komplexe Dateninteraktionen zu bewältigen. Vergesst die Idee, einfach eine PDF hochzuladen und das Beste zu hoffen; wir werden sehen, wie man es wirklich überlegen lässt, indem man mehrere verschiedene Datenquellen nutzt.
Mein Posteingang wurde, wie bei vielen von euch, mit Fragen überflutet, wie man über die grundlegenden RAG-Konfigurationen (Retrieval-Augmented Generation) hinauskommt. Die Leute bauen unglaubliche Anwendungen, stoßen jedoch an eine Wand, wenn ihre KI Antworten auf Fragen liefern muss, die das Zusammenfassen von Informationen aus einer Datenbank, einem Dokumentensatz, und einer Live-API erfordern. Es ist nicht mehr nur ein einfaches „finden Sie diesen Text“. Es ist ein Problem des „herausfindens, was wo zu fragen ist, und dann die Antworten zu kombinieren“. Und ehrlich gesagt, damit kämpfe ich auch in einem persönlichen Projekt für einen Kunden, der einen Nischen-E-Commerce-Shop betreibt – stellt euch einen KI-Assistenten vor, der den Produktbestand überprüfen (Datenbank), die Nutzerbewertungen konsultieren (Dokumente) und verwandte Artikel basierend auf Echtzeitpreisen vorschlagen muss (API). Meine anfängliche Konfiguration von LlamaIndex, obwohl sie für den Bewertungsbereich geeignet war, hat bei der Multi-Source-Synthese völlig versagt.
Heute werden wir also die fortgeschrittenen Fähigkeiten des Abfrage-Engines von LlamaIndex zur Synthese von Multi-Source-Daten erkunden. Es geht nicht nur darum, verschiedene Datentypen zu indizieren; es geht darum, eine Abfrage-Engine zu entwickeln, die intelligent die Informationsbeschaffung über diese verschiedenen Quellen orchestriert, um komplexe und multifaktorielle Fragen zu beantworten. Wir sprechen darüber, von einem einfachen Abruf-Mechanismus zu einem ausgeklügelten Routing- und Planungs-System zu wechseln.
Die Evolution von „Eine Frage Stellen“ in LlamaIndex
Erinnert ihr euch an die erste Erscheinung von LlamaIndex? Es war großartig, um unstrukturierte Daten in etwas zu verwandeln, mit dem ein LLM interagieren konnte. Man lud Dokumente hoch, baute einen Index und stellte Fragen. Einfach und effektiv. Aber das Leben ist nicht immer so einfach. Unsere Daten liegen nicht immer in ordentlich strukturierten Textdateien vor. Sie sind über SQL-Datenbanken, NoSQL-Speicher, APIs und eine Vielzahl von PDFs verstreut.
Der ursprüngliche Ansatz bestand oft darin, separate Indizes für jede Datenquelle zu erstellen. Ihr hattet euren Dokumenten-Index, euren SQL-Index, vielleicht ein API-Tool. Dann habt ihr manuell entschieden, welche ihr je nach Eingaben des Benutzers abfragen wollt. Das funktioniert für einfache Fälle, aber was ist mit einer Frage wie: „Was sind die durchschnittlichen Bewertungen der Produkte, die im letzten Quartal gestartet wurden, und sind davon welche mit offenen Support-Tickets?“
Diese Frage erfordert:
- Abfrage einer Datenbank nach den Produktstartdaten und den durchschnittlichen Bewertungen.
- Abfrage eines anderen Systems (vielleicht einer separaten Dokumentenspeicherung oder einer API) nach den offenen Support-Tickets, die mit diesen Produkten verbunden sind.
- Synthese der beiden Informationsstücke, um eine kohärente Antwort zu liefern.
Hier hat LlamaIndex wirklich sein Angebot verbessert, indem es von isolierten Abrufmechanismen zu integrierten Abfrage-Engines übergegangen ist, die solche multifaktoriellen Anfragen verstehen und darauf reagieren können.
Über die Grundlegende Abfrage hinaus: Planung und Routing von Anfragen
Die Magie geschieht mit dem, was LlamaIndex „Abfrageplanung“ und „Routing“ nennt. Anstatt sich mit dem Abruf von Textteilen zufrieden zu geben, versucht die Abfrage-Engine, die oft von einem LLM selbst betrieben wird, zunächst die Absicht des Benutzers zu verstehen und dann die beste Strategie zu bestimmen, um darauf zu reagieren. Dies beinhaltet:
- Unterfragen Identifizieren: Eine komplexe Frage in kleinere, unabhängige Fragen zu zerlegen.
- Unterfragen den Werkzeugen/Indizes Zuordnen: Festzustellen, welche spezifische Datenquelle (z. B. eine SQL-Datenbank, ein Vektordokumenten-Index, ein API-Endpunkt) am besten geeignet ist, um jede Unterfrage zu beantworten.
- Abfragen Ausführen: Diese Unteranfragen gegen die gewählten Werkzeuge zu starten.
- Ergebnisse Synthesizieren: Die einzelnen Antworten zu nehmen und in eine einzige umfassende Antwort zu kombinieren.
Dies ist kein nur theoretisches Konzept; es wird praktisch umgesetzt durch Elemente wie die `QueryPipeline` von LlamaIndex, den `RouterQueryEngine` und die Fähigkeit, benutzerdefinierte `Tools` zu definieren.
Einrichtung zur Multi-Source-Synthese: Ein Praktisches Beispiel
Lasst uns eine vereinfachte Version des Problems meines E-Commerce-Kunden durchgehen. Stellt euch vor, wir haben drei Datenquellen:
- Produkten-Datenbank: Eine SQL-Datenbank mit Produkt-IDs, Namen, Preisen und Startdaten.
- Bewerdokumente: Eine Sammlung von Nutzerbewertungen (PDFs, Textdateien) für jedes Produkt.
- Inventar-API: Eine einfache API, die die aktuellen Lagerbestände für eine gegebene Produkt-ID zurückgibt.
Unser Ziel ist es, auf eine Frage wie: „Erzählt mir von ‘Fancy Widget Pro’ – wie viel kostet es, was sagen die Nutzer darüber, und ist es derzeit auf Lager?“ zu antworten.
Schritt 1: Vorbereiten Eurer Datenquellen und Werkzeuge
Zuerst müssen wir jede Datenquelle für LlamaIndex als „Tool“ zugänglich machen.
A. SQL-Datenbankwerkzeug
Wir werden das `SQLTableRetrieverTool` von LlamaIndex dafür verwenden. Nehmen wir an, ihr habt eine einfache SQLite-Datenbank namens `products.db` mit einer Tabelle `products`.
from llama_index.core import SQLDatabase
from sqlalchemy import create_engine, text
from llama_index.core.tools import SQLTableRetrieverTool
# Erstellen Sie eine fiktive Datenbank und Tabelle für die Demonstration
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=(
"Nützlich, um Informationen über Produkte wie Name, Preis und Startdatum abzufragen. "
"Der Eingabe muss eine SQL-Abfrage für die Tabelle 'products' sein."
)
)
Ninas Bewertungen: Dieses `SQLTableRetrieverTool` ist ein Lebensretter. Vor ihm habe ich benutzerdefinierte Funktionen geschrieben, um mit Datenbanken zu interagieren, und hatte das Gefühl, jedes Mal das Rad neu zu erfinden. Dieses Tool macht die Dinge viel einfacher, auch wenn man immer darauf achten muss, dass die Eingabe so gestaltet ist, dass das LLM gute SQL-Abfragen generiert.
B. Werkzeug zum Dokumenten-Index von Bewertungen
Für die Bewertungen werden wir einen Vektorindex basierend auf einigen fiktiven Bewertungsdokumenten erstellen.
import os
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.tools import QueryEngineTool
# Erstellen Sie ein Verzeichnis und fiktive Bewertungsdateien
os.makedirs("reviews", exist_ok=True)
with open("reviews/FWP001_reviews.txt", "w") as f:
f.write("Bewertungen zu Fancy Widget Pro:\n")
f.write("1. 'Ich liebe das Fancy Widget Pro einfach! So schnell und zuverlässig.' - Nutzer A\n")
f.write("2. 'Etwas teuer, aber es lohnt sich wegen der Qualität.' - Nutzer B\n")
f.write("3. 'Verbessert meinen Workflow erheblich.' - Nutzer C\n")
with open("reviews/MGS002_reviews.txt", "w") as f:
f.write("Bewertungen zu Mega Gadget Super:\n")
f.write("1. 'Die Akkulaufzeit ist unglaublich!' - Nutzer X\n")
f.write("2. 'Verwirrender Einrichtungsprozess.' - Nutzer Y\n")
# Dokumente laden und einen Index erstellen
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": "Hilfreich, um Fragen zu Produktbewertungen basierend auf den Nutzerbewertungen zu beantworten. "
"Der Eingabewert sollte ein spezifischer Produktname oder -identifikator sein."}
)
Ninas Bewertungen: Der `QueryEngineTool` ist Ihr bevorzugtes Werkzeug, um jeden vorhandenen LlamaIndex-Abfrage-Engine in ein Tool einzubetten. Es ist unglaublich flexibel. Stellen Sie nur sicher, dass Ihre `description` super klar ist, damit das LLM weiß, wann es verwendet werden soll.
C. Inventar-API-Tool
Für die API simulieren wir eine einfache Python-Funktion als API-Aufruf unter Verwendung von `FunctionTool`.
from llama_index.core.tools import FunctionTool
# Inventar-API simulieren
def get_stock_level(product_id: str) -> str:
"""
Gibt den aktuellen Lagerbestand für eine gegebene Produkt-ID zurück.
Args:
product_id (str) : Die Produkt-ID.
Returns:
str : Ein String, der den Lagerbestand angibt, z.B. "Auf Lager", "Niedriger Bestand", "Ausverkauft".
"""
if product_id == "FWP001":
return "Auf Lager"
elif product_id == "MGS002":
return "Niedriger Bestand"
else:
return "Ausverkauft"
inventory_tool = FunctionTool.from_defaults(fn=get_stock_level,
description=(
"Hilfreich, um den aktuellen Lagerbestand eines Produkts zu überprüfen. "
"Der Eingabewert sollte eine Produkt-ID (z.B. 'FWP001') sein."
))
Ninas Bewertungen: `FunctionTool` ist ein reines Genie. Sie können fast jede Python-Funktion umhüllen und sie Ihrem LLM zugänglich machen. So verbinden Sie sich mit echten APIs, internen Diensten oder führen sogar lokale Skripte aus. Es ist eine erhebliche Änderung, um externe Aktionen in die Fähigkeiten Ihrer KI zu integrieren.
Schritt 2: Erstellen Sie den Abfrage-Engine-Router
Jetzt, da wir unsere einzelnen Werkzeuge haben, benötigen wir eine Methode, damit LlamaIndex sie intelligent auswählt und verwendet. Hier kommt der `RouterQueryEngine` ins Spiel. Er verwendet ein LLM, um zu entscheiden, welches Tool (oder welche Sequenz von Tools) basierend auf der Benutzeranfrage verwendet werden soll.
from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.selectors import LLMSingleSelector
from llama_index.llms.openai import OpenAI # Vorausgesetzt, Sie haben einen OpenAI API-Schlüssel konfiguriert
# LLM initialisieren (z.B. OpenAI) für Routing und Synthese
llm = OpenAI(model="gpt-3.5-turbo") # Oder gpt-4, je nach Bedarf und Budget
# Alle Werkzeuge kombinieren
all_tools = [sql_tool, review_tool, inventory_tool]
# RouterQueryEngine erstellen
router_query_engine = RouterQueryEngine(
selector=LLMSingleSelector.from_defaults(llm=llm),
query_engine_tools=all_tools,
verbose=True # Auf True gesetzt, um die Routing-Entscheidungen anzuzeigen
)
Ninas Perspektive: Der `LLMSingleSelector` ist die Standardmethode, oft ausreichend, um dem Router anzuzeigen, welches Tool verwendet werden soll. Für komplexere Szenarien bietet LlamaIndex weitere Selektoren oder Sie können sogar einen maßgeschneiderten erstellen. Das Setzen von `verbose=True` ist während der Entwicklung absolut entscheidend – es zeigt Ihnen, was das LLM „denkt“, während es versucht, Ihre Anfrage zu routen, was wertvoll für das Debugging ist.
Schritt 3: Abfragen des Multi-Source-Engines
Stellen wir unsere komplexe Frage:
response = router_query_engine.query("Erzählen Sie mir von 'Fancy Widget Pro' – wie viel kostet es, was sagen die Nutzer darüber und ist es aktuell auf Lager?")
print(response)
Wenn Sie das ausführen, sehen Sie die `verbose`-Ausgabe, die den Denkprozess des LLM zeigt:
- Es wird identifizieren, dass „Preis“ das `sql_tool` benötigt.
- „Was sagen die Nutzer“ benötigt das `review_tool`.
- „Aktuell auf Lager“ benötigt das `inventory_tool`.
Das LLM wird dann jedes dieser Tools ausführen, deren jeweilige Antworten erhalten und schließlich alles in eine einzige kohärente Antwort zusammenfassen. Es ist, als hätte man einen kleinen Dirigenten für Ihre Daten!
Eine typische Ausgabe könnte wie folgt aussehen:
> Auswahl des Abfrage-Engine-Tools: sql_tool
> Auswahl des Abfrage-Engine-Tools: review_tool
> Auswahl des Abfrage-Engine-Tools: inventory_tool
Das Fancy Widget Pro (Produkt-ID FWP001) kostet 129,99 $. Die Nutzer lieben es normalerweise und beschreiben es als "schnell und zuverlässig" und behaupten, dass es "ihren Workflow erheblich verbessert" hat, obwohl einige erwähnen, dass es "etwas teuer ist". Es ist aktuell auf Lager.
Das ist eine erhebliche Verbesserung im Vergleich zur manuellen Abfrage jeder Quelle. Das LLM übernimmt die Orchestrierung, was die Interaktion viel natürlicher und leistungsfähiger macht.
Erweiterte Szenarien: Abfrage-Pipelines und rekursives Routing
Der `RouterQueryEngine` ist großartig, um ein einzelnes Tool für die Beantwortung einer Unterfrage auszuwählen. Aber was, wenn die Ausgabe eines Tools als Eingabe für ein anderes verwendet werden muss? Oder wenn Sie eine spezifische Sequenz von Operationen benötigen, die nicht durch eine einfache Auswahl eines einzelnen Tools verwaltet werden kann?
Hier wird der `QueryPipeline` unglaublich mächtig. Er ermöglicht es Ihnen, mehrere Komponenten zusammenzuketten, einschließlich Tools, Retrievals, LLMs und sogar anderen Abfrage-Engines, um einen gerichteten azyklischen Graphen (DAG) zu bilden.
Stellen Sie sich ein Szenario vor: „Finden Sie alle Produkte, die in den letzten 6 Monaten eingeführt wurden, die einen niedrigen Bestand und positive Bewertungen haben.“
- Fragen Sie die SQL-Datenbank nach Produkten, die in den letzten 6 Monaten eingeführt wurden.
- Überprüfen Sie für jede Produkt-ID aus Schritt 1 den Lagerbestand über die API. Filtern Sie nach „Niedriger Bestand“.
- Fragen Sie die Bewertungsdokumente für das Sentiment der verbleibenden Produkte ab. Filtern Sie nach „positiven Bewertungen“.
- Synthesizierung der endgültigen Liste.
Es handelt sich um einen mehrstufigen bedingten Prozess. Sie könnten eine `QueryPipeline` hierfür erstellen, bei der die Ausgabe eines Schrittes die Eingabe des nächsten wird, möglicherweise mit einem LLM dazwischen, um die промежуточные Ergebnisse zu verarbeiten oder die nächste Stufe zu entscheiden.
Obwohl wir hier kein vollständiges Beispiel einer `QueryPipeline` erstellen (das ist ein Thema für sich!), seien Sie sich bewusst, dass es die Flexibilität für die tatsächliche Automatisierung komplexer Workflows innerhalb Ihrer LlamaIndex-Anwendung bietet. Sie können sogar einen `RouterQueryEngine` innerhalb einer `QueryPipeline` integrieren, um rekursive Entscheidungen zu treffen.
Wichtige Punkte für Ihr nächstes KI-Projekt
- Kartografieren Sie Ihre Datenquellen: Bevor Sie auch nur eine Zeile Code schreiben, identifizieren Sie klar alle Datenquellen, mit denen Ihre KI interagieren muss. Verstehen Sie deren Struktur (strukturiert, unstrukturiert, API-gesteuert).
- Definieren Sie klare Werkzeuge: Für jede Datenquelle erstellen Sie ein spezifisches LlamaIndex `Tool` (zum Beispiel `SQLTableRetrieverTool`, `QueryEngineTool`, `FunctionTool`). Schreiben Sie klare und beschreibende `metadata` für jedes Werkzeug. Diese Beschreibung ist das, was das LLM nutzt, um zu entscheiden, wann es aufgerufen wird. Nehmen Sie sich die Zeit dafür; das ist die Eingabeaufforderungs-Engineering für Ihre Werkzeuge!
- Beginnen Sie mit dem `RouterQueryEngine`: Für anfängliche Multi-Source-Projekte ist der `RouterQueryEngine` oft der einfachste Einstiegspunkt. Er verwaltet die Entscheidungsfindung basierend auf dem LLM für Sie.
- Verwenden Sie `verbose=True` großzügig: Wirklich, das ist Ihr bester Freund. Es gibt Ihnen Einblicke in das rationale Denken des LLM und hilft Ihnen, Ihre Werkzeugbeschreibungen zu verfeinern, wenn der Router unerwartete Entscheidungen trifft.
- Betrachten Sie `QueryPipeline` für Arbeitsabläufe: Wenn Ihre Fragen sequentielle Schritte, bedingte Logik oder wo die Ausgabe eines Werkzeugs direkt ein anderes speist, beinhalten, fangen Sie an, über `QueryPipeline` nachzudenken. Es ist komplizierter einzurichten, bietet jedoch ohne Präzedenzfall Kontrolle über mehrstufige Interaktionen.
- Iterieren Sie über die Werkzeugbeschreibungen: Die Fähigkeit des LLM, das richtige Werkzeug auszuwählen, hängt enorm davon ab, wie Sie den Zweck jedes Werkzeugs sowie dessen erwartete Eingaben/Ausgaben beschrieben haben. Scheuen Sie sich nicht, mit verschiedenen Formulierungen zu experimentieren.
Die Fähigkeit von LlamaIndex, intelligent Abfragen über verschiedene Datenquellen zu orchestrieren, stellt einen großen Fortschritt für die Erstellung von wirklich intelligenten Agenten dar. Dies bringt uns weg von einer starren, fest codierten Logik und näher zu Systemen, die in der Lage sind, über Informationsbedürfnisse nachzudenken und dynamisch Daten aus den passendsten Orten abzurufen. Der E-Commerce-Assistent meines Kunden ist jetzt viel intelligenter und in der Lage, Preise aus der Datenbank zu extrahieren, das Nutzerfeedback aus Bewertungen abzuleiten und die Lagerbestände über die API abzurufen, alles aus einer einzigen Anfrage in natürlicher Sprache. Das ist wirklich beeindruckend!
Das war’s für heute, Freunde! Gehen Sie raus und bauen Sie unglaublich intelligente und multikulturelle KI-Agenten. Lassen Sie mich in den Kommentaren wissen, was Sie erstellen!
Verwandte Artikel
- **TITEL: Die CLI-Tools, die ich liebe und warum Sie sie auch lieben sollten**
- Wie man KI-SDKs integriert
- Best Practices für die Entwicklung von KI-Agenten
🕒 Published: