Zum Hauptinhalt springen

Einführung

Das Laravel AI SDK bietet eine einheitliche und ausdrucksstarke API zur Interaktion mit KI-Anbietern wie OpenAI, Anthropic und Gemini. Mit dem AI SDK können Sie intelligente Agenten mit Tools und strukturierten Ausgaben erstellen, Bilder generieren, Sprache synthetisieren und transkribieren, Vektor-Embeddings erzeugen und viele weitere KI-Funktionen über eine konsistente, Laravel-typische Schnittstelle nutzen.
Das Laravel AI SDK ist ein offizielles Paket, das in Laravel 13 hinzugefügt wurde. Es wird als laravel/ai bereitgestellt und ermöglicht die Nutzung mehrerer KI-Anbieter über eine einheitliche API.

Übersicht der unterstützten Anbieter

FunktionUnterstützte Anbieter
TextgenerierungOpenAI, OpenAI Compatible, Anthropic, Gemini, Azure, Bedrock, Groq, xAI, DeepSeek, Mistral, Ollama, OpenRouter
BildgenerierungOpenAI, Gemini, xAI, Azure, Bedrock, OpenRouter
Sprachsynthese (TTS)OpenAI, ElevenLabs, Gemini
Spracherkennung (STT)OpenAI, ElevenLabs, Mistral, Gemini
EmbeddingsOpenAI, Gemini, Azure, Bedrock, Cohere, Mistral, Jina, VoyageAI, Ollama, OpenRouter
RerankingCohere, Jina, VoyageAI
DateienOpenAI, Anthropic, Gemini, Azure

Installation

1

Paket installieren

Installieren Sie das Laravel AI SDK über Composer.
composer require laravel/ai
2

Konfigurationsdatei und Migrationen veröffentlichen

Veröffentlichen Sie die Konfigurationsdatei und die Migrationen mit dem Artisan-Befehl vendor:publish.
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
3

Migrationen ausführen

Führen Sie die Datenbankmigrationen aus. Dabei werden die Tabellen agent_conversations und agent_conversation_messages erstellt, in denen der Gesprächsverlauf gespeichert wird.
php artisan migrate

Konfiguration

Umgebungsvariablen

Tragen Sie in Ihre .env-Datei die API-Schlüssel der KI-Anbieter ein, die Sie verwenden möchten.
ANTHROPIC_API_KEY=
AZURE_OPENAI_API_KEY=
COHERE_API_KEY=
DEEPSEEK_API_KEY=
ELEVENLABS_API_KEY=
GEMINI_API_KEY=
GROQ_API_KEY=
MISTRAL_API_KEY=
OLLAMA_API_KEY=
OPENAI_API_KEY=
OPENROUTER_API_KEY=
JINA_API_KEY=
VOYAGEAI_API_KEY=
XAI_API_KEY=
Die Standardmodelle für Text, Bild, Audio, Transkription und Embeddings können außerdem in config/ai.php konfiguriert werden.

Benutzerdefinierte Basis-URL

Wenn Sie Anfragen über einen Proxydienst leiten möchten, können Sie pro Anbieter eine benutzerdefinierte URL festlegen.
'providers' => [
    'openai' => [
        'driver' => 'openai',
        'key' => env('OPENAI_API_KEY'),
        'url' => env('OPENAI_URL'),
    ],
    'anthropic' => [
        'driver' => 'anthropic',
        'key' => env('ANTHROPIC_API_KEY'),
        'url' => env('ANTHROPIC_BASE_URL'),
    ],
],
Benutzerdefinierte Basis-URLs stehen für OpenAI, Anthropic, Gemini, Groq, Cohere, DeepSeek, xAI und OpenRouter zur Verfügung.

OpenAI-kompatible Anbieter

Wenn Sie eine OpenAI-kompatible API verwenden – zum Beispiel LM Studio, vLLM, Together, Fireworks oder ein lokales Gateway – können Sie einen Anbieter mit dem Treiber openai-compatible konfigurieren. url ist erforderlich; wenn Sie key angeben, wird er als Bearer-Token gesendet.
'providers' => [
    'local' => [
        'driver' => 'openai-compatible',
        'url' => env('LOCAL_AI_URL'),
        'key' => env('LOCAL_AI_API_KEY'),
    ],
],
Nach der Konfiguration können Sie den Anbieter wie jeden anderen über seinen Namen ansprechen.
agent()->prompt('What is Laravel?', provider: 'local', model: 'local-model');
Wenn Sie ein Standard-Textmodell konfigurieren, müssen Sie das Modell nicht bei jedem Aufruf angeben.
'local' => [
    'driver' => 'openai-compatible',
    'url' => env('LOCAL_AI_URL'),
    'key' => env('LOCAL_AI_API_KEY'),
    'models' => [
        'text' => [
            'default' => env('LOCAL_AI_MODEL'),
        ],
    ],
],
Der OpenAI-kompatible Anbieter unterstützt Textgenerierung, Streaming, Tools, strukturierte Ausgaben und Bildanhänge. Wenn Ihr Endpunkt zusätzliche Felder im Request-Body benötigt, verwenden Sie die Anbieteroptionen.

Lab-Enum

Verwenden Sie das Lab-Enum, um Anbieter im Code zu referenzieren.
use Laravel\Ai\Enums\Lab;

Lab::Anthropic;
Lab::OpenAI;
Lab::Gemini;

Agenten

Agenten sind der grundlegende Baustein des Laravel AI SDK. Mit dem Befehl make:agent erzeugen Sie eine Agentenklasse.
php artisan make:agent SalesCoach

# Agent mit strukturierter Ausgabe erzeugen
php artisan make:agent SalesCoach --structured
Die erzeugten Agenten werden im Verzeichnis app/Ai/Agents/ abgelegt. Nachfolgend sehen Sie einen Agenten, der alle wichtigen Schnittstellen implementiert.
<?php

namespace App\Ai\Agents;

use App\Ai\Tools\RetrievePreviousTranscripts;
use App\Models\History;
use App\Models\User;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasStructuredOutput;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable;
use Stringable;

class SalesCoach implements Agent, Conversational, HasTools, HasStructuredOutput
{
    use Promptable;

