End-zu-End GraphRAG mit FalkorDB, Embeddings und LangGraph-Routing
Ein hybrider GraphRAG-Ablauf in einem Film-Datensatz: Graphabfragen mit FalkorDB, Embeddings von MiniLM für die Vektorsuche sowie LangGraph zur Entscheidung über den zu verwendenden Pfad.
Große Sprachmodelle antworten fließend auf Grundlage von Trainingsdaten, stolpern jedoch, wenn die Frage eine neue Struktur erfordert – etwa wer welchen Film inszeniert hat, welche Schauspieler mitspielten oder welche Verbindungen zwei Entitäten verknüpfen. GraphRAG-Systeme schließen diese Lücke, indem sie eine Vektorsuche in unstrukturiertem Text mit expliziten Graphenabfragen zu Beziehungen kombinieren und anschließend ein LLM dazu nutzen, beides miteinander in Einklang zu bringen.
In dieser Anleitung wird ein funktionsfähiger Workflow für Filmdaten erstellt: FalkorDB als Graphenspeicher, Hugging Face MiniLM-Embeddings für semantische Suche, auf Groq gehostete Modelle zur Routenfindung und Antwortgenerierung, LangChain-Hilfsmittel für die Datenabfrage sowie LangGraph zur Steuerung des Ablaufs. Es handelt sich dabei nicht um eine Demo, sondern um ein Muster, das auf jeden Bereich übertragen werden kann, in dem Beziehungen genauso wichtig sind wie Absätze.
Warum Graphen zu Vektoren hinzukommen
Die Vektorsuche findet ähnliche Abschnitte. Graphabfragen finden typisierte Pfade. Wenn man nach Filmen von Christopher Nolan fragt, ist eine Graphenkante präziser als eine Schätzung auf Basis des nächsten Nachbarn. Bei der Anfrage nach „verrückten Raubfilm-Vertonungen wie Inception“ kommen die Vektoren zum Tragen. Echte Assistenten benötigen beides sowie einen Router, der entscheidet, welchen Weg eingeschlagen werden soll – oder wann ein Hybridweg verwendet werden muss.
MATCH (d:Director {name: 'Christopher Nolan'})-[:DIRECTED]->(m:Movie) RETURN m.title
MATCH (m:Movie)-[r]->(d:Director) RETURN m, r, d
Umgebung und FalkorDB
Erstellen Sie eine virtuelle Umgebung, installieren Sie ggf. Jupyter für ein exploratives Notebook und fixieren Sie die Versionen. Die Oberfläche von LangChain ändert sich; das Fixieren ist Teil der Reproduzierbarkeit.
$ pip install jupyterlab
$ jupyter lab
# 1. SETUP WSL (Run in Windows PowerShell as Administrator)
wsl --install
# Restart your computer if prompted, then create your Linux username/password.
# Inside the WSL/Ubuntu terminal, update packages:
sudo apt update && sudo apt upgrade -y
# 2. SET ENVIRONMENT VARIABLES (Paste your keys from Groq & Hugging Face)
export GROQ_API_KEY="your_groq_api_key_here"
export HUGGINGFACEHUB_API_TOKEN="your_hf_token_here"
# 3. ENVIRONMENT & DEPENDENCY SETUP
# Install Python pip and virtual environment tools
sudo apt install python3-pip python3-venv -y
# Create and activate a project directory
mkdir movie-graphrag && cd movie-graphrag
python3 -m venv venv
source venv/bin/activate
# Verify everything is correctly configured
echo "Groq Key: $GROQ_API_KEY"
echo "HF Token: $HUGGINGFACEHUB_API_TOKEN"
Führen Sie FalkorDB lokal mit Docker aus oder nutzen Sie eine verwaltete Instanz, falls dies zu Ihrem Team passt. Lokaler Docker hält die Experimente kostengünstig:
docker run -p 6379:6379 -p 3000:3000 -it --rm -v ./data:/data falkordb/falkordb:edge
Installieren Sie genau die Bibliotheksliste, mit der dieses Workflow getestet wurde, nachdem ältere LangChain-Installationen entfernt wurden:
pip uninstall langchain langchain-core langchain-community langchain-groq \
langchain-huggingface langgraph -y
pip install falkordb pandas pydantic sentence-transformers
pip install "langchain==0.3.26"
pip install "langchain-core==0.3.68"
pip install "langchain-community==0.3.23"
pip install "langchain-groq==0.2.5"
pip install "langchain-huggingface==0.1.2"
pip install "langgraph==0.3.34"
Laden des IMDB-stiligen Datensatzes
Laden Sie eine CSV-Datei im Top-1000-Stil mit Filmen herunter und laden Sie sie anschließend mit den Import-Methoden sowie der Verbindungs-Einrichtung, die Ihr Notebook erwartet:
import os, re, sys, logging
import pandas as pd
from typing import List, TypedDict, Literal
from falkordb import FalkorDB
from langchain_community.document_loaders.csv_loader import CSVLoader
from langchain_community.vectorstores.falkordb_vector import FalkorDBVector
from langchain_community.graphs import FalkorDBGraph
from langchain_community.chains.graph_qa.falkordb import FalkorDBQAChain
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.output_parsers import PydanticToolsParser
from pydantic import BaseModel, Field # pydantic v2 — not langchain_core.pydantic_v1
from langchain_huggingface import HuggingFaceEmbeddings # not langchain.embeddings (deprecated)
from langchain_groq import ChatGroq
from langgraph.graph import END, StateGraph
GROQ_API_KEY = "your_groq_api_key"
CSV_PATH = "imdb_top_1000.csv"
os.environ["HF_TOKEN"] = "your_hf_token"
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
# Connect to FalkorDB and select the graph
db = FalkorDB(host='localhost', port=6379)
graph = db.select_graph('imdb')
data = pd.read_csv(CSV_PATH)
Aufbau des Wissensgraphen
Erstellen Sie Filmknoten mit Eigenschaften wie Titel, Jahr und Zertifizierungsstatus. Erstellen Sie außerdem Knoten für Regisseure und Schauspieler. Verbinden Sie sie mithilfe typisierter Beziehungen, damit Cypher-artige Abfragen Fragen zu Besetzung und Crew beantworten können, ohne darauf angewiesen zu sein, dass ein Embedding sich an die Verbindung erinnert.
def clean_column(column_data):
"""Remove special characters that would break Cypher queries."""
return column_data.apply(
lambda x: re.sub(r"[^a-zA-Z0-9\s]", "", x) if pd.notnull(x) else 'NA'
)
for col in ['Series_Title', 'Director', 'Certificate', 'Runtime', 'Genre',
'Overview', 'Star1', 'Star2', 'Star3', 'Star4']:
data[col] = clean_column(data[col])
data['IMDB_Rating'] = data['IMDB_Rating'].fillna('NA')
data['Released_Year'] = pd.to_numeric(data['Released_Year'], errors='coerce').fillna(-1)
star_columns = ['Star1', 'Star2', 'Star3', 'Star4']
for index, row in data.iterrows():
movie_title = row['Series_Title']
director_name = row['Director']
released_year = int(row['Released_Year']) if row['Released_Year'] != -1 else None
if released_year is None:
print(f"Skipping '{movie_title}' — invalid year.")
continue
movie_node = (
f"MERGE (m:Movie {{"
f"title: '{movie_title}', year: {released_year}, "
f"certificate: '{row['Certificate']}', runtime: '{row['Runtime']}', "
f"genre: '{row['Genre']}', imdb_rating: {row['IMDB_Rating']}, "
f"description: '{row['Overview']}'"
f"}})"
)
director_node = f"MERGE (d:Director {{name: '{director_name}'}})"
directed_relation = "MERGE (d)-[:DIRECTED]->(m)"
star_nodes, starred_relations = "", ""
for s, star_col in enumerate(star_columns, start=1):
star_name = row[star_col]
if star_name != 'NA':
star_nodes += f"MERGE (s{s}:Star {{name: '{star_name}'}})\n"
starred_relations += f"MERGE (s{s})-[:STARRED_IN]->(m)\n"
cypher_query = (
f"{movie_node} {director_node} {directed_relation} "
f"{star_nodes.strip()}\n{starred_relations.strip()}"
)
graph.query(cypher_query)
print("Knowledge Graph created.")
Embeddings für semantische Abfragen
Verwenden Sie all-MiniLM-L6-v2 über das moderne Hugging Face-Integrationspaket anstelle von veralteten Import-Pfaden:
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
result = graph.query(
"MATCH (m:Movie) RETURN m.title AS title, m.description AS description"
)
documents = [
Document(
page_content=row[1] if row[1] else "",
metadata={"title": row[0], "description": row[1]}
)
for row in result.result_set if row[1]
]
vector_index = FalkorDBVector(host='localhost', port=6379, embedding=embedding_model)
vector_index.add_documents(documents)
print("Vector index created.")
Speichern Sie Vektoren neben dem Graphen oder in Koordination damit, sodass hybride Knoten Filmtitel aus der semantischen Suche abrufen und diese anschließend über Beziehungen erweitern können.
GraphState für LangGraph
Definieren Sie ein TypedDict (oder Äquivalentes) namens GraphState, das die Benutzerfrage, die Routenentscheidung, Unterabfragen, Vektorergebnisse, Graphantworten sowie die endgültige Antwort enthält. LangGraph speichert diesen Zustand über die Knoten hinweg, sodass nachfolgende Anfragen den Kontext wiederverwenden können, anstatt von einem leeren Prompt auszugehen.
class GraphState(TypedDict):
"""
Tracks state across the entire LangGraph workflow.
Every node reads from and writes to this dictionary.
"""
question: str
documents: object
movie_titles: List[str]
subqueries: object
prompt_with_context: object
Abfragerouting
Nicht jede Frage sollte an jedes Unterystem gesendet werden. Ein Router klassifiziert, ob die Frage hauptsächlich relationell, hauptsächlich semantisch, hybrid oder außerhalb des Aufgabengebiets liegt. Dadurch wird die Latenz reduziert und widersprüchlicher Kontext vermieden.
llm = ChatGroq(groq_api_key=GROQ_API_KEY, model_name="llama-3.3-70b-versatile")
class RouteQuery(BaseModel):
"""Route a user query to the most relevant datasource."""
datasource: Literal["vector search", "graph query"] = Field(
...,
description="Route to 'vector search' for similarity queries, "
"'graph query' for relationship/fact queries.",
)
structured_llm_router = llm.with_structured_output(RouteQuery)
route_system_prompt = """You are an expert at routing user questions.
Route to VECTOR SEARCH for questions involving:
- Similarity (similar, related, like, closest, relevant)
- Themes or topics (movies about space, about love, etc.)
- "Find movies similar to X"
Route to GRAPH QUERY for questions involving:
- Specific facts (who directed X, what year was X released)
- Specific people (movies by Christopher Nolan)
- Filtering by property (movies from 1990, Action movies)
"""
route_prompt = ChatPromptTemplate.from_messages([
("system", route_system_prompt),
("human", "{question}"),
])
question_router = route_prompt | structured_llm_router
def route_question(state: GraphState):
source = question_router.invoke({"question": state["question"]})
if source.datasource == "vector search":
return "decomposer"
else:
return "graph_qa"
Zerlegungsfunktion
Wenn der hybride Weg genutzt wird, zerlegt eine Zerlegungsfunktion die Benutzerfrage in Unterabfragen, die von den Vektor- und Graphknoten verarbeitet werden können:
class SubQuery(BaseModel):
"""A single sub-query decomposed from the original question."""
sub_query: str = Field(
..., description="A unique paraphrasing of the original question.",
)
decompose_system = """You are an expert at breaking down complex questions.
Given a user question, split it into exactly two sub-queries:
1. A query for vector similarity search (find related/similar items)
2. A query for a graph database (find specific relationships or facts)
Example:
Question: Find movies directed by Christopher Nolan related to dreams.
sub_query 1: Find movies related to dreams or the subconscious.
sub_query 2: Find movies directed by Christopher Nolan.
"""
decompose_prompt = ChatPromptTemplate.from_messages([
("system", decompose_system),
("human", "{question}"),
])
llm_with_tools = llm.bind_tools([SubQuery])
parser = PydanticToolsParser(tools=[SubQuery])
query_analyzer = decompose_prompt | llm_with_tools | parser
def decomposer(state: GraphState):
question = state["question"]
subqueries = query_analyzer.invoke({"question": question})
return {"subqueries": subqueries, "question": question}
Vektorsuchenknoten
Implementieren Sie eine Ähnlichkeitssuche mit den aktuellen LangChain-Auswertungshilfen:
def vector_search(state: GraphState):
question = state["question"]
retriever = vector_index.as_retriever(search_kwargs={"k": 3})
qa_prompt = ChatPromptTemplate.from_messages([
("system",
"You are a movie expert. Use the context below to answer the question.\n\n"
"Context:\n{context}"),
("human", "{input}"),
])
combine_docs_chain = create_stuff_documents_chain(llm, qa_prompt)
retrieval_chain = create_retrieval_chain(retriever, combine_docs_chain)
result = retrieval_chain.invoke({"input": question})
source_docs = result.get("context", [])
extracted_data, movie_titles = [], []
for doc in source_docs:
title = doc.metadata.get("title", "Unknown")
description = doc.metadata.get("description", "")
extracted_data.append({"title": title, "description": description})
movie_titles.append(title)
return {
"movie_titles": movie_titles,
"documents": extracted_data,
"question": question,
"subqueries": state["subqueries"],
}
Graph-FAQ-Knoten
Übersetzen Sie relationale Unterfragen in Graphabfragen. Bei einer Anfrage im Stil einer Filmografie eines Regisseurs sollte der Graph Titel zurückgeben, die durch „geleitet von“-Kanten miteinander verbunden sind, anstatt eine umformulierte Schätzung:
def graph_qa(state: GraphState):
question = state["question"]
graph_wrapper = FalkorDBGraph(database="imdb", host="localhost", port=6379)
chain = FalkorDBQAChain.from_llm(
llm,
graph=graph_wrapper,
verbose=True,
allow_dangerous_requests=True,
)
result = chain.invoke({"query": question})
answer = result.get("result", str(result))
return {"documents": answer, "question": question}
Graph-basierte QA mit Vektorkontext
Der hybride Knoten übernimmt semantisch ermittelte Titel und erweitert sie um graphische Strukturen – Besetzung, Crew, verwandte Filme – bevor das LLM eine endgültige Antwort verfasst:
def graph_qa_with_context(state: GraphState):
titles = state["movie_titles"]
question = state["question"]
input_query = (
f"Return the title, genre, director, and IMDB rating of movies "
f"with these titles: {str(titles)}"
)
graph_wrapper = FalkorDBGraph(database="imdb", host="localhost", port=6379)
chain = FalkorDBQAChain.from_llm(
llm,
graph=graph_wrapper,
verbose=True,
allow_dangerous_requests=True,
return_intermediate_steps=True,
)
result = chain.invoke({"query": input_query})
context = ""
steps = result.get("intermediate_steps", [])
if len(steps) > 1:
context = str(steps[1].get("context", ""))
return {
"documents": context,
"subqueries": state["subqueries"],
"question": question,
}
Antwortknoten
Normalisieren Sie die endgültige Antwort in natürlicher Sprache, fügen Sie gegebenenfalls die Herkunft hinzu und löschen Sie Zwischendaten, die nicht an den Kunden weitergegeben werden sollen:
def respond(state: GraphState):
question = state["question"]
context = state["documents"]
respond_prompt = ChatPromptTemplate.from_messages([
("system",
"You are a helpful movie expert assistant.\n"
"Use the context below to answer the user's question clearly and concisely.\n\n"
"Context:\n{context}"),
("human", "{question}"),
])
answer = (respond_prompt | llm).invoke({"context": context, "question": question})
return {"documents": answer.content}
LangGraph-Ablauf verbinden
Vernetzen Sie die Knoten Router, Dekomposer, Vektor, Graph, Hybrid und Antwort mit bedingten Kanten, die den Route-Bezeichnungen entsprechen:
workflow = StateGraph(GraphState)
# Register all nodes
workflow.add_node("graph_qa", graph_qa)
workflow.add_node("decomposer", decomposer)
workflow.add_node("vector_search", vector_search)
workflow.add_node("graph_qa_with_context", graph_qa_with_context)
workflow.add_node("respond", respond)
# Conditional entry point — route_question decides the first node
workflow.set_conditional_entry_point(
route_question,
{
"decomposer": "decomposer",
"graph_qa": "graph_qa",
},
)
# Hybrid path
workflow.add_edge("decomposer", "vector_search")
workflow.add_edge("vector_search", "graph_qa_with_context")
workflow.add_edge("graph_qa_with_context", "respond")
workflow.add_edge("respond", END)
# Direct graph path
workflow.add_edge("graph_qa", END)
app = workflow.compile()
Visualisieren Sie den Graphen zur Dokumentation und Einführung:
from IPython.display import Image, display
try:
display(Image(app.get_graph().draw_mermaid_png()))
except Exception:
pass
Test und interaktive Konsole
Führen Sie skriptbasierte Fragen durch, die relationale, semantische sowie hybride Fälle abdecken:
# Graph query — specific fact question
result1 = app.invoke({"question": "Which movies did Christopher Nolan direct?"})
print(result1["documents"])
Dann verwenden Sie einen einfachen Konsole-Loop für manuelle Untersuchungen:
print("\n" + "=" * 60)
print("INTERACTIVE MODE — type a question (or 'quit' to exit)")
print("=" * 60)
while True:
user_question = input("\nYour question: ").strip()
if user_question.lower() in ("quit", "exit", "q"):
print("Goodbye!")
break
if not user_question:
continue
try:
result = app.invoke({"question": user_question})
print("\nANSWER:", result["documents"])
except Exception as e:
print(f"Error: {e}")
Ergebnisse, die überprüft werden sollten
Stellen Sie sicher, dass Nolan-stilige Regiefragen graphbasierte Titel zurückgeben, dass Stimmungsfragen semantisch sinnvolle Filme liefern und dass hybride Fragen beide Arten von Belegen angeben. Wenn die Antworten abweichen, prüfen Sie die Zustandsdarstellungen zwischen den Knoten und nicht nur den endgültigen String.
Zusammenfassung und Anpassungstipps
GraphRAG ist genauso ein Routing-Problem wie ein Speicherproblem. FalkorDB (oder jede andere Graph-Datenbank mit niedriger Latenz) bietet eine strukturierte Organisation der Daten. Embeddings ermöglichen ein ungenaues, aber schnelles Abrufen von Informationen. LangGraph sorgt dafür, dass der Ablauf klar genug ist, um getestet werden zu können. Ersetzen Sie Filme durch Elemente aus Ihrem eigenen Bereich – wie Bauteile und Lieferanten, Patienten und Protokolle sowie Dienstleistungen und Abhängigkeiten – während Sie die gleichen Knotenrollen beibehalten: Routen, abrufen, erweitern, antworten.
Markieren Sie Versionen, führen Sie für jeden Routentyp eine „goldene“ Fragestellungssammlung und protokollieren Sie Zustandswechsel. Diese betriebliche Disziplin ist wichtiger als das Demo-Datensatz, mit dem Sie angefangen haben.
Entwurfsnotizen, die auch im Produktivbetrieb Bestand haben
Die Entitätsauflösung wird bei echten Implementierungen eine zentrale Rolle spielen. Filmtitel sind relativ eindeutig; Firmennamen und Produkt-SKUs hingegen nicht. Planen Sie einen NormalisierungsSchritt vor der Erstellung der Knoten und führen Sie eine Zuordnung von Rohstrings zu kanonischen IDs durch. Ohne diese Vorgehensweise werden Graphabfragen unstrukturiert und vectorbasierte Suchergebnisse auf Duplikate verweisen.
Die Schema-Entwicklung erfordert genauso wie SQL Migrations. Das Hinzufügen eines neuen Beziehungs types ist in einem Notebook einfach, doch schwierig, sobald Dashboards von alten Verbindungen abhängen. Versionieren Sie Ihr Graphschema und speichern Sie es neben dem Workflow-Code.
Latenzbudgets sollten klar definiert sein. Anrufe bei Router-LLMs fügen bereits vor dem eigentlichen Abruf Zeit hinzu. Für Systeme mit hohem QPS sollten Regeln oder kleine Klassifikatoren für offensichtliche relationale Muster („Wer hat X inszeniert?“) verwendet werden, während das LLM-Routing für unklaren Text reserviert bleibt.
Die Bewertung sollte die Genauigkeit der Route getrennt von der Qualität der Antwort bewerten. Eine perfekte Antwort auf dem falschen Weg verbraucht dennoch Ressourcen und versagt, wenn ein Untersystem ausfällt. Führen Sie einen Chaos-Test durch, indem Sie das Graph oder den Vektorindex deaktivieren und überprüfen, ob sich der Arbeitsablauf tatsächlich verschlechtert.
Sicherheit ist wichtig: Die Erstellung von Graphabfragen muss eingeschränkt werden. Verwenden Sie lieber parametrisierte Vorlagen statt freiformiger Cypher-Anfragen aus einem Modell. Dasselbe Prinzip, das bei SQL-Tools gilt, gilt auch hier.
Kostenkontrolle: Cachen Sie Embeddings für stabile Dokumente sowie Entscheidungen des Routers für identische Fragen innerhalb einer kurzen TTL und vermeiden Sie hybride Erweiterungen, wenn bereits reine Graphanalysen hochzuverlässige Ergebnisse liefern.
Wenn Sie dies in einem Interview erläutern, zeichnen Sie zunächst das State-Objekt und anschließend die Kanten. Interviewer folgen dem Kontrollfluss schneller als Paketnamen. Erwähnen Sie FalkorDB wegen der Geschwindigkeit bei Property-Graphs, MiniLM für lokale Embeddings und Groq nur als eine mögliche LLM-Plattform – Ihre Architektur sollte nicht an einen einzigen Inferenzanbieter gebunden sein.
Schließlich sollten die Fehlermeldungen dokumentiert werden, die den Benutzern angezeigt werden, wenn das Diagramm leer ist oder der Router nicht reagiert. Stille „Halluzinationen“ sind der Grund, warum GraphRAG-Demos bereits nach der ersten Woche das Vertrauen verlieren. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Einrichtungen auf Route-Ebene grün, bevor Sie das Diagrammschema um neue Entitätsarten erweitern. Halten Sie die Route…
Halten Sie die Ebenen-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene-Fixierungen grün, bevor das Graphenschema auf neue Entitätsarten erweitert wird. Halten Sie die Streckenebene- FiHalten Sie die Strukturen in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene in Grün, bevor Sie das Graphenschema auf neue Entity-Typen erweitern. Halten Sie die Einrichtungen auf Route-Ebene grünÜbersetzen Sie den folgenden englischen Text ins Deutsche. Geben Sie nur die deutsche Übersetzung aus:- Graphen für Finanzkriminalität mit mehreren Agenten unter Verwendung von LangChain, LangGraph und LangSmith — Supervisor-Routing, parallele Überprüfungen, Untergraphen, Unterbrechungen, Bewertungen sowie Schutzmechanismen für Ermittlungsprozesse auf höchstem Niveau.
- Ephemerer semantischer Suchmaschinenansatz mit LangGraph – wann Vektoren nicht gespeichert werden sollten — Sitzungsspezifische Embeddings, die bei Beendigung der Sitzung verschwinden, schaffen klare Grenzen und ermöglichen den späteren Wechsel zu Redis oder Azure AI Search lediglich durch einen Anpassung des Speicheradapters.