LangSmith

Monitoring & Debugging mit LangSmith


Inhaltsverzeichnis

  1. Kurzüberblick: Warum LangSmith?
    1. LangSmith im Entwicklungs-Workflow
  2. Setup: API-Key und Umgebung
    1. LangSmith-Account erstellen
    2. API-Keys in Google Colab Secrets hinterlegen
  3. Das kleinstmögliche funktionierende Beispiel
  4. Traces verstehen: Die Grundstruktur
    1. Run-Typen
    2. Beispiel: Chain mit mehreren Runs
    3. Threads: Gespräche über mehrere Traces hinweg
  5. Praktisches Beispiel: Agent mit Tools tracken
  6. Datasets: Systematisches Testen
    1. Dataset erstellen (UI oder Code)
    2. Agent gegen Dataset evaluieren
  7. Feedback: Qualität messen
    1. Manuelles Feedback (UI)
    2. Programmatisches Feedback
    3. Automatische Evaluierung mit LLM-as-Judge
  8. Integration in LangGraph-Workflows
  9. Best Practices
    1. Projekt-Organisation
    2. Tags für bessere Organisation
    3. Fehler debuggen
    4. Performance-Monitoring
    5. Einzelne Chains und Runs benennen mit .with_config()
    6. Tool-Tests ohne Tracing: .func()
    7. Trace-Patterns erkennen
    8. Problembereiche systematisch finden (Quick Workflow)
    9. Web-UI Filter: Traces gezielt finden
  10. Vergleich: LangSmith vs. Alternatives
  11. Häufige Fragen (FAQ)
    1. “Werden alle Daten an LangSmith gesendet?”
    2. “Kostet LangSmith extra?”
    3. “Wie lange werden Traces gespeichert?”
    4. “Wie deaktiviere ich Tracing?”
    5. “Kann ich LangSmith ohne LangChain nutzen?”
    6. “Was passiert, wenn ich den API-Key vergesse?”
  12. Abgrenzung zu verwandten Dokumenten

Kurzüberblick: Warum LangSmith?

LangChain und LangGraph ermöglichen den Bau komplexer KI-Anwendungen. Doch bei der Entwicklung stellen sich schnell Fragen:

  • Warum hat die Chain eine bestimmte Antwort produziert?
  • Welche Retrieval-Schritte wurden in welcher Reihenfolge ausgeführt?
  • Wo ist der Fehler in einer 10-Schritte-RAG-Pipeline?
  • Wie gut funktioniert das System mit echten Nutzerfragen?

LangSmith beantwortet diese Fragen durch:

  • Vollständiges Tracing aller LLM-Calls, Tool-Aufrufe und Chain-Schritte
  • Visuelle Darstellung komplexer Workflows
  • Dataset-Management für systematische Evaluierung
  • Performance-Monitoring in Produktion
  • Feedback-Collection von Nutzern

Kernprinzip: Jede Ausführung wird automatisch protokolliert und kann nachvollzogen werden – ohne zusätzlichen Code im Workflow selbst.

LangSmith im Entwicklungs-Workflow

flowchart TB
    DEV[Development<br/>LangChain/LangGraph Code]
    RUN[Code Execution<br/>Chain/RAG/Tool Runs]
    LANGSMITH[LangSmith Platform<br/>Automatic Tracing]
    UI[LangSmith Web UI<br/>Visualization & Analysis]
    DEBUG[Debug & Optimize<br/>Based on Insights]

    DEV --> RUN
    RUN -->|Automatic| LANGSMITH
    LANGSMITH --> UI
    UI --> DEBUG
    DEBUG -.Improve Code.-> DEV

    subgraph "No Code Changes Needed"
        RUN
        LANGSMITH
    end

    style LANGSMITH fill:#d5e8d4
    style UI fill:#dae8fc

Setup: API-Key und Umgebung

LangSmith-Account erstellen

  1. Kostenlosen Account anlegen: eu.smith.langchain.com
  2. API-Key generieren: Settings → API Keys → Create API Key (im EU-Workspace)
  3. Optional: Organisation und Projekte anlegen

[!WARNING] EU-Endpoint verwenden
Für diesen Kurs immer den EU-Endpoint verwenden: https://eu.api.smith.langchain.com. Account und API-Key müssen ebenfalls im EU-Workspace erstellt werden, sonst erscheinen Traces nicht im erwarteten Projekt. APAC-Account (Asia-Pacific): https://ap.api.smith.langchain.com (seit SDK 0.8.x).

API-Keys in Google Colab Secrets hinterlegen