    public function __construct(public User $user) {}

    public function instructions(): Stringable|string
    {
        return 'You are a sales coach, analyzing transcripts and providing feedback and an overall sales strength score.';
    }

    public function messages(): iterable
    {
        return History::where('user_id', $this->user->id)
            ->latest()
            ->limit(50)
            ->get()
            ->reverse()
            ->map(function ($message) {
                return new Message($message->role, $message->content);
            })->all();
    }

    public function tools(): iterable
    {
        return [new RetrievePreviousTranscripts];
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'feedback' => $schema->string()->required(),
            'score' => $schema->integer()->min(1)->max(10)->required(),
        ];
    }
}

Prompt

Über die Methode prompt() senden Sie eine Nachricht an den Agenten.
$response = (new SalesCoach)->prompt('Analyze this sales transcript...');
return (string) $response;
Mit der statischen Methode make() können Sie eine Instanz erzeugen und Abhängigkeiten über den Container auflösen lassen.
$agent = SalesCoach::make(user: $user);
Anbieter, Modell und Timeout lassen sich als Argumente von prompt() überschreiben.
$response = (new SalesCoach)->prompt(
    'Analyze this sales transcript...',
    provider: Lab::Anthropic,
    model: 'claude-haiku-4-5-20251001',
    timeout: 120,
);

Gesprächskontext

Wenn Sie das Conversational-Interface implementieren und eine Methode messages() definieren, wird der bisherige Gesprächsverlauf an die KI übergeben. Das Trait RemembersConversations speichert und lädt den Gesprächsverlauf automatisch aus der Datenbank.
use Laravel\Ai\Concerns\RemembersConversations;

class SalesCoach implements Agent, Conversational
{
    use Promptable, RemembersConversations;

    public function instructions(): string
    {
        return 'You are a sales coach...';
    }
}
Beginnen Sie eine Unterhaltung mit forUser() und setzen Sie sie mit continue() fort, indem Sie die zurückgegebene conversationId verwenden.
$response = (new SalesCoach)->forUser($user)->prompt('Hello!');
$conversationId = $response->conversationId;

$response = (new SalesCoach)->continue($conversationId, as: $user)->prompt('Tell me more about that.');

Strukturierte Ausgaben

Implementieren Sie das HasStructuredOutput-Interface und definieren Sie in der Methode schema() ein JSON-Schema, um die Antwort der KI als strukturierte Daten zu erhalten.
public function schema(JsonSchema $schema): array
{
    return ['score' => $schema->integer()->required()];
}

$response = (new SalesCoach)->prompt('Analyze this...');
return $response['score'];

Verschachtelte Objekte

public function schema(JsonSchema $schema): array
{
    return [
        'score' => $schema->integer()->required(),
        'metadata' => $schema->object(fn ($schema) => [
            'confidence' => $schema->string()->enum(['low', 'medium', 'high'])->required(),
            'language' => $schema->string()->required(),
        ])->required(),
    ];
}

Arrays von Objekten

public function schema(JsonSchema $schema): array
{
    return [
        'feedback' => $schema->array()->items(
            $schema->object(fn ($schema) => [
                'comment' => $schema->string()->required(),
                'score' => $schema->integer()->required(),
            ])
        )->required(),
    ];
}

anyOf (Auswahl aus mehreren Schemata)

Wenn ein Wert einem von mehreren möglichen Schemata entsprechen soll, verwenden Sie die Methode anyOf.
public function schema(JsonSchema $schema): array
{
    return [
        'content' => $schema->anyOf([
            $schema->object(fn ($schema) => [
                'type' => $schema->string()->enum(['article'])->required(),
                'title' => $schema->string()->required(),
            ]),
            $schema->object(fn ($schema) => [
                'type' => $schema->string()->enum(['image'])->required(),
                'url' => $schema->string()->required(),
            ]),
        ])->required(),
    ];
}

Anhänge

Über das Argument attachments können Sie dem Agenten Dokumente oder Bilder übergeben.
use Laravel\Ai\Files;

$response = (new SalesCoach)->prompt(
    'Analyze the attached sales transcript...',
    attachments: [
        Files\Document::fromStorage('transcript.pdf'),
        Files\Document::fromPath('/home/laravel/transcript.md'),
        $request->file('transcript'),
    ]
);
Bilder lassen sich auf gleiche Weise anhängen.
$response = (new ImageAnalyzer)->prompt('What is in this image?', attachments: [
    Files\Image::fromStorage('photo.jpg'),
    Files\Image::fromPath('/home/laravel/photo.jpg'),
    $request->file('photo'),
]);

Streaming

Mit der Methode stream() können Sie die Antwort chunkweise zurückgeben. Das eignet sich, um lange Antworten in Echtzeit an das Frontend zu senden.
Route::get('/coach', function () {
    return (new SalesCoach)->stream('Analyze this sales transcript...');
});
Mit einem then()-Callback lässt sich die Verarbeitung nach Abschluss des Streams beschreiben.
use Laravel\Ai\Responses\StreamedAgentResponse;

Route::get('/coach', function () {
    return (new SalesCoach)
        ->stream('Analyze this sales transcript...')
        ->then(function (StreamedAgentResponse $response) {
            // $response->text, $response->events, $response->usage...
        });
});
Sie können den Stream auch manuell iterieren.
$stream = (new SalesCoach)->stream('Analyze this sales transcript...');

foreach ($stream as $event) {
    // ...
}

Vercel-AI-SDK-Protokoll

Wenn Sie im Frontend das Vercel AI SDK verwenden, rufen Sie usingVercelDataProtocol() auf.
Route::get('/coach', function () {
    return (new SalesCoach)->stream('Analyze...')->usingVercelDataProtocol();
});

Broadcasting

Ereignisse aus dem Stream können an Broadcast-Kanäle, etwa Laravel Echo, gesendet werden.
use Illuminate\Broadcasting\Channel;

$stream = (new SalesCoach)->stream('Analyze this sales transcript...');

