Startseite / Artikel / Praktische Notizen: Architektur des Agent-Verbesserungslaufs: Bewertung auf Produktionsniveau

Praktische Notizen: Architektur des Agent-Verbesserungslaufs: Bewertung auf Produktionsniveau

Schrittweise Anleitung zu den Praktischen Notizen: Architektur des Agent-Verbesserungslaufs: Bewertung auf Produktionsniveau – Verträge, Überprüfungen sowie Code-Blöcke für Teams, die dieses Muster einsetzen.

4955 Wörter

Die folgenden Notizen skizzieren einen praktischen Ansatz zu „Architecting the Agent Improvement Loop: Production-Grade Eval Pipelines“. Der Schwerpunkt liegt auf Verträgen, Überprüfungen und Code-Platzhaltern statt auf motivierenden Formulierungen.

Einführung

Während der Einführungsphase 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. Notieren Sie außerdem die Laufzeiten sowie die Kosten für Token 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. Legen Sie nach aufwändigen Schritten einen Zwischencheckpunkt an. Das Wiederaufnehmen des Prozesses sollte keine erneuten Kosten für denselben LLM-Aufruf verursachen, wenn ein Operator einen späteren Knoten erneut ausführt.

Inhaltsverzeichnis

Während der Erstellung des Inhaltsverzeichnisses 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. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreuer ohne das Durchlesen des gesamten Systems überprüfen können. Erstellen Sie nach aufwändigen Schritten einen Checkpoint. Das Wiederaufnehmen des Vorgangs sollte keine doppelte Abrechnung für denselben LLM-Aufruf verursachen, wenn ein Betreuer einen späteren Knoten erneut ausführt.

Phase 1: Grundlagen

Während der Phase 1 Foundation-Phase 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. 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. Legen Sie nach kostspieligen Schritten einen Kontrollpunkt an – das Resume sollte keine doppelten Gebühren für denselben LLM-Aufruf erheben, wenn ein Operator einen späteren Knoten erneut versucht.

Einrichtung der Umgebung

Während der Phase des Aufbaus der Umgebung 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. Legen Sie nach teuren Schritten Kontrollpunkte an. Das Wiederaufnehmen des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf veranlassen, wenn ein Operator einen späteren Knoten erneut versucht.

# Install the libraries we need
pip install langgraph langchain langchain-openai langsmith
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=your_langsmith_key
export LANGSMITH_PROJECT=agent-improvement-loop
export OPENAI_API_KEY=your_openai_key
# Step 1: Import the pieces we need
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
# Step 2: Define two tools the agent can call
@tool
def get_account_info(account_id: str) -> str:
    """Look up basic information for an account by account_id."""
    fake_accounts = {
        "A100": "Account A100: plan=pro, status=active, email=ada@example.com",
        "A200": "Account A200: plan=free, status=suspended, email=turing@example.com",
    }
    return fake_accounts.get(account_id, f"No account found with id {account_id}")

@tool
def get_recent_orders(account_id: str) -> str:
    """Return the three most recent orders for a given account_id."""
    fake_orders = {
        "A100": "Orders for A100: #9001 shipped, #9002 processing, #9003 returned",
        "A200": "Orders for A200: no orders in the last 90 days",
    }
    return fake_orders.get(account_id, f"No orders for {account_id}")
# Step 3: Wire the tools into a ReAct agent
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [get_account_info, get_recent_orders]
agent = create_react_agent(model, tools)

Lassen Sie uns den Agenten testen

Wenn Sie die Phase „Lass uns testen“ durchgehen, schreiben Sie zunächst den Vertrag auf: 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 Artefakte, definieren Sie Erfolgsprüfungen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Erstellen Sie Kontrollpunkte nach aufwändigen Schritten. Das Resume sollte bei einer Neuprobe eines späteren Knotens nicht denselben LLM-Aufruf erneut berechnen.

# Step 4: Invoke the agent with a simple query
result = agent.invoke({
    "messages": [{"role": "user", "content": "What plan is account A100 on?"}]
})

for message in result["messages"]:
    print(message.type, ":", message.content)