Schritt 1: Secrets in Colab einrichten

  1. In Google Colab: Schlüssel-Symbol 🔑 in der linken Seitenleiste
  2. Neue Secrets hinzufügen:
    • OPENAI_API_KEY: Eigener OpenAI-Key
    • LANGSMITH_API_KEY: LangSmith-Key (beginnt mit lsv2_pt_...)
    • Optional: HF_TOKEN für Hugging Face

Schritt 2: Umgebung einrichten (Standard-Setup)

[!WARNING] Reihenfolge-Regel: Env-Vars vor Imports
LangSmith-Env-Vars müssen gesetzt sein, bevor langchain, langsmith oder genai_lib importiert werden. Der Tracer liest die Env-Vars beim ersten Import — späteres Setzen wird ignoriert. Env-Vars ganz oben in der Setup-Cell, vor allen Imports setzen.

#@title 🔧 Umgebung einrichten{ display-mode: "form" }
!uv pip install --system -q git+https://github.com/ralf-42/GenAI.git#subdirectory=04_modul

import os

# ✅ LangSmith Env-Vars ZUERST – vor allen Imports!
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_PROJECT"]    = "M02-LangSmith-Setup"  # Konvention: "M##-Thema"
os.environ["LANGSMITH_ENDPOINT"]   = "https://eu.api.smith.langchain.com"

# Erst danach: genai_lib und weitere Imports
from genai_lib.utilities import check_environment, get_ipinfo, setup_api_keys, mprint

setup_api_keys(['OPENAI_API_KEY', 'LANGSMITH_API_KEY'], create_globals=False)
print()
check_environment()
print()
get_ipinfo()

Wichtig:

  • Env-Vars stehen vor dem genai_lib-Import – das ist Pflicht laut Best Practices
  • Projektname-Konvention: "M##-Thema" (z.B. "M05-Structured-Output") – Traces sind sofort dem Modul zuzuordnen
  • create_globals=False verhindert globale Variablen (Best Practice)
  • Ab jetzt werden alle LangChain/LangGraph-Operationen automatisch getrackt

Das kleinstmögliche funktionierende Beispiel

Der schnellste Weg zum Verständnis: Ein einfacher LLM-Call mit automatischem Tracing.

from langchain.chat_models import init_chat_model

# Normaler LLM-Setup (wie gewohnt)
llm = init_chat_model("openai:gpt-5.4-nano")

# Einfacher Call - wird automatisch getrackt!
response = llm.invoke("Erkläre LangSmith in einem Satz.")
print(response.content)

Was passiert im Hintergrund:

  1. LangSmith empfängt automatisch alle Daten (Input, Output, Latenz, Token)
  2. Ein “Trace” wird erstellt und in der Web-UI angezeigt
  3. Kein zusätzlicher Code nötig – funktioniert “out of the box”

Nächster Schritt: LangSmith-Dashboard öffnen und den Trace inspizieren


Traces verstehen: Die Grundstruktur

LangSmith organisiert alle Daten in einer klaren Hierarchie:

flowchart TB
    PROJECT["Project<br>Container für alle Traces<br>z.B. 'M08-RAG-Chain'"]
    THREAD["Thread<br>Gesprächs-Sequenz<br>session_id / conversation_id"]
    TRACE["Trace<br>Eine vollständige Anfrage<br>z.B. RAG-Ausführung"]
    RUN["Run<br>Einzelne Operation<br>llm · chain · tool · ..."]
    TAGS["Tags<br>Filterbare Labels"]
    META["Metadata<br>Key-Value-Paare"]
    FEEDBACK["Feedback<br>Score 0.0 – 1.0"]

    PROJECT --> THREAD
    THREAD --> TRACE
    TRACE --> RUN
    RUN -.-> TAGS
    RUN -.-> META
    RUN -.-> FEEDBACK

    style PROJECT fill:#e1f5ff
    style THREAD fill:#fff3cd
    style TRACE fill:#dae8fc
    style RUN fill:#d5e8d4
    style TAGS fill:#f5f5f5
    style META fill:#f5f5f5
    style FEEDBACK fill:#f5f5f5
Konzept Bedeutung
Project Container für alle zusammengehörigen Traces (z.B. ein Kursmodul)
Thread Sequenz mehrerer Traces für ein Gespräch — verknüpft via session_id
Trace Vollständige Aufzeichnung einer einzelnen Anfrage
Run Einzelner Schritt innerhalb eines Trace (llm, chain, tool …)
Tags Labels zur Filterung und Kategorisierung von Runs
Metadata Zusätzliche Key-Value-Daten pro Run (z.B. User-ID, Version)
Feedback Bewertung eines Runs — manuell oder automatisch (Score 0.0–1.0)

Run-Typen

LangSmith kennt 7 Run-Typen (Werte immer lowercase):

