Code Standards

[!NOTE] Coding-Konventionen
Die Standards bündeln Importstruktur, Stilregeln, Sicherheitsmuster und Testkonventionen für Kursnotebooks und Beispielcode.


Inhaltsverzeichnis

  1. LangChain 1.0+ Features
  2. Namenskonventionen
    1. Python Style Guide (PEP 8)
    2. Aussagekräftige Namen
  3. Import-Struktur
    1. Import-Konflikte vermeiden
  4. Code-Stil
    1. Maximale Zeilenlänge
    2. Docstrings
    3. Kommentare
  5. Breaking Changes: 0.x → 1.0+
    1. Migration-Tabelle
    2. Beispiel-Migration
  6. Security Best Practices
    1. API-Keys sicher verwalten
    2. Input-Validierung
    3. PII-Handling
  7. Testing Best Practices
    1. Unit Tests
    2. Integration Tests
  8. Weitere Ressourcen
  9. Abgrenzung zu verwandten Dokumenten

LangChain 1.0+ Features

Die 7 MUST-HAVE Features für LangChain 1.0+ sind vollständig dokumentiert in:

LangChain Einsteiger enthält das Tutorial mit ausführlichen Erklärungen und Mermaid-Diagrammen.

Kurzübersicht der 7 Patterns:

# Feature Beschreibung
1 init_chat_model() Unified Model Initialization für alle Provider
2 with_structured_output() Native Structured Outputs mit Pydantic
3 @tool Decorator Tool-Definitionen mit Type Hints
4 create_agent() Moderne Agent-API basierend auf LangGraph
5 LCEL \| Chains Lesbare Chain-Syntax mit Pipe-Operator
6 Middleware Granulare Kontrolle über Agent-Loop
7 Content Blocks Provider-agnostische multimodale Inhalte

Neu in v1.2.0: Tool Extras und response_format für Agents (siehe LangChain Einsteiger Abschnitte 5.3 und 6.2)


Namenskonventionen

Python Style Guide (PEP 8)

  • snake_case für:
    • Variablen: model_output, training_data
    • Funktionen: load_model(), preprocess_text()
    • Module: utilities.py, multimodal_rag.py
  • PascalCase für:
    • Klassen: TypedDict, BaseModel (Pydantic)
    • Beispiele: ResearchState, Person
  • UPPER_CASE für:
    • Konstanten: MAX_TOKENS, DEFAULT_TEMPERATURE

Aussagekräftige Namen

# ✅ GUT: Beschreibende Namen
model_provider = "openai"
temperature = 0.0
max_retries = 3

# ❌ SCHLECHT: Kryptische Namen
mp = "openai"
temp = 0.0
mr = 3

Import-Struktur

Standard-Reihenfolge für Imports:

# . Standardbibliotheken
import os
from pathlib import Path
from typing import List, Dict

# . LangChain Integrationen
from langchain_chroma import Chroma

# . LangChain Core (LCEL)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
from langchain_core.output_parsers import StrOutputParser

# . LangChain Top-Level
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent

# . Projekt-Module
from genai_lib.utilities import setup_api_keys

Import-Konflikte vermeiden

# ✅ EMPFOHLEN: Aliasing verwenden
from PIL import Image as PILImage
from IPython.display import Image as IPImage

# ✅ ALTERNATIVE: Modul-Import
import PIL.Image
from IPython import display
# Nutzung: PIL.Image.open() und display.Image()

# ❌ VERMEIDEN: Direkter Import (Konflikt!)
from PIL import Image
from IPython.display import Image  # Überschreibt PIL.Image!

Code-Stil

Maximale Zeilenlänge

  • 88 Zeichen (Black-Standard)
  • Bei Überschreitung: Zeilenumbruch verwenden
# ✅ GUT: Zeilenumbruch bei langen Chains
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# ❌ SCHLECHT: Zu lange Zeile
chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser()

Docstrings

def process_documents(docs: List[str], chunk_size: int = 1000) -> List[str]:
    """
    Verarbeitet Dokumente und teilt sie in Chunks.

    Args:
        docs: Liste von Dokumenten als Strings
        chunk_size: Maximale Größe eines Chunks (default: 1000)

    Returns:
        Liste von Chunks als Strings

    Raises:
        ValueError: Wenn docs leer ist
    """
    if not docs:
        raise ValueError("docs darf nicht leer sein")

    # Implementation...
    return chunks

Kommentare

# ✅ GUT: Erklärt das "Warum"
# Middleware verhindert versehentliches Löschen von Dateien
middleware = [HumanInTheLoopMiddleware(tool_names=["delete_file"])]

# ❌ SCHLECHT: Erklärt das "Was" (offensichtlich aus Code)
# Erstellt eine Liste mit einem HumanInTheLoopMiddleware-Objekt
middleware = [HumanInTheLoopMiddleware(tool_names=["delete_file"])]

Breaking Changes: 0.x → 1.0+

Migration-Tabelle

Alt (0.x) Neu (1.0+) Status
ChatOpenAI() direkt init_chat_model() ⛔ Deprecated
PydanticOutputParser with_structured_output() ⛔ Deprecated
Tool() wrapper @tool decorator ⛔ Deprecated
initialize_agent() create_agent() ⛔ Deprecated
AgentExecutor create_agent() (gibt Graph zurück) ⛔ Deprecated

Beispiel-Migration

ALT (0.x):

from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)  # Altbeispiel
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION)

NEU (1.0+):

from langchain.chat_models import init_chat_model
from langchain.agents import create_agent

llm = init_chat_model("openai:gpt-5.4-nano")
agent = create_agent(model=llm, tools=tools, debug=True)

Security Best Practices

API-Keys sicher verwalten

# ✅ GUT: Umgebungsvariablen
from dotenv import load_dotenv
import os

load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")

# ❌ SCHLECHT: Hardcoded API-Keys
api_key = "sk-..."  # NIEMALS!

Input-Validierung

from pydantic import BaseModel, Field, field_validator

class UserInput(BaseModel):
    query: str = Field(min_length=1, max_length=500)

    @field_validator('query')
    def validate_query(cls, v):
        if not v.strip():
            raise ValueError("Query darf nicht leer sein")
        return v.strip()

PII-Handling

from langchain.agents.middleware import PIIMiddleware

# PII automatisch erkennen und entfernen
middleware = [
    PIIMiddleware(
        patterns=["email", "phone", "ssn"],
        redact=True
    )
]

Testing Best Practices

Unit Tests

import pytest
from langchain_core.tools import tool

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

    result = add.invoke({"a": 2, "b": 3})
    assert result == 5

Integration Tests

def test_agent_with_tools():
    llm = init_chat_model("openai:gpt-5.4-nano")

    @tool
    def get_weather(location: str) -> str:
        """Mock weather tool."""
        return f"Sunny in {location}"

    agent = create_agent(model=llm, tools=[get_weather])
    response = agent.invoke({
        "messages": [{"role": "user", "content": "Weather in Berlin?"}]
    })

    assert "Berlin" in response["messages"][-1].content

Weitere Ressourcen


[!TIP] Vertiefung
Ausführliche LangChain-Beispiele mit Mermaid-Diagrammen stehen im Dokument LangChain Einsteiger.

Abgrenzung zu verwandten Dokumenten

Dokument Frage
Zuerst lesen Welche Dokumente sind vor dem ersten Kursprojekt am wichtigsten?
Lesepfade Welche Reihenfolge passt zu Rolle, Ziel und Vorkenntnissen?

Version: 2.1
Stand: Mai 2026
Kurs: Generative KI. Verstehen. Anwenden. Gestalten.