Wenn Sie die Phase „Lass uns testen“ durchgehen, schreiben Sie zunächst den Vertrag auf: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gespeichert sein, den Operator ohne das Lesen des gesamten Graphen überprüfen können.

human : What plan is account A100 on?
ai :
tool : Account A100: plan=pro, status=active, email=ada@example.com
ai : Account A100 is on the pro plan.

Phase 2: Protokollsammlung

Die Phase der Protokollsammlung in Phase 2 funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie die Notizen zum Rollback, bevor Sie den Umfang erweitern. Dokumentieren Sie gleichzeitig den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Halten Sie den Zustand der Graphen strukturiert und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen der Verarbeitung.

Aus der Produktion aktuelle Protokolle abrufen

Das Herunterladen neuer Spuren aus der Ausführungsphase funktioniert am besten, wenn es als messbare Oberfläche behandelt wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie die Rollback-Anmerkung, bevor Sie den Umfang erweitern. 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 einen verworrenen Ablauf. Halten Sie den Zustand der Graphen flach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Wiederaufnehmen der Ausführung.

# Step 1: Create a LangSmith client
from langsmith import Client
from datetime import datetime, timedelta

client = Client()
# Step 2: List recent root runs from our project
recent_runs = list(client.list_runs(
    project_name="agent-improvement-loop",
    is_root=True,
    start_time=datetime.utcnow() - timedelta(days=1),
))

print(f"Found {len(recent_runs)} root runs in the last 24 hours")
Found 42 root runs in the last 24 hours

Die benötigten Felder sammeln

Die Phase des Sammelns der Felder funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, 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. Halten Sie den Zustand des Graphen flach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen bei der Fortsetzung der Verarbeitung. Die Phase des Sammelns der Felder funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Halten Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort gespeichert werden, den Betreuer ohne Durchsicht des gesamten Graphen prüfen können.

# Step 3: Build a compact trace record from each run
def compact_trace(run):
    return {
        "run_id": str(run.id),
        "inputs": run.inputs,
        "outputs": run.outputs,
        "error": run.error,
        "latency_ms": (run.end_time - run.start_time).total_seconds() * 1000
            if run.end_time else None,
        "tool_calls": [
            child.name for child in client.list_runs(
                trace_id=run.trace_id, run_type="tool"
            )
        ],
    }

traces = [compact_trace(run) for run in recent_runs]
print(f"Collected {len(traces)} compact traces")
print("Example tool calls:", traces[0]["tool_calls"])
Collected 42 compact traces
Example tool calls: ['get_account_info']
# Step 4: Inspect the first trace end to end
import json
print(json.dumps(traces[0], indent=2, default=str))
{
  "run_id": "b1d2e3f4-...",
  "inputs": {"messages": [{"role": "user", "content": "What plan is account A100 on?"}]},
  "outputs": {"messages": [{"role": "ai", "content": "Account A100 is on the pro plan."}]},
  "error": null,
  "latency_ms": 1423.51,
  "tool_calls": ["get_account_info"]
}

Phase 3: Erweiterung von Spuren mit Scores

In der Phase 3 zur Erweiterung von Spuren sollten die 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 versteckte 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 zum Produkt selbst, nicht zu späteren Optimierungen. Setzen Sie menschliche Freigabe für Schritte voraus, die Geld ausgeben oder Produktionsdaten ändern. Eine Verkabelung zur Kompilierzeit bedeutet nicht automatisch vollständige Geschäftsabdeckung.

Schicht 1: Überprüfung der Korrektheit von tools basierend auf Code

Für die auf Code der Ebene 1 basierende Phase sollten 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 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 Ablaufverfahren. Authentifizieren Sie sich am Gateway und erteilen Sie erneut Berechtigungen auf der Datenebene. Ein alleiniges Trägertoken stellt keine Trennlinie zwischen verschiedenen Nutzern dar.

# Step 1: Define a rule that says which tool SHOULD be called for a given query
import re