Run-Typ Bedeutung Typisches Beispiel
llm Direkte LLM-Aufrufe (Chat, Completion) llm.invoke()
chain Verkettungen, Workflows, Agenten-Schritte prompt | llm | parser, LangGraph-Nodes
tool Tool-/Funktionsaufrufe @tool Decorator
retriever Dokumentenabruf aus Vektordatenbanken vectorstore.as_retriever()
embedding Embedding-Berechnungen embeddings.embed_query()
prompt Prompt-Template-Verarbeitung ChatPromptTemplate.format_messages()
parser Output-Parser StrOutputParser()

Wichtige Hinweise:

  • chain ist der häufigste Typ — er deckt alles ab, was kein direkter LLM-Call, kein Tool etc. ist. RAG-Pipelines und LCEL-Chains erscheinen typischerweise als chain.
  • Default-Fallback: Unbekannte oder falsch geschriebene run_type-Werte (z.B. "LLM" statt "llm") fallen automatisch auf "chain" zurück.
  • Kosten-Tracking (ab 2026): LangSmith bietet eine einheitliche Kostenübersicht über den gesamten Workflow — nicht nur für llm-Runs. Custom Cost Metadata kann für beliebige Run-Typen übergeben werden.

Beispiel: Chain mit mehreren Runs

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# LCEL-Chain (aus LangChain-Anleitung bekannt)
prompt = ChatPromptTemplate.from_template("Erkläre {topic} für Einsteiger.")
chain = prompt | llm | StrOutputParser()

result = chain.invoke({"topic": "Vektordatenbanken"})

Im LangSmith-Trace sichtbar:

graph TB
    CHAIN[Chain Run - Gesamt<br/>Latenz: 1.5s]
    PROMPT[Prompt Run<br/>Template-Formatierung<br/>0.1s]
    LLM[LLM Run - GPT-4o-mini<br/>Input: 'Erkläre Vektordatenbanken...'<br/>Output: 'Vektordatenbanken speichern...'<br/>Tokens: 245 in=12, out=233<br/>Latenz: 1.2s]
    PARSER[Parser Run<br/>String-Extraktion<br/>0.2s]

    CHAIN --> PROMPT
    CHAIN --> LLM
    CHAIN --> PARSER

    style CHAIN fill:#e1f5ff
    style PROMPT fill:#ffe6cc
    style LLM fill:#d5e8d4
    style PARSER fill:#dae8fc

ASCII-Darstellung:

Chain Run (Gesamt)
├─ Prompt Run (Template-Formatierung)
├─ LLM Run (GPT-4o-mini Call)
│  ├─ Input: "Erkläre Vektordatenbanken für Einsteiger."
│  ├─ Output: "Vektordatenbanken speichern..."
│  ├─ Tokens: 245 (Input: 12, Output: 233)
│  └─ Latenz: 1.2s
└─ Parser Run (String-Extraktion)

Threads: Gespräche über mehrere Traces hinweg

Ein Thread verknüpft mehrere Traces zu einer Gesprächs-Sequenz — z.B. alle Nachrichten einer Chat-Session. Die Verknüpfung erfolgt über session_id oder conversation_id in den Metadaten.

# Thread-ID in den Metadaten setzen
config = {
    "configurable": {"thread_id": "session-42"},
    "metadata": {"session_id": "session-42"},  # → LangSmith gruppiert Traces als Thread
}

response = agent.invoke(
    {"messages": [{"role": "user", "content": "Hallo!"}]},
    config=config,
)

Im LangSmith-Dashboard: Threads-Ansicht zeigt den vollständigen Gesprächsverlauf über alle Traces hinweg — ideal für Debugging von Multi-Turn-Gesprächen.


Praktisches Beispiel: Agent mit Tools tracken

Tools und Agents profitieren besonders von LangSmith, da ihre Entscheidungswege oft komplex sind.

from langchain_core.tools import tool
from langchain.agents import create_agent

# Tool definieren (wie in LangChain-Anleitung)
@tool
def multiply(a: int, b: int) -> int:
    """Multipliziert zwei Zahlen."""
    return a * b

@tool
def add(a: int, b: int) -> int:
    """Addiert zwei Zahlen."""
    return a + b

# Agent erstellen
tools = [multiply, add]
agent = create_agent(
    model=llm,
    tools=tools,
    system_prompt="Du bist ein Rechen-Agent. Nutze Tools für Berechnungen.",
)

# Agent ausführen - komplexe Frage
response = agent.invoke({
    "messages": [{"role": "user", "content": "Berechne (5 * 8) + 3"}]
})

Im LangSmith-Trace wird sichtbar:

