Kosten senken von LLM in serverless – Praktischer Leitfaden zu Cache, Quantisierung und Batch-Inferenz

Erfahren Sie, wie Sie Cache, Quantisierung und Batch-Inferenz kombinieren, um die Kosten und Latenz von Sprachmodellen in einer serverlosen Architektur erheblich zu senken.

Obniżanie kosztów LLM w serverless – praktyczny przewodnik po cache, kwantyzacji i batch inference

In den letzten Jahren haben sich Sprachmodelle (LLM) zu einem Schlüsselbestandteil moderner Produkte entwickelt – von Chatbots bis hin zu Empfehlungssystemen. Ihr Potenzial wächst, gleichzeitig steigen jedoch die Rechenkosten und die Anforderungen an niedrige Latenz, insbesondere in einer serverlosen Architektur, bei der wir für jeden Millisekunden‑CPU‑Zyklus zahlen. In diesem Artikel zeigen wir, wie man drei bewährte Techniken – Cache, Quantisierung und Batch‑Inference – kombiniert, um die LLM‑Kosten in serverlosen Umgebungen effektiv zu senken, ohne die Service‑Qualität zu beeinträchtigen.

Warum herkömmliche Ansätze nicht ausreichen

In einem serverlosen Modell werden Funktionen (z. B. AWS Lambda) bei Bedarf aufgerufen und skalieren automatisch. Das ist praktisch, aber jeder Aufruf bedeutet das Starten einer Umgebung, das Laden des Modells und die Verarbeitung der Anfrage. Bei großen Modellen (Dutzende GB Speicher) können die Start‑ und Speicherkosten die eigentlichen Verarbeitungs‑Kosten übersteigen. Zusätzlich erhöht das Fehlen eines ständig „warmen“ Prozesses die Latenz, was in interaktiven Anwendungen inakzeptabel ist.

Cache‑Strategien für LLM‑Ergebnisse in AWS Lambda

Der einfachste Weg, Kosten und Latenz zu reduzieren, ist das Caching. Wenn ein Teil der Anfragen wiederkehrend ist (z. B. FAQ‑Fragen, Dokumentations‑Abfragen), kann das Modell‑Ergebnis in einem schnellen Speicher wie Amazon DynamoDB oder ElastiCache (Redis) abgelegt werden. Beim nächsten Funktionsaufruf prüfen wir zuerst den Cache – existiert die Antwort, geben wir sie sofort zurück und umgehen damit den teuren Modellaufruf.

  • Der Cache‑Schlüssel sollte sowohl den Anfrage‑Inhalt als auch die Modell‑Version enthalten, um Inkonsistenzen zu vermeiden.
  • TTL (time‑to‑live) entfernt automatisch veraltete Ergebnisse und begrenzt den Speicherverbrauch.
  • Der Cache‑Wert kann bei RAG (retrieval‑augmented generation) auch Suchergebnisse umfassen, was den Prozess zusätzlich beschleunigt.

Eine mögliche Implementierung in Lambda sieht so aus:

import json, boto3, hashlib

def handler(event, context):
    query = event['query']
    key = hashlib.sha256(query.encode()).hexdigest()
    cache = boto3.client('dynamodb')
    resp = cache.get_item(TableName='LLMCache', Key={'pk': {'S': key}})
    if 'Item' in resp:
        return json.loads(resp['Item']['response']['S'])
    # … Aufruf des Modells …
    result = run_llm(query)
    cache.put_item(TableName='LLMCache', Item={'pk': {'S': key}, 'response': {'S': json.dumps(result)}, 'ttl': {'N': str(int(time.time())+86400)}})
    return result

Quantisierung – Präzision reduzieren ohne Qualitätsverlust

Quantisierung ist eine Technik zur Reduktion der Präzision von Modellgewichten (z. B. von 32‑Bit‑Float zu 8‑Bit‑Integer). Dadurch schrumpft die Modellgröße um das 4‑ bis 5‑fache, und der RAM‑Verbrauch sowie die GPU/CPU‑Anforderungen sinken. In der Praxis bedeutet das, dass das Modell in eine kleinere Lambda‑Funktion (z. B. 2 GB statt 8 GB) geladen und schneller ausgeführt werden kann.

Wichtige Kompromisse:

  • Quantisierung kann leichte Genauigkeitsverluste verursachen – besonders bei Aufgaben, die präzise Zahlen benötigen (z. B. Mathematik).
  • Nicht alle Frameworks unterstützen int8 out‑of‑the‑box; häufig werden Bibliotheken wie ONNX Runtime oder Hugging Face Transformers mit der Erweiterung bitsandbytes verwendet.
  • In serverlosen Umgebungen sollte man zwei Modi testen: Post‑Training‑Quantisierung (schnell, ohne Retraining) und Quantization‑Aware‑Training (aufwändiger, aber bessere Qualität).

Beispiel für das Laden eines quantisierten Modells in Python:

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_id = "bigscience/bloom-560m"
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.int8, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_id)

Batch‑Inference in serverlosen Umgebungen

Batch‑Inference bedeutet, mehrere Anfragen zu bündeln und sie gleichzeitig in einem Modellaufruf zu verarbeiten. In einer serverlosen Architektur lässt sich das auf zwei Arten erreichen:

  • Aggregation in einer Warteschlange – z. B. Amazon SQS oder EventBridge. Die Lambda‑Funktion sammelt Nachrichten für kurze Zeit (z. B. 50 ms) und führt das Modell über den gesamten Batch aus.
  • Verwendung einer Async-Schicht – asynchrone Aufrufe, die IDs zurückgeben und später die Ergebnisse nach Abschluss des Batches abrufen.

