Zum Hauptinhalt springen

Laravel + LLM: KI-Funktionen sauber in eine bestehende App bauen

Ein Sprachmodell „anzuschließen" ist in zehn Zeilen erledigt. Es so anzuschließen, dass es unter Last, bei Fehlern und auf der Rechnung nicht aus dem Ruder läuft, ist die eigentliche Arbeit. Hier ist das Muster, das sich in der Praxis bewährt.

Kurzantwort

Ein LLM „anzuschließen" dauert zehn Zeilen – produktionsreif wird es erst durch sechs bekannte Laravel-Bausteine. Der Kern: Modellaufrufe sind langsam, nicht deterministisch und kosten Geld – behandeln Sie sie entsprechend:

  • Zugriff hinter ein Interface kapseln – austauschbar und testbar.
  • Langsame Aufrufe in eine Queue (tries, timeout, backoff).
  • Sichtbarer Chat: Streaming statt Warten.
  • Kosten steuern: Cache, kleines Modell, Token-Limit, Logging.
  • Antworten gegen ein Schema validieren + Fallback.
  • Im Test eine Fake-Implementierung statt echter API.

Die Versuchung ist groß, den ersten LLM-Aufruf einfach in den Controller zu schreiben: Request rein, OpenAI-Aufruf, Antwort zurück. Im Prototyp funktioniert das. In Produktion sorgt genau dieses Muster dann für hängende Requests, Timeouts beim Nutzer, doppelte Abbuchungen von Tokens und Features, die sich nicht testen lassen.

Dabei sind die Lösungen alle aus der normalen Laravel-Welt bekannt – Service-Klassen, Queues, Caching, Tests. Man muss sie nur bewusst auf die Eigenheiten von LLMs anwenden: Aufrufe sind langsam, nicht deterministisch und kosten pro Aufruf Geld. Schauen wir uns das Schritt für Schritt an – am Beispiel einer Funktion wie dem KI-Advisor, der in Skilltix Lernende berät und Kurse empfiehlt.

01Web-Requestnimmt an, gibt sofort zurück
02Queue-Jobtries · timeout · backoff
03LLM-Servicehinter Interface, Anbieter austauschbar
04Schema-Validierungvalidieren statt vertrauen
05Speichern / BroadcastErgebnis zurück an den Nutzer
Schlägt ein Aufruf fehl, greift begrenztes Retry mit wachsendem Backoff – statt eines ewig hängenden Requests.

1. Den LLM-Zugriff hinter eine eigene Schnittstelle legen

Sprechen Sie den Anbieter nie direkt aus dem halben Code an. Kapseln Sie ihn hinter ein eigenes Interface. Das kostet fünf Minuten und zahlt sich dreifach aus: Sie können den Anbieter später wechseln (OpenAI, Azure, ein selbst gehostetes Modell), die Logik an einer Stelle anpassen – und im Test eine Fake-Implementierung einsetzen.

// app/Services/Ai/CourseAdvisor.php
interface CourseAdvisor
{
    public function recommend(string $goal, array $context): Recommendation;
}

Die konkrete Implementierung ruft die API auf, die restliche Anwendung kennt nur das Interface. Über Laravels Service-Container binden Sie die echte Klasse – im Test die Fake-Variante.

2. Langsame Aufrufe in eine Queue verlagern