foreach ($stream as $event) {
    $event->broadcast(new Channel('channel-name'));
}
Mit broadcastOnQueue() erfolgt das Broadcasten über eine Queue.
(new SalesCoach)->broadcastOnQueue(
    'Analyze this sales transcript...',
    new Channel('channel-name'),
);

Sehr große Ereignisse überspringen

Manche Broadcast-Plattformen begrenzen WebSocket-Nachrichten auf etwa 10 KB. Datenintensive Stream-Ereignisse wie große Tool-Ergebnisse können diese Grenze überschreiten und beim Broadcasten fehlschlagen. Mit dem Attribut WithoutBroadcasting können Sie bestimmte Ereignistypen vom Broadcast ausschließen.
<?php

namespace App\Ai\Agents;

use Laravel\Ai\Attributes\WithoutBroadcasting;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Promptable;
use Laravel\Ai\Streaming\Events\ToolCall;
use Laravel\Ai\Streaming\Events\ToolResult;

#[WithoutBroadcasting(ToolCall::class, ToolResult::class)]
class SearchAgent implements Agent, HasTools
{
    use Promptable;

    // ...
}
Ausgeschlossene Ereignisse werden nicht per Broadcast versendet, aber weiterhin in der Tabelle agent_conversation_messages gespeichert. Dadurch kann das Frontend nach Abschluss des Streams weiterhin auf die vollständigen Tool-Daten zugreifen. Dies funktioniert sowohl über die Queue (broadcastOnQueue) als auch synchron (broadcast / broadcastNow).

Queue

Mit der Methode queue() können Sie Prompts asynchron in die Queue stellen.
use Laravel\Ai\Responses\AgentResponse;

Route::post('/coach', function (Request $request) {
    (new SalesCoach)
        ->queue($request->input('transcript'))
        ->then(function (AgentResponse $response) { /* ... */ })
        ->catch(function (Throwable $e) { /* ... */ });

    return back();
});

Tools

Mit Tools kann die KI Funktionen in Ihrem Code aufrufen. Mit dem Befehl make:tool erzeugen Sie eine Toolklasse.
php artisan make:tool RandomNumberGenerator
<?php

namespace App\Ai\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;

class RandomNumberGenerator implements Tool
{
    public function description(): Stringable|string
    {
        return 'This tool may be used to generate cryptographically secure random numbers.';
    }

    public function handle(Request $request): Stringable|string
    {
        return (string) random_int($request['min'], $request['max']);
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'min' => $schema->integer()->min(0)->required(),
            'max' => $schema->integer()->required(),
        ];
    }
}
Registrieren Sie Tools in der Methode tools() des Agenten.
public function tools(): iterable
{
    return [new RandomNumberGenerator];
}

Ähnlichkeitssuche als Tool

Ein Tool für die Ähnlichkeitssuche mit Vektor-Embeddings lässt sich unkompliziert einbinden.
use App\Models\Document;
use Laravel\Ai\Tools\SimilaritySearch;

public function tools(): iterable
{
    return [
        SimilaritySearch::usingModel(Document::class, 'embedding'),
    ];
}
Sie können zusätzliche Optionen angeben.
SimilaritySearch::usingModel(
    model: Document::class,
    column: 'embedding',
    minSimilarity: 0.7,
    limit: 10,
    query: fn ($query) => $query->where('published', true),
),
Eine eigene Suchlogik lässt sich per Closure definieren.
new SimilaritySearch(using: function (string $query) {
    return Document::query()
        ->where('user_id', $this->user->id)
        ->whereVectorSimilarTo('embedding', $query)
        ->limit(10)
        ->get();
}),
Mit withDescription() passen Sie die Beschreibung des Tools an.
SimilaritySearch::usingModel(Document::class, 'embedding')
    ->withDescription('Search the knowledge base for relevant articles.'),

Dateisystem-Tools

Mit der Fabrik FileStorage können Sie Ihrem Agenten Zugriff auf Filesystem-Disks von Laravel geben. Die Methode all gibt einen Satz von Tools zurück, mit denen der Agent Dateien auf der angegebenen Disk auflisten, lesen, URLs erzeugen, schreiben, löschen und kopieren kann.
use Laravel\Ai\Tools\FileStorage;

public function tools(): iterable
{
    return FileStorage::all('local');
}
Wenn Sie nur Lesezugriff gewähren möchten, verwenden Sie die Methode readOnly.
return FileStorage::readOnly('local');
Diese Methoden liefern eine Illuminate\Support\Collection zurück, sodass Sie die bereitgestellten Tools weiter filtern können.
use Laravel\Ai\Tools\Filesystem\DeleteFile;

return FileStorage::all('s3')
    ->reject(fn ($tool) => $tool instanceof DeleteFile);

MCP-Tools

Wenn Ihre Anwendung Laravel MCP verwendet, können Sie Ihrem Agenten die Tools bereitstellen, die ein Model-Context-Protocol-Server veröffentlicht. Mit dem Laravel-MCP-Client können Sie sich mit entfernten oder lokalen MCP-Servern verbinden und deren Tools direkt an den Agenten übergeben.
Für die Nutzung von MCP-Tools muss das Paket Laravel MCP in Ihrer Anwendung installiert sein.
Die Methode tools des MCP-Clients liefert eine Collection zurück, die Sie mit dem Spread-Operator ... in das tools-Array des Agenten einfügen.
use App\Ai\Tools\RandomNumberGenerator;
use Laravel\Mcp\Client;

/**
 * Get the tools available to the agent.
 *
 * @return Tool[]
 */
public function tools(): iterable
{
    return [
        ...Client::web('https://mcp.example.com')
            ->withToken($token)
            ->tools(),

        new RandomNumberGenerator,
    ];
}
Das AI SDK umschließt jedes MCP-Tool automatisch, sodass der Agent es wie jedes andere Tool aufrufen kann. Sie können auch benannte MCP-Clients verwenden.
use Laravel\Mcp\Facades\Mcp;

public function tools(): iterable
{
    return [
        ...Mcp::client('github')->tools(),
    ];
}
Ebenso können Sie sich mit einem lokalen MCP-Server verbinden.
use Laravel\Mcp\Client;

