Laravel AI SDK: Ein praktischer Leitfaden mit echten Code-Beispielen

• von Tobias Schäfer • 7 min read

Als Taylor Otwell auf der Laracon India 2026 das offizielle Laravel AI SDK vorgestellt hat, war mein erster Gedanke: „Das hätte ich vor zwei Jahren gebraucht.”

Denn genau das, was das SDK jetzt elegant löst – Agents, strukturierte Ausgaben, Provider-Failover, Embeddings – habe ich mir für mitKai selbst zusammengebaut. Mit deutlich mehr Schmerzen.

In diesem Artikel zeige ich dir das SDK anhand konkreter Beispiele. Nicht mit Hello-World-Demos, sondern mit Code, den du in echten Projekten einsetzen kannst.


Installation und Setup

composer require laravel/ai
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
php artisan migrate

In deiner .env:

ANTHROPIC_API_KEY=your-key-here
OPENAI_API_KEY=your-key-here

Die Konfiguration liegt in config/ai.php. Du kannst dort beliebig viele Provider hinterlegen – OpenAI, Anthropic, Gemini, Groq, xAI, DeepSeek, Mistral, Ollama und mehr.


Agents: KI mit Persönlichkeit

Agents sind das Herzstück des SDK. Statt lose Prompts an eine API zu schicken, definierst du spezialisierte Klassen mit eigenen Anweisungen, Tools und Ausgabeformaten.

Einen Agent erstellen

php artisan make:agent ProductDescriptionWriter

Das generiert eine Klasse, die du nach deinen Bedürfnissen anpasst:

<?php

namespace App\Ai\Agents;

use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasStructuredOutput;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Concerns\Promptable;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Attributes\Temperature;
use Laravel\Ai\Attributes\MaxTokens;
use Laravel\Ai\JsonSchema;

#[Provider('anthropic')]
#[Temperature(0.7)]
#[MaxTokens(4096)]
class ProductDescriptionWriter implements Agent, HasStructuredOutput, HasTools
{
    use Promptable;

    public function __construct(
        private string $shopName,
        private string $targetAudience,
        private string $tone = 'professionell, aber zugänglich',
    ) {}

    public function instructions(): string
    {
        return <<<PROMPT
            Du bist ein erfahrener E-Commerce-Texter für den Shop "{$this->shopName}".
            Zielgruppe: {$this->targetAudience}.
            Ton: {$this->tone}.

            Regeln:
            - Schreibe ausschließlich auf Basis der gelieferten Produktdaten.
            - Erfinde KEINE Features, die nicht in den Daten stehen.
            - Nutze keine generischen Phrasen wie "hochwertig" oder "perfekter Begleiter".
            - Beginne mit dem konkreten Nutzen, nicht mit einer Floskel.
            - Baue relevante Keywords natürlich in den Text ein.
        PROMPT;
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'title' => $schema->string()
                ->description('SEO-optimierter Produkttitel')
                ->required(),
            'description' => $schema->string()
                ->description('Produktbeschreibung als HTML mit semantischer Struktur')
                ->required(),
            'meta_description' => $schema->string()
                ->description('Meta-Description, max. 155 Zeichen')
                ->required(),
            'keywords' => $schema->array()
                ->items($schema->string())
                ->description('Relevante SEO-Keywords')
                ->required(),
        ];
    }

    public function tools(): iterable
    {
        return [
            new \App\Ai\Tools\FetchCategoryContext,
        ];
    }
}

Den Agent einsetzen

use App\Ai\Agents\ProductDescriptionWriter;

$agent = new ProductDescriptionWriter(
    shopName: 'OutdoorPro',
    targetAudience: 'Erfahrene Wanderer, 30-55 Jahre',
    tone: 'kompetent, direkt, ohne Floskeln',
);

$response = $agent->prompt(
    "Schreibe eine Produktbeschreibung für:
    Name: Trekking-Rucksack Alpine 45L
    Material: Nylon 210D, wasserdicht
    Gewicht: 1,8 kg
    Features: Rückenbelüftung, verstellbarer Hüftgurt
    Kategorie: Mehrtagestouren"
);

// Strukturierter Zugriff
$response['title'];            // "Trekking-Rucksack Alpine 45L – 1,8 kg für..."
$response['description'];      // "<h2>...</h2><p>...</p>"
$response['meta_description']; // "Der Alpine 45L wiegt nur 1,8 kg und..."
$response['keywords'];         // ["trekking-rucksack", "45l", "mehrtagestouren"]