Ein Modellaufruf dauert je nach Aufgabe von einer bis zu vielen Sekunden. Das gehört nicht in den Web-Request. Faustregel: Muss der Nutzer nicht in Echtzeit zusehen, läuft der Aufruf in einem Queue-Job. Der Request kommt sofort zurück („wird erstellt …"), der Job arbeitet im Hintergrund, das Ergebnis wird per Broadcast, Polling oder Benachrichtigung nachgereicht.

// app/Jobs/GenerateRecommendation.php
class GenerateRecommendation implements ShouldQueue
{
    public int $tries = 3;
    public int $timeout = 60;
    public array $backoff = [5, 15, 45];

    public function handle(CourseAdvisor $advisor): void
    {
        $result = $advisor->recommend($this->goal, $this->context);

        $this->user->recommendations()->create([
            'goal'    => $this->goal,
            'courses' => $result->courseIds,
        ]);
    }
}

Mit $tries, $timeout und gestaffeltem $backoff bekommen Sie genau das Verhalten, das man bei einer externen, manchmal überlasteten API braucht: begrenzte Wiederholungen mit wachsendem Abstand statt eines ewig hängenden Requests.

3. Bei sichtbarem Chat: Streaming statt Warten

Für einen Chat-Assistenten ist Warten auf die komplette Antwort die schlechteste Variante – fünf Sekunden Stille fühlen sich kaputt an. Hier streamen Sie die Antwort token-für-token zum Frontend. Technisch über Server-Sent Events (SSE) oder eine streamende Response; im Frontend wächst die Antwort dann live. Das Ergebnis fühlt sich sofort an, obwohl die Gesamtdauer gleich bleibt.

Streaming und Queue schließen sich nicht aus: Der sichtbare Chat streamt, während rechenintensive Nebenaufgaben (etwa das Matching im Hintergrund) als Job laufen.

4. Kosten von Anfang an steuerbar machen

Jeder Aufruf kostet – proportional zu den verarbeiteten Tokens. Wer das nicht aktiv steuert, lernt es auf der Monatsrechnung. Die wirksamsten Hebel:

  • Cachen: Identische oder sehr ähnliche Anfragen nicht zweimal an das Modell schicken. Ein Cache::remember() um deterministische Aufrufe spart real Geld.
  • Richtiges Modell je Aufgabe: Klassifizieren und Extrahieren brauchen kein Spitzenmodell. Das größte Modell nur dort, wo es den Unterschied macht.
  • Token begrenzen & protokollieren: Maximale Antwortlänge setzen und den Verbrauch pro Feature mitloggen – so sehen Sie, welche Funktion was kostet.
  • Rate-Limits: Pro Nutzer begrenzen, was er auslösen kann – schützt vor Missbrauch und vor Kostenspitzen.

5. Mit nicht deterministischen Antworten umgehen

Ein LLM liefert nicht garantiert valides JSON, nicht garantiert das erwartete Format und gelegentlich Unsinn. Behandeln Sie die Antwort wie Eingaben aus einer fremden Quelle: validieren, nicht vertrauen. Wo Sie strukturierte Daten brauchen, nutzen Sie die Structured-Output-/JSON-Mode-Funktionen der Anbieter und prüfen das Ergebnis danach trotzdem gegen ein Schema. Schlägt die Validierung fehl, greift ein definierter Fallback – nicht eine kaputte Seite.

Wichtig bei personenbezogenen Daten: Was in den Prompt wandert, verlässt – je nach Anbieter – Ihre Infrastruktur. Welcher Integrationsweg DSGVO-konform ist und wie Sie Daten vorher minimieren, habe ich im Artikel LLM-Integration DSGVO-konform beschrieben.

6. Testbar bleiben

Weil der LLM-Zugriff hinter einem Interface liegt (Schritt 1), ersetzen Sie ihn im Test durch eine Fake-Implementierung mit festen Antworten. So testen Sie Ihre eigene Logik – Wird das Ergebnis korrekt gespeichert? Greift der Fallback bei ungültiger Antwort? – schnell und deterministisch, ohne echte API und ohne Kosten.

// im Test: echten Advisor durch Fake ersetzen
$this->app->bind(CourseAdvisor::class, fn () => new FakeCourseAdvisor(
    returns: new Recommendation(courseIds: [1, 2, 3])
));

Ihre Tests prüfen damit das, was Sie kontrollieren – Ihre Anwendung –, statt das Modell, das Sie nicht kontrollieren.

Die Bausteine im Überblick

Anforderung Laravel-Baustein
Anbieter austauschbar & testbarInterface + Service-Container-Binding
Langsame Aufrufe entkoppelnQueue-Job mit $tries, $timeout, $backoff
Antwort fühlt sich sofort anStreaming (SSE) im Chat
Kosten begrenzenCache, kleines Modell, Token-Limit, Logging
Unzuverlässige AntwortenSchema-Validierung + Fallback
Schnelle TestsFake-Implementierung des Interfaces

Produktionsreife-Checkliste

Bevor ein KI-Feature live geht, sollte jeder dieser Punkte ein Häkchen haben:

  • LLM-Zugriff liegt hinter einem Interface, der Anbieter ist per Container-Binding austauschbar.
  • Langsame Aufrufe laufen in der Queue – mit tries, timeout und gestaffeltem backoff.
  • Sichtbarer Chat streamt; rechenintensive Nebenaufgaben bleiben im Hintergrund-Job.
  • Kosten sind gedeckelt: Caching, passend kleines Modell, Token-Limit, Verbrauch pro Feature geloggt.
  • Rate-Limits pro Nutzer schützen vor Missbrauch und Kostenspitzen.
  • Antworten werden gegen ein Schema validiert, bei Fehlern greift ein definierter Fallback.
  • Personenbezogene Daten werden vor dem Prompt minimiert (siehe LLM-Integration DSGVO-konform).
  • Tests nutzen eine Fake-Implementierung statt der echten API.
  • Monitoring & Alerting auf Fehlerrate, Latenz und Kosten sind aktiv.

Fazit

Eine KI-Funktion „funktioniert" schnell – aber produktionsreif wird sie erst durch die unspektakulären Dinge: Kapselung, Queues, Streaming, Kostenkontrolle, Validierung, Tests. Das Schöne daran: Es ist kein KI-Spezialwissen, sondern solides Laravel-Handwerk, bewusst auf die Eigenheiten von Sprachmodellen angewandt. Genau dort entscheidet sich, ob ein KI-Feature ein netter Demo-Effekt bleibt oder zuverlässig im Alltag trägt.

Häufige Fragen

Sollte ein LLM-Aufruf in Laravel synchron oder über eine Queue laufen?
Für alles, was länger als ein paar Sekunden dauert oder nicht sofort sichtbar sein muss, gehört der Aufruf in einen Queue-Job. Das hält Web-Requests schnell, entkoppelt langsame Modellantworten vom Nutzer und erlaubt sauberes Retry- und Timeout-Handling. Nur für direkt sichtbaren Chat lohnt sich stattdessen Streaming.
Wie hält man die LLM-Kosten in einer Laravel-App im Griff?
Durch Caching identischer Anfragen, knappe und gut strukturierte Prompts, ein passend kleines Modell je Aufgabe, Begrenzung der Token pro Anfrage sowie Protokollierung des Token-Verbrauchs pro Feature. So bleibt der Verbrauch messbar und steuerbar statt zur Überraschung auf der Rechnung zu werden.
Wie testet man Features, die ein LLM aufrufen?
Indem man den LLM-Client hinter eine eigene Schnittstelle legt und ihn im Test durch eine Fake-Implementierung ersetzt, die feste Antworten liefert. So bleiben Tests schnell, deterministisch und unabhängig von der echten API – und prüfen die eigene Logik statt das Modell.

KI-Feature in Ihrer Laravel-App?

Ob Chat-Assistent, Klassifizierung oder Empfehlung – ich integriere LLMs sauber in bestehende und neue Laravel-Anwendungen, von der Architektur bis zum Betrieb. Lassen Sie uns über Ihren Anwendungsfall sprechen.

Projekt anfragen Mehr zu Laravel

← Zurück zum Ratgeber