sequenceDiagram
	autonumber
    participant User
    participant Agent
    participant LLM
    participant multiply as Tool: multiply
    participant add as Tool: add
    participant LangSmith

    User->>Agent: "Berechne (5 * 8) + 3"
    Agent->>LangSmith: Trace Start
    Agent->>LLM: Process request with tools
    LLM->>LLM: Decide: Need multiply(5, 8)
    LLM-->>Agent: Tool call: multiply(5, 8)
    Agent->>multiply: Execute multiply(5, 8)
    multiply-->>Agent: Result: 40
    Agent->>LangSmith: Log: Tool Run (multiply)
    Agent->>LLM: Tool result: 40
    LLM->>LLM: Decide: Need add(40, 3)
    LLM-->>Agent: Tool call: add(40, 3)
    Agent->>add: Execute add(40, 3)
    add-->>Agent: Result: 43
    Agent->>LangSmith: Log: Tool Run (add)
    Agent->>LLM: Tool result: 43
    LLM-->>Agent: Final answer
    Agent-->>User: "Das Ergebnis ist 43"
    Agent->>LangSmith: Trace Complete

    Note over LangSmith: Every step logged:<br/>Inputs, Outputs,<br/>Latency, Tokens

Wichtig: Jeder Schritt ist einzeln inspizierbar – Input, Output, Latenz, Fehler.


Datasets: Systematisches Testen

Datasets ermöglichen wiederholbare Tests mit definierten Inputs und erwarteten Outputs.

Dataset erstellen (UI oder Code)

Variante A: Über UI

  1. LangSmith → Datasets → Create Dataset
  2. Beispiele hinzufügen (Input/Output-Paare)

Variante B: Programmatisch

from langsmith import Client

client = Client(api_url=os.environ["LANGSMITH_ENDPOINT"])

# Dataset mit Beispielen
examples = [
    {"inputs": {"question": "Was ist 5 * 8?"}, "outputs": {"answer": "40"}},
    {"inputs": {"question": "Addiere 10 und 15"}, "outputs": {"answer": "25"}},
    {"inputs": {"question": "Was ist die Hauptstadt von Frankreich?"}, "outputs": {"answer": "Paris"}},
]

dataset_name = "Rechen-Agent-Tests"
dataset = client.create_dataset(dataset_name=dataset_name)

client.create_examples(
    inputs=[e["inputs"] for e in examples],
    outputs=[e["outputs"] for e in examples],
    dataset_id=dataset.id,
)

Agent gegen Dataset evaluieren

from langsmith.evaluation import evaluate

def predict(inputs: dict) -> dict:
    """Wrapper für Agent-Aufruf"""
    response = agent.invoke({
        "messages": [{"role": "user", "content": inputs["question"]}]
    })
    # Antwort aus letzter Message extrahieren
    return {"answer": response["messages"][-1].content}

# Evaluierung starten
results = evaluate(
    predict,
    data=dataset_name,
    experiment_prefix="Agent-v1",
)

Ergebnis:

  • Jeder Test-Case wird einzeln ausgeführt
  • Traces für alle Runs werden automatisch gespeichert
  • Vergleich über UI: Welche Fragen wurden korrekt beantwortet?

Feedback: Qualität messen

Feedback ermöglicht es, die Qualität von Antworten zu bewerten – manuell oder automatisch.

Manuelles Feedback (UI)

In der LangSmith-UI kann jeder Run bewertet werden:

  • Daumen hoch/runter
  • Sterne (1-5)
  • Freitext-Kommentar

Programmatisches Feedback

Run-IDs über @traceable mit run_tree-Injection ermitteln – der moderne Weg (kein response["__run"].id mehr, da veraltet und unzuverlässig):

from langsmith import traceable, Client

client = Client(api_url=os.environ["LANGSMITH_ENDPOINT"])

@traceable(run_type="chain", name="AgentRun")
def agent_ausfuehren(frage: str, run_tree=None) -> str:
    """Agent-Ausführung – run_tree wird automatisch injiziert."""
    response = agent.invoke({
        "messages": [{"role": "user", "content": frage}]
    })
    return response["messages"][-1].content

# Agent ausführen
antwort = agent_ausfuehren("Was ist 5 * 8?")

# Run-ID über letzten Run im Projekt ermitteln
runs = list(client.list_runs(
    project_name=os.environ["LANGSMITH_PROJECT"], limit=1
))
if runs:
    client.create_feedback(
        run_id=runs[0].id,
        key="user_satisfaction",
        score=1.0,   # 0.0 = schlecht, 1.0 = gut
        comment="Antwort war präzise und korrekt.",
    )

Automatische Evaluierung mit LLM-as-Judge

LangChainStringEvaluator ist deprecated. Modernes Pattern: function-based Evaluators — einfache Python-Funktionen mit Signatur (run, example) -> dict:

from langsmith.evaluation import evaluate
from langsmith import traceable

