Code Standards

Coding-Konventionen und Best Practices


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

🎯 LangChain 1.0+ Features

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

👉 Einsteiger LangChain - 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 Einsteiger LangChain 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 Community
from langchain_community.vectorstores 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)
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-4o-mini", temperature=0.0)
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-4o-mini")

    @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


💡 Tipp: Für ausführliche LangChain-Beispiele mit Mermaid-Diagrammen siehe Einsteiger LangChain!


Version: 2.0 (konsolidiert)
Stand: Januar 2026
Kurs: Generative KI. Verstehen. Anwenden. Gestalten.