def expected_tool_for_query(query: str) -> str:
    q = query.lower()
    if re.search(r"\b(order|shipment|shipped|return)\b", q):
        return "get_recent_orders"
    if re.search(r"\b(plan|account|status|email)\b", q):
        return "get_account_info"
    return "any"

def score_tool_correctness(trace):
    query = trace["inputs"]["messages"][0]["content"]
    expected = expected_tool_for_query(query)
    actual = trace["tool_calls"][0] if trace["tool_calls"] else None
    if expected == "any":
        return 1.0
    return 1.0 if actual == expected else 0.0
# Step 2: Score qualitative properties with an LLM judge
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

judge_model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

judge_prompt = ChatPromptTemplate.from_messages([
    ("system", "You are an expert reviewer of AI agent responses. "
               "Rate the response on a scale of 1 to 5 for helpfulness. "
               "Respond with only a single integer, nothing else."),
    ("user", "User question: {question}\n\nAgent response: {response}\n\nScore:"),
])

def score_helpfulness(trace):
    question = trace["inputs"]["messages"][0]["content"]
    response = trace["outputs"]["messages"][-1]["content"]
    chain = judge_prompt | judge_model
    result = chain.invoke({"question": question, "response": response})
    try:
        return int(result.content.strip()) / 5.0
    except ValueError:
        return 0.0

Ebene 3: Die Autorenprüfung als Annotation-Warteschlange

In der Autorüberprüfungsphase der Schicht 3 sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor jeder Codeänderung 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. 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. Setzen Sie menschliche Freigabe bei Vorgängen ein, die Geld kosten oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen entsprechen nicht der Geschäftsabschlussqualität. In der Autorüberprüfungsphase der Schicht 3 sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor jeder Codeänderung 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. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den die Operator ohne Lesen des gesamten Inhalts prüfen können.

aph.

# Step 3: Model a human review signal
def score_human(trace, human_labels: dict) -> float | None:
    run_id = trace["run_id"]
    return human_labels.get(run_id)

human_labels = {
    "b1d2e3f4-...": 1.0,
    "c2e3f4g5-...": 0.0,
}

Kombinieren der drei Schichten

Während der Phase des Kombinierens der drei Schichten 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. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Erstellen Sie Kontrollpunkte nach kostspieligen Schritten. Das System sollte bei erneuten Versuchen eines Operators an einem späteren Knoten nicht denselben LLM-Aufruf erneut berechnen.

# Step 4: Run all three scorers and attach scores to each trace
def enrich(trace):
    trace["scores"] = {
        "tool_correctness": score_tool_correctness(trace),
        "helpfulness": score_helpfulness(trace),
        "human": score_human(trace, human_labels),
    }
    return trace

enriched = [enrich(t) for t in traces]
print(json.dumps(enriched[0]["scores"], indent=2))
{
  "tool_correctness": 1.0,
  "helpfulness": 0.8,
  "human": null
}

Phase 4: Mustererkennung

Während der Phase 4 „Mustererkennung“ 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 großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Legen Sie nach teuren Schritten Zwischenkontrollpunkte an. Das Wiederaufnehmen des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf verursachen, wenn ein Operator einen späteren Knoten erneut ausführt.

Fehlerfilterung

Beim Bearbeiten der Phase „Filtern von Fehlern“ 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 Artefakte, definieren Sie Erfolgsprüfungen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Legen Sie nach aufwändigen Schritten einen Kontrollpunkt an. Die Wiederaufnahme des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf veranlassen, wenn ein Operator einen späteren Knoten erneut versucht.

# Step 1: Keep only traces where at least one score is low
def is_low_scoring(trace):
    scores = trace["scores"]
    if scores["human"] is not None and scores["human"] < 0.5:
        return True
    if scores["tool_correctness"] < 0.5:
        return True
    if scores["helpfulness"] < 0.6:
        return True
    return False

failures = [t for t in enriched if is_low_scoring(t)]
print(f"{len(failures)} of {len(enriched)} traces flagged as low scoring")

Beim Bearbeiten der Phase „Filtern von Fehlern“ 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. Legen Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gespeichert werden, den Operator ohne das Durchlesen des gesamten Graphen überprüfen können.