# Einfacher Evaluator: exakter Vergleich
def korrektheit_evaluator(run, example) -> dict:
    predicted = run.outputs.get("answer", "").strip().lower()
    expected  = example.outputs.get("answer", "").strip().lower()
    return {"key": "correctness", "score": 1.0 if predicted == expected else 0.0}

# LLM-as-Judge Evaluator
@traceable
def llm_judge(run, example) -> dict:
    predicted = run.outputs.get("answer", "")
    expected  = example.outputs.get("answer", "")
    prompt = (
        f"Bewerte die Antwort auf einer Skala von 0 bis 1.<br>"
        f"Erwartete Antwort: {expected}<br>"
        f"Tatsächliche Antwort: {predicted}<br>"
        f"Antworte nur mit einer Zahl zwischen 0 und 1."
    )
    try:
        score = float(llm.invoke(prompt).content.strip())
    except ValueError:
        score = 0.0
    return {"key": "quality", "score": score}

# Evaluierung ausführen
results = evaluate(
    predict,
    data=dataset_name,
    evaluators=[korrektheit_evaluator, llm_judge],
    experiment_prefix="Agent-v1-auto-eval",
)

Vorteile:

  • Skalierbar: 100+ Beispiele automatisch testen
  • Konsistent: Gleiche Bewertungskriterien
  • Nachvollziehbar: LLM-Begründungen werden gespeichert

Integration in LangGraph-Workflows

LangSmith trackt auch komplexe LangGraph-State-Machines automatisch.

from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages

class ChatState(TypedDict):
    messages: Annotated[list, add_messages]

def agent_node(state: ChatState):
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

# Graph bauen
graph = StateGraph(ChatState)
graph.add_node("agent", agent_node)
graph.add_edge(START, "agent")
graph.add_edge("agent", END)

# Mit Checkpointer kompilieren
checkpointer = MemorySaver()
compiled_graph = graph.compile(checkpointer=checkpointer)

# Ausführen - wird automatisch getrackt!
config = {"configurable": {"thread_id": "demo-session"}}
result = compiled_graph.invoke(
    {"messages": [{"role": "user", "content": "Hallo!"}]},
    config=config,
)

Im LangSmith-Trace:

  • Vollständiger Graph-Ablauf sichtbar
  • Jeden Node-Durchlauf einzeln inspizierbar
  • State-Änderungen nachvollziehbar
  • Checkpointing-Events protokolliert

Best Practices

Projekt-Organisation

Konvention: Modulname direkt in der Setup-Cell setzen

# ✅ Modulname in der Setup-Cell – vor allen Imports!
os.environ["LANGSMITH_PROJECT"] = "M05-Structured-Output"

Wichtig: LANGSMITH_PROJECT wird beim ersten Trace via lru_cache eingefroren. Spätere os.environ-Änderungen haben keinen Effekt. Daher den Modulnamen einmal korrekt in der Setup-Cell setzen – dann funktioniert es zuverlässig.

Standard-Setup im Notebook-Header

#@title 🔧 Umgebung einrichten{ display-mode: "form" }
!uv pip install --system -q git+https://github.com/ralf-42/GenAI.git#subdirectory=04_modul

import os

# ✅ LangSmith Env-Vars ZUERST – vor allen Imports!
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_PROJECT"]    = "M05-Structured-Output"  # Modulname anpassen
os.environ["LANGSMITH_ENDPOINT"]   = "https://eu.api.smith.langchain.com"

# Erst danach: genai_lib und weitere Imports
from genai_lib.utilities import setup_api_keys, check_environment, get_ipinfo

setup_api_keys(['OPENAI_API_KEY', 'LANGSMITH_API_KEY'], create_globals=False)
check_environment()
get_ipinfo()

Modulspezifischer Abschnitt im Notebook (nach dem Setup):

# LangSmith: Aktives Projekt für diesen Abschnitt
import os
print(f"📊 LangSmith-Projekt: {os.environ['LANGSMITH_PROJECT']}")

# invoke() direkt – Projekt bereits korrekt in Setup-Cell gesetzt
run_cfg = {"run_name": "M05_Kap6_StructuredTrace", "tags": ["M05", "structured-output"]}
result = llm.with_structured_output(MyModel).with_config(**run_cfg).invoke("...")

Konventionen:

Kontext Projektname
Notebook "M##-Thema" z.B. "M05-Structured-Output"
Produktion "chatbot-production"
Experiment "rag-experiment-2026-03"

💡 Edge Case: Falls ein Projekt-Wechsel nach Notebook-Start nötig ist (z.B. kein Kernel-Neustart möglich), kann ls.tracing_context(project_name=...) als Workaround verwendet werden.

Tags für bessere Organisation

from langsmith import traceable

