Latenode

LangChain Tools: Vollständiger Leitfaden zum Erstellen und Verwenden benutzerdefinierter LLM-Tools mit Codebeispielen 2025

Erfahren Sie, wie Sie LangChain Tools erstellen und nutzen, um die KI-Integration mit externen Systemen zu verbessern und Automatisierung sowie Funktionalität zu optimieren.

11 Min. Lesezeit
Illustration zur Erstellung und Nutzung benutzerdefinierter LangChain LLM-Tools

LangChain-Tools sind Python-basierte Lösungen, die eine nahtlose Interaktion zwischen großen Sprachmodellen (LLMs) und externen Systemen wie APIs und Datenbanken ermöglichen. Durch strukturierte Funktionsaufrufe versetzen diese Tools LLMs in die Lage, Aufgaben wie das Abrufen von Live-Daten, das Ausführen von Abfragen oder die Automatisierung von Workflows zu übernehmen. Dieser Ansatz schließt die Lücke zwischen KI-gestütztem Denken und umsetzbaren Ergebnissen und eignet sich ideal für Anwendungsfälle, die Echtzeit-Updates oder Systemintegrationen erfordern.

LangChain-Tools sind besonders effektiv für Anwendungen wie Kundenservice-Bots, technische Supportsysteme und Finanzassistenten. Entwickler können zwischen zwei Erstellungsmethoden wählen: dem @tool-Decorator für einfache Fälle oder der BaseTool-Unterklasse für erweiterte Anpassungen. Beide Ansätze legen Wert auf klare Funktionssignaturen, robuste Fehlerbehandlung und präzise Eingabevalidierung, um Zuverlässigkeit sicherzustellen.

Für Teams, die eine Alternative zur individuellen Entwicklung suchen, vereinfachen Plattformen wie Latenode die Automatisierung mit vorgefertigten Konnektoren und visuellen Workflows. So lassen sich beispielsweise Tools wie Notion, WhatsApp oder Google Sheets ohne umfangreiche Programmierung unkompliziert integrieren. Das reduziert Entwicklungszeit und Wartungsaufwand, sodass sich Teams auf wirkungsvolle Lösungen konzentrieren können.

Ein benutzerdefiniertes LangChain-Tool erstellen

Architektur und Kernkomponenten von LangChain-Tools

LangChain-Tools basieren auf einem strukturierten Framework, das Python-Funktionen in Schnittstellen umwandelt, die von großen Sprachmodellen (LLMs) aufgerufen werden können. Dieses Setup ermöglicht eine reibungslose Interaktion zwischen KI-Modellen und externen Systemen. Im Folgenden betrachten wir die Kernkomponenten, durch die diese Tools effektiv funktionieren.

Die wichtigsten Komponenten von LangChain-Tools

Die Funktionalität von LangChain-Tools wird von fünf entscheidenden Komponenten getragen. Jede übernimmt eine eigene Aufgabe, um einen nahtlosen Betrieb und eine zuverlässige Kommunikation zwischen Tools und LLMs sicherzustellen:

  • Funktionssignatur
    Die Funktionssignatur dient als Vorlage für die Schnittstelle des Tools. Sie definiert die Parameter, die das Tool akzeptiert, sowie seine Ausgaben. Python-Typhinweise spielen eine zentrale Rolle bei der Gestaltung dieser Signatur und helfen LLMs, das passende Tool für bestimmte Aufgaben zu identifizieren. Der Name der Funktion fungiert als eindeutige Kennung und leitet das LLM bei der Auswahl des richtigen Tools während der Ausführung.
  • Tool-Beschreibungen
    Tool-Beschreibungen vermitteln LLMs ein klares Verständnis davon, was ein Tool macht. In einfacher, natürlicher Sprache erklären sie, wann und wie das Tool verwendet werden sollte und welche Ergebnisse es liefert. Klare und präzise Beschreibungen sind entscheidend, um Missverständnisse oder eine falsche Tool-Nutzung zu vermeiden.
  • Parameterschema
    Das Parameterschema definiert die Regeln und Struktur für die Eingaben des Tools. Mithilfe von Python-Typhinweisen können Entwickler Schemas erstellen, die Einschränkungen, Standardwerte und benutzerdefinierte Validierungsregeln festlegen. Das stellt sicher, dass Eingabedaten korrekt formatiert sind, senkt das Risiko von Laufzeitfehlern und erhöht die allgemeine Zuverlässigkeit.
  • Rückgabeverarbeitung
    Diese Komponente bestimmt, wie die Ausgabe eines Tools verarbeitet und an das LLM zurückgegeben wird. Tools können Ausgaben in unterschiedlichen Formen erzeugen, etwa als Klartext, strukturierte Daten oder komplexe Objekte. Das Rückgabeformat ist entscheidend dafür, dass das LLM die Ergebnisse innerhalb seines umfassenderen Workflows effektiv nutzen kann.
  • Fehlerbehandlung
    Die Fehlerbehandlung ist ein entscheidender, aber häufig übersehener Aspekt. Tools müssen in der Lage sein, Probleme wie Netzwerkausfälle, Rate Limits oder ungültige Eingaben zu verarbeiten. Eine effektive Fehlerbehandlung stellt sicher, dass ein einzelner Fehler nicht den Betrieb eines gesamten Agenten unterbricht – besonders wichtig in Produktionsumgebungen.