9 of 42 traces flagged as low scoring

Klassifizierung von Clustering-Fehlern in Kategorien

Die Phase der Klassifizierung von Clustering-Fehlern in Kategorien funktioniert am besten, wenn sie als messbare Struktur behandelt wird. Erfassen Sie vor Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlfall sowie die Notizen zur Rücksetzung. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholversuche, menschliche Kontrollen und die Handhabung von Fehlnachrichten gehören zum Produkt selbst, nicht zu späteren Optimierungen. Halten Sie den Zustand der Graphen einfach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen der Verarbeitung.

# Step 2: Tag each failure with a category based on its scores
def categorize(trace):
    scores = trace["scores"]
    if scores["tool_correctness"] < 0.5:
        return "wrong_tool"
    if scores["helpfulness"] < 0.6 and scores["tool_correctness"] >= 0.5:
        return "unhelpful_answer"
    if scores["human"] is not None and scores["human"] < 0.5:
        return "human_flagged"
    return "other"

from collections import Counter
categories = Counter(categorize(t) for t in failures)
print(categories.most_common())
[('wrong_tool', 5), ('unhelpful_answer', 3), ('human_flagged', 1)]
# Step 3: Print the inputs and outputs for every wrong_tool failure
wrong_tool = [t for t in failures if categorize(t) == "wrong_tool"]
for trace in wrong_tool[:3]:
    print("QUERY:", trace["inputs"]["messages"][0]["content"])
    print("TOOLS CALLED:", trace["tool_calls"])
    print("RESPONSE:", trace["outputs"]["messages"][-1]["content"])
    print("---")
QUERY: Is my subscription active?
TOOLS CALLED: ['get_recent_orders']
RESPONSE: I could not find any recent orders to confirm your subscription status.
---
QUERY: Tell me about my subscription to your product
TOOLS CALLED: ['get_recent_orders']
RESPONSE: There are no recent orders for this account.
---

Phase 5: Offline-Testsuite

Die Phase 5 Offline-Testphase funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein optimales 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 einen verworrenen Ablauf. Halten Sie den Zustand der Graphen einfach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Störungen beim Wiederaufnehmen nach Unterbrechungen.

Datensatz erstellen

Die Phase des Erstellens des Datensatzes funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Halten Sie den Zustand des Graphen einfach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen der Verarbeitung.

# Step 1: Create a LangSmith dataset for our agent
dataset_name = "agent-production-failures"

dataset = client.create_dataset(
    dataset_name=dataset_name,
    description="Production traces where the agent failed. Each example captures the user query and the expected tool call.",
)
print(f"Created dataset: {dataset.id}")

Die Phase des Erstellens des Datensatzes funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Halten Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort gespeichert werden, den Betreiber ohne das Durchlesen des gesamten Graphen überprüfen können.

Created dataset: 3f2a1b0c-...
# Step 2: Convert each failure trace into a dataset example
examples = []
for trace in failures:
    query = trace["inputs"]["messages"][0]["content"]
    expected_tool = expected_tool_for_query(query)
    examples.append({
        "inputs": {"question": query},
        "outputs": {"expected_tool": expected_tool},
        "metadata": {"category": categorize(trace), "source_run_id": trace["run_id"]},
    })

client.create_examples(dataset_id=dataset.id, examples=examples)
print(f"Added {len(examples)} examples to {dataset_name}")
Added 9 examples to agent-production-failures
# Step 3: Write an evaluator that checks the agent's tool call against the expected tool
def tool_match_evaluator(inputs: dict, outputs: dict, reference_outputs: dict):
    actual_messages = outputs.get("messages", [])
    tool_called = None
    for m in actual_messages:
        if getattr(m, "tool_calls", None):
            tool_called = m.tool_calls[0]["name"]
            break
    expected = reference_outputs["expected_tool"]
    score = 1.0 if (expected == "any" or tool_called == expected) else 0.0
    return {"key": "tool_match", "score": score}

Die Zielfunktion

