Tipps & Tricks

5 Powerful Python Decorators to Optimize LLM Applications

5 min Lesezeit
5 Powerful Python Decorators to Optimize LLM Applications

Python-Dekoratoren sind maßgeschneiderte Lösungen, die darauf abzielen, komplexe Softwarelogik in verschiedenen Anwendungen, einschließlich solcher, die auf LLMs basieren, zu vereinfachen. Der Umgang mit LLMs erfordert häufig den Umgang mit unvorhersehbaren, langsamen und oft kostspieligen Drittanbieter-APIs. Dekoratoren bieten zahlreiche Möglichkeiten, diese Aufgaben zu optimieren, indem sie beispielsweise API-Aufrufe mit optimierter Logik umhüllen.

Im Folgenden werden fünf nützliche Python-Dekoratoren vorgestellt, die Ihnen helfen, Ihre LLM-basierten Anwendungen zu optimieren, ohne dass dabei eine spürbare zusätzliche Belastung entsteht. Die begleitenden Beispiele veranschaulichen die Syntax und den Ansatz zur Verwendung jedes Dekorators. Sie werden manchmal ohne tatsächliche LLM-Nutzung gezeigt, sind jedoch letztlich Codeausschnitte, die Teil größerer Anwendungen sein sollen.

1. In-Memory-Caching

Diese Lösung stammt aus der Standardbibliothek functools von Python und ist nützlich für rechenintensive Funktionen wie solche, die LLMs verwenden. Wenn wir einen LLM-API-Aufruf in der unten definierten Funktion hätten, würde das Umhüllen mit einem LRU (Least Recently Used) Dekorator einen Cache-Mechanismus hinzufügen, der redundante Anfragen mit identischen Eingaben (Prompts) in derselben Ausführung oder Sitzung verhindert. Dies ist eine elegante Möglichkeit, Latenzprobleme zu optimieren.

from functools import lru_cache
import time
@lru_cache(maxsize=100)
def summarize_text(text: str) -> str:
    print("Sending text to LLM...")
    time.sleep(1)  # Eine Simulation der Netzwerkverzögerung
    return f"Summary of {len(text)} characters."
print(summarize_text("The quick brown fox."))  # Dauert eine Sekunde
print(summarize_text("The quick brown fox."))  # Sofort

2. Caching auf Persistenter Festplatte

Im Hinblick auf Caching geht die externe Bibliothek diskcache einen Schritt weiter, indem sie einen persistenten Cache auf der Festplatte implementiert, konkret über eine SQLite-Datenbank. Dies ist sehr nützlich, um Ergebnisse zeitaufwändiger Funktionen wie LLM-API-Aufrufen zu speichern. Auf diese Weise können Ergebnisse bei späteren Aufrufen schnell abgerufen werden, wenn sie benötigt werden. Ziehen Sie in Betracht, dieses Dekorator-Muster zu verwenden, wenn das In-Memory-Caching nicht ausreicht, da die Ausführung eines Skripts oder einer Anwendung möglicherweise gestoppt wird.

import time
from diskcache import Cache
# Erstellen eines leichten lokalen SQLite-Datenbankverzeichnisses
cache = Cache(".local_llm_cache")
@cache.memoize(expire=86400)  # 24 Stunden zwischengespeichert

def fetch_llm_response(prompt: str) -> str:
    print("Calling expensive LLM API...")  # Ersetzen Sie dies durch einen tatsächlichen LLM-API-Aufruf
    time.sleep(2)  # Simulation der API-Latenz
    return f"Response to: {prompt}"
print(fetch_llm_response("What is quantum computing?"))  # 1. Funktionsaufruf
print(fetch_llm_response("What is quantum computing?"))  # Sofortiger Zugriff von der Festplatte!

3. Netzwerkresiliente Anwendungen

Da LLMs häufig aufgrund vorübergehender Fehler sowie Zeitüberschreitungen und „502 Bad Gateway“-Antworten im Internet ausfallen können, kann die Verwendung einer Netzwerkresilienz-Bibliothek wie tenacity zusammen mit dem @retry-Dekorator helfen, diese häufigen Netzwerkfehler abzufangen.

Das folgende Beispiel veranschaulicht diese Implementierung von Resilienzverhalten, indem es zufällig eine 70%ige Wahrscheinlichkeit eines Netzwerkfehlers simuliert. Probieren Sie es mehrmals aus, und irgendwann werden Sie diesen Fehler sehen: völlig erwartet und beabsichtigt!

