Praktische Hinweise: Erstellen Sie einen selbstkorrigierenden AI-Agenten mit Self-RAG & LangGraph
Schritt-für-Schritt-Anleitung zu den Praktischen Hinweisen: Erstellen Sie einen selbstkorrigierenden AI-Agenten mit Self-RAG & LangGraph – inklusive Verträgen, Überprüfungen sowie Code-Blöcken für Teams, die dieses Muster einsetzen.
Quellen: Build a Self-Correcting AI Agent with Self-RAG & LangGraph
Dieser Leitfaden zeigt Schritt für Schritt den Weg von Rohstoffen bis zu einem funktionsfähigen System auf: Erstellung eines selbstkorrigierenden KI-Agenten mit Self-RAG und LangGraph. Der Schwerpunkt liegt auf ausführbaren Schritten, expliziten Überprüfungen sowie Code, den man ohne Rätseln über die Absicht direkt in ein Repository einfügen kann.
Warum Standard-RAG-Pipelines anfällig sind
Zur Erklärung, warum Standard-RAG-Pipelines anfällig sind, sollten Eingaben, der Verantwortliche für einen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Operator:innen sollten in der Lage sein, einen Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Die Konfiguration sollte außerhalb des Anwendungscode liegen. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort zusammengefasst sein, den Operator:innen überprüfen können, ohne den gesamten Graphen durchlesen zu müssen. Es sollten die Passagen zitiert werden, auf denen die Antwort tatsächlich beruht. Ohne Zitate können Operator:innen nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
Der lineare Pipeline: Abrufen und Annahme
Für den linearen Pipeline-Prozess: Definieren Sie vor dem Ändern des Codes die Eingaben, den Verantwortlichen für die jeweilige Schritt und die Abbruchkriterien. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zuständen schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern – ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
[User Query] ──> [Vector Database] ──> [Top-K Chunks] ──> [LLM Prompt] ──> [Final Answer]
Anatomie eines stillen Fehlers
Für eine „Anatomie eines stillen Fehlers“ sollten Eingaben, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Man sollte kleine, testbare Einheiten vor umfangreichen Skripten bevorzugen. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
Die Ursache: Blinder Glaube
Zur Ursache: Blinder Vertrauensgrundsatz – definieren Sie die Eingaben, den Verantwortlichen für den Schritt sowie die Abbruchkriterien, bevor Sie Code ändern. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zuständen schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
Die Lösung: Einführung selbstreflektierender Schleifen
Zur Lösung: Mit der Einführung selbstreflektierender Schleifen sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Erhalten Sie Zeiten sowie Kosten für Token oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von einer Demo-Umgebung in eine gemeinsam genutzte Umgebung wechselt. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden. Zur Lösung: Mit der Einführung selbstreflektierender Schleifen sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produktionsumfeld.
CT, spätestens bei der Polierung.Von blindem Abrufen zu Selbstreflexion: Das Self-RAG-Muster
Beim Arbeiten an „Von blindem Abrufen zu Selbstreflexion: Das Self-RAG-Muster“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie was bei teilweisen Fehlern geschieht. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Erinnerungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen. Häufige Änderungen der Anfragen beheben selten ein schwaches Abrufverhalten.
Die drei Säulen der Selbstkorrektur
Beim Arbeiten an „The Three Pillars of Self-Correction“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Arbeiten ab. Messen Sie die Erinnerungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Abrufverhalten.
[ Query ]
│
▼
1. Is Retrieval Needed? ──(No)──► Generate directly from parametric memory
│
(Yes)
▼
[ Retrieve ]
│
▼
2. Are Docs Relevant? ──(No)──► Reformulate search query & retry
│
(Yes)
▼
[ Generate ]
│
▼
3. Is Answer Faithful? ──(No)──► Regenerate or extract better context
│
(Yes)
▼
[ Final Output ]
Reflection Tokens als Steuersignale
Wenn Sie Reflection Tokens als Steuersignale verwenden, schreiben Sie zunächst den Vertrag auf: erforderliche Eingaben, Erfolgsignal sowie was bei einem teilweisen Versagen geschieht. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Einsatzbereich von einer Demo in gemeinsame Umgebungen wechselt. Cachen Sie stabile Systemanweisungen sowie Tool-Schemata. Das erneute Senden identischer Preambles ist eine häufige Ursache für Ressourcenverbrauch. Wenn Sie Reflection Tokens als Steuersignale verwenden, schreiben Sie zunächst den Vertrag auf: erforderliche Eingaben, Erfolgssignal sowie was bei einem teilweisen Versagen geschieht. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholte Versuche, menschliche Kontrollen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Die Architektur der Selbstreflexion
Die Architektur der Selbstreflexion funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie einen gelungenen Fall, einen Fehlerfall sowie die Notizen zur Rücksetzung, bevor Sie den Umfang erweitern. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Trennen Sie die Strategie zur Aufteilung in Teile von der Strategie zum Abrufen. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
graph TD
Start[User Query] --> DecideNeed{Is Retrieval Needed?}
DecideNeed -- No --> GenerateDirect[Generate Output]
DecideNeed -- Yes --> Retrieve[Retrieve Documents]
Retrieve --> GradeDocs[Grade Document Relevance]
GradeDocs -- Irrelevant --> Fallback[Rewrite Query / Fallback]
GradeDocs -- Relevant --> GenerateRef[Generate Response with Context]
GenerateRef --> GradeFaith[Grade Faithfulness & Hallucinations]
GradeFaith -- Hallucinated --> GenerateRef
GradeFaith -- Faithful --> GradeUtility[Grade Utility]
GradeUtility -- Low Utility --> Rewrite[Refine Response]
GradeUtility -- High Utility --> End[Final Answer]
Vergleich von Ablaufverfahren und Workflows
Der Vergleich von Pipelines und Workflows funktioniert am besten, wenn er als messbarer Bereich betrachtet wird. Erfassen Sie ein perfektes Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Trennen Sie die Strategie zur Aufteilung in Teile von der Strategie zum Abrufen. Ein Änderungs an einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
Architektur mit LangGraph: Von linearen Ketten zu Zustandsmaschinen
Architecting with LangGraph: From Linear Chains to State Machines funktioniert am besten, wenn es als messbare Größe betrachtet wird. Erfassen Sie ein optimales Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Erfassen Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Prozess von einer Demo in gemeinsam genutzte Umgebungen verschiebt. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zur Abrufung. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern. Architecting with LangGraph: From Linear Chains to State Machines funktioniert am besten, wenn es als messbare Größe betrachtet wird. Erfassen Sie ein optimales Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Linear RAG: [Query] ──> [Retrieve] ──> [Generate] ──> [Response] (No correction)
Self-RAG: [Query] ──> [Retrieve] ──> [Evaluate] ──┬─ (Valid) ──> [Response]
▲ │
└─────── (Invalid) ──────┘ (Loop & Refine)
Die Grenzen linearer Ketten
Für „Die Grenzen linearer Ketten“ sollten Eingaben, der Verantwortliche für einen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Operator:innen sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Vorzuziehen sind kleine, testbare Einheiten statt umfangreicher Skripte. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können Operator:innen nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
Die KI-Zustandsmaschine entmystifiziert
Zur Entmystifizierung der AI-State-Machine sollten Eingaben, Verantwortliche für die einzelnen Schritte sowie Ausstiegskriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Ergebnisdokumente, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
┌──────────────────────┐
│ Start │
└──────────┬───────────┘
▼
┌──────────────┐ ┌──────────────────────┐
│ Formulate │◄─┤ Retrieve Docs ├─┐
│ New Query │ └──────────────────────┘ │
└──────▲───────┘ │
│ ▼
┌──────┴───────┐ ┌──────────────────────┐ │
│ Re-Retrieve │ │ Grade Relevance │─┘
└──────────────┘ └──────────┬───────────┘
▼
┌──────────────────────┐
│ Generate Answer │
└──────────┬───────────┘
▼
┌──────────────────────┐
│ Grade Hallucination │
└──────────────────────┘
Innenansicht der Kernkomponenten von LangGraph
In „Inside the LangGraph Core Components“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Betreiber sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen der Laufzeiten sowie der Kosten für Token oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo-Umgebung in eine gemeinsam genutzte Umgebung wechselt. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Betreiber nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden. In „Inside the LangGraph Core Components“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Betreiber sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch die Notfallbehandlung gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung fehlerhafter Nachrichten gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Beim Arbeiten an „Implementing the Central Graph State“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen – häufige Änderungen der Anfragen beheben selten ein schwaches Suchsystem.
from typing import List, TypedDict
class GraphState(TypedDict):
"""
Represents the central state of our Self-RAG agent.
This TypedDict serves as the single source of truth passed between
each node in the LangGraph execution flow.
"""
question: str # The original user query
generation: str # The most recent answer generated by the LLM
documents: List[str] # Relevant text passages retrieved from our database
steps: List[str] # An audit trail tracking the sequence of execution steps
Aufbau des Graphen, Teil 1: Definition von Zustands- und Aktionselementen
Beim Arbeiten an „Building the Graph, Teil 1: Defining State and Action Nodes“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Messen Sie die Genauigkeit anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchverhalten.
Verständnis von statebasiertem Orchestrieren
Beim Arbeiten an „Understanding State-Based Orchestration“ sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo in gemeinsam genutzte Umgebungen übergeht. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragenanweisungen anpassen. Häufige Änderungen der Anfragenanweisungen beheben selten ein schwaches Suchsystem. Beim Arbeiten an „Understanding State-Based Orchestration“ sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.
+-------------------------------------------------------------+
| GRAPH STATE |
| - question: str |
| - documents: List[Document] |
| - generation: str |
| - relevance_grade: str |
+-------------------------------------------------------------+
|
+----------------------+----------------------+
| | |
v v v
+--------------+ +--------------+ +--------------+
| Retrieve | | Grade Docs | | Generate |
| Node | | Node | | Node |
+--------------+ +--------------+ +--------------+
Entwurf des gemeinsamen Zustandsregisters
Der Entwurf des gemeinsamen Zustandsregisters funktioniert am besten, wenn er als messbarer Ansatz betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Trennen Sie die Aufteilungspolitik von der Abrufpolitik. Eine Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
from typing import List, Dict, Any
from typing_extensions import TypedDict
from langchain_core.documents import Document
class GraphState(TypedDict):
"""
Represents the state of our Self-RAG graph.
Attributes:
question: The user query string.
documents: A list of retrieved document chunks.
generation: The generated answer from the LLM.
relevance_grade: The evaluation score of our documents ('yes' or 'no').
"""
question: str
documents: List[Document]
generation: str
relevance_grade: str
Der Abrufknoten: Schnittstelle zu Wissensbasen
Der Abrufknoten: Die Interaktion mit Wissensbasen funktioniert am besten, wenn sie als messbare Ebene betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie die Rollback-Anmerkung, bevor Sie den Umfang erweitern. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Trennen Sie die Chunking-Strategie von der Abrufstrategie. Ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_core.embeddings import FakeEmbeddings
# Initialize a mock vector store to simulate a production knowledge base
embeddings = FakeEmbeddings(size=1536)
vectorstore = InMemoryVectorStore(embeddings)
# Seed our vector store with sample documentation chunks
vectorstore.add_documents([
Document(page_content="LangGraph is a library for building stateful, multi-actor applications with LLMs.", metadata={"source": "docs"}),
Document(page_content="Self-RAG is an architecture that introduces self-reflection and grading into retrieval chains.", metadata={"source": "paper"}),
Document(page_content="Vector databases index text embeddings to enable fast semantic similarity search.", metadata={"source": "tech-blog"})
])
# Create a retriever interface
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
def retrieve(state: GraphState) -> Dict[str, Any]:
"""
Retrieve documents from the vector database based on the current question.
Args:
state (GraphState): The current state of the graph.
Returns:
dict: An update to the state containing the retrieved documents.
"""
print("--- NODE: RETRIEVING DOCUMENTS ---")
question = state["question"]
# Perform the semantic vector search
retrieved_docs = retriever.invoke(question)
# Return the updated document list to the graph state
return {"documents": retrieved_docs}
Der Erstellungsknoten: kontextbewusste Synthese
Der Generate Node: Context-Aware Synthesis funktioniert am besten, wenn er als messbare Größe betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Erfassen Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Prozess von einer Demo in gemeinsam genutzte Umgebungen verschiebt. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zur Abrufung. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern. Der Generate Node: Context-Aware Synthesis funktioniert am besten, wenn er als messbare Größe betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.language_models.fake import FakeListLLM
# Set up a mock LLM that simulates generating structured responses
# In production, replace this with: from langchain_openai import ChatOpenAI
llm = FakeListLLM(responses=[
"Self-RAG is an advanced architecture that uses self-reflection and document grading to improve retrieval accuracy."
])
def generate(state: GraphState) -> Dict[str, Any]:
"""
Generate an answer using the retrieved documents as grounding context.
Args:
state (GraphState): The current state of the graph.
Returns:
dict: An update to the state containing the generated answer.
"""
print("--- NODE: GENERATING ANSWER ---")
question = state["question"]
documents = state["documents"]
# Format the retrieved documents into a single context block
context = "\n\n".join([doc.page_content for doc in documents])
# Construct the instruction prompt
prompt = ChatPromptTemplate.from_template(
"You are an assistant for question-answering tasks.\n"
"Use the following pieces of retrieved context to answer the question.\n"
"If you do not know the answer, say that you do not know.\n"
"Question: {question}\n"
"Context: {context}\n"
"Answer:"
)
# Format the prompt with our state variables and run the model
chain = prompt | llm
generation = chain.invoke({"question": question, "context": context})
# Save the generated response to the state
return {"generation": generation}
Der Grade Documents Node: Der Qualitätsinspektor
Für den Knoten „Dokumente der Klasse“: Der Qualitätsinspektor sollte vor dem Ändern des Codes die Eingaben, den Verantwortlichen für den Schritt sowie die Abbruchkriterien definieren. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Man sollte kleine, testbare Einheiten vor umfangreichen Skripten bevorzugen. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
+-------------------+
| Retrieved Docs |
+-------------------+
|
v
+-----------------------+
| Is Doc Relevant? |
+-----------------------+
/ \
Yes / \ No
/ \
v v
+-------------------+ +------------------+
| Keep in State | | Filter / Discard |
| (Pass to Gen) | | (Trigger Loop) |
+-------------------+ +------------------+
from pydantic import BaseModel, Field
from langchain_core.output_parsers import JsonOutputParser
class DocumentGrade(BaseModel):
"""Binary score for document relevance assessment."""
binary_score: str = Field(
description="Relevance score for the document. Must be 'yes' or 'no'."
)
def grade_documents(state: GraphState) -> Dict[str, Any]:
"""
Assess whether the retrieved documents are relevant to the user question.
Filters out any irrelevant documents from the state.
Args:
state (GraphState): The current state of the graph.
Returns:
dict: Updated documents list and a global relevance grade flag.
"""
print("--- NODE: GRADING RETRIEVED DOCUMENTS ---")
question = state["question"]
documents = state["documents"]
# Use a mock parser to simulate LLM grading
# In production, use: llm.with_structured_output(DocumentGrade)
parser = JsonOutputParser(pydantic_object=DocumentGrade)
filtered_docs = []
has_relevant_doc = "no"
# Evaluate each document individually
for doc in documents:
# Construct a strict grading prompt
grade_prompt = (
f"Question: {question}\n"
f"Document: {doc.page_content}\n"
"Assess if this document is relevant to the question. Output JSON with key 'binary_score' as 'yes' or 'no'."
)
# Simulating LLM evaluation logic (in production, run the LLM chain here)
# For our mock run, if the query terms overlap with the document, mark 'yes'
is_relevant = any(term.lower() in doc.page_content.lower() for term in question.split())
score = "yes" if is_relevant else "no"
if score == "yes":
print(f" -> DOCUMENT GRADING: [RELEVANT] - Source: {doc.metadata.get('source')}")
filtered_docs.append(doc)
has_relevant_doc = "yes"
else:
print(f" -> DOCUMENT GRADING: [NOT RELEVANT] - Source: {doc.metadata.get('source')}")
# Update state with filtered documents and set the control flag
return {
"documents": filtered_docs,
"relevance_grade": has_relevant_doc
}
Aufbau des Graphen, Teil 2: Verknüpfung von Entscheidungen mit bedingten Kanten
Zur Erstellung des Graphen, Teil 2: Verknüpfung von Entscheidungen mit bedingten Kanten – definieren Sie die Eingaben, den Verantwortlichen für den Schritt sowie die Abbruchkriterien, bevor Sie Code ändern. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
+------------------+
| route_question |
+--------+---------+
|
+--------------+--------------+
| |
[web_search] [retrieve]
| |
+--------------> +------------+-------------+
| grade_documents |
+------------+--------------+
|
+-----+-----+
| Decision |
+-----+-----+
|
+-----------------+-----------------+
| |
(transform_query) (generate)
^ |
| +------+------+
| | Decision |
| +------+------+
| |
+--- [hallucination / unsat] -------+------> [__end__]
Der Eingangspunkt-Router: Zunächst die Abfrage überprüfen
Für den Entry Point Router: Zunächst die Abfrage überprüfen – definieren Sie vor dem Codeändern die Eingaben, den Verantwortlichen für den Schritt sowie die Abbruchkriterien. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen der Laufzeiten sowie der Kosten für Token oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden. Für den Entry Point Router: Zunächst die Abfrage überprüfen – definieren Sie vor dem Codeändern die Eingaben, den Verantwortlichen für den Schritt sowie die Abbruchkriterien. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören dazu.
Produkt – keine spätere Polierung.# router.py
from typing import Literal
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from state import AgentState
# Define the structured output schema for our router
class RouteQuery(BaseModel):
"""Route a user query to the most authoritative datasource."""
datasource: Literal["vectorstore", "web_search"] = Field(
...,
description="Given a user question choose to route it to web search or a vectorstore.",
)
def route_question(state: AgentState) -> str:
"""
Routes the initial question to either the vectorstore retrieval node or web search.
Args:
state (AgentState): The current graph state containing the user query.
Returns:
str: The next node to execute ("vectorstore" or "web_search").
"""
print("--- ROUTING QUESTION ---")
question = state["question"]
# Initialize our LLM with structured output mapping to our Pydantic schema
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
structured_router = llm.with_structured_output(RouteQuery)
# Create the routing system prompt
system_prompt = """You are an expert router directing user questions to a vectorstore or web search.
The vectorstore contains highly technical documentation regarding LangGraph, LangChain, and state machines.
Use the vectorstore for these specialized topics. Otherwise, use web_search for general knowledge or current events."""
route_prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", "{question}"),
])
# Run the router chain
router_chain = route_prompt | structured_router
decision = router_chain.invoke({"question": question})
if decision.datasource == "web_search":
print("--- ROUTING TO WEB SEARCH ---")
return "web_search"
print("--- ROUTING TO VECTORSTORE ---")
return "retrieve"
The Context Gate: Bewertung der Relevanz von Dokumenten
Beim Arbeiten mit „The Context Gate: Bewertung der Relevanz von Dokumenten“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Erinnerungsrate anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen. Häufige Änderungen der Anfragen beheben selten ein schwaches Suchsystem.
# context_gate.py
from state import AgentState
def decide_to_generate(state: AgentState) -> str:
"""
Evaluates the document grading state to choose the next step.
If any documents were graded as relevant, we proceed to answer generation.
If all documents were deemed irrelevant, we rewrite the query to try again.
Args:
state (AgentState): The current state of the agent.
Returns:
str: Next node to execute ("generate" or "transform_query").
"""
print("--- ASSESSING DOCUMENT RELEVANCE ---")
# Retrieve the decision variable set by the grading node
run_web_search = state.get("run_web_search", False)
if run_web_search:
# No documents were relevant, we must rewrite and search the web
print("--- DECISION: ALL DOCUMENTS IRRELEVANT, ROUTING TO QUERY TRANSFORMATION ---")
return "transform_query"
# We found relevant documents, we can proceed safely to generation
print("--- DECISION: RELEVANT DOCUMENTS FOUND, ROUTING TO GENERATE ---")
return "generate"
The Self-Correction Loop: Überprüfung von Treue und Nützlichkeit
Beim Arbeiten an „The Self-Correction Loop: Verifying Faithfulness and Utility“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Messen Sie die Erinnerungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Abrufverhalten.
+-------------------------+
| Answer Generated |
+------------+------------+
|
v
+--------------------------------+
| Is the answer grounded in |
| retrieved context? |
+----------------+---------------+
|
+---------------+---------------+
| |
[No] [Yes]
| |
v v
+-------------------+ +---------------------+
| Re-route to: | | Is the answer |
| "generate" | | actually useful? |
+-------------------+ +----------+----------+
|
+--------------+--------------+
| |
[No] [Yes]
| |
v v
+-------------------+ +------------------+
| Re-route to: | | Re-route to: |
| "transform_query" | | "__end__" |
+-------------------+ +------------------+
# self_correction.py
from typing import Literal
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from state import AgentState
class GradeHallucinations(BaseModel):
"""Binary score for hallucination present in generation."""
binary_score: Literal["yes", "no"] = Field(
...,
description="Answer is grounded in the facts, 'yes' or 'no'",
)
class GradeAnswer(BaseModel):
"""Binary score to assess if answer addresses question."""
binary_score: Literal["yes", "no"] = Field(
...,
description="Answer addresses the question, 'yes' or 'no'",
)
def grade_generation_v_documents_and_question(state: AgentState) -> str:
"""
Grades the generation for hallucinations and utility.
Args:
state (AgentState): The current graph state.
Returns:
str: Next step path ("supported" -> check utility, "not supported" -> regenerate, "not useful" -> rewrite query)
"""
print("--- CHECKING FOR HALLUCINATIONS ---")
question = state["question"]
documents = state["documents"]
generation = state["generation"]
# Initialize evaluator LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# ----------------------------------------
# STEP 1: Groundedness (Hallucination) Check
# ----------------------------------------
hallucination_grader = llm.with_structured_output(GradeHallucinations)
hallucination_system_prompt = """You are an objective grader assessing whether an LLM generation is grounded in / supported by a set of retrieved facts.
Give a binary score of 'yes' if the generation is strictly grounded in and supported by the provided facts. Otherwise, give 'no'."""
hallucination_prompt = ChatPromptTemplate.from_messages([
("system", hallucination_system_prompt),
("human", "Set of facts: \n\n {documents} \n\n LLM generation: {generation}"),
])
# Format document contents into a single string context
doc_context = "\n\n".join([doc.page_content for doc in documents])
hallucination_chain = hallucination_prompt | hallucination_grader
res = hallucination_chain.invoke({"documents": doc_context, "generation": generation})
if res.binary_score == "no":
print("--- DECISION: HALLUCINATION DETECTED! RE-TRYING GENERATION ---")
return "generate"
print("--- DECISION: GENERATION IS GROUNDED IN DOCUMENTS ---")
# ----------------------------------------
# STEP 2: Utility (Answer Relevance) Check
# ----------------------------------------
answer_grader = llm.with_structured_output(GradeAnswer)
answer_system_prompt = """You are an objective grader assessing whether an LLM generation addresses and resolves the user's question.
Give a binary score of 'yes' if the answer directly addresses and completely answers the user's question. Otherwise, give 'no'."""
answer_prompt = ChatPromptTemplate.from_messages([
("system", answer_system_prompt),
("human", "User question: \n\n {question} \n\n LLM generation: {generation}"),
])
answer_chain = answer_prompt | answer_grader
res_answer = answer_chain.invoke({"question": question, "generation": generation})
if res_answer.binary_score == "yes":
print("--- DECISION: ANSWER IS USEFUL AND ACCURATE. ENDING GRAPH ---")
return "useful"
print("--- DECISION: ANSWER DOES NOT FULLY ADDRESS QUESTION. REWRITING QUERY ---")
return "not useful"
Assembling and Compiling the StateGraph
Beim Aufbau und Kompilieren des StateGraphs sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo in gemeinsame Umgebungen wechselt. Messen Sie die Trefferquote anhand einer festgelegten Fragestellung, bevor Sie die Anfragenanweisungen anpassen. Häufige Änderungen der Anfragenanweisungen beheben selten ein schwaches Suchsystem. Beim Aufbau und Kompilieren des StateGraphs sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.
# graph_builder.py
from langgraph.graph import END, StateGraph
from state import AgentState
# Import node functions from Part 1
from nodes import retrieve, generate, transform_query, web_search, grade_documents
# Import conditional routing edges
from router import route_question
from context_gate import decide_to_generate
from self_correction import grade_generation_v_documents_and_question
# Initialize our state-based graph
workflow = StateGraph(AgentState)
# ----------------------------------------
# 1. Register All Computational Nodes
# ----------------------------------------
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade_documents", grade_documents)
workflow.add_node("generate", generate)
workflow.add_node("transform_query", transform_query)
workflow.add_node("web_search", web_search)
# ----------------------------------------
# 2. Configure Node Routing & Transitions
# ----------------------------------------
# The entry point of our execution is dynamic, decided by the routing edge
workflow.set_conditional_entry_point(
route_question,
{
"web_search": "web_search",
"retrieve": "retrieve",
},
)
# After retrieval, we must immediately grade our retrieved documents
workflow.add_edge("retrieve", "grade_documents")
# Once documents are graded, the Context Gate decides where to go
workflow.add_conditional_edges(
"grade_documents",
decide_to_generate,
{
"transform_query": "transform_query",
"generate": "generate",
},
)
# If query transformation occurs, we execute a web search to gather new data
workflow.add_edge("transform_query", "web_search")
# After web searching, we feed those newly acquired documents back to the grade step
workflow.add_edge("web_search", "grade_documents")
# Once generation occurs, our Self-Correction edge decides the final quality check
workflow.add_conditional_edges(
"generate",
grade_generation_v_documents_and_question,
{
"generate": "generate", # Loop back to fix hallucination
"not useful": "transform_query", # Loop back to rewrite query and search
"useful": END, # Exit cleanly
},
)
# ----------------------------------------
# 3. Compile and Run the Graph
# ----------------------------------------
app = workflow.compile()
# visualize.py
from graph_builder import app
try:
# Print the plain text visualization of the state machine architecture
app.get_graph().print_ascii()
except Exception as e:
print(f"ASCII generation failed: {e}")
+----------------+
| __start__ |
+-------+--------+
|
+---------+---------+
v v
+------------+ +------------+
| web_search | | retrieve |
+-----+------+ +-----+------+
| |
| v
| +-----+------+
| | grade_docs |
| +-----+------+
| |
+---------+---------+
|
v
+---------+---------+
| decide_to_gen |
+----+---------+----+
| |
+----------+ +----------+
v v
+-----+------+ +-----+------+
| transform_q| | generate |
+-----+------+ +-----+------+
| |
| v
| +---------+---------+
| | self_correct |
| +----+----+----+----+
| | | |
+--------------------------+ | +---> [__end__]
v
(regenerate)
Engineering Synthesis
Engineering Synthesis funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie die Notizen zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Trennen Sie die Strategie zur Aufteilung in Teile von der Strategie zum Abrufen. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
Anwendungen in der Praxis
„Real-World Applications“ funktioniert am besten, wenn sie als messbarer Rahmen betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein gelungenes Beispiel, einen Fehlerfall sowie die Notizen zur Rücksetzung. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Ergebnisse, definieren Sie Erfolgskriterien und lehnen Sie stille, unvollständige Abschlüsse ab. Trennen Sie die Strategie zur Aufteilung in Teile von der Strategie zum Abrufen. Ein Veränderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
Fortgeschrittene Kundensupport-Bots
Advanced Customer Support Bots funktionieren am besten, wenn sie als messbarer Bereich betrachtet werden. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erfassen Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Einsatzbereich von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zur Abrufung. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern. Advanced Customer Support Bots funktionieren am besten, wenn sie als messbarer Bereich betrachtet werden. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Dokumentieren Sie den erfolgreichen Ablauf sowie den Notfallablauf gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von fehlerhaften Nachrichten gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Automatisierte Faktenprüfungssysteme
Für automatisierte Faktenprüfungssysteme sollten die Eingaben, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Bediener sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Es sind kleinere, testbare Einheiten vorzuziehen statt umfangreicher Skripte. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortungsbereich verweisen und nicht auf ein verworrenes Ablaufschema. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Bediener nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
Dynamische Empfehlungsmaschinen
Für dynamische Empfehlungsmaschinen sollten die Eingaben, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Ergebnisdokumente, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.
Wissenschaftliche Forschungsassistenten
Für wissenschaftliche Forschungsassistenten sollten die Eingaben, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Bediener sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Erhalten Sie Zeiten sowie Kosten für Token oder Abfragen zusammen mit den funktionalen Ergebnissen fest. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von einer Demo-Umgebung in eine gemeinsam genutzte Umgebung wechselt. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Bediener nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden. Für wissenschaftliche Forschungsassistenten sollten die Eingaben, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Bediener sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung fehlerhafter Nachrichten gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Wann sollten Sie welchen Ansatz verwenden?
Beim Bearbeiten der Frage „Wann sollten Sie welchen Ansatz verwenden?“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine häufige Änderung der Anfragen behebt selten ein schwaches Suchverhalten.
Produktionsrichtlinien: Kosten, Latenz und Beobachtbarkeit
Beim Arbeiten an „Production Guardrails: Costs, Latency, and Observability“ sollten Sie zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgsprüfungen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Prompts anpassen. Ein häufiges Wechseln der Prompts behebt selten ein schwaches Suchverhalten.
Kosten und Latenz durch asymmetrisches Routing ausgleichen
Beim Arbeiten an der Ausbalancierung von Kosten und Latenz mit asymmetrischem Routing sollte man zunächst den Vertrag festhalten: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Pfad von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragenanweisungen anpassen. Häufige Änderungen der Anfragenanweisungen beheben selten ein schwaches Suchsystem. Beim Arbeiten an der Ausbalancierung von Kosten und Latenz mit asymmetrischem Routing sollte man zunächst den Vertrag festhalten: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Wiederherstellungsprozess gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Hartstopp-Schaltkreise im LangGraph-Zustand
Hartstopp-Schaltkreise im LangGraph-Zustand funktionieren am besten, wenn sie als messbare Struktur betrachtet werden. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Rücksetznotiz, bevor Sie den Umfang erweitern. Ziehen Sie kleine, testbare Einheiten vor großen, komplexen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf einen verworrenen Ablauf. Trennen Sie die Chunking-Strategie von der Abrufstrategie – Änderungen an einer sollten nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.
from typing import Dict, TypedDict, Literal
# Define graph state with a loop counter to act as a circuit breaker
class GraphState(TypedDict):
question: str
generation: str
documents: list[str]
loop_step: int # Tracks iterations to prevent runaway execution costs
MAX_RETRIES = 3
def grade_generation_route(state: GraphState) -> Literal["web_search", "finalize", "max_retries_exceeded"]:
"""
Evaluates the quality of generation and routes the agent accordingly.
Why: Acts as a deterministic circuit breaker when LLMs get stuck in correction loops.
"""
current_step = state.get("loop_step", 0)
# 1. Evaluate circuit breaker before making any expensive LLM calls
if current_step >= MAX_RETRIES:
return "max_retries_exceeded"
# 2. Simulated grader check (In production, this queries your grading model)
is_accurate = False # Assume we failed the grade in this step
if is_accurate:
return "finalize"
else:
# Route back for retrieval/generation rewrite
return "web_search"
Gestrukturierte Anfragen für deterministische Bewertung
Strukturierte Anfragen für deterministische Bewertung funktionieren am besten, wenn sie als messbare Struktur betrachtet werden. Erfassen Sie ein perfektes Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisdokumente, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Ergebnisse ab. Legen Sie Budgets für Tokens pro Turnus und pro Sitzung fest. Agentenbasierte Tools erweitern den Kontext oft übermäßig; feste Obergrenzen verhindern, dass Demonstrationen zu unerwarteten Rechnungen werden.
from langchain_core.pydantic_v1 import BaseModel, Field
class GradeDocument(BaseModel):
"""Binary score for document relevance assessment."""
binary_score: str = Field(
description="Relevance score for the document. Must be 'yes' or 'no'."
)
explanation: str = Field(
description="A brief, single-sentence justification for the given score."
)
Auswertung der Graphenausführung mit Überwachungsmechanismen
Die Verfolgung der Graphenausführung mit Observability-Engines funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Erfassen Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Ablauf von einer Demo in gemeinsame Umgebungen verschiebt. Trennen Sie die Chunking-Strategie von der Abrufstrategie – ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern. Die Verfolgung der Graphenausführung mit Observability-Engines funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
[User Query] ──> [retrieve] ──> [grade_documents] (Score: No)
│
▼
[finalize] <── [generate] <── [web_search] (Updated State: Loop Count = 1)
Was ein state-getriebener Workflow offenbart
Für das, was ein staatgesteuertes Workflow offenbart, sollten Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgenen Zuständen schließen zu müssen. Zur Vorzugsbehandlung kommen kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Pipeline-System. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Indexierungsfehlern unterscheiden.
Operative Checkliste
Die operative Checkliste funktioniert am besten, wenn sie als messbarer Überblick behandelt wird. Erfassen Sie ein „goldenes Transkript“, einen Fehlfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort gesammelt sein, den die Operator ohne das Durchlesen des gesamten Systems überprüfen können.
Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zum Abrufen. Ein Änderungsantrag an einer Seite sollte nicht zwangsläufig zu einem Neuschreiben der anderen führen, wenn sich die Qualitätsmetriken ändern.
Setzen Sie menschliche Überprüfung für Vorgänge ein, die Geld kosten oder Produktionsdaten verändern. Eine Verkabelung zur Laufzeit bedeutet noch nicht vollständige Geschäftsabdeckung.
Schreiben Sie ein kurzes Handbuch: Wie man Schlüssel rotiert, wie man die Warteschlange leert und wie man den letzten Eingang rückgängig macht.
Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Vorgänge ab.
Vor der Weiterentwicklung des Stack sollten Sie Versionen einfrieren, ein „goldenes Transkript“ für den kritischen Weg erstellen und die Schritte zum Rückschalten überprüfen. Gemeinsam genutzte Umgebungen benötigen Geschwindigkeitsbeschränkungen, Überprüfungen der Zuordnung sowie einen klaren Verantwortlichen für die Rotation von Geheimnissen. Ziehen Sie langweilige Zuverlässigkeit einer cleveren, einmaligen Demonstration vor.
Batch-Hinweis für eeb69aedbcbc: Halten Sie die Anbieter-Schlüssel außerhalb des Repositories, legen Sie eine Obergrenze für Tokens pro Sitzung fest und speichern Sie die Transkripte neben den Evaluierungs-Dateien, damit spätere Modellwechsel vergleichbar bleiben.