In der Phase der Zielfunktion sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden, bevor der Code geändert wird. 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. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung von Fehlnachrichten gehören zum Produkt selbst und nicht zu späteren Optimierungen. Setzen Sie menschliche Freigabe für Schritte voraus, die Geld kosten oder Produktionsdaten ändern. Eine Verkabelung zur Kompilierzeit bedeutet nicht automatisch vollständige Geschäftsabdeckung.

# Step 4: Wrap our agent in a function that takes a LangSmith example and returns its output
def run_agent(inputs: dict) -> dict:
    result = agent.invoke({
        "messages": [{"role": "user", "content": inputs["question"]}]
    })
    return result

Phase 6: Schließen des Kreislaufs

Zur Abschlussphase Phase 6 sollten die Eingabedaten, 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 versteckte Zustände schließen zu müssen. Bevorzugen Sie kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Setzen Sie menschliche Freigabe bei Vorgängen ein, die Geld ausgeben oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen bedeuten noch keine vollständige Abdeckung des Geschäftsablaufs.

Ausführung der Bewertung

Zur Durchführung der Bewertungsphase sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien 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 Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Setzen Sie menschliche Freigabe für Schritte ein, die Geld kosten oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen entsprechen nicht der Geschäftsabschlussqualität.

# Step 1: Run the evaluator across the dataset with the current agent
from langsmith.evaluation import evaluate

experiment_results = evaluate(
    run_agent,
    data=dataset_name,
    evaluators=[tool_match_evaluator],
    experiment_prefix="agent-v1-baseline",
    max_concurrency=4,
)

Während der Evaluierungsphase sollten die Eingabedaten, 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. Die Konfiguration sollte außerhalb des Anwendungscode gespeichert werden. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort zusammengefasst sein, den die Operator überprüfen können, ohne den gesamten Ablaufverlauf durchlesen zu müssen.

View the evaluation results for experiment: 'agent-v1-baseline-...' at:
https://smith.langchain.com/o/.../datasets/.../compare?selectedSessions=...

9/9 runs | avg tool_match: 0.33

Veröffentlichung einer Korrektur und erneute Evaluierung

Wenn Sie an der Implementierung von „Shipping a fix and stage“ arbeiten, notieren Sie zunächst den Vertrag: erforderliche Eingaben, Erfolgsindikatoren 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 Notfallplan gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Legen Sie nach kostspieligen Schritten einen Kontrollpunkt an – das System sollte bei erneuten Versuchen eines Operators keine doppelten Gebühren für denselben LLM-Aufruf erheben.

# Step 2: Update the tool docstring to teach the agent about subscriptions
@tool
def get_account_info_v2(account_id: str) -> str:
    """Look up basic information for an account, including plan, status,
    subscription tier, and contact email. Use this tool for any question
    about the account itself, including subscription status."""
    fake_accounts = {
        "A100": "Account A100: plan=pro, status=active, email=ada@example.com",
        "A200": "Account A200: plan=free, status=suspended, email=turing@example.com",
    }
    return fake_accounts.get(account_id, f"No account found with id {account_id}")

tools_v2 = [get_account_info_v2, get_recent_orders]
agent_v2 = create_react_agent(model, tools_v2)

def run_agent_v2(inputs: dict) -> dict:
    result = agent_v2.invoke({
        "messages": [{"role": "user", "content": inputs["question"]}]
    })
    return result
# Step 3: Run the evaluator on the v2 agent
experiment_results_v2 = evaluate(
    run_agent_v2,
    data=dataset_name,
    evaluators=[tool_match_evaluator],
    experiment_prefix="agent-v2-docstring-fix",
    max_concurrency=4,
)
View the evaluation results for experiment: 'agent-v2-docstring-fix-...' at:
https://smith.langchain.com/o/.../datasets/.../compare?selectedSessions=...

9/9 runs | avg tool_match: 0.89

Vorher und nachher

Beim Arbeiten in der Vor- und Nachphase 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 großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Legen Sie nach teuren Schritten Kontrollpunkte an. Das System sollte bei einer Wiederholung eines späteren Knotens nicht erneut die gleiche LLM-Aufrufgebühr berechnen.