import random
from tenacity import retry, wait_exponential, stop_after_attempt, retry_if_exception_type
class RateLimitError(Exception): pass
# Bis zu 4 Mal wiederholen, mit Wartezeiten von 2, 4 und 8 Sekunden zwischen den Versuchen
@retry(
    wait=wait_exponential(multiplier=2, min=2, max=10),
    stop=stop_after_attempt(4),
    retry=retry_if_exception_type(RateLimitError)
)
def call_flaky_llm_api(prompt: str):
    print("Attempting to call API...")
    if random.random() < 0.7:  # Simulation einer 70%igen Wahrscheinlichkeit eines API-Fehlers
        raise RateLimitError("Rate limit exceeded! Backing off.")
    return "Text has been successfully generated!"
print(call_flaky_llm_api("Write a haiku"))

4. Client-seitige Drosselung

Dieser kombinierte Dekorator verwendet die Bibliothek ratelimit, um die Häufigkeit von Aufrufen einer (in der Regel stark nachgefragten) Funktion zu steuern: nützlich, um clientseitige Limits bei der Verwendung externer APIs zu vermeiden. Das folgende Beispiel tut dies, indem es Limits für Anfragen pro Minute (RPM) definiert. Der Anbieter wird Anfragen von einer Clientanwendung ablehnen, wenn zu viele gleichzeitige Anfragen gestartet werden.

from ratelimit import limits, sleep_and_retry
import time
# Strikte Durchsetzung eines Limits von 3 Aufrufen pro 10-Sekunden-Fenster
@sleep_and_retry
@limits(calls=3, period=10)
def generate_text(prompt: str) -> str:
    print(f"[{time.strftime('%X')}] Processing: {prompt}")
    return f"Processed: {prompt}"
# Die ersten 3 werden sofort ausgegeben, der 4. pausiert und respektiert damit das Limit
for i in range(5):
    generate_text(f"Prompt {i}")

5. Strukturierte Ausgabe-Bindung

Der fünfte Dekorator in dieser Liste verwendet die Bibliothek magentic in Verbindung mit Pydantic, um einen effizienten Interaktionsmechanismus mit LLMs über APIs bereitzustellen und strukturierte Antworten zu erhalten. Dies vereinfacht den Prozess des Aufrufs von LLM-APIs. Dieser Prozess ist wichtig, um LLMs dazu zu bringen, formatierte Daten wie JSON-Objekte zuverlässig zurückzugeben. Der Dekorator würde die zugrunde liegenden System-Prompts und die Pydantic-gesteuerte Analyse behandeln, was die Nutzung von Tokens optimiert und dazu beiträgt, einen saubereren Code zu erhalten.

Um dieses Beispiel auszuprobieren, benötigen Sie einen OpenAI API-Schlüssel.

# WICHTIG: Ein gesetzter OPENAI_API_KEY ist erforderlich, um dieses simulierte Beispiel auszuführen
from magentic import prompt
from pydantic import BaseModel
class CapitalInfo(BaseModel):
    capital: str
    population: int
# Ein Dekorator, der das Prompt einfach auf den Pydantic-Rückgabetyp abbildet
@prompt("What is the capital and population of {country}?")
def get_capital_info(country: str) -> CapitalInfo:
    ...  # Kein Funktionskörper erforderlich!
info = get_capital_info("France")
print(f"Capital: {info.capital}, Population: {info.population}")

Fazit

In diesem Artikel wurden fünf Python-Dekoratoren vorgestellt und veranschaulicht, die auf verschiedenen Bibliotheken basieren und eine besondere Bedeutung im Kontext von LLM-basierten Anwendungen haben, um die Logik zu vereinfachen, Prozesse effizienter zu gestalten oder die Netzwerkresilienz zu verbessern, unter anderem. Weitere Informationen zu leistungsstarken Python-Dekoratoren finden Sie in unserem Artikel über leistungsstarke Python-Dekoratoren sowie in unserem Überblick über wichtige Python-Bibliotheken für LLM-Ingenieure.

Iván Palomares Carrascosa ist ein führender Experte, Schriftsteller, Redner und Berater im Bereich KI, maschinelles Lernen, Deep Learning und LLMs. Er schult und leitet andere an, wie sie KI in der realen Welt nutzen können.

```

Bildquelle: ai-generated-gemini

KI Snack

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert