> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel AI SDK

> Der vollständige Leitfaden zum Laravel AI SDK, das mehrere KI-Anbieter wie OpenAI, Anthropic und Gemini über eine einheitliche Schnittstelle bereitstellt. Behandelt werden Agenten, Bildgenerierung, Audio, Embeddings und das Testen.

## Einführung

Das [Laravel AI SDK](https://github.com/laravel/ai) 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.

<Info>
  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.
</Info>

## Übersicht der unterstützten Anbieter

| Funktion              | Unterstützte Anbieter                                                                                          |
| --------------------- | -------------------------------------------------------------------------------------------------------------- |
| Textgenerierung       | OpenAI, OpenAI Compatible, Anthropic, Gemini, Azure, Bedrock, Groq, xAI, DeepSeek, Mistral, Ollama, OpenRouter |
| Bildgenerierung       | OpenAI, Gemini, xAI, Azure, Bedrock, OpenRouter                                                                |
| Sprachsynthese (TTS)  | OpenAI, ElevenLabs, Gemini                                                                                     |
| Spracherkennung (STT) | OpenAI, ElevenLabs, Mistral, Gemini                                                                            |
| Embeddings            | OpenAI, Gemini, Azure, Bedrock, Cohere, Mistral, Jina, VoyageAI, Ollama, OpenRouter                            |
| Reranking             | Cohere, Jina, VoyageAI                                                                                         |
| Dateien               | OpenAI, Anthropic, Gemini, Azure                                                                               |

## Installation

<Steps>
  <Step title="Paket installieren">
    Installieren Sie das Laravel AI SDK über Composer.

    ```shell theme={null}
    composer require laravel/ai
    ```
  </Step>

  <Step title="Konfigurationsdatei und Migrationen veröffentlichen">
    Veröffentlichen Sie die Konfigurationsdatei und die Migrationen mit dem Artisan-Befehl `vendor:publish`.

    ```shell theme={null}
    php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
    ```
  </Step>

  <Step title="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.

    ```shell theme={null}
    php artisan migrate
    ```
  </Step>
</Steps>

## Konfiguration

### Umgebungsvariablen

Tragen Sie in Ihre `.env`-Datei die API-Schlüssel der KI-Anbieter ein, die Sie verwenden möchten.

```ini theme={null}
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.

```php theme={null}
'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.

```php theme={null}
'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.

```php theme={null}
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.

```php theme={null}
'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](#anbieteroptionen).

### Lab-Enum

Verwenden Sie das `Lab`-Enum, um Anbieter im Code zu referenzieren.

```php theme={null}
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.

```shell theme={null}
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 theme={null}
<?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(),
        ];
    }
}
```

```mermaid theme={null}
flowchart TD
    A["Prompt des Nutzers"] --> B["Agent::prompt()"]
    B --> C["Optionen anhängen"]
    C -->|"bei Conversational"| D["Gesprächsverlauf anhängen"]
    C -->|"bei HasTools"| E["Toolliste anhängen"]
    C -->|"bei HasStructuredOutput"| F["JSON-Schema anhängen"]
    D --> G["An den KI-Anbieter senden"]
    E --> G
    F --> G
    B --> G
    G --> H["Antwort"]
    H -->|"Tool-Aufruf"| I["Tool ausführen"]
    I --> G
    H -->|"fertig"| J["AgentResponse"]
```

### Prompt

Über die Methode `prompt()` senden Sie eine Nachricht an den Agenten.

```php theme={null}
$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.

```php theme={null}
$agent = SalesCoach::make(user: $user);
```

Anbieter, Modell und Timeout lassen sich als Argumente von `prompt()` überschreiben.

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
public function schema(JsonSchema $schema): array
{
    return ['score' => $schema->integer()->required()];
}

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

#### Verschachtelte Objekte

```php theme={null}
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

```php theme={null}
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`.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
(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 theme={null}
<?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.

```php theme={null}
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.

```shell theme={null}
php artisan make:tool RandomNumberGenerator
```

```php theme={null}
<?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.

```php theme={null}
public function tools(): iterable
{
    return [new RandomNumberGenerator];
}
```

#### Ähnlichkeitssuche als Tool

Ein Tool für die Ähnlichkeitssuche mit Vektor-Embeddings lässt sich unkompliziert einbinden.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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](/de/filesystem) 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.

```php theme={null}
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`.

```php theme={null}
return FileStorage::readOnly('local');
```

Diese Methoden liefern eine `Illuminate\Support\Collection` zurück, sodass Sie die bereitgestellten Tools weiter filtern können.

```php theme={null}
use Laravel\Ai\Tools\Filesystem\DeleteFile;

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

### MCP-Tools

Wenn Ihre Anwendung [Laravel MCP](/de/mcp) verwendet, können Sie Ihrem Agenten die Tools bereitstellen, die ein [Model-Context-Protocol](https://modelcontextprotocol.io)-Server veröffentlicht. Mit dem [Laravel-MCP-Client](/de/mcp#mcp-client) können Sie sich mit entfernten oder lokalen MCP-Servern verbinden und deren Tools direkt an den Agenten übergeben.

<Info>
  Für die Nutzung von MCP-Tools muss das Paket [Laravel MCP](/de/mcp) in Ihrer Anwendung installiert sein.
</Info>

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.

```php theme={null}
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](/de/mcp#named-clients) verwenden.

```php theme={null}
use Laravel\Mcp\Facades\Mcp;

public function tools(): iterable
{
    return [
        ...Mcp::client('github')->tools(),
    ];
}
```

Ebenso können Sie sich mit einem [lokalen MCP-Server](/de/mcp#client-connecting) verbinden.

```php theme={null}
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](/de/mcp#mcp-client).

### 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.

```php theme={null}
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.

```php theme={null}
(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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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 theme={null}
<?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 theme={null}
<?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.

```shell theme={null}
php artisan make:agent-middleware LogPrompts
```

Lassen Sie den Agenten das Interface `HasMiddleware` implementieren und registrieren Sie die Middleware in der Methode `middleware()`.

```php theme={null}
<?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 theme={null}
<?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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

| Attribut              | Beschreibung                                          |
| --------------------- | ----------------------------------------------------- |
| `#[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 theme={null}
<?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.

```php theme={null}
// 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 theme={null}
<?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.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
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

```php theme={null}
$path = $image->store();
$path = $image->storeAs('image.jpg');
$path = $image->storePublicly();
$path = $image->storePubliclyAs('image.jpg');
```

### Bildgenerierung per Queue

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
$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

```php theme={null}
$path = $audio->store();
$path = $audio->storeAs('audio.mp3');
$path = $audio->storePublicly();
$path = $audio->storePubliclyAs('audio.mp3');
```

### Sprachsynthese per Queue

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
$transcript = Transcription::fromStorage('audio.mp3')->diarize()->generate();
```

### Transkription per Queue

```php theme={null}
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.

```php theme={null}
use Illuminate\Support\Str;

// Über Stringable
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();
```

```php theme={null}
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.

```php theme={null}
$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.

<Steps>
  <Step title="Migration erstellen">
    ```php theme={null}
    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();
    ```
  </Step>

  <Step title="Model konfigurieren">
    ```php theme={null}
    protected function casts(): array
    {
        return ['embedding' => 'array'];
    }
    ```
  </Step>

  <Step title="Ähnlichkeitssuche">
    ```php theme={null}
    // 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();
    ```
  </Step>
</Steps>

Es stehen auch Low-Level-Methoden zur Verfügung.

```php theme={null}
$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.

```php theme={null}
'caching' => [
    'embeddings' => [
        'cache' => true,
        'store' => env('CACHE_STORE', 'database'),
    ],
],
```

Sie können den Cache auch pro Anfrage steuern.

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
$response = Reranking::of($documents)->limit(5)->rerank('search query');
```

### Reranking von Collections

Eloquent-Collections lassen sich direkt reranken.

```php theme={null}
// 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.

```php theme={null}
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.

```php theme={null}
$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.

```php theme={null}
use Laravel\Ai\Files;

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

### Dateien abrufen und löschen

```php theme={null}
// Abrufen
$file = Document::fromId('file-id')->get();
$file->id;
$file->mimeType();

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

### Anbieter angeben

```php theme={null}
$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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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

```php theme={null}
$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.

```php theme={null}
$store->add(
    Document::fromPath('/path/to/document.pdf'),
    metadata: [
        'author' => 'Taylor Otwell',
        'department' => 'Engineering',
        'year' => 2026,
    ]
);
```

### Dateien aus einem Store entfernen

```php theme={null}
$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.

```php theme={null}
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

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
SalesCoach::fake([
    ['score' => 87],
]);
```

<Info>
  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.
</Info>

Zum Testen anonymer Agenten verwenden Sie `AnonymousAgent::fake()`.

```php theme={null}
use Laravel\Ai\AnonymousAgent;

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

### Bildgenerierung testen

```php theme={null}
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

```php theme={null}
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

```php theme={null}
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

```php theme={null}
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

```php theme={null}
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

```php theme={null}
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

```php theme={null}
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.

```php theme={null}
$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.

<AccordionGroup>
  <Accordion title="Agenten">
    * `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
  </Accordion>

  <Accordion title="Bilder, Audio und Transkription">
    * `GeneratingImage` — vor der Bildgenerierung
    * `ImageGenerated` — nach der Bildgenerierung
    * `GeneratingAudio` — vor der Audiogenerierung
    * `AudioGenerated` — nach der Audiogenerierung
    * `GeneratingTranscription` — vor der Transkription
    * `TranscriptionGenerated` — nach der Transkription
  </Accordion>

  <Accordion title="Embeddings und Reranking">
    * `GeneratingEmbeddings` — vor der Embedding-Erzeugung
    * `EmbeddingsGenerated` — nach der Embedding-Erzeugung
    * `Reranking` — vor dem Reranking
    * `Reranked` — nach dem Reranking
  </Accordion>

  <Accordion title="Dateien und Stores">
    * `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
  </Accordion>
</AccordionGroup>


## Related topics

- [Übersicht der neuen Features in Laravel 13](/de/blog/laravel-13-new-features.md)
- [Laravel-Updates März 2026](/de/blog/changelog/202603.md)
- [Laravel AI SDK-Integration](/de/packages/laravel-copilot-sdk/ai-sdk.md)
- [Laravel-AI-SDK-Integration - VOICEVOX für Laravel](/de/packages/laravel-voicevox/ai-sdk.md)
- [Amazon-Bedrock-Treiber für das Laravel AI SDK](/de/packages/laravel-amazon-bedrock.md)