Decorator- oder BaseTool-Unterklassenmethode

LangChain bietet zwei zentrale Ansätze zur Erstellung von Tools, die jeweils auf unterschiedliche Komplexitätsgrade und Anwendungsfälle zugeschnitten sind. Diese Methoden sind der @tool-Decorator und die BaseTool-Unterklasse.

  • Der @tool-Decorator
    Dieser Ansatz ist auf Einfachheit ausgelegt. Er ermöglicht Entwicklern, Python-Funktionen mit minimalem Aufwand schnell in LangChain-kompatible Tools umzuwandeln. Der Decorator übernimmt Aufgaben wie die Schemaerstellung, Parameterprüfung und grundlegende Fehlerkapselung automatisch. Er eignet sich ideal für einfache Vorgänge wie API-Aufrufe, einfache Berechnungen oder Datentransformationen, bei denen keine Zustandsverwaltung oder komplexe Initialisierung erforderlich ist.
  • Die BaseTool-Unterklasse
    Für weitergehende Anforderungen bietet die BaseTool-Unterklassenmethode umfangreiche Anpassungsmöglichkeiten. Sie eignet sich für Tools, die komplexe Logik, zustandsbehaftete Vorgänge oder erweiterte Fehlerbehandlung erfordern. Entwickler können benutzerdefinierte Initialisierungen, asynchrone Vorgänge und komplexere Rückgabetypen implementieren. Diese Methode erfordert zwar mehr Programmierung, bietet jedoch die Flexibilität, die für produktionsreife Tools nötig ist – insbesondere bei Authentifizierung, persistenten Verbindungen oder detaillierter Geschäftslogik.

Den richtigen Ansatz wählen

Die Wahl zwischen diesen Methoden hängt von der Komplexität und dem vorgesehenen Einsatz des Tools ab. Einfache Tools beginnen häufig mit dem Decorator-Ansatz und können später zu unterklassenbasierten Implementierungen weiterentwickelt werden, wenn die Anforderungen wachsen. Bei Tools, die eine robuste Fehlerbehandlung oder die Integration mit komplexen Systemen benötigen, kann der Start mit der BaseTool-Unterklasse jedoch Zeit sparen und spätere Architekturprobleme vermeiden.

Benutzerdefinierte Tools mit korrekter Validierung erstellen

Beim Entwickeln benutzerdefinierter Tools ist es wichtig, sich auf eine strenge Eingabevalidierung, effektive Fehlerbehandlung und klare Dokumentation zu konzentrieren. Diese Elemente gewährleisten, dass Tools zuverlässig arbeiten und sich nahtlos in große Sprachmodelle (LLMs) integrieren.

So erstellen Sie ein einfaches Tool

Der @tool-Decorator bietet eine einfache Methode zur Erstellung von LangChain-Tools. Er generiert automatisch Schemas und übernimmt die grundlegende Validierung, wodurch er sich ideal für unkomplizierte Vorgänge eignet.

Hier ist ein Beispiel für ein Tool zur Wetterabfrage:

from langchain.tools import tool
from typing import Optional
import requests