public function tools(): iterable
{
    return [
        ...Client::local('php', ['artisan', 'mcp:start'])->tools(),
    ];
}
Details zur Erstellung von MCP-Clients und zur Authentifizierung (Bearer-Token, OAuth usw.) finden Sie in der MCP-Client-Dokumentation.

Anbieter-Tools

Dies sind spezielle Tools, die die KI-Anbieter nativ implementieren.

Websuche

Fügt dem Agenten eine Websuche hinzu. Unterstützt werden Anthropic, OpenAI, Gemini und OpenRouter.
use Laravel\Ai\Providers\Tools\WebSearch;

public function tools(): iterable
{
    return [new WebSearch];
}
Optional lassen sich die Anzahl der Treffer, erlaubte Domains und der Standort einschränken.
(new WebSearch)->max(5)->allow(['laravel.com', 'php.net']),
(new WebSearch)->location(city: 'New York', region: 'NY', country: 'US');

Web-Fetch

Ein Tool, das den Inhalt einer angegebenen URL abruft. Unterstützt werden Anthropic und Gemini.
use Laravel\Ai\Providers\Tools\WebFetch;

public function tools(): iterable
{
    return [new WebFetch];
}

(new WebFetch)->max(3)->allow(['docs.laravel.com']),

Dateisuche

Ein Tool, das Dokumente aus einem Vektorspeicher durchsucht. Unterstützt werden OpenAI und Gemini.
use Laravel\Ai\Providers\Tools\FileSearch;

public function tools(): iterable
{
    return [new FileSearch(stores: ['store_id'])];
}

// Mehrere Stores angeben
new FileSearch(stores: ['store_1', 'store_2']);

// Nach Metadaten filtern
new FileSearch(stores: ['store_id'], where: ['author' => 'Taylor Otwell', 'year' => 2026]);
Auch komplexe Filter über FileSearchQuery sind möglich.
use Laravel\Ai\Providers\Tools\FileSearchQuery;

new FileSearch(stores: ['store_id'], where: fn (FileSearchQuery $query) =>
    $query->where('author', 'Taylor Otwell')
          ->whereNot('status', 'draft')
          ->whereIn('category', ['news', 'updates'])
);

Subagenten

Agenten können auch aus der tools()-Methode eines anderen Agenten zurückgegeben werden. Wenn Sie einen Agenten als Tool registrieren, kann der übergeordnete Agent bestimmte Aufgaben an einen Subagenten delegieren und dessen Ergebnis in die ursprüngliche Antwort einbetten. Das ist nützlich, wenn ein Allzweck-Agent auf spezialisierte Agenten mit eigenen Anweisungen, Tools, Modell- oder Anbietereinstellungen zugreifen soll. Ein Beispiel: Ein Kundenservice-Agent delegiert Fragen zur Rückerstattungsrichtlinie an einen spezialisierten Erstattungsagenten.
<?php

namespace App\Ai\Agents;

use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Promptable;

class CustomerSupportAgent implements Agent, HasTools
{
    use Promptable;

    public function instructions(): string
    {
        return 'You help customers with account, order, and billing questions. Delegate refund policy questions to the refunds specialist.';
    }

    public function tools(): iterable
    {
        return [
            new RefundsAgent,
        ];
    }
}
Um festzulegen, wie der Subagent gegenüber dem übergeordneten Agenten erscheint, implementieren Sie das Interface CanActAsTool und definieren einen Namen und eine Beschreibung für das Tool.
<?php

namespace App\Ai\Agents;

use App\Ai\Tools\LookupOrder;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\CanActAsTool;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Promptable;

#[Provider(Lab::Anthropic)]
class RefundsAgent implements Agent, CanActAsTool, HasTools
{
    use Promptable;

    public function instructions(): string
    {
        return 'You are a refunds specialist. Use order details and the refund policy to give concise eligibility guidance.';
    }

    public function name(): string
    {
        return 'refunds_specialist';
    }

    public function description(): string
    {
        return 'Determine whether an order is eligible for a refund and explain the next step.';
    }

    public function tools(): iterable
    {
        return [
            new LookupOrder,
        ];
    }
}
Wenn ein Subagent CanActAsTool nicht implementiert, verwendet Laravel den Klassennamen als Tool-Namen und generiert automatisch eine allgemeine Beschreibung. Jeder Aufruf eines Subagenten erfolgt unabhängig; der Gesprächsverlauf des übergeordneten Agenten wird nicht übernommen.

Middleware

Sie können Middleware zu einem Agenten hinzufügen, um Prompts und Antworten abzufangen.
php artisan make:agent-middleware LogPrompts
Lassen Sie den Agenten das Interface HasMiddleware implementieren und registrieren Sie die Middleware in der Methode middleware().
<?php

namespace App\Ai\Agents;

use App\Ai\Middleware\LogPrompts;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasMiddleware;
use Laravel\Ai\Promptable;

class SalesCoach implements Agent, HasMiddleware
{
    use Promptable;

    public function middleware(): array
    {
        return [new LogPrompts];
    }
}
Beispiel für eine Middleware-Klasse:
<?php

namespace App\Ai\Middleware;

use Closure;
use Laravel\Ai\Prompts\AgentPrompt;

class LogPrompts
{
    public function handle(AgentPrompt $prompt, Closure $next)
    {
        Log::info('Prompting agent', ['prompt' => $prompt->prompt]);
        return $next($prompt);
    }
}
Mit then() können Sie zusätzliche Verarbeitungsschritte nach der Antwort ergänzen.
public function handle(AgentPrompt $prompt, Closure $next)
{
    return $next($prompt)->then(function (AgentResponse $response) {
        Log::info('Agent responded', ['text' => $response->text]);
    });
}

Anonyme Agenten

Ohne eine eigene Klasse zu definieren, können Sie mit dem Helper agent() anonyme Agenten verwenden.
use function Laravel\Ai\{agent};

$response = agent(
    instructions: 'You are an expert at software development.',
    messages: [],
    tools: [],
)->prompt('Tell me about Laravel');
Auch anonyme Agenten mit strukturierter Ausgabe sind möglich.
use Illuminate\Contracts\JsonSchema\JsonSchema;

