LlamaIndex Plus LangGraph: Ein sauberes Muster für RAG-Agenten
Wie man eine Wissensdatenbank mit LlamaIndex erstellt und sie als Tool einem LangGraph-Agenten zur Verfügung stellt, wobei Persistenz, Chroma sowie der reine Retrieval-Modus erläutert werden.
Quellen: RAG Without the Guesswork: A Standardized LangGraph + LlamaIndex Pattern.
Der Blindpunkt und die Arbeitsteilung
Ein LangGraph-Agent weiß nur das, was sein LLM während des Trainings aufgenommen hat. Fragen zu einer internen Preispolitik, dem Finanzbericht des letzten Quartals oder einem letzten Woche fertiggestellten Handbuch erhalten entweder ein Eingeständnis der Unwissenheit oder, schlimmer noch, eine selbstsichere Fälschung.
Retrieval-Augmented Generation (RAG) schließt diese Lücke. Zum Zeitpunkt der Abfrage holt es relevante Auszüge aus Ihren eigenen Dokumenten ab und gibt sie dem LLM als Kontext, bevor es antwortet – dadurch liest das Modell statt zu raten. RAG ist eine Funktion, die einem einzelnen Agent hinzugefügt wird. Es handelt sich dabei nicht um ein neues Orchestrierungsmuster, weshalb Supervisor, Subgraphen und Send außerhalb dieses Konzepts bleiben. Vorausgesetzt wird lediglich eine gewisse Vertrautheit mit der Struktur eines LangGraph-Agenten sowie mit der Art und Weise, ihm Werkzeuge zur Verfügung zu stellen.
Es ist möglich, den Pipeline-Prozess in LangGraph manuell aufzubauen: Man schreibt seinen eigenen Chunker, die Code für die Embedding-Berechnung sowie den Vektorindex und die Abfragemechanismen. Viele Teams tun dies – doch es handelt sich dabei um erhebliche Aufwände für etwas, das bereits gelöst ist. LlamaIndex wurde genau dazu entwickelt, diese Arbeit zu übernehmen. Es ist mit Abstand die ausgereifteste und beliebteste Option für den Datenteil einer KI-Anwendung und umfasst das Laden, Chunken, Embedding, Indexieren sowie Abfragen. Der Orchestrierungsteil, also Zustandsverwaltung, Kontrollfluss und mehrstufiges Reasoning, liegt bei LangGraph.
Diese Aufteilung führt zur Architektur, die die meisten produktiven RAG-Systeme verwenden: LlamaIndex erstellt und stellt die Wissensbasis bereit. LangGraph betrachtet sie als Werkzeug und entscheidet, wann darauf zugegriffen werden soll.
Ein mentaler Modell für LlamaIndex
Betrachten Sie LlamaIndex als einen Bibliothekar für Ihr LLM. Das LLM gleicht einem brillanten Forschungsassistenten, der einen großen Teil des Internets gelesen hat, aber noch nie die Unterlagen Ihres Unternehmens eingesehen hat – und niemand kann von ihm verlangen, einen 10.000-seitigen Ordner auswendig zu lernen. Deshalb tritt der Bibliothekar ein: Er liest jedes Dokument, zerlegt es in kleine, suchbare Indexkarten (Blöcke), speichert diese Karten an einem Ort, an dem eine schnelle Suche nach Themen möglich ist (einen Vektorindex), und holt jeweils nur die 3 bis 5 relevantesten Karten, wenn der Assistent etwas fragt. Der Assistent merkt sich nie etwas – es kommen nur einige Auszüge, und die Verarbeitung erfolgt anhand dieser.
Der fünfstufige Prozess
Jedes RAG-System, unabhängig vom Framework, durchläuft dieselben fünf Stufen, und LlamaIndex bietet eine klare Abstraktion für jede davon.
1. LOAD → Read raw files (PDF, Word, web pages, databases) into Documents
2. CHUNK → Split Documents into small, retrievable Nodes
3. EMBED → Convert each Node's text into a vector (a list of numbers
representing meaning)
4. STORE → Save those vectors in a Vector Index for fast lookup
5. RETRIEVE → At query time, embed the user's question, find the most
similar Nodes, and return them as context
Die ersten vier Phasen laufen einmal, wenn die Wissensdatenbank erstellt wird – das wird als Indexierung bezeichnet. Die fünfte Phase läuft jedes Mal, wenn ein Benutzer eine Frage stellt – das wird als Abfragen bezeichnet. Die Zeit für die Indexierung im Vergleich zur Abfristzeit ist vermutlich das wichtigste Konzept in RAG, und es lohnt sich, sich daran zu erinnern.
Das Vokabular
Documentbezeichnet einen Rohdateninhalt, wie beispielsweise ein PDF, eine Webseite oder eine Datenbankzeile samt deren Metadaten. Es handelt sich dabei um die unverarbeitete, vollständige Einheit.Nodeist ein aus einemDocumentabgetrennter Teil. LLMs und Embedding-Modelle arbeiten besser mit fokussierten, kurzen Textabschnitten als mit ganzen Dokumenten, weshalb LlamaIndex jedesDocumentin vieleNode-Objekte aufteilt. Die Nodes übertragen Metadaten an ihre Elternobjekte, sodass jeder Teil wieder auf seine Quelle zurückverfolgt werden kann.SimpleDirectoryReaderist der übliche Lader: Weisen Sie ihn auf ein Verzeichnis hin, und er liest PDFs, Texte, Word-Dateien sowie andere Formate und erzeugt pro Datei ein oder mehrereDocument-Objekte.VectorStoreIndexist die Hauptklassen für das Indexieren. MitDocument- oderNode-Objekten werden diese eingebettet und ein suchbarer Vektorindex erstellt – entweder im Speicher oder in einer externen Vektordatenbank, falls diese konfiguriert ist.Settingsist ein globales Konfigurationsobjekt. Die LLM- und Embedding-Modelle werden einmal darauf festgelegt, und jedes Komponente greift darauf zu, sodass sie bei jeder Aufruf nicht erneut übergeben werden müssen.QueryEngineist das, an das man tatsächlich Fragen stellt. Es stammt von.as_query_engine()auf einem Index, und ein einziger Aufruf embeddet die Abfrage, führt eine Ähnlichkeitssuche durch und gibt den ermittelten Kontext an das LLM weiter, um eine endgültige Antwort zu erhalten.Retrieverstammt von.as_retriever()auf einem Index und kümmert sich nur um den Suchvorgang. Es gibt die rohen, passendenNode-Objekte zurück und erzeugt keine Antwort, was für Fälle geeignet ist, in denen die Extraktion und Generierung getrennte, steuerbare Schritte sein sollten. Genau das ist die Situation, sobald LangGraph hinzukommt.
Der Pipeline wird zunächst ohne LangGraph selbst erstellt.
Eine funktionierende Pipeline in etwa zehn Zeilen
Zuerst erfolgt die Installation.
# Core package + OpenAI LLM and embedding integrations (the common starting setup)
pip install llama-index-core llama-index-llms-openai llama-index-embeddings-openai
# Readers for common file types (PDF, Word, etc.)
pip install llama-index-readers-file pypdf
LlamaIndex wird absichtlich in vielen kleinen Paketen bereitgestellt. llama-index-core enthält die Framework-Logik, während die Auswahl des LLM, des Embedding-Modells, der Vektordatenbank sowie des Dateileseers jeweils in einem separaten Paket liegt, das nur bei Bedarf installiert wird. Dadurch bleiben die Installationen leicht.
Eine kleine Konfigurationsdatei legt die globalen Standardwerte fest.
# ── llamaindex_config.py ─────────────────────────────────────
import os
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# Settings is global - configure once, used everywhere in LlamaIndex
Settings.llm = OpenAI(
model="gpt-4o-mini", # Used for generating final answers from retrieved context
temperature=0.1, # Low temperature: factual, not creative
)
Settings.embed_model = OpenAIEmbedding(
model="text-embedding-3-small", # Used to convert text into vectors
)
# Controls how documents are split into Nodes (chunks)
Settings.chunk_size = 512 # Max tokens per chunk
Settings.chunk_overlap = 50 # Overlap between consecutive chunks, to preserve context across boundaries
Zu chunk_size: Zu große Blöcke enthalten so viel Text, dass die Auswertung ungenau wird, da ein heruntergeladener Block möglicherweise nur zu 10 Prozent relevant ist. Zu kleine Blöcke führen zum Verlust des umliegenden Kontexts, den das LLM benötigt, um eine Aussage zu verstehen. Ein Anfangswert von 512 Token mit einer Überlappung von 50 Token ist üblich und sinnvoll, wobei anschließend je nach Dokument angepasst wird.
Dann die Wissensdatenbank selbst:
# ── build_knowledge_base.py ──────────────────────────────────
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
# ── LOAD: Read all files in a folder into Document objects ──
documents = SimpleDirectoryReader("./data").load_data()
print(f"Loaded {len(documents)} documents")
# ── CHUNK + EMBED + STORE: all three happen inside this one call ──
# VectorStoreIndex automatically:
# 1. Splits each Document into Nodes (using Settings.chunk_size)
# 2. Embeds each Node (using Settings.embed_model)
# 3. Stores the vectors in an in-memory index
index = VectorStoreIndex.from_documents(documents, show_progress=True)
# ── RETRIEVE + GENERATE: ask a question ──────────────────────
query_engine = index.as_query_engine(
similarity_top_k=3, # Retrieve the 3 most relevant chunks for each query
)
response = query_engine.query("What is our refund policy for enterprise customers?")
print(response)
Etwa zehn Zeilen reichen aus, um ein funktionsfähiges RAG-System zu erstellen – das ist das „Hello World“ des Frameworks und ein guter Beleg dafür, warum es existiert. Die manuelle Umsetzung würde einen benutzerdefinierten Trenner, eine Schleife zur Aufrufung des Embedding-Modells, eine Suche nach dem nächsten Nachbarn sowie ein Prompt-Muster erfordern.
Speichern des Index
Während des Aufbaus des Index wird jeder Datenblock durch das Embedding-Modell gejagt, was Geld und Zeit kostet; daher ist ein Neubau bei jedem Anwendungsstart verschwenderisch. Das Speichern des Index auf der Festplatte und dessen Später Laden vermeidet das.
# ── Save the index after building it ─────────────────────────
index.storage_context.persist(persist_dir="./storage")
# ── Load it back later without re-embedding anything ──────────
from llama_index.core import StorageContext, load_index_from_storage
storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)
storage_context.persist() speichert die Vektordaten, die Metadaten der Knoten sowie den Dokumentenspeicher in einem lokalen Ordner, und load_index_from_storage() erstellt aus diesen Dateien denselben Index erneut – ohne erneutes Einbetten und ohne API-Aufrufe. Es folgt derselben Idee des einmaligen Aufbaus, der anschließenden Speicherung sowie der kostengünstigen Neu laden, wie sie ein LangGraph Checkpointer verwendet.
Eine echte Vektordatenbank
Ein Index im Arbeitsspeicher eignet sich für Prototypen. In der Produktion wird in der Regel eine speziell entwickelte Vektordatenbank benötigt, die für Millionen von Vektoren, gleichzeitige Lesevorgänge sowie skalierbares Metadatenfiltern konzipiert ist. Chroma ist hier ein Beispiel dafür.
# ── Using Chroma as a persistent, production-grade vector store ──
# pip install llama-index-vector-stores-chroma chromadb
import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext, VectorStoreIndex
chroma_client = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = chroma_client.get_or_create_collection("my_knowledge_base")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# Build the index directly into Chroma
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context
)
# Later, in a different process, reconnect without re-indexing:
index = VectorStoreIndex.from_vector_store(vector_store=vector_store)
Der Austausch ähnelt dem von Checkpointern. Man tauscht ein einzelnes Objekt aus (den In-Memory-Speicher für ChromaVectorStore, genauso wie MemorySaver durch SqliteSaver ersetzt wird), während der Abfragemotor sowie die anschließende Abruflogik unverändert bleiben. Pinecone, Qdrant, Weaviate sowie die meisten anderen Vektordatenbanken, die von LlamaIndex unterstützt werden, funktionieren auf dieselbe Weise.
Die Verbindung der beiden Frameworks
Hier liegt das Kernproblem: Die Frameworks sprechen unterschiedliche Sprachen – ein LlamaIndex QueryEngine ist kein LangGraph-Tool, da ein LangGraph-Agent Tools erwartet, die mit dem @tool-Decorator von LangChain erstellt wurden.
Die Integration ist einfach. Definieren Sie eine normale Python-Funktion, setzen Sie @tool darauf und lassen Sie ihren Körper query_engine.query(...) aufrufen. Das ist die gesamte Integration. LangGraph muss nichts über die Interna von LlamaIndex wissen, denn es betrachtet die Funktion als ein Tool, das einen String entgegennimmt und einen String zurückgibt, genauso wie alle anderen Tools.
# ── MODULE 3: TOOLS (LlamaIndex-backed) ─────────────────────
from langchain_core.tools import tool
# The query_engine built in Part B - created once, at startup
# (In a real app, you'd load this from persisted storage, not rebuild it every time)
@tool
def search_knowledge_base(query: str) -> str:
"""Search the internal knowledge base for company policies, product
documentation, and internal procedures. Use this whenever the user asks
a question that might be answered by internal company documents rather
than general knowledge.
Args:
query: A natural-language question to search for.
Returns:
A synthesized answer based on the most relevant retrieved documents.
"""
response = query_engine.query(query)
return str(response)
Die Dokumentation ist genauso wichtig wie bei jedem anderen Tool. Die LLM des Agents liest sie, um zu entscheiden, wann dieses Tool aufgerufen werden soll, anstatt aus seinem eigenen Wissen zu antworten oder ein anderes Tool zu nutzen.
Der vollständige Agent
Hier ist das vollständige Agent-Template mit einem von LlamaIndex unterstützten RAG-Tool im Tools-Modul. Ansonsten ändert sich nichts.
# ============================================================
# LANGGRAPH + LLAMAINDEX RAG AGENT — COMPLETE TEMPLATE
# Extends: Part 1 (core structure)
# ============================================================
# ── MODULE 1: IMPORTS & CONFIGURATION ───────────────────────
import os
from typing import Literal
# LangChain / LangGraph imports (the orchestration layer)
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage, BaseMessage
from langchain_core.tools import tool
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.memory import MemorySaver
# LlamaIndex imports (the retrieval / data layer)
from llama_index.core import (1
Settings, SimpleDirectoryReader, VectorStoreIndex,
StorageContext, load_index_from_storage
)
from llama_index.llms.openai import OpenAI as LlamaOpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# LangGraph's chat model - used by the agent's reasoning
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# LlamaIndex's model config - used internally by the query engine
# Note: these are SEPARATE from the LangGraph llm above. Each framework
# manages its own model instances; they don't share state.
Settings.llm = LlamaOpenAI(model="gpt-4o-mini", temperature=0.1)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.chunk_size = 512
# ── MODULE 2: STATE ──────────────────────────────────────────
class State(MessagesState):
pass # messages field inherited; extend if your agent needs more
# ── MODULE 3: TOOLS (RAG-backed) ─────────────────────────────
# Build or load the LlamaIndex knowledge base ONCE, at startup
PERSIST_DIR = "./storage"
if os.path.exists(PERSIST_DIR):
# Reload existing index - no re-embedding, fast startup
storage_context = StorageContext.from_defaults(persist_dir=PERSIST_DIR)
index = load_index_from_storage(storage_context)
else:
# First run - build the index and persist it
documents = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(documents, show_progress=True)
index.storage_context.persist(persist_dir=PERSIST_DIR)
query_engine = index.as_query_engine(similarity_top_k=3)
@tool
def search_knowledge_base(query: str) -> str:
"""Search internal company documents for policies, product specs,
procedures, and other domain-specific information. Use this for any
question that requires knowledge specific to this organization rather
than general world knowledge."""
response = query_engine.query(query)
return str(response)
tools = [search_knowledge_base]
llm_with_tools = llm.bind_tools(tools)
tool_node = ToolNode(tools)
# ── MODULE 4: NODES ──────────────────────────────────────────
def agent_node(state: State) -> dict:
"""The reasoning node. Decides whether to answer directly or
search the knowledge base first."""
system_prompt = SystemMessage(content=(
"You are a helpful assistant with access to an internal knowledge base. "
"Use the search_knowledge_base tool when the user asks about company-specific "
"information. For general questions, answer directly."
))
messages = [system_prompt] + state["messages"]
response = llm_with_tools.invoke(messages)
return {"messages": [response]}
# ── MODULE 5: ROUTING ────────────────────────────────────────
def should_continue(state: State) -> Literal["tools", "__end__"]:
last_message = state["messages"][-1]
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "tools"
return "__end__"
# ── MODULE 6: GRAPH ASSEMBLY ─────────────────────────────────
graph_builder = StateGraph(State)
graph_builder.add_node("agent", agent_node)
graph_builder.add_node("tools", tool_node)
graph_builder.add_edge(START, "agent")
graph_builder.add_conditional_edges(
"agent", should_continue,
{"tools": "tools", "__end__": END}
)
graph_builder.add_edge("tools", "agent")
graph = graph_builder.compile(checkpointer=MemorySaver())
# ── MODULE 7: ENTRYPOINT ──────────────────────────────────────
if __name__ == "__main__":
config = {"configurable": {"thread_id": "session-001"}}
print("RAG agent ready. Ask about your documents, or anything else.\n")
while True:
user_text = input("You: ").strip()
if not user_text or user_text.lower() == "exit":
break
response = graph.invoke(
{"messages": [HumanMessage(content=user_text)]},
config=config
)
print(f"Agent: {response['messages'][-1].content}\n")
Was passiert bei einer Anfrage
Die Verfolgung einer einzelnen Anfrage macht die Arbeitsteilung klar.
User: "What's our policy on remote work?"
↓
[agent_node] — LangGraph's LLM reads the message, recognizes this needs
internal info, decides to call search_knowledge_base
↓
[tools] — ToolNode executes search_knowledge_base("What's our policy on remote work?")
↓
Inside the tool: query_engine.query(...) runs —
this is 100% LlamaIndex, invisible to LangGraph:
1. Embeds the query
2. Searches the vector index for the 3 closest chunks
3. Feeds those chunks + the question to Settings.llm
4. Returns a synthesized answer string
↓
[agent_node] — LangGraph's LLM receives the tool's string result,
and crafts the final response shown to the user
↓
Response to user
Die Grenze ist klar definiert. LangGraph stößt niemals auf einen Node, eine Embedding-Struktur oder einen Vektor, sondern nur auf ein Tool, das Text zurückgibt – genauso wie search_web oder calculate. LlamaIndex kommt weder auf messages, state noch auf einen thread_id zu, sondern es werden lediglich eine Eingabestring und eine Ausgabeanwort übertragen. Jedes Framework nutzt seine Stärken, und eine Funktionsaufruf bildet dabei die Verbindung zwischen ihnen.
Modus „Nur Retriever“ für mehr Kontrolle
Das Muster query_engine.query() bietet die einfachste Integration und eignet sich für die meisten Fälle. Manchmal ist jedoch mehr Kontrolle nötig – beispielsweise dann, wenn das eigene LLM des LangGraph-Agenten die endgültige Antwort unter Verwendung des vorhandenen Systemprompts und des Konversationskontexts schreiben soll, anstatt auf LlamaIndex’s interne Settings.llm zurückzugreifen, welches eine separate, unvollständige Antwort erzeugt.
In diesem Fall sollten Sie anstelle eines QueryEngine einen Retriever verwenden. Er führt nur den Suchvorgang durch und gibt rohe Datenblöcke zurück; was danach geschieht, liegt beim Agenten.
# ── Retriever-only tool: returns raw chunks, not a synthesized answer ──
retriever = index.as_retriever(similarity_top_k=3)
@tool
def retrieve_documents(query: str) -> str:
"""Retrieve relevant document excerpts from the internal knowledge base.
Returns raw excerpts for you to read and reason over yourself -
use this when you need to cite specific sources or combine information
from multiple documents."""
nodes = retriever.retrieve(query)
# Format each retrieved chunk with its source for transparency
formatted_chunks = []
for i, node in enumerate(nodes):
source = node.metadata.get("file_name", "unknown source")
formatted_chunks.append(f"[Excerpt {i+1} from {source}]\n{node.text}")
return "\n\n---\n\n".join(formatted_chunks)
Durch diese Konfiguration ruft der agent_node seine eigene LLM-Funktion auf – mithilfe von llm_with_tools sowie der vollständigen Konversationsgeschichte und des Systemprompt – liest er die Rohauszüge ein und schreibt anschließend die Antwort. Das bringt echte Vorteile: Der Agent kann angeben, aus welchem Dokument eine Information stammt, er kann die abgerufenen Auszüge mit früheren Gesprächspunkten verbinden, und die Nutzer hören eine einheitliche Stimme, anstatt zwei LLMs in unterschiedlichen Stilen.
Welchen wählen?
Wählen Sie QueryEngine für die einfachste Integration, wenn es ausreicht, dass die LLM von LlamaIndex eine auf Abfragen basierende Antwort als eigenständigen String erzeugt. Das eignet sich für die meisten Chatbots und Assistenten.
Wählen Sie Retriever, wenn Quellenangaben erforderlich sind, wenn die Haupt-LLM des Agents einen konstanten Stil in der Darstellung und im Denken sowohl bei abgerufenen als auch bei nicht abgerufenen Antworten beibehalten soll, oder wenn die abgerufenen Teile vor der endgültigen Antwort mit Ergebnissen anderer Tools kombiniert werden müssen.
Schlüsselwortreferenz
Laden und Indizieren. Ein Document ist eine geladene Quelle – entweder eine Datei oder eine Seite. Ein Node ist ein Teil davon, die abrufbare Einheit, wobei Metadaten auf seine Herkunft verweisen. SimpleDirectoryReader("./path").load_data() lädt alle unterstützten Dateien in einem Verzeichnis als Document-Objekte. Settings ist das globale Konfigurations-Singleton, und Settings.llm, Settings.embed_model sowie Settings.chunk_size werden einmalig für alle Komponenten festgelegt. VectorStoreIndex.from_documents(documents) teilt die Daten in Blöcke auf, fügt sie ein und speichert sie in einem einzigen Aufruf.
Abfragen. index.as_query_engine(similarity_top_k=3) liefert einen QueryEngine, der die top-k Blöcke abruft und außerdem eine synthetisierte Antwort erstellt. index.as_retriever(similarity_top_k=3) liefert einen Retriever, der nur die top-k Blöcke abruft – das eignet sich für Szenarien, in denen Ihre eigene LLM die Synthese übernimmt. query_engine.query("...") führt den gesamten Ablauf von Abruf bis Erstellung aus und gibt ein Response-Objekt zurück, wobei str(response) den Text extrahiert. retriever.retrieve("...") führt ausschließlich den Abruf durch und gibt Node-Objekte zurück, die .text und .metadata bereitstellen.
Beständigkeit. index.storage_context.persist(persist_dir="./storage") speichert den Index, sodass bei Neustarts keine erneute Einbettung erforderlich ist. StorageContext.from_defaults(persist_dir="./storage") in Kombination mit load_index_from_storage(...) lädt ihn wieder hoch. ChromaVectorStore, PineconeVectorStore und QdrantVectorStore sind externe Backend-Lösungen, die den standardmäßigen In-Memory-Speicher ersetzen, ähnlich wie die Checkpointer von LangGraph.
Die Brücke. Eine @tool-Funktion, deren Körper query_engine.query(...) aufruft, stellt die gesamte Integration dar: LangGraph erkennt ein gewöhnliches Tool, während LlamaIndex weiterhin eingebettet bleibt. Es existieren auch getrennte LLM-Konfigurationen. Settings.llm ist das interne Modell von LlamaIndex, das nur innerhalb des Abfragemotors verwendet wird, während das LangGraph-llm des Agents für die eigentliche Schlussfolgerungsleistung zuständig ist. Beide laufen unabhängig voneinander und teilen weder Historie noch Zustand.
Brauchen Sie das?
- Falls der Agent nur allgemeines Wissen, Mathematik oder eine Live-Web-Suche benötigt, ist LlamaIndex nicht erforderlich – das grundlegende Template mit Standard-Tools reicht aus.
- Falls er aus einer festen Menge an Dokumenten antworten muss, wie beispielsweise Richtlinien, Handbüchern oder selten geänderten Berichten, ist es genau richtig, einen
QueryEngineals Tool zu verwenden.
Retriever-Muster.interrupt()-Funktion und platzieren Sie den Suchaufruf in einem Knoten, der auf die Genehmigung wartet, wie es bei allen sensiblen Werkzeugen der Fall ist.Zwei Frameworks und eine Schnittstelle
Die zentrale Botschaft ist, dass das Verleihen von praktischem Wissen an Agenten kein LangGraph-Problem darstellt. Es handelt sich dabei um ein Daten-Problem, und ein Datenframework ist das richtige Werkzeug dafür. Ein komplexes Mehr-Agenten-System besteht tatsächlich aus mehreren einzelnen Agentengraphen, die miteinander verbunden sind, und der Zugriff auf Wissen folgt demselben modularen Prinzip.
LlamaIndex kümmert sich um Indexierung und Abruf, während LangGraph für das Reasoning und die Orchestrierung zuständig ist. Die gesamte Verbindung erfolgt über eine mit @tool dekorierte Funktion. Das ist keine Einschränkung, sondern eine angemessene Kopplung, da jedes Framework in seinem Bereich bleibt und jede Seite unabhängig aktualisiert werden kann. Die Vektordatenbank kann ausgetauscht werden, ohne den Graphen zu berühren, und ein Supervisor-Muster kann hinzugefügt werden, ohne die Abruflogik zu verändern.
Verwandte Literatur
- MCP für LangGraph Agents, Schritt für Schritt: Server, Transportmechanismen und der Adapter-Brückenelement — Erlernen Sie das Model Context Protocol von den Rollen von Host, Client und Server über einen FastMCP-Server, stdio gegenüber HTTP, langchain-mcp-adapters sowie typische Fehlerquellen in LangGraph.
- Erstellen Sie ShopBot: einen LangGraph-Support-Agenten mit Speicherfunktionen, Werkzeugen und Möglichkeit zur Genehmigung von Rückerstattungen — Bauen Sie einen Kundensupport-Agenten in LangGraph Modul für Modul auf: Zustandsverwaltung, Werkzeuge, Knoten, Routing, zusammenfassende Berichte sowie eine Funktion, die auf die Genehmigung einer Rückerstattung wartet.