@tool
def get_weather_data(city: str, country_code: Optional[str] = "US") -> str:
    """
    Ruft aktuelle Wetterinformationen für eine bestimmte Stadt ab.

    Args:
        city: Der Name der Stadt, für die Wetterdaten abgerufen werden sollen.
        country_code: Zweistelliger Ländercode (Standard: US).

    Returns:
        Wetterinformationen als formatierter String.
    """
    try:
        api_key = "your_api_key_here"
        url = "http://api.openweathermap.org/data/2.5/weather"
        params = {
            "q": f"{city},{country_code}",
            "appid": api_key,
            "units": "imperial"
        }
        response = requests.get(url, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()
        temp = data["main"]["temp"]
        description = data["weather"][0]["description"]
        return f"Aktuelles Wetter in {city}: {temp}°F, {description}"
    except requests.exceptions.RequestException as e:
        return f"Fehler beim Abrufen der Wetterdaten: {str(e)}"
    except KeyError as e:
        return f"Ungültiges Antwortformat: {str(e)} fehlt"

Für fortgeschrittenere Anwendungsfälle, etwa bei benutzerdefinierter Initialisierung oder der Verarbeitung interner Zustände, bietet die BaseTool-Unterklasse mehr Flexibilität:

from langchain.tools import BaseTool
from typing import Type
from pydantic import BaseModel, Field

class DatabaseQueryInput(BaseModel):
    query: str = Field(description="Auszuführende SQL-Abfrage")
    table: str = Field(description="Name der Zieltabelle")

class DatabaseQueryTool(BaseTool):
    name = "database_query"
    description = "SQL-Abfragen für die Unternehmensdatenbank ausführen"
    args_schema: Type[BaseModel] = DatabaseQueryInput

    def __init__(self, connection_string: str):
        super().__init__()
        self.connection_string = connection_string
        self.connection = None

    def _run(self, query: str, table: str) -> str:
        if not self.connection:
            self.connection = self._establish_connection()
        # Abfrage mit korrekter Validierung ausführen
        return self._execute_safe_query(query, table)

Best Practices für Tool-Namen und -Beschreibungen

Klare und aussagekräftige Namen für Tools helfen LLMs, ihren Zweck und ihre Verwendung zu verstehen. Verwenden Sie handlungsorientierte Verben in Tool-Namen, beispielsweise search_documents statt docs, und vermeiden Sie Abkürzungen, die das LLM verwirren könnten. Konsistenz bei zusammengehörigen Tools ist ebenso wichtig: Die Benennung mehrerer API-Tools als api_get_user, api_create_user und api_delete_user schafft beispielsweise eine logische Gruppierung.

Beschreibungen sollten prägnant und aktiv formuliert sein und den Zweck des Tools, erforderliche Eingaben sowie erwartete Ausgaben klar darstellen. Vergleichen Sie diese beiden Beispiele:

# Schlechte Beschreibung
@tool
def calc(x: float, y: float) -> float:
    """Führt mathematische Berechnungen aus"""
    return x + y

# Effektive Beschreibung
@tool
def add_numbers(first_number: float, second_number: float) -> float:
    """
    Addiert zwei Zahlen und gibt die Summe zurück.

    Verwenden Sie dieses Tool, wenn Sie eine grundlegende Addition numerischer Werte durchführen müssen.
    Beide Eingaben müssen Zahlen sein (Ganzzahlen oder Dezimalzahlen).

    Args:
        first_number: Die erste zu addierende Zahl.
        second_number: Die zweite zu addierende Zahl.

    Returns:
        Die Summe der beiden Eingabezahlen.
    """
    return first_number + second_number

Parametertypisierung und Eingabevalidierung

Eine präzise Parametertypisierung ist entscheidend, um Laufzeitprobleme zu vermeiden und LLM-Interaktionen zu steuern. Die Typhinweise von Python und Pydantic-Modelle lassen sich gut kombinieren, um die Validierung durchzusetzen.

Beispiel für eine grundlegende Typvalidierung:

from typing import List, Dict, Optional, Union
from datetime import datetime
from enum import Enum

class Priority(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"

@tool
def create_task(
    title: str,
    description: Optional[str] = None,
    priority: Priority = Priority.MEDIUM,
    due_date: Optional[datetime] = None,
    tags: List[str] = []
) -> Dict[str, Union[str, int]]:
    """
    Erstellt eine neue Aufgabe im Projektmanagementsystem.

    Args:
        title: Titel der Aufgabe (erforderlich, maximal 100 Zeichen).
        description: Detaillierte Aufgabenbeschreibung (optional).
        priority: Prioritätsstufe der Aufgabe (niedrig, mittel, hoch).
        due_date: Zeitpunkt, zu dem die Aufgabe abgeschlossen sein soll (ISO-Format).
        tags: Liste von Tags zur Kategorisierung der Aufgabe.

    Returns:
        Dictionary mit einer Aufgaben-ID und einer Bestätigungsnachricht.
    """
    if len(title) > 100:
        raise ValueError("Der Titel darf maximal 100 Zeichen enthalten")
    if due_date and due_date < datetime.now():
        raise ValueError("Das Fälligkeitsdatum darf nicht in der Vergangenheit liegen")
    task_id = generate_task_id()
    return {
        "task_id": task_id,
        "message": f"Aufgabe '{title}' wurde erfolgreich erstellt"
    }

Beispiel für eine erweiterte Validierung mit Pydantic-Modellen:

from pydantic import BaseModel, Field, validator
from typing import List
import re

class EmailInput(BaseModel):
    recipients: List[str] = Field(description="Liste der E-Mail-Adressen")
    subject: str = Field(description="Betreffzeile der E-Mail", max_length=200)
    body: str = Field(description="Inhalt der E-Mail")

    @validator('recipients')
    def validate_emails(cls, v):
        email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        for email in v:
            if not re.match(email_pattern, email):
                raise ValueError(f"Ungültige E-Mail-Adresse: {email}")
        return v

    @validator('subject')
    def validate_subject(cls, v):
        if not v.strip():
            raise ValueError("Der Betreff darf nicht leer sein")
        return v.strip()

@tool
def send_email(email_data: EmailInput) -> str:
    """
    Sendet eine E-Mail nach Validierung an bestimmte Empfänger.

    Alle E-Mail-Adressen werden vor dem Versand validiert.
    Die Betreffzeile ist erforderlich und darf nicht leer sein.
    """
    # Validierte E-Mail senden
    return f"E-Mail an {len(email_data.recipients)} Empfänger gesendet"

Fehlerbehandlung und Exception-Management

Sobald Eingaben validiert sind, wird eine robuste Fehlerbehandlung entscheidend, damit Workflows auch bei auftretenden Problemen intakt bleiben. Eine gut konzipierte Fehlerbehandlung verhindert, dass ein einzelner Fehler den gesamten Prozess unterbricht, und liefert hilfreiches Feedback für das Debugging.

Hier ist ein Beispiel für einen Decorator, der die Fehlerbehandlung toolübergreifend standardisiert:

import logging
from functools import wraps
import requests

def handle_tool_errors(func):
    """Decorator zur Standardisierung der Fehlerbehandlung über alle Tools hinweg."""
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except requests.exceptions.Timeout as e:
            logging.error(f"Zeitüberschreitung aufgetreten: {e}")
            return "Zeitüberschreitung der Anfrage"
        except Exception as e:
            logging.error(f"Ein Fehler ist aufgetreten: {e}")
            return f"Fehler: {e}"
    return wrapper
sbb-itb-23997f1

Tools mit Agenten und Workflows integrieren

Die Integration von LangChain-Tools in Agenten beinhaltet die Auswahl der passenden Tools und die Sicherstellung einer reibungslosen Aufgabenausführung.

Tools mit Agenten verbinden

Hier ist ein Beispiel für die Einrichtung eines Agenten mit mehreren Tools für einen Kundenservice-Anwendungsfall:

from langchain.agents import initialize_agent, AgentType
from langchain.llms import OpenAI
from langchain.tools import tool
import requests
from datetime import datetime

@tool
def lookup_order_status(order_id: str) -> str:
    """
    Ruft den aktuellen Status einer Kundenbestellung anhand ihrer ID ab.

    Args:
        order_id: Die eindeutige Kennung der Bestellung (z. B. ORD-12345).

    Returns:
        Informationen zum Bestellstatus einschließlich Versanddetails.
    """
    # Simulierter API-Aufruf
    api_response = requests.get(f"https://api.company.com/orders/{order_id}")
    if api_response.status_code == 200:
        data = api_response.json()
        return f"Bestellung {order_id}: {data['status']} – Voraussichtliche Lieferung: {data['delivery_date']}"
    return f"Bestellung {order_id} wurde im System nicht gefunden"

@tool
def process_refund_request(order_id: str, reason: str) -> str:
    """
    Bearbeitet eine Rückerstattungsanfrage eines Kunden.

    Args:
        order_id: Die Bestell-ID, für die eine Rückerstattung angefordert wird.
        reason: Der vom Kunden angegebene Grund für die Rückerstattungsanfrage.

    Returns:
        Bestätigung der Rückerstattungsanfrage zusammen mit einer Referenznummer.
    """
    refund_id = f"REF-{datetime.now().strftime('%Y%m%d')}-{order_id[-5:]}"
    return f"Rückerstattung für {order_id} eingeleitet. Referenz: {refund_id}. Bearbeitungszeit: 3–5 Werktage."

# Agenten mit Tools initialisieren
llm = OpenAI(temperature=0)
tools = [lookup_order_status, process_refund_request]

agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    max_iterations=3
)

# Der Agent wählt anhand der Nutzereingabe das passende Tool aus
response = agent.run("Ich möchte die Bestellung ORD-67890 prüfen und eine Rückerstattung beantragen, weil der Artikel beschädigt angekommen ist")

In diesem Beispiel verwendet der Agent die Eingabeanfrage, um zu bestimmen, welche Tools aktiviert werden sollen. Wenn mehrere Tools verfügbar sind, kann ihre Organisation in spezialisierten Gruppen sowohl Genauigkeit als auch Effizienz verbessern. So können Tools beispielsweise nach ihrer Funktion gruppiert werden, etwa für bestellbezogene oder produktbezogene Aufgaben:

from langchain.agents import AgentExecutor
from langchain.tools import BaseTool

class CustomerServiceAgent:
    def __init__(self):
        self.order_tools = [lookup_order_status, process_refund_request, additional_order_tool]
        self.product_tools = [additional_product_tool, additional_product_tool_2]

    def route_to_specialist(self, query: str) -> AgentExecutor:
        if "order" in query.lower() or "refund" in query.lower():
            return initialize_agent(self.order_tools, llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION)
        elif "product" in query.lower() or "inventory" in query.lower():
            return initialize_agent(self.product_tools, llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION)
        else:
            # Standardmäßig allgemeine Tools verwenden
            return initialize_agent(self.order_tools[:2], llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION)

Diese Methode stellt sicher, dass Anfragen an die relevantesten Tools weitergeleitet werden, und schafft so eine schlankere Nutzererfahrung.

Erweiterte Tool-Muster für komplexe Workflows

Bei Workflows, die mehrere unabhängige API-Aufrufe oder Datenbankabfragen erfordern, kann die asynchrone Ausführung die Effizienz erheblich steigern. Statt Aufgaben nacheinander zu verarbeiten, ermöglichen asynchrone Muster die parallele Ausführung:

import asyncio
from langchain.tools import tool
import aiohttp
from typing import List

@tool
async def fetch_user_data_async(user_id: str) -> str:
    """
    Ruft das Profil eines Nutzers asynchron ab.

    Args:
        user_id: Die eindeutige Kennung des Nutzers.

    Returns:
        Profildetails als JSON-String.
    """
    async with aiohttp.ClientSession() as session:
        async with session.get(f"https://api.userservice.com/users/{user_id}") as response:
            if response.status == 200:
                data = await response.json()
                return f"Nutzer {user_id}: {data['name']}, {data['email']}, {data['subscription_tier']}"
            return f"Nutzer {user_id} nicht gefunden"

@tool
async def fetch_usage_metrics_async(user_id: str) -> str:
    """
    Ruft Nutzungsstatistiken für einen Nutzer asynchron ab.

    Args:
        user_id: Die Kennung des Nutzers.

    Returns:
        Nutzungsdetails einschließlich Anzahl der API-Aufrufe und Speichernutzung.
    """
    async with aiohttp.ClientSession() as session:
        async with session.get(f"https://api.analytics.com/usage/{user_id}") as response:
            if response.status == 200:
                data = await response.json()
                return f"Nutzung für {user_id}: {data['api_calls']} Aufrufe, {data['storage_gb']} GB Speicher"
            return f"Keine Nutzungsdaten für {user_id}"

async def parallel_user_analysis(user_ids: List[str]) -> List[str]:
    """Führt mehrere asynchrone Aufgaben zur Abrufung von Nutzerdaten aus."""
    tasks = []
    for user_id in user_ids:
        tasks.append(fetch_user_data_async(user_id))
        tasks.append(fetch_usage_metrics_async(user_id))
    results = await asyncio.gather(*tasks)
    return results

Dieser Ansatz spart nicht nur Zeit, sondern stellt auch sicher, dass das System komplexe Workflows effizient verarbeiten kann.

Für Aufgaben, die Kontext über mehrere Interaktionen hinweg benötigen, können zustandsbehaftete Tools eingesetzt werden. Diese Tools speichern Informationen und ermöglichen kumulative Analysen sowie eine bessere Nachverfolgung:

from typing import Dict, Any
import json
from datetime import datetime
from langchain.tools import BaseTool

class StatefulAnalyticsTool(BaseTool):
    name = "analytics_tracker"
    description = "Nutzerverhaltensmuster über mehrere Interaktionen hinweg verfolgen und analysieren"

    def __init__(self):
        super().__init__()
        self.session_data: Dict[str, Any] = {}
        self.interaction_count = 0

    def _run(self, action: str, data: str) -> str:
        self.interaction_count += 1

        if action == "track_event":
            event_data = json.loads(data)
            event_type = event_data.get("type")
            if event_type not in self.session_data:
                self.session_data[event_type] = []
            self.session_data[event_type].append({
                "timestamp": datetime.now().isoformat(),
                "data": event_data,
                "interaction_number": self.interaction_count
            })
            return f"Ereignis {event_type} erfasst. Interaktionen insgesamt: {self.interaction_count}"

        elif action == "analyze_patterns":
            if not self.session_data:
                return "Noch keine Daten zur Analyse erfasst"
            patterns = {}
            for event_type, events in self.session_data.items():
                patterns[event_type] = {
                    "count": len(events),
                    "frequency": len(events) / self.interaction_count
                }
            return f"Verhaltensmuster: {json.dumps(patterns, indent=2)}"

        return "Unbekannte Aktion. Verwenden Sie 'track_event' oder 'analyze_patterns'"

Überlegungen für den Produktionseinsatz von LangChain-Tools

Der Übergang von LangChain-Tools aus der Entwicklung in die Produktion erfordert einen durchdachten Ansatz, um Herausforderungen bei Performance, Sicherheit und Wartung zu bewältigen. Diese Aspekte sind entscheidend, damit Tools in realen Umgebungen effizient und sicher arbeiten.

Tool-Performance optimieren

Engpässe bei der Performance in Produktionsumgebungen entstehen häufig durch langsame Antworten externer APIs, ineffiziente Logik oder zu viele synchrone Vorgänge [1][2]. Diese Probleme treten besonders deutlich auf, wenn Tools große Mengen gleichzeitiger Anfragen verarbeiten oder mit APIs interagieren, die Rate Limits durchsetzen.

Eine Möglichkeit zur Verbesserung der Performance sind asynchrone Ausführungsmuster, durch die Tools mehrere Anfragen gleichzeitig verarbeiten können. Dieser Ansatz ist besonders effektiv für I/O-gebundene Vorgänge, wie das folgende Beispiel zeigt:

import asyncio
import aiohttp
from langchain.tools import StructuredTool
from pydantic import BaseModel

class BatchAPITool(BaseModel):
    """Optimiertes Tool zur gleichzeitigen Verarbeitung mehrerer API-Anfragen."""

    async def fetch_data_batch(self, endpoints: list[str]) -> dict:
        """Verarbeitet mehrere API-Endpunkte gleichzeitig mit Fehlerbehandlung."""
        async with aiohttp.ClientSession(
            timeout=aiohttp.ClientTimeout(total=10),
            connector=aiohttp.TCPConnector(limit=20)
        ) as session:
            tasks = [self._fetch_single(session, url) for url in endpoints]
            results = await asyncio.gather(*tasks, return_exceptions=True)
            return {
                "successful": [r for r in results if not isinstance(r, Exception)],
                "failed": [str(r) for r in results if isinstance(r, Exception)],
                "total_processed": len(results)
            }

    async def _fetch_single(self, session: aiohttp.ClientSession, url: str) -> dict:
        try:
            async with session.get(url) as response:
                if response.status == 200:
                    return await response.json()
                return {"error": f"HTTP {response.status}"}
        except asyncio.TimeoutError:
            return {"error": "Zeitüberschreitung der Anfrage"}
        except Exception as e:
            return {"error": f"Anfrage fehlgeschlagen: {str(e)}"}

# Strukturiertes Tool mit asynchroner Unterstützung erstellen
batch_tool = StructuredTool.from_function(
    func=BatchAPITool().fetch_data_batch,
    name="batch_api_processor",
    description="Mehrere API-Endpunkte gleichzeitig verarbeiten, um die Performance zu verbessern"
)

Neben der asynchronen Ausführung sind Rate Limiting und Caching wesentliche Bestandteile einer robusten Produktionsstrategie. Rate Limiting verhindert, dass Tools API-Kontingente überschreiten, während Caching die Häufigkeit von API-Aufrufen senkt, indem Antworten für einen bestimmten Zeitraum gespeichert werden.

Rate Limiting mit exponentiellem Backoff

Um APIs mit Rate Limits zuverlässig zu verarbeiten, ist die Implementierung exponentieller Backoff-Strategien wichtig. Das folgende Beispiel zeigt einen Decorator, der Anfragen mit zunehmenden Verzögerungen wiederholt:

import random
from functools import wraps
import asyncio

def rate_limited_retry(max_retries=3, base_delay=1.0):
    """Decorator zur Behandlung von Rate Limits mit exponentiellem Backoff."""
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            for attempt in range(max_retries + 1):
                try:
                    return await func(*args, **kwargs)
                except Exception as e:
                    if "rate limit" in str(e).lower() and attempt < max_retries:
                        delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
                        await asyncio.sleep(delay)
                        continue
                    raise e
            return {"error": "Maximale Anzahl von Wiederholungsversuchen überschritten"}
        return wrapper
    return decorator

Caching-Strategien

Caching kann die Reaktionsfähigkeit erheblich verbessern und API-Aufrufe reduzieren, indem häufig abgerufene Daten gespeichert werden. Hier ist ein Beispiel für ein einfaches Caching-System:

from datetime import datetime, timedelta
from typing import Dict, Any, Optional

class ToolCache:
    def __init__(self, default_ttl_minutes: int = 15):
        self.cache: Dict[str, Dict[str, Any]] = {}
        self.default_ttl = timedelta(minutes=default_ttl_minutes)

    def get(self, key: str) -> Optional[Any]:
        if key in self.cache:
            entry = self.cache[key]
            if datetime.now() < entry["expires"]:
                return entry["data"]
            else:
                del self.cache[key]
        return None

    def set(self, key: str, data: Any, ttl_minutes: Optional[int] = None) -> None:
        ttl = timedelta(minutes=ttl_minutes) if ttl_minutes else self.default_ttl
        self.cache[key] = {
            "data": data,
            "expires": datetime.now() + ttl
        }

# Globale Cache-Instanz
tool_cache = ToolCache()

Durch die Kombination dieser Techniken – asynchrone Ausführung, Rate Limiting und Caching – können LangChain-Tools in Produktionsumgebungen eine reibungslosere und zuverlässigere Performance erreichen.

Sicherheit bei der Tool-Entwicklung

Performance ist ein wichtiger Schwerpunkt, doch Sicherheit ist beim Einsatz von LangChain-Tools in der Produktion ebenso entscheidend. Tools greifen häufig mit erweiterten Berechtigungen auf externe Systeme zu, wodurch sie für Risiken wie unzureichende Eingabevalidierung und zu weitreichende Zugriffsrechte anfällig sind.

Eingabevalidierung mit Pydantic-Modellen

Pydantic-Modelle bieten eine robuste Grundlage für die Validierung von Eingaben. Durch die Durchsetzung strenger Regeln tragen sie dazu bei, dass bösartige oder ungültige Daten das System nicht beeinträchtigen. Hier ist ein Beispiel für ein sicheres Eingabemodell:

from pydantic import BaseModel, Field

class SecureAPIRequest(BaseModel):
    """Sicheres Eingabemodell mit umfassender Validierung."""
    endpoint: str = Field(..., regex=r'^[a-zA-Z0-9/_-]+$', max_length=200)
    user_id: str = Field(..., regex=r'^[a-zA-Z0-9-]+$')
    # Zusätzliche Felder und Validatoren können hier ergänzt werden, um Eingaben weiter abzusichern

API-Tools absichern

Das folgende Beispiel zeigt ein sicheres API-Tool, das Eingabevalidierung und zusätzliche Sicherheitsprüfungen integriert:

def create_secure_api_tool():
    """Erstellt ein API-Tool mit integrierter Sicherheitsvalidierung."""

    def secure_api_call(request: SecureAPIRequest) -> str:
        # Zusätzliche Sicherheitsprüfungen
        if not _is_authorized_user(request.user_id):
            return "Fehler: Nicht autorisierter Zugriffsversuch"

        if not _is_allowed_endpoint(request.endpoint):
            return "Fehler: Endpunkt nicht zulässig"

        try:
            # Den eigentlichen API-Aufruf mit validierten Eingaben ausführen
            result = _execute_api_request(request)
            return _sanitize_response(result)
        except Exception:
            # Niemals interne Fehlerdetails offenlegen
            return "Fehler: Verarbeitung der Anfrage fehlgeschlagen"

    return StructuredTool.from_function(
        func=secure_api_call,
        name="secure_api_tool",
        description="API-Anfragen mit umfassender Sicherheitsvalidierung ausführen"
    )

API-Antworten bereinigen

Um zu verhindern, dass sensible Informationen offengelegt werden, sollten Antworten vor ihrer Rückgabe bereinigt werden:

def _sanitize_response(response: dict) -> str:
    """Entfernt sensible Informationen aus API-Antworten."""
    sensitive_keys = ['password', 'token', 'secret', 'key', 'credential']

    def clean_dict(obj):
        if isinstance(obj, dict):
            return {k: clean_dict(v) for k, v in obj.items() 
                    if k.lower() not in sensitive_keys}
        elif isinstance(obj, list):
            return [clean_dict(item) for item in obj]
        return obj

    cleaned = clean_dict(response)
    return str(cleaned)[:1000]  # Antwortgröße begrenzen

Berechtigungsmanagement

Das Berechtigungsmanagement sollte dem Prinzip der geringsten Rechte folgen und sicherstellen, dass Tools nur Zugriff auf die Ressourcen erhalten, die sie für ihre Aufgaben benötigen. Rollenbasierte Zugriffskontrollen können nicht autorisierte Aktionen zusätzlich einschränken und die allgemeine Sicherheit erhöhen [1][3].

Der visuelle Integrationsansatz von Latenode

LangChain-Tools erfordern häufig manuelle Programmierung und kontinuierliche Wartung, was sowohl zeitaufwendig als auch ressourcenintensiv sein kann. Latenode vereinfacht diesen Prozess dagegen mit vorgefertigten Konnektoren für Hunderte von Services und macht bei den meisten gängigen Integrationen individuelle Programmierung überflüssig.

Latenode im Vergleich zur manuellen LangChain-Entwicklung

Der Unterschied zwischen der Erstellung benutzerdefinierter LangChain-Tools und dem visuellen Workflow-Design von Latenode ist deutlich, insbesondere bei Entwicklungszeit und Komplexität. So erfordert die Entwicklung eines benutzerdefinierten Tools für Google Sheets normalerweise umfangreiche Programmierung für Aufgaben wie Fehlerbehandlung, Authentifizierung und Datenvalidierung. Mit Latenode lässt sich dieselbe Funktionalität über eine intuitive Drag-and-Drop-Oberfläche umsetzen.

Betrachten Sie einen Workflow, der Kundenfeedback verarbeitet und eine Tabelle aktualisiert. Normalerweise wären dafür separate Tools zur Datenverarbeitung, API-Authentifizierung und Tabellenbearbeitung erforderlich. Latenode vereinfacht dies zu einer visuellen Abfolge wie: Webhook → OpenAI GPT-4 → Google Sheets. Jeder Konnektor in dieser Kette umfasst integrierte Authentifizierung und Fehlerverwaltung, wodurch ein Großteil des manuellen Aufwands entfällt.

Latenode unterstützt die Integration mit über 300 Apps und mehr als 200 KI-Modellen und deckt damit ein breites Spektrum an Anforderungen für die Geschäftsautomatisierung ohne individuellen Code ab. Dieser Ansatz ist besonders vorteilhaft für Teams, die zuverlässige Lösungen ohne die zusätzliche Belastung durch fortlaufende Wartung suchen. Indem Latenode sowohl Entwicklungs- als auch Wartungsprozesse vereinfacht, erleichtert die Plattform den Übergang zu einem effizienten Systemmanagement.

Neben der Beschleunigung der Entwicklung reduziert diese Plattform auch die Herausforderungen bei der Pflege individuell entwickelter Tools erheblich.

Aufwand reduzieren und Wartbarkeit verbessern

Die programmatische Tool-Entwicklung umfasst häufig das Debugging komplexer Funktionsaufrufe und die Verwaltung der Parameteranalyse – ein mühsamer und fehleranfälliger Prozess. Latenode beseitigt diese Hürden, indem es LLM-zu-System-Interaktionen über sein visuelles Workflow-Design ermöglicht und Integrationen auch für Nicht-Entwickler zugänglich macht.

Funktionen wie die integrierte Ausführungshistorie und Workflow-Neustarts ermöglichen Teams, Probleme schnell zu diagnostizieren und zu beheben, ohne ganze Workflows neu erstellen zu müssen. Damit entfällt ein Großteil der Unsicherheit, die typischerweise mit dem Debugging individueller Tools verbunden ist.

Darüber hinaus erhöht Latenodes AI Code Copilot die Flexibilität, indem Teams JavaScript direkt in Workflows generieren und bearbeiten können. Diese Funktion schließt die Lücke zwischen visuellem Design und individueller Logik, sodass Teams maßgeschneiderte Funktionen hinzufügen können, ohne zwischen verschiedenen Entwicklungsumgebungen wechseln zu müssen. Diese nahtlose Integration hilft Teams dabei, sich auf schlanke und effektive Automatisierungslösungen zu konzentrieren.

Die Wartung wird zusätzlich vereinfacht, da Latenode API-Änderungen, Authentifizierungsupdates und die Zuverlässigkeit von Konnektoren automatisch verwaltet. Das erspart Teams die kontinuierliche Aufgabe, externe API-Updates zu überwachen und individuelle Implementierungen anzupassen, wodurch langfristiger Aufwand reduziert wird.

Vorgefertigte Konnektoren für schnellere Integrationen

Latenodes vorgefertigte Konnektoren bieten Teams eine schnellere und effizientere Möglichkeit zur Integration externer Systeme und minimieren gleichzeitig den Wartungsbedarf. Diese Integrationen sind darauf ausgelegt, Fehlerbehandlung und API-Updates automatisch zu verwalten, wodurch wertvolle Zeit und Aufwand gespart werden.

Die Konnektor-Bibliothek der Plattform umfasst beliebte Business-Tools wie Notion, Stripe, WhatsApp, Telegram und LinkedIn. Jeder Konnektor beinhaltet vorkonfigurierte Authentifizierung und unterstützt gängige Anwendungsfälle, sodass ein reibungsloser Betrieb gewährleistet bleibt, selbst wenn sich APIs weiterentwickeln.

Für die Automatisierung persönlicher Messenger geht Latenode über Standard-API-Integrationen hinaus. Die Plattform ermöglicht Automatisierung für WhatsApp, LinkedIn und Telegram und unterstützt damit personalisierte Ansprache sowie CRM-ähnliche Workflows. Die Umsetzung solcher Funktionen als benutzerdefinierte LangChain-Tools wäre aufgrund der Herausforderungen bei Authentifizierung und Compliance äußerst komplex.

Zusätzlich ermöglicht Latenodes integrierte Datenbank eine strukturierte Datenverwaltung direkt innerhalb von Workflows. In Verbindung mit Headless-Browser-Automatisierung unterstützt sie komplexe Automatisierungsanwendungsfälle, die andernfalls mehrere benutzerdefinierte Tools und externe Services erfordern würden.

Für Teams, die zwischen Eigenentwicklung und Kauf abwägen, erweist sich Latenodes Preismodell – basierend auf Ausführungszeit statt auf Gebühren pro Aufgabe – häufig als kostengünstigere Option. Im Vergleich zu den Entwicklungs- und Wartungskosten benutzerdefinierter LangChain-Tools kann dies zu erheblichen Einsparungen führen.

References

FAQ

Frequently Asked Questions

Der @tool-Dekorator bietet eine unkomplizierte Möglichkeit, Python-Funktionen in LangChain Tools umzuwandeln. Durch das einfache Umhüllen einer Funktion weist er automatisch zentrale Attribute wie Namen und Beschreibung des Tools zu und übernimmt diese Angaben aus dem Funktionsnamen und dem Docstring. Damit eignet er sich hervorragend für einfache Tools oder zum schnellen Testen von Ideen.

Für Workflows mit höheren Anforderungen ist die Ableitung von BaseTool die bessere Wahl. Diese Methode bietet mehr Flexibilität: Sie können eigene Attribute definieren, erweiterte Validierungen implementieren, Fehler verwalten und komplexere Verhaltensweisen gestalten. Sie eignet sich insbesondere für Tools, die Anforderungen auf Produktionsniveau erfüllen oder komplexe Workflows verarbeiten müssen.

Zusammengefasst ist der @tool-Dekorator ideal für schnelle und einfache Setups, während BaseTool die erste Wahl für fortschrittlichere und zuverlässigere Tools ist.

War das hilfreich? Teile es →

Faktencheck von

Oleg Zankov

CEO Latenode, No-code-Experte

Mit einer Philosophie, die auf Innovation, Problemlösung und Benutzererfahrung basiert, konzentriere ich mich darauf, Teams zu befähigen, maßgeschneiderte Integrationen zu erstellen und Arbeitsabläufe einfach und effizient zu automatisieren. Mit umfangreicher Erfahrung in den Bereichen Geschäftsentwicklung, Technologieunternehmertum und Softwareentwicklung erkannte ich den Bedarf an einer zugänglicheren, skalierbareren und anpassungsfähigeren Integrationslösung. So entstand Latenode.com. Mit unserer Plattform können Unternehmen die Macht der Technologie nutzen, ohne umfassende Programmierkenntnisse zu benötigen. Leidenschaftlich daran interessiert, eine Zukunft zu fördern, in der Technologie uns dient und nicht umgekehrt, ist es meine Mission, komplexe Prozesse zu vereinfachen. Ich glaube an die Demokratisierung der Technologie und daran, Teams mit den Werkzeugen auszustatten, um in einer zunehmend digitalen Welt zu innovieren, zu wachsen und erfolgreich zu sein.

Autorenprofil →

Weiterlesen