Warum das wichtig ist: Ohne strukturierte Ausgaben bekommst du Freitext, den du anschließend parsen musst. Mit dem Schema bekommst du exakt das Format, das du brauchst – jedes Mal.


Tools: Wenn der Agent mehr Kontext braucht

Manchmal braucht ein Agent Informationen, die nicht im Prompt stehen. Dafür gibt es Tools – Funktionen, die der Agent selbstständig aufrufen kann.

Ein Tool erstellen

php artisan make:tool FetchCategoryContext
<?php

namespace App\Ai\Tools;

use App\Models\Category;
use Illuminate\Contracts\Support\Stringable;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\JsonSchema;
use Laravel\Ai\Tools\Request;

class FetchCategoryContext implements Tool
{
    public function description(): Stringable|string
    {
        return 'Ruft Kontext über eine Produktkategorie ab: '
             . 'Zielgruppe, Preissegment und verwandte Kategorien.';
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'category_name' => $schema->string()
                ->description('Name der Kategorie')
                ->required(),
        ];
    }

    public function handle(Request $request): Stringable|string
    {
        $category = Category::where('name', 'like', "%{$request['category_name']}%")
            ->with('parent')
            ->first();

        if (! $category) {
            return 'Kategorie nicht gefunden.';
        }

        return json_encode([
            'name' => $category->name,
            'audience' => $category->target_audience,
            'price_segment' => $category->price_segment,
            'parent' => $category->parent?->name,
            'product_count' => $category->products()->count(),
        ]);
    }
}

Der Agent entscheidet selbst, ob und wann er das Tool aufruft. Wenn du ihm einen Produktnamen mit Kategorie gibst, wird er den Kategorie-Kontext laden, um bessere Texte zu schreiben.


Embeddings und Vektorsuche: Semantisch statt keyword-basiert

Für mitKai war Deduplizierung eine der größten Herausforderungen: Wie stelle ich sicher, dass 500 Rucksack-Beschreibungen nicht alle gleich klingen? Embeddings lösen das elegant.

Setup mit pgvector

// Migration
Schema::ensureVectorExtensionExists();

Schema::create('product_descriptions', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constrained();
    $table->text('description');
    $table->vector('embedding', dimensions: 1536)->index();
    $table->timestamps();
});

Embeddings generieren und speichern

use Illuminate\Support\Str;

$description = 'Der Alpine 45L wiegt nur 1,8 kg und bietet...';
$embedding = Str::of($description)->toEmbeddings();

ProductDescription::create([
    'product_id' => $product->id,
    'description' => $description,
    'embedding' => $embedding,
]);

Ähnliche Beschreibungen finden

// Vor dem Speichern prüfen: Ist der neue Text zu ähnlich zu bestehenden?
$similar = ProductDescription::query()
    ->whereVectorSimilarTo('embedding', $newEmbedding, minSimilarity: 0.92)
    ->where('product_id', '!=', $product->id)
    ->limit(5)
    ->get();

if ($similar->isNotEmpty()) {
    // Text ist zu ähnlich zu bestehenden Beschreibungen
    // → Neu generieren mit angepasstem Prompt
}

Praxistipp: Eine Ähnlichkeit von 0.92+ bedeutet, dass die Texte fast identisch sind. Wir nutzen das als Qualitätssicherung: Wenn ein neuer Text zu nah an einem bestehenden ist, wird er automatisch mit einem variierten Prompt neu generiert.


Provider-Failover: Ausfallsicherheit eingebaut

In der Produktion willst du nicht, dass dein Shop stehen bleibt, weil OpenAI ein Rate-Limit hat. Failover ist eingebaut:

$response = $agent->prompt(
    'Schreibe eine Beschreibung für...',
    provider: ['anthropic', 'openai', 'gemini'],
);

Das SDK probiert Anthropic zuerst. Wenn das fehlschlägt – nächster Provider. Kein eigenes Retry-Handling nötig.


Massengenerierung mit Queues

Für Bulk-Operationen (z. B. 5.000 Produktbeschreibungen) willst du nicht synchron arbeiten. Das SDK integriert sich nahtlos mit Laravels Queue-System:

use App\Ai\Agents\ProductDescriptionWriter;

// Einzelnes Produkt in die Queue
$agent->queue("Schreibe eine Beschreibung für: {$productData}")
    ->then(function ($response) use ($product) {
        $product->update([
            'description' => $response['description'],
            'meta_description' => $response['meta_description'],
        ]);
    })
    ->catch(function (Throwable $e) use ($product) {
        Log::error("Beschreibung fehlgeschlagen für Produkt {$product->id}", [
            'error' => $e->getMessage(),
        ]);
    });

Für tausende Produkte packst du das in einen Job:

// In einem BatchJob
$products->each(function ($product) use ($agent) {
    $agent->queue($this->buildPrompt($product))
        ->then(fn ($response) => $this->saveDescription($product, $response));
});

Streaming: Echtzeit-Ausgabe im Frontend

Wenn du eine Chat-Oberfläche oder Live-Vorschau brauchst:

// In einem Controller
Route::get('/preview-description', function (Request $request) {
    $agent = new ProductDescriptionWriter(
        shopName: $request->shop_name,
        targetAudience: $request->audience,
    );

    return $agent->stream($request->prompt);
});

Für Vercel AI SDK (z. B. mit einem Vue- oder React-Frontend):

return $agent->stream($request->prompt)->usingVercelDataProtocol();

Testing: KI-Features testbar machen

Das Beste am SDK für mich als Entwickler: Du kannst KI-Features endlich vernünftig testen.

use App\Ai\Agents\ProductDescriptionWriter;

public function test_generates_product_description(): void
{
    ProductDescriptionWriter::fake([
        json_encode([
            'title' => 'Trekking-Rucksack Alpine 45L',
            'description' => '<h2>Leicht und geräumig</h2><p>...</p>',
            'meta_description' => 'Der Alpine 45L für Mehrtagestouren.',
            'keywords' => ['trekking-rucksack', '45l'],
        ]),
    ]);

    $response = $this->post('/api/generate-description', [
        'product_id' => $this->product->id,
    ]);

    $response->assertOk();

    ProductDescriptionWriter::assertPrompted(
        fn ($prompt) => $prompt->contains('Alpine 45L')
    );
}
public function test_handles_provider_failure_gracefully(): void
{
    ProductDescriptionWriter::fake()
        ->preventStrayPrompts();

    // Dein Code kann nicht versehentlich echte API-Calls machen
}

Warum das ein Gamechanger ist: Vor dem SDK mussten wir HTTP-Calls mocken, JSON-Responses manuell bauen und hoffen, dass die Provider-API sich nicht ändert. Jetzt: Agent::fake(), und fertig.


Was ich gerne früher gehabt hätte

Wenn ich mitKai heute von Null bauen würde, würde ich das Laravel AI SDK als Fundament nutzen. Konkret hätte mir Folgendes Wochen an Entwicklungszeit gespart:

FeatureVorher (selbst gebaut)Jetzt (AI SDK)
Provider-WechselEigene Abstraktion mit Interfacesprovider: ['anthropic', 'openai']
Strukturierte AusgabenJSON parsen + Validierung + Fehlerbehandlungschema() Methode mit JsonSchema
DeduplizierungEigene Embedding-Pipeline + Cosine SimilaritywhereVectorSimilarTo()
MassengenerierungEigenes Queue-Handling mit Retry-Logik$agent->queue() mit then()/catch()
TestsHTTP-Mocks + Fixture-FilesAgent::fake() + Assertions

Das heißt nicht, dass du mitKai nicht mehr brauchst – die Geschäftslogik (Shop-Anbindung, SEO-Optimierung, HTML-Generierung, Deduplizierung im Kontext) bleibt komplex. Aber das Fundament darunter ist jetzt deutlich solider.


Fazit

Das Laravel AI SDK ist keine Spielerei. Es ist ein durchdachtes, produktionsreifes Framework für KI-Integrationen, das sich nahtlos in das Laravel-Ökosystem einfügt – von Queues über Testing bis hin zu Eloquent.

Wenn du Laravel nutzt und KI-Features planst, gibt es keinen Grund mehr, eigene Abstraktionen zu bauen.

Die drei wichtigsten Dinge, die du dir merken solltest:

  1. Agents sind Klassen, keine Prompts. Definiere deine KI-Interaktionen wie jeden anderen Service.
  2. Strukturierte Ausgaben machen KI berechenbar. Kein JSON-Parsing mehr, keine überraschenden Formate.
  3. Agent::fake() allein ist den Umstieg wert. Testbare KI-Features waren überfällig.

Im Begleitartikel Laravel wird zur KI-Plattform – und das verändert mehr als du denkst schaue ich mir an, was Laravels KI-Offensive strategisch bedeutet – für Shop-Betreiber, für Agenturen und für das PHP-Ökosystem.