$response = agent(
    schema: fn (JsonSchema $schema) => ['number' => $schema->integer()->required()],
)->prompt('Generate a random number less than 100');

Agentenkonfiguration (PHP-Attribute)

Standardeinstellungen eines Agenten lassen sich deklarativ über PHP-Attribute festlegen.
AttributBeschreibung
#[Provider]Legt den zu verwendenden Anbieter fest
#[Model]Legt das zu verwendende Modell fest
#[MaxSteps]Maximale Anzahl an Tool-Aufruf-Schritten
#[MaxTokens]Maximale Token-Anzahl
#[Temperature]Temperatur-Parameter (0.0 bis 1.0)
#[TopP]Wahrscheinlichkeit für Nucleus Sampling (0.0 bis 1.0)
#[Timeout]Timeout (in Sekunden)
#[UseCheapestModel]Wählt automatisch das günstigste Modell
#[UseSmartestModel]Wählt automatisch das leistungsfähigste Modell
<?php

namespace App\Ai\Agents;

use Laravel\Ai\Attributes\MaxSteps;
use Laravel\Ai\Attributes\MaxTokens;
use Laravel\Ai\Attributes\Model;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Attributes\Temperature;
use Laravel\Ai\Attributes\Timeout;
use Laravel\Ai\Attributes\TopP;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Promptable;

#[Provider(Lab::Anthropic)]
#[Model('claude-haiku-4-5-20251001')]
#[MaxSteps(10)]
#[MaxTokens(4096)]
#[Temperature(0.7)]
#[Timeout(120)]
#[TopP(0.9)]
class SalesCoach implements Agent
{
    use Promptable;
}
Für die Modellauswahl gibt es Abkürzungsattribute.
// Verwende das günstigste Modell
#[UseCheapestModel]
class SimpleSummarizer implements Agent
{
    use Promptable;
}

// Verwende das leistungsfähigste Modell
#[UseSmartestModel]
class ComplexReasoner implements Agent
{
    use Promptable;
}

Anbieteroptionen

Wenn Sie das Interface HasProviderOptions implementieren, können Sie anbieterspezifische Optionen übergeben.
<?php

namespace App\Ai\Agents;

use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasProviderOptions;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Promptable;

class SalesCoach implements Agent, HasProviderOptions
{
    use Promptable;

    public function providerOptions(Lab|string $provider): array
    {
        return match ($provider) {
            Lab::OpenAI => [
                'reasoning' => ['effort' => 'low'],
                'frequency_penalty' => 0.5,
                'presence_penalty' => 0.3,
            ],
            Lab::Anthropic => [
                'thinking' => ['budget_tokens' => 1024],
            ],
            default => [],
        };
    }
}

Bildgenerierung

Mit der Klasse Image können Sie Bilder generieren. Unterstützt werden die Anbieter OpenAI, Gemini und xAI.
use Laravel\Ai\Image;

$image = Image::of('A donut sitting on the kitchen counter')->generate();
$rawContent = (string) $image;
Sie können Qualität, Seitenverhältnis und Timeout angeben.
$image = Image::of('A donut sitting on the kitchen counter')
    ->quality('high')
    ->landscape()
    ->timeout(120)
    ->generate();
Auch das Bearbeiten anhand eines Referenzbildes ist möglich.
use Laravel\Ai\Files;

$image = Image::of('Update this photo to be in the style of an impressionist painting.')
    ->attachments([Files\Image::fromStorage('photo.jpg')])
    ->landscape()
    ->generate();

Bilder speichern

$path = $image->store();
$path = $image->storeAs('image.jpg');
$path = $image->storePublicly();
$path = $image->storePubliclyAs('image.jpg');

Bildgenerierung per Queue

use Laravel\Ai\Responses\ImageResponse;

Image::of('A donut sitting on the kitchen counter')
    ->portrait()
    ->queue()
    ->then(function (ImageResponse $image) {
        $path = $image->store();
    });

Sprachsynthese (TTS)

Mit der Klasse Audio können Sie Text in Sprache umwandeln. Unterstützt werden die Anbieter OpenAI und ElevenLabs.
use Laravel\Ai\Audio;

$audio = Audio::of('I love coding with Laravel.')->generate();
$rawContent = (string) $audio;
Sie können das Geschlecht der Stimme, eine konkrete Voice-ID sowie Anweisungen für den Sprechstil angeben.
$audio = Audio::of('I love coding with Laravel.')->female()->generate();
$audio = Audio::of('I love coding with Laravel.')->voice('voice-id-or-name')->generate();
$audio = Audio::of('I love coding with Laravel.')->female()->instructions('Said like a pirate')->generate();

Audio speichern

$path = $audio->store();
$path = $audio->storeAs('audio.mp3');
$path = $audio->storePublicly();
$path = $audio->storePubliclyAs('audio.mp3');

Sprachsynthese per Queue

use Laravel\Ai\Responses\AudioResponse;

Audio::of('I love coding with Laravel.')
    ->queue()
    ->then(function (AudioResponse $audio) {
        $path = $audio->store();
    });

Transkription (STT)

Mit der Klasse Transcription können Sie Audiodateien in Text umwandeln. Unterstützt werden die Anbieter OpenAI, ElevenLabs und Mistral.
use Laravel\Ai\Transcription;

$transcript = Transcription::fromPath('/home/laravel/audio.mp3')->generate();
$transcript = Transcription::fromStorage('audio.mp3')->generate();
$transcript = Transcription::fromUpload($request->file('audio'))->generate();

return (string) $transcript;

Sprechertrennung (Diarisierung)

Mit diarize() erhalten Sie eine Transkription, die nach Sprechern getrennt ist.
$transcript = Transcription::fromStorage('audio.mp3')->diarize()->generate();

Transkription per Queue

use Laravel\Ai\Responses\TranscriptionResponse;

Transcription::fromStorage('audio.mp3')
    ->queue()
    ->then(function (TranscriptionResponse $transcript) { /* ... */ });

Embeddings

Wandeln Sie Text in eine Vektor-Repräsentation um, die sich zum Beispiel für die Ähnlichkeitssuche nutzen lässt.
use Illuminate\Support\Str;

// Über Stringable
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();
use Laravel\Ai\Embeddings;