Vorteile:

  • Bessere GPU/CPU‑Auslastung – das Modell wird einmal für eine größere Token‑Menge gestartet.
  • Reduzierung der Anzahl von „Cold Starts“ – eine Funktion bedient viele Anfragen.
  • Kostensenkung im Betrieb – wir zahlen für einen Aufruf statt für viele.

Beispielcode, der Anfragen aggregiert:

import json, boto3, time

sqs = boto3.client('sqs')
QUEUE_URL = 'https://sqs.region.amazonaws.com/123456789012/llm-requests'
BATCH_SIZE = 8
MAX_WAIT = 0.1

def poll_batch():
    batch = []
    start = time.time()
    while len(batch) < BATCH_SIZE and (time.time() - start) < MAX_WAIT:
        msgs = sqs.receive_message(QueueUrl=QUEUE_URL, MaxNumberOfMessages=1, WaitTimeSeconds=0)
        if 'Messages' in msgs:
            batch.append(msgs['Messages'][0])
    return batch

def handler(event, context):
    batch = poll_batch()
    queries = [json.loads(m['Body'])['query'] for m in batch]
    results = run_llm_batch(queries)  # einmaliger Aufruf des Modells
    for msg, res in zip(batch, results):
        sqs.delete_message(QueueUrl=QUEUE_URL, ReceiptHandle=msg['ReceiptHandle'])
        # optional: Antwort an eine andere Queue senden
    return {'processed': len(batch)}

Kombination von drei Techniken – End‑to‑End‑Architektur

Die größten Einsparungen erzielen wir, indem wir Cache, Quantisierung und Batch‑Inference kombinieren. Ein typischer Serverless‑Workflow sieht folgendermaßen aus:

  1. Die Anfrage gelangt über API Gateway und wird in eine SQS‑Warteschlange gestellt.
  2. Lambda wird ausgelöst, holt ein Batch von Anfragen und prüft zuerst den Cache (Redis/DynamoDB).
  3. Anfragen, die nicht im Cache sind, werden gruppiert und an das quantisierte Modell weitergeleitet (z. B. ONNX Runtime im int8‑Modus).
  4. Die Ergebnisse werden im Cache gespeichert und an den Client zurückgegeben (z. B. über SNS oder direkt per HTTP).

Diese Struktur reduziert die Anzahl vollständiger Modellaufrufe, verringert den Speicherbedarf für die Funktionsausführung und ermöglicht dank Batch‑Inference eine effizientere Ressourcennutzung.

Praktische Checkliste für Produktteams

  • Analyse der Anfragen: Identifizieren Sie wiederkehrende Muster und bestimmen Sie, welche davon gecached werden sollten.
  • Modell‑ und Formatwahl: Nutzen Sie ein Modell im ONNX‑Format oder eine fertige int8‑Version.
  • Cache‑Implementierung: Konfigurieren Sie DynamoDB oder Redis mit geeignetem TTL und einem Hash‑Key basierend auf dem Anfrageinhalt.
  • Batch‑Strategie: Legen Sie die maximale Batch‑Größe und die maximale Wartezeit fest – passen Sie beides an das Latenz‑SLA an.
  • Monitoring und Alerts: Verfolgen Sie Cache‑Hit‑Rate, durchschnittliche Inferenzzeit und Lambda‑Kosten.
  • A/B‑Tests: Vergleichen Sie die optimierte Version mit dem Baseline hinsichtlich Kosten und Antwortqualität.

Typische Fehler und Kompromisse

Bei der Implementierung können leicht folgende Fallen auftreten:

  • Zu aggressives TTL: Eine zu kurze Lebensdauer im Cache führt zu häufigen Aktualisierungen und verringert den Nutzen.
  • Zu großes Batch: Erhöht die Latenz einer einzelnen Anfrage – ein ausgewogenes Verhältnis zwischen Kosten und SLA ist entscheidend.
  • Ungeeignete Quantisierung: Ein Modell, das auf int4 quantisiert ist, kann die Inferenz stark beschleunigen, erhöht jedoch das Risiko von Halluzinationen.
  • Fehlendes Kosten‑Monitoring: Ohne regelmäßige Analyse der AWS‑Rechnungen kann man leicht übersehen, dass zusätzliche SQS‑Kosten die Einsparungen durch den Cache übersteigen.
„Die Optimierung von LLMs in Serverless ist kein einmaliger Vorgang, sondern ein kontinuierlicher Prozess, bei dem Kosten, Latenz und Qualität ausbalanciert werden.“

Fazit und Einladung zur Zusammenarbeit

Die Reduzierung von Kosten und Latenz von LLMs in einer Serverless‑Architektur erfordert ein bewusstes Zusammenspiel von Cache, Quantisierung und Batch‑Inference. Dadurch können Produktteams intelligente Funktionen skalieren und gleichzeitig Budget und Nutzererlebnis im Griff behalten. Wenn Sie Unterstützung beim Design einer solchen Architektur, bei der Modelloptimierung oder bei der Automatisierungsimplementierung bei Coderia.it benötigen, kontaktieren Sie uns – wir helfen Ihnen, Ihre Ideen in effiziente, kostengünstig optimierte Lösungen zu verwandeln.

Loslegen

Ein Projekt im Kopf?

Beschreiben Sie es in wenigen Sätzen. Ich antworte innerhalb von 24 Stunden mit Angebot und Stack-Vorschlag.