@traceable(
    run_type="chain",
    tags=["rag", "produktiv", "version-2.0"],
)
def my_rag_chain(question: str):
    # RAG-Logik hier
    pass

Fehler debuggen

flowchart LR
    FAIL[Chain fails<br/>Wrong answer]
    OPEN[Open LangSmith UI<br/>Find failed run]
    INSPECT[Inspect Trace<br/>Identify issue]
    FIX[Fix Code<br/>Prompt or<br/>Retrieval config]
    RETEST[Re-run Chain<br/>New trace created]
    COMPARE[Compare in UI<br/>Before vs After]
    SUCCESS{Fixed?}

    FAIL --> OPEN
    OPEN --> INSPECT
    INSPECT --> FIX
    FIX --> RETEST
    RETEST --> COMPARE
    COMPARE --> SUCCESS
    SUCCESS -->|No| INSPECT
    SUCCESS -->|Yes| END([Done])

    style FAIL fill:#f8cecc
    style SUCCESS fill:#d5e8d4
    style COMPARE fill:#dae8fc

Typischer Workflow:

  1. Chain liefert falsche Antwort
  2. LangSmith öffnen → Run finden
  3. Trace inspizieren: An welcher Stelle ging es schief?
  4. Prompt oder Retrieval-Konfiguration anpassen
  5. Erneut testen → Vergleichen im UI

Vorteil: Direkter Vorher/Nachher-Vergleich im LangSmith-UI.

Performance-Monitoring

# Metadaten hinzufügen für Filterung
from langsmith import traceable

@traceable(metadata={"user_id": "student_42", "environment": "colab"})
def process_query(query: str):
    return chain.invoke({"question": query})

Nutzen:

  • Langsame Runs identifizieren (Latenz > 5s)
  • Token-Verbrauch pro Student analysieren
  • Fehlerraten nach Umgebung filtern

Einzelne Chains und Runs benennen mit .with_config()

Automatisches Tracing erfasst alle Runs – aber ohne explizite Namen sind sie im Dashboard schwer zu unterscheiden. .with_config() gibt einzelnen Chains, LLM-Aufrufen und Structured-Output-Chains einen eindeutigen Namen und Tags.

Prinzip: Config-Parameter vorab in einer separaten Variable festlegen

# Config-Parameter in einer eigenen Variable definieren
run_cfg = {
    "run_name": "M07_Kap3_LCEL_Grundchain",  # Konvention: M##_Kap##_Typ
    "tags":     ["M07", "lcel", "chain"],     # Filterbar im LangSmith-Dashboard
}

chain = (
    ChatPromptTemplate.from_template("Erkläre {topic} für Einsteiger.")
    | llm
    | StrOutputParser()
).with_config(**run_cfg)

result = chain.invoke({"topic": "Vektordatenbanken"})

Auf LLM-Aufrufe anwenden

run_cfg = {
    "run_name": "M03_Kap1_LLM_Basis",
    "tags":     ["M03", "llm"],
}

named_llm = llm.with_config(**run_cfg)
response  = named_llm.invoke("Was ist ein Sprachmodell?")

Auf with_structured_output() anwenden

from pydantic import BaseModel, Field

class Person(BaseModel):
    name: str = Field(description="Vollständiger Name")
    alter: int = Field(description="Alter in Jahren")

run_cfg = {
    "run_name": "M05_Kap3_PersonExtraktion",
    "tags":     ["M05", "structured-output"],
}

structured_llm = llm.with_structured_output(Person).with_config(**run_cfg)
ergebnis = structured_llm.invoke("Emma Müller ist 34 Jahre alt.")

Regeln für run_cfg:

Parameter Konvention Beispiel
run_name "M##_Kap##_Typ" (Modul, Kapitel, Kurzname) "M05_Kap3_PersonExtraktion"
tags Liste: ["M##", "typ", ...] ["M05", "structured-output"]

⚠️ Regel: .with_config() gehört in den Abschnitt, der Tracing erklärt – nicht pauschal auf jede Chain im Notebook. In Lehr-Notebooks einmalig pro Kapitel demonstrieren.

Tool-Tests ohne Tracing: .func()

Beim Testen einzelner @tool-Funktionen entsteht mit .invoke() immer ein Trace. Für isolierte Unit-Tests die Python-Funktion direkt über .func() aufrufen – komplett am Runnable-Framework vorbei.

from langchain_core.tools import tool

@tool
def celsius_nach_fahrenheit(temperatur: float) -> float:
    """Rechnet Celsius in Fahrenheit um."""
    return round(temperatur * 9 / 5 + 32, 2)

# ✅ Kein Trace – direkte Python-Funktion
ergebnis = celsius_nach_fahrenheit.func(temperatur=37.0)
print(ergebnis)  # 98.6

# ⚠️ Mit Trace – geht durch das Runnable-Framework
ergebnis = celsius_nach_fahrenheit.invoke({"temperatur": 37.0})

Wann .func() einsetzen:

  • ✅ Isolierte Unit-Tests von Tool-Funktionen (Kapitel vor der LangSmith-Demo)
  • ✅ Wenn Tracing-Unterdrückung via Context Manager nicht zuverlässig funktioniert
  • ❌ Nicht verwenden, wenn das Runnable-Verhalten (Schema-Validierung, Callbacks) getestet werden soll

💡 Didaktischer Mehrwert: Der Kontrast .func() vs. .invoke() macht sichtbar, was das Runnable-Framework zusätzlich leistet – ideal für Lehr-Notebooks.


Trace-Patterns erkennen

Traces sind mehr als ein Debug-Log — sie machen systematische Verhaltensmuster sichtbar. Die folgenden Patterns treten immer wieder auf, quer durch alle Chain- und RAG-Typen:

Pattern Erkennungszeichen im Trace Ursache / Gegenmittel
Over-Retrieval Retriever läuft bei Fragen, die kein Dokument benötigen (z.B. reine Wissensfragen) RAG-Routing zu pauschal → Conditional-Routing vor Retriever einbauen
Retry-Loop Gleicher LLM-Call mit identischen Inputs wiederholt, jeweils error Fehlende Fehlerbehandlung in der Chain → Error-Handling ergänzen
Token-Akkumulation LLM-Input wächst mit jedem Schritt stark an Kein Context-Management → Sliding-Window oder Summarization
Missing Tool Use Agent antwortet direkt ohne Tools, obwohl passende Tools verfügbar Tool-Beschreibung unklar → Tool-Docstring verbessern
Langsamer Retriever retriever-Run dominiert die Gesamtlatenz Zu viele k Dokumente oder langsamer Vectorstore → k reduzieren
Leere Retrieval-Ergebnisse retriever-Run liefert 0 Dokumente Query-Formulierung passt nicht zu Chunk-Stil → Query-Rewriting oder MMR

Reales Beispiel — Over-Retrieval in einer RAG-Chain:

User: "Was ist LangSmith?"
→ Retriever: retrieve_documents(query="LangSmith")   ← unnötig bei Wissensfrage
→ Tool: 0 relevante Dokumente gefunden
→ LLM: antwortet aus Modell-Wissen                  ← hätte direkt funktioniert

Ohne LangSmith-Trace wäre der Grund für die erhöhte Latenz nicht erkennbar gewesen. Gegenmittel: Routing-Schritt vor dem Retriever — nur bei dokumentenspezifischen Fragen retrieven.

Programmatische Pattern-Analyse mit show_trace():

from genai_lib.utilities import show_trace

# Letzte 3 Runs anzeigen
show_trace("M08-RAG-Chain", limit=3)

# Mit Step-Analyse des letzten Runs (zeigt alle Retrieval-Schritte)
show_trace("M08-RAG-Chain", show_steps=True)

show_steps=True listet alle Child-Runs (Typ, Name, Status, Dauer) — ideal um Over-Retrieval und leere Retrieval-Ergebnisse direkt im Notebook sichtbar zu machen.

Problembereiche systematisch finden (Quick Workflow)

Wenn eine Chain “irgendwie schlecht” wirkt, hilft eine feste Reihenfolge statt Ad-hoc-Debugging:

  1. Failed/Slow/Expensive Runs filtern (Projekt + Tags + Zeitraum)
  2. Top-Pattern clustern (z.B. Over-Retrieval, Token-Akkumulation, leere Ergebnisse — siehe 9.7)
  3. Einen Fix pro Pattern umsetzen (Prompt, Retrieval-Konfiguration, Routing)
  4. Vorher/Nachher vergleichen (gleiche Testfragen oder Dataset-Evals)

Im Kurs reichen Schritte 1–4 vollständig aus. Alerts und Production-Monitoring (p95-Latenz, Kostenbudgets, automatische Schwellwerte) sind für Production-Deployments relevant.

Web-UI Filter: Traces gezielt finden

Die LangSmith-Oberfläche unter eu.smith.langchain.com bietet leistungsstarke Filter — besonders nützlich, wenn das Projekt viele Runs enthält.

Nützlichste Filter-Kombinationen für den Kurs:

Szenario Filter Wert
Nur Fehler anzeigen Status Error
Langsame Runs finden Latency > 10s
Viele Child-Runs Child Runs > 5
Spezifische Chain Name contains "rag"
Experiment A vs. B Tags experiment-A / experiment-B
Zeitraum eingrenzen Start Time Last 1 hour / Last 24 hours