// Mehrere Texte in einem Schritt verarbeiten
$response = Embeddings::for(['Napa Valley has great wine.', 'Laravel is a PHP framework.'])->generate();
$response->embeddings; // [[0.123, 0.456, ...], [0.789, 0.012, ...]]
Anbieter, Modell und Anzahl der Dimensionen lassen sich ebenfalls angeben.
$response = Embeddings::for(['Napa Valley has great wine.'])
    ->dimensions(1536)
    ->generate(Lab::OpenAI, 'text-embedding-3-small');

Vektorsuche (pgvector)

Beispielkonfiguration einer Vektorsuche mit PostgreSQL und der pgvector-Erweiterung.
1

Migration erstellen

Schema::ensureVectorExtensionExists();

Schema::create('documents', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('content');
    $table->vector('embedding', dimensions: 1536);
    $table->timestamps();
});

// HNSW-Index hinzufügen
$table->vector('embedding', dimensions: 1536)->index();
2

Model konfigurieren

protected function casts(): array
{
    return ['embedding' => 'array'];
}
3

Ähnlichkeitssuche

// Suche mit einem Embedding-Vektor
$documents = Document::query()
    ->whereVectorSimilarTo('embedding', $queryEmbedding, minSimilarity: 0.4)
    ->limit(10)
    ->get();

// Wird ein String übergeben, werden Embeddings automatisch erzeugt
$documents = Document::query()
    ->whereVectorSimilarTo('embedding', 'best wineries in Napa Valley')
    ->limit(10)
    ->get();
Es stehen auch Low-Level-Methoden zur Verfügung.
$documents = Document::query()
    ->select('*')
    ->selectVectorDistance('embedding', $queryEmbedding, as: 'distance')
    ->whereVectorDistanceLessThan('embedding', $queryEmbedding, maxDistance: 0.3)
    ->orderByVectorDistance('embedding', $queryEmbedding)
    ->limit(10)
    ->get();

Embeddings zwischenspeichern

Sie können Embeddings zwischenspeichern, um denselben Text nicht mehrfach zu berechnen. Die Standardeinstellungen für den Cache legen Sie in config/ai.php fest.
'caching' => [
    'embeddings' => [
        'cache' => true,
        'store' => env('CACHE_STORE', 'database'),
    ],
],
Sie können den Cache auch pro Anfrage steuern.
$response = Embeddings::for(['Napa Valley has great wine.'])->cache()->generate();
$response = Embeddings::for(['Napa Valley has great wine.'])->cache(seconds: 3600)->generate();

// Ebenso über Stringable
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: true);
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: 3600);

Reranking

Suchergebnisse können anhand ihrer Relevanz zu einer Anfrage neu sortiert werden (Reranking). Unterstützt werden die Anbieter Cohere und Jina.
use Laravel\Ai\Reranking;

$response = Reranking::of([
    'Django is a Python web framework.',
    'Laravel is a PHP web application framework.',
    'React is a JavaScript library for building user interfaces.',
])->rerank('PHP frameworks');

$response->first()->document; // "Laravel is a PHP web application framework."
$response->first()->score;    // 0.95
$response->first()->index;    // 1
Mit limit() schränken Sie die Anzahl der zurückgegebenen Ergebnisse ein.
$response = Reranking::of($documents)->limit(5)->rerank('search query');

Reranking von Collections

Eloquent-Collections lassen sich direkt reranken.
// Einzelnes Feld
$posts = Post::all()->rerank('body', 'Laravel tutorials');

// Mehrere Felder (werden als JSON gesendet)
$reranked = $posts->rerank(['title', 'body'], 'Laravel tutorials');

// Eigene Textgenerierung per Closure
$reranked = $posts->rerank(fn ($post) => $post->title.': '.$post->body, 'Laravel tutorials');

// Mit weiteren Optionen
$reranked = $posts->rerank(
    by: 'content',
    query: 'Laravel tutorials',
    limit: 10,
    provider: Lab::Cohere,
);

Dateiverwaltung

Sie können Dateien zu einem KI-Anbieter hochladen und später darauf verweisen.
use Laravel\Ai\Files\Document;
use Laravel\Ai\Files\Image;

// Aus einem Pfad
$response = Document::fromPath('/home/laravel/document.pdf')->put();
$response = Image::fromPath('/home/laravel/photo.jpg')->put();

// Aus dem Storage
$response = Document::fromStorage('document.pdf', disk: 'local')->put();
$response = Image::fromStorage('photo.jpg', disk: 'local')->put();

// Aus einer URL
$response = Document::fromUrl('https://example.com/document.pdf')->put();
$response = Image::fromUrl('https://example.com/photo.jpg')->put();

return $response->id;
Auch Strings und Formular-Uploads sind möglich.
$stored = Document::fromString('Hello, World!', 'text/plain')->put();
$stored = Document::fromUpload($request->file('document'))->put();

Auf gespeicherte Dateien verweisen

Bereits hochgeladene Dateien können Sie über ihre ID an einen Agenten anhängen.
use Laravel\Ai\Files;

$response = (new SalesCoach)->prompt(
    'Analyze the attached sales transcript...',
    attachments: [Files\Document::fromId('file-id')]
);

Dateien abrufen und löschen

// Abrufen
$file = Document::fromId('file-id')->get();
$file->id;
$file->mimeType();

// Löschen
Document::fromId('file-id')->delete();

Anbieter angeben

$response = Document::fromPath('/home/laravel/document.pdf')->put(provider: Lab::Anthropic);

Anbieterspezifische Optionen angeben

Über die Methode withProviderOptions können Sie anbieterspezifische Upload-Optionen übergeben. So können Sie zum Beispiel den purpose-Wert für OpenAI-Dateien setzen.
use Laravel\Ai\Files\Document;

$response = Document::fromPath('/home/laravel/knowledge.txt')
    ->withProviderOptions(['purpose' => 'assistants'])
    ->put();
Wenn Sie pro Anbieter unterschiedliche Optionen angeben möchten, übergeben Sie eine Closure.
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Files\Document;