Before (v1):       After (v2):
wrong_tool: 5      wrong_tool: 1
unhelpful: 3       unhelpful: 0
human: 1           human: 0
avg score: 0.33    avg score: 0.89

Bewertung und Testing

Während der Evaluierungs- und Testphase sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen 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. Legen Sie nach aufwändigen Schritten Zwischenkontrollpunkte an. Die Wiederaufnahme des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf veranlassen, wenn ein Operator einen späteren Knoten erneut ausführt. Während der Evaluierungs- und Testphase sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Operator ohne das Durchlesen des gesamten Graphen prüfen können.

# Full loop driver
def run_improvement_loop():
    # 1. Pull traces
    runs = list(client.list_runs(
        project_name="agent-improvement-loop",
        is_root=True,
        start_time=datetime.utcnow() - timedelta(days=1),
    ))
    traces = [compact_trace(r) for r in runs]

    # 2. Enrich with scores
    enriched = [enrich(t) for t in traces]

    # 3. Find failures and categorize them
    failures = [t for t in enriched if is_low_scoring(t)]
    categories = Counter(categorize(t) for t in failures)

    # 4. Add failures to the dataset
    new_examples = [{
        "inputs": {"question": t["inputs"]["messages"][0]["content"]},
        "outputs": {"expected_tool": expected_tool_for_query(
            t["inputs"]["messages"][0]["content"])},
        "metadata": {"category": categorize(t), "source_run_id": t["run_id"]},
    } for t in failures]

    if new_examples:
        client.create_examples(dataset_id=dataset.id, examples=new_examples)

    # 5. Re-evaluate the current agent against the full dataset
    result = evaluate(
        run_agent_v2,
        data=dataset_name,
        evaluators=[tool_match_evaluator],
        experiment_prefix="daily-regression",
    )

    return {
        "traces_collected": len(traces),
        "failures_found": len(failures),
        "by_category": dict(categories),
        "examples_added": len(new_examples),
    }

print(run_improvement_loop())
{
  "traces_collected": 186,
  "failures_found": 12,
  "by_category": {"wrong_tool": 4, "unhelpful_answer": 6, "human_flagged": 2},
  "examples_added": 12,
  "regression_score": 0.87
}

Wie man es weiter verbessern kann

Die Phase „Wie man es verbessern kann“ funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein optimales Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Dokumentieren Sie den erfolgreichen Ablauf sowie den Wiederherstellungsprozess gemeinsam. Wiederholversuche, menschliche Kontrollen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Halten Sie den Zustand der Graphen einfach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen des Ablaufs.

Operative Kontrollliste

Für die Phase der operativen Kontrollliste sollten vor dem Ändern des Codes Eingaben, Verantwortliche für die einzelnen Schritte sowie Ausstiegskriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zustände schließen zu müssen.

Erhalten Sie Aufzeichnungen der Laufzeiten sowie der Kosten für Token oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Weg von einer Demo in gemeinsam genutzte Umgebungen verschiebt.

Führen Sie menschliche Freigabe für Schritte ein, die Geld kosten oder Produktionsdaten ändern. Eine Verkabelung zur Kompilierzeit bedeutet noch nicht vollständige Geschäftsabdeckung.

Verfolgen Sie Kosten und Latenz neben der Qualität. Eine etwas schlechtere Antwort, die 10-mal günstiger ist, könnte der richtige Kompromiss für die Produktion sein.

Speichern Sie Abhängigkeitsversionen ab und dokumentieren Sie den Bilddigest, mit dem die Demo ausgeführt wurde. Reproduzierbarkeit ist besser als kollektives Wissen.

Ziehen Sie kleine, testbare Einheiten vor großen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf einen verworrenen Ablauf.

