Startseite / Artikel

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.

Verlag: REACTAPP.TOP30 Min. Lesezeit6935 Wörter

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.