$response = Document::fromPath('/home/laravel/training.jsonl')
    ->withProviderOptions(fn (Lab|string $provider) => match ($provider) {
        Lab::OpenAI => ['purpose' => 'fine-tune'],
        default => [],
    })
    ->put();

Vektorspeicher

Mit Vektorspeichern (Vector Stores) können Sie Dokumente auf Anbieterseite verwalten lassen.
use Laravel\Ai\Stores;

// Erstellen
$store = Stores::create('Knowledge Base');
$store = Stores::create(
    name: 'Knowledge Base',
    description: 'Documentation.',
    expiresWhenIdleFor: days(30),
);
return $store->id;

// Abrufen
$store = Stores::get('store_id');
$store->id;
$store->name;
$store->fileCounts;
$store->ready;

// Löschen
Stores::delete('store_id');
$store->delete();

Dateien zum Store hinzufügen

$store = Stores::get('store_id');

// Dateien auf verschiedene Arten hinzufügen
$document = $store->add('file_id');
$document = $store->add(Document::fromId('file_id'));
$document = $store->add(Document::fromPath('/path/to/document.pdf'));
$document = $store->add(Document::fromStorage('manual.pdf'));
$document = $store->add($request->file('document'));

$document->id;
$document->fileId;
Sie können auch Metadaten anhängen.
$store->add(
    Document::fromPath('/path/to/document.pdf'),
    metadata: [
        'author' => 'Taylor Otwell',
        'department' => 'Engineering',
        'year' => 2026,
    ]
);

Dateien aus einem Store entfernen

$store->remove('file_id');

// Wenn zusätzlich die Datei selbst gelöscht werden soll
$store->remove('file_abc123', deleteFile: true);

Failover

Wenn Sie mehrere Anbieter als Array angeben, wird bei einem Fehlschlag des ersten Anbieters automatisch auf den nächsten umgeschaltet.
use App\Ai\Agents\SalesCoach;
use Laravel\Ai\Image;

// Failover bei Agenten
$response = (new SalesCoach)->prompt(
    'Analyze this sales transcript...',
    provider: [Lab::OpenAI, Lab::Anthropic],
);

// Failover bei der Bildgenerierung
$image = Image::of('A donut sitting on the kitchen counter')
    ->generate(provider: [Lab::Gemini, Lab::xAI]);

Testen

Das Laravel AI SDK stellt Fakes bereit, mit denen Sie testen können, ohne echte APIs aufzurufen.

Agenten testen

use App\Ai\Agents\SalesCoach;
use Laravel\Ai\Prompts\AgentPrompt;

// Fake mit festen Antworten
SalesCoach::fake();
SalesCoach::fake(['First response', 'Second response']);

// Dynamische Antworten per Closure
SalesCoach::fake(function (AgentPrompt $prompt) {
    return 'Response for: '.$prompt->prompt;
});

// Zusicherungen
SalesCoach::assertPrompted('Analyze this...');
SalesCoach::assertPrompted(function (AgentPrompt $prompt) {
    return $prompt->contains('Analyze');
});
SalesCoach::assertNotPrompted('Missing prompt');
SalesCoach::assertNeverPrompted();
Auch für die Queue stehen Zusicherungen zur Verfügung.
use Laravel\Ai\QueuedAgentPrompt;

SalesCoach::assertQueued('Analyze this...');
SalesCoach::assertQueued(function (QueuedAgentPrompt $prompt) {
    return $prompt->contains('Analyze');
});
SalesCoach::assertNotQueued('Missing prompt');
SalesCoach::assertNeverQueued();
Mit preventStrayPrompts() wird eine Ausnahme ausgelöst, wenn ein Prompt aufgerufen wird, der nicht als Fake definiert wurde.
SalesCoach::fake()->preventStrayPrompts();
Wenn Sie einen Agenten mit strukturierter Ausgabe faken, können Sie die Antwort als Array angeben. Der Agent liefert dann eine strukturierte Antwort mit den angegebenen Daten zurück.
SalesCoach::fake([
    ['score' => 87],
]);
Wenn fake() bei einem Agenten mit strukturierter Ausgabe ohne explizit angegebene Fake-Daten aufgerufen wird, generiert Laravel automatisch Fake-Daten, die dem vom Agenten definierten Schema entsprechen.
Zum Testen anonymer Agenten verwenden Sie AnonymousAgent::fake().
use Laravel\Ai\AnonymousAgent;

AnonymousAgent::fake(['Test response']);

Bildgenerierung testen

use Laravel\Ai\Image;
use Laravel\Ai\Prompts\ImagePrompt;

Image::fake();
Image::fake([base64_encode($firstImage), base64_encode($secondImage)]);
Image::fake(function (ImagePrompt $prompt) {
    return base64_encode('...');
});

Image::assertGenerated(function (ImagePrompt $prompt) {
    return $prompt->contains('sunset') && $prompt->isLandscape();
});
Image::assertNotGenerated('Missing prompt');
Image::assertNothingGenerated();

Image::assertQueued(fn (QueuedImagePrompt $prompt) => $prompt->contains('sunset'));
Image::assertNotQueued('Missing prompt');
Image::assertNothingQueued();

Image::fake()->preventStrayImages();

Sprachsynthese testen

use Laravel\Ai\Audio;
use Laravel\Ai\Prompts\AudioPrompt;

Audio::fake();
Audio::fake([base64_encode($firstAudio), base64_encode($secondAudio)]);
Audio::fake(function (AudioPrompt $prompt) {
    return base64_encode('...');
});

Audio::assertGenerated(function (AudioPrompt $prompt) {
    return $prompt->contains('Hello') && $prompt->isFemale();
});
Audio::assertNotGenerated('Missing prompt');
Audio::assertNothingGenerated();

Audio::assertQueued(fn (QueuedAudioPrompt $prompt) => $prompt->contains('Hello'));
Audio::assertNotQueued('Missing prompt');
Audio::assertNothingQueued();

Audio::fake()->preventStrayAudio();

Transkription testen

use Laravel\Ai\Transcription;
use Laravel\Ai\Prompts\TranscriptionPrompt;