Vor der Veröffentlichung des Stacks sollten Versionen eingefroren werden, ein „goldener“ Transkript für den kritischen Pfad erstellt und die Rollback-Schritte bestätigt werden. Gemeinsam genutzte Umgebungen benötigen Rate Limits, Überprüfungen der Nutzungsrechte sowie einen klaren Verantwortlichen für die Rotation von Geheimnissen. Man sollte langweilige Zuverlässigkeit vor cleveren, einmaligen Demonstrationen bevorzugen.

Batch-Hinweis für febbeae44915: Halten Sie die Anbieter-Schlüssel außerhalb des Repositories, legen Sie eine Obergrenze für Session-Tokens fest und speichern Sie die Transkripte neben den Evaluierungs-Fixtures, damit spätere Modellwechsel vergleichbar bleiben.

Beim Arbeiten an Phase 0 der Sicherheitsstärkung sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. 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.

Verstärkungsmaßnahme Detail 0/961: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Die erste Stufe der Verstärkungsmaßnahmen funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erfassen Sie außerdem die Zeiten sowie den Token- oder Abfragedurchsatz neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt.

Verstärkungsmaßnahme Detail 1/961: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Zur zweiten Phase der Verstärkungsmaßnahmen sollten vor dem Ändern des Codes die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien 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. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.

Detail der Verstärkungsmaßnahme 2/961: Messen Sie für diese Maßnahme die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch und entscheiden Sie anschließend anhand eines festgelegten Fragekatalogs statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Beim Bearbeiten der Stufe 3 zur Sicherheitsstärkung 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 Stufe als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die relevanten Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab.

Sicherheitsdetail 3/961: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Anweisung und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragekatalogs – und nicht nur aufgrund von Einzelfällen –, ob die Änderung beibehalten werden soll.

Die Stufe 4 zur Sicherheitsstärkung funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Bewahren Sie Konfigurationen außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt werden, den Betreiber ohne das Durchlesen des gesamten Systems prüfen können.

Verstärkungsmaßnahme Detail 4/961: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Für die fünfte Stufe der Verstärkungsmaßnahme sollten vor dem Ändern des Codes die Eingabedaten, der Verantwortliche für den Schritt sowie die Abschlusskriterien 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. Bevorzugen Sie kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzelne Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren.

Verstärkungsmaßnahme Detail 5/961: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Beim Bearbeiten der Stufe 6 der Sicherheitsstärkung sollten Sie zunächst den Ablaufplan aufschreiben: erforderliche Eingaben, Erfolgsindikatoren 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-Umgebung in gemeinsam genutzte Umgebungen übergeht.

Sicherheitsstärkungsdetail 6/961: Messen Sie für diese Anweisung die Gesamtlaufzeit, die Fehlerklasse sowie den Tokenverbrauch und entscheiden Sie anschließend anhand eines festgelegten Fragekatalogs statt aufgrund von Einzelfallbeobachtungen, ob die Änderung beibehalten werden soll.

Die Stufe 7 der Sicherheitsstärkung funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlfall sowie eine Notiz zur Rücksetzung. Dokumentieren Sie gleichzeitig den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Versuche, menschliche Kontrollpunkte und die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.

Verstärkungsmaßnahme Detail 7/961: Messen Sie die Laufzeit, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Zur achten Stufe der Verstärkungsmaßnahme sollten die Eingabedaten, der Verantwortliche für den Schritt sowie die Abschlusskriterien vor der Codeänderung 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 Stufe als Vertrag zwischen den Eingabedaten und den validierten Ausgabedaten. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab.

Verstärkungsmaßnahme Detail 8/961: Messen Sie die Laufzeit, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.

Beim Bearbeiten der Stufe 9 der Sicherheitsmaßnahmen sollten Sie zunächst den Ablaufplan aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreiber ohne das Durchlesen des gesamten Systems überprüfen können.

Sicherheitsmaßnahme Detail 9/961: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Maßnahme und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragekatalogs – und nicht nur aufgrund von Einzelfällen –, ob die Änderung beibehalten werden soll.

Die Stufe 10 der Sicherheitsmaßnahmen funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlfall sowie eine Notiz zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzelne Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren.

Härtungsdetail 10/961: Messen Sie die Wall-Time, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.