Drei Kern-Views für den Kurs:

1. Debugging:    Status = Error  +  Project = M##-...
2. Latenz:       Latency > 5s   +  Child Runs > 3
3. Experiment:   Tag "experiment-A" vs. Tag "experiment-B" (Compare-View)

Weitere Web-UI-Tipps:

  • Playground direkt aus Trace: Trace öffnen → “Open in Playground” — Prompt live editieren, Modell wechseln, sofort testen
  • Compare-Ansicht: Zwei Runs auswählen → “Compare” — zeigt Input/Output/Latenz/Tokens nebeneinander; ideal für Vorher/Nachher nach einem Fix
  • Trace-Baum navigieren: Linke Seitenleiste zeigt verschachtelte Child-Runs; Klick auf einen Child-Run öffnet Input/Output/Latenz direkt
  • Export: Run-Tabelle (gefiltert) → “Export” → CSV (nur Tabellen-Spalten); einzelne Traces → JSON (natives Format, nicht änderbar). Für vollständige Daten: client.list_runs() + pandas.DataFrame.to_csv()

💡 Tipp: LangSmith-UI im zweiten Browser-Tab öffnen — so sind Traces direkt während der Entwicklung sichtbar, ohne den Notebook-Tab zu wechseln.


Vergleich: LangSmith vs. Alternatives

Aspekt LangSmith Print/Logs LangGraph Debug
Setup 3 Zeilen Code Immer verfügbar Graph-spezifisch
Visualisierung Interaktive UI Terminal-Output Stream-Modus
Historie Persistent Verloren nach Neustart Session-basiert
Datasets Integriert Manuell verwalten Nicht verfügbar
Team-Kollaboration URL-Sharing Screenshots Nicht verfügbar
Produktion Monitoring Nicht skalierbar Nur Development

Fazit für den Kurs:

  • Woche 1: LangSmith parallel zu Print-Debugging einführen
  • Woche 2: LangSmith als primäres Debug-Tool etablieren
  • Ab Woche 3: LangSmith für RAG-Evaluation und Chain-Optimierung nutzen

Häufige Fragen (FAQ)

“Werden alle Daten an LangSmith gesendet?”

Ja, standardmäßig:

  • Alle Inputs und Outputs
  • Metadaten (Latenz, Tokens, etc.)
  • Fehler und Stack-Traces

Kontrolle:

  • Sensitive Daten vorher filtern/anonymisieren
  • Selective Tracing mit @traceable(enabled=False)
  • Self-Hosted LangSmith für vollständige Kontrolle

“Kostet LangSmith extra?”

Free Tier: Kostenloser Einstieg verfügbar (ausreichend für erstes Ausprobieren) Paid Tiers: Verschiedene Pläne für Production-Nutzung

“Wie lange werden Traces gespeichert?”

Traces werden maximal 400 Tage aufbewahrt. Danach werden sie automatisch gelöscht.

Längerfristige Speicherung: Wichtige Runs als Dataset exportieren — Datasets unterliegen keiner automatischen Löschfrist.

# Run dauerhaft in ein Dataset überführen
client.create_example_from_run(run_id=run_id, dataset_name="wichtige-runs")

“Wie deaktiviere ich Tracing?”

# Temporär deaktivieren
os.environ["LANGSMITH_TRACING"] = "false"

# Für einzelne Funktionen
from langsmith import traceable

@traceable(enabled=False)
def nicht_getrackt():
    pass

“Kann ich LangSmith ohne LangChain nutzen?”

Ja, mit dem @traceable Decorator:

from langsmith import traceable

@traceable
def custom_function(input_data):
    # Beliebiger Python-Code
    return result

“Was passiert, wenn ich den API-Key vergesse?”

# Setup prüft automatisch, ob Keys vorhanden sind
setup_api_keys(['OPENAI_API_KEY', 'LANGSMITH_API_KEY'], create_globals=False)

# Falls Key fehlt: Klare Fehlermeldung mit Hinweis auf Colab Secrets

Best Practice: Alle benötigten Keys zu Beginn im Setup-Block definieren.

💡 Tipp: LangSmith-UI immer im zweiten Browser-Tab öffnen – so können Traces direkt während der Entwicklung inspiziert werden!

🔑 Wichtig: Alle API-Keys werden sicher in Google Colab Secrets hinterlegt und niemals im Code sichtbar!

Abgrenzung zu verwandten Dokumenten

Dokument Frage
LangSmith Best Practices Welche Tracing- und Evaluationsmuster gelten in produktionsnahen Projekten?
Evaluation & Observability Welche Qualitätsfragen werden mit Traces und Testsets beantwortet?

Version: 1.0
Stand: Mai 2026
Kurs: Generative KI mit LangChain 1.1+