Transcription::fake();
Transcription::fake(['First transcription text.', 'Second transcription text.']);
Transcription::fake(function (TranscriptionPrompt $prompt) {
    return 'Transcribed text...';
});

Transcription::assertGenerated(function (TranscriptionPrompt $prompt) {
    return $prompt->language === 'en' && $prompt->isDiarized();
});
Transcription::assertNotGenerated(fn (TranscriptionPrompt $prompt) => $prompt->language === 'fr');
Transcription::assertNothingGenerated();

Transcription::assertQueued(fn (QueuedTranscriptionPrompt $prompt) => $prompt->isDiarized());
Transcription::assertNotQueued(fn (QueuedTranscriptionPrompt $prompt) => $prompt->language === 'fr');
Transcription::assertNothingQueued();

Transcription::fake()->preventStrayTranscriptions();

Embeddings testen

use Laravel\Ai\Embeddings;
use Laravel\Ai\Prompts\EmbeddingsPrompt;

Embeddings::fake();
Embeddings::fake([[$firstEmbeddingVector], [$secondEmbeddingVector]]);
Embeddings::fake(function (EmbeddingsPrompt $prompt) {
    return array_map(
        fn () => Embeddings::fakeEmbedding($prompt->dimensions),
        $prompt->inputs
    );
});

Embeddings::assertGenerated(function (EmbeddingsPrompt $prompt) {
    return $prompt->contains('Laravel') && $prompt->dimensions === 1536;
});
Embeddings::assertNotGenerated(fn (EmbeddingsPrompt $prompt) => $prompt->contains('Other'));
Embeddings::assertNothingGenerated();

Embeddings::assertQueued(fn (QueuedEmbeddingsPrompt $prompt) => $prompt->contains('Laravel'));
Embeddings::assertNotQueued(fn (QueuedEmbeddingsPrompt $prompt) => $prompt->contains('Other'));
Embeddings::assertNothingQueued();

Embeddings::fake()->preventStrayEmbeddings();

Reranking testen

use Laravel\Ai\Reranking;
use Laravel\Ai\Prompts\RerankingPrompt;
use Laravel\Ai\Responses\Data\RankedDocument;

Reranking::fake();
Reranking::fake([[
    new RankedDocument(index: 0, document: 'First', score: 0.95),
    new RankedDocument(index: 1, document: 'Second', score: 0.80),
]]);

Reranking::assertReranked(function (RerankingPrompt $prompt) {
    return $prompt->contains('Laravel') && $prompt->limit === 5;
});
Reranking::assertNotReranked(fn (RerankingPrompt $prompt) => $prompt->contains('Django'));
Reranking::assertNothingReranked();

Dateien testen

use Laravel\Ai\Files;
use Laravel\Ai\Contracts\Files\StorableFile;
use Laravel\Ai\Files\Document;

Files::fake();

Document::fromString('Hello, Laravel!', mimeType: 'text/plain')->as('hello.txt')->put();

Files::assertStored(fn (StorableFile $file) =>
    (string) $file === 'Hello, Laravel!' && $file->mimeType() === 'text/plain'
);
Files::assertNotStored(fn (StorableFile $file) => (string) $file === 'Hello, World!');
Files::assertNothingStored();

Files::assertDeleted('file-id');
Files::assertNotDeleted('file-id');
Files::assertNothingDeleted();

Vektorspeicher testen

use Laravel\Ai\Stores;

Stores::fake(); // Dateioperationen werden ebenfalls gefakt

$store = Stores::create('Knowledge Base');

Stores::assertCreated('Knowledge Base');
Stores::assertCreated(fn (string $name, ?string $description) => $name === 'Knowledge Base');
Stores::assertNotCreated('Other Store');
Stores::assertNothingCreated();

Stores::assertDeleted('store_id');
Stores::assertNotDeleted('other_store_id');
Stores::assertNothingDeleted();
Auch Zusicherungen zu Dateioperationen an einem Store sind möglich.
$store = Stores::get('store_id');
$store->add('added_id');
$store->remove('removed_id');

$store->assertAdded('added_id');
$store->assertRemoved('removed_id');
$store->assertNotAdded('other_file_id');
$store->assertNotRemoved('other_file_id');

// Inhalte per Closure prüfen
$store->add(Document::fromString('Hello, World!', 'text/plain')->as('hello.txt'));
$store->assertAdded(fn (StorableFile $file) => $file->name() === 'hello.txt');
$store->assertAdded(fn (StorableFile $file) => $file->content() === 'Hello, World!');

Events

Das Laravel AI SDK dispatcht die folgenden Events. Durch Abonnieren dieser Events lassen sich Logging, Monitoring und Ähnliches umsetzen.
  • PromptingAgent — vor dem Senden eines Prompts
  • AgentPrompted — nach dem Senden eines Prompts
  • StreamingAgent — beim Start des Streamings
  • AgentStreamed — nach Abschluss des Streamings
  • InvokingTool — vor dem Aufruf eines Tools
  • ToolInvoked — nach dem Aufruf eines Tools
  • GeneratingImage — vor der Bildgenerierung
  • ImageGenerated — nach der Bildgenerierung
  • GeneratingAudio — vor der Audiogenerierung
  • AudioGenerated — nach der Audiogenerierung
  • GeneratingTranscription — vor der Transkription
  • TranscriptionGenerated — nach der Transkription
  • GeneratingEmbeddings — vor der Embedding-Erzeugung
  • EmbeddingsGenerated — nach der Embedding-Erzeugung
  • Reranking — vor dem Reranking
  • Reranked — nach dem Reranking
  • StoringFile — vor dem Speichern einer Datei
  • FileStored — nach dem Speichern einer Datei
  • FileDeleted — nach dem Löschen einer Datei
  • CreatingStore — vor dem Anlegen eines Stores
  • StoreCreated — nach dem Anlegen eines Stores
  • AddingFileToStore — vor dem Hinzufügen einer Datei zum Store
  • FileAddedToStore — nach dem Hinzufügen einer Datei zum Store
  • RemovingFileFromStore — vor dem Entfernen einer Datei aus dem Store
  • FileRemovedFromStore — nach dem Entfernen einer Datei aus dem Store
Zuletzt geändert am 13. Juli 2026