Skip to content

Laravel AI SDK

簡介

Laravel AI SDK 提供了一個統一且具表達力的 API,用於與 OpenAI、Anthropic、Gemini 等 AI 服務商進行互動。透過 AI SDK,您可以建構具有工具和結構化輸出的智慧 Agents、生成圖片、合成與轉錄音訊、建立向量嵌入 (Embeddings) 等等 — 所有的這一切都使用了統一且對 Laravel 友好的介面。

安裝

您可以透過 Composer 安裝 Laravel AI SDK:

shell
composer require laravel/ai

接著,您應該使用 vendor:publish Artisan 指令來發佈 AI SDK 的設定檔與遷移 (Migration) 檔案:

shell
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"

最後,您應該執行應用程式的資料庫遷移。這將會建立 agent_conversationsagent_conversation_messages 資料表,AI SDK 使用這些資料表來支援其對話儲存功能:

shell
php artisan migrate

設定

您可以在應用程式的 config/ai.php 設定檔中定義 AI 服務商的憑證,或是作為環境變數定義在應用程式的 .env 檔案中:

ini
ANTHROPIC_API_KEY=
COHERE_API_KEY=
ELEVENLABS_API_KEY=
GEMINI_API_KEY=
MISTRAL_API_KEY=
OLLAMA_API_KEY=
OPENAI_API_KEY=
JINA_API_KEY=
VOYAGEAI_API_KEY=
XAI_API_KEY=

用於文字、圖片、音訊、轉錄與嵌入的預設模型也可以在您應用程式的 config/ai.php 設定檔中進行設定。

自定義基礎 URL

預設情況下,Laravel AI SDK 會直接連接到各個服務商的公開 API 端點 (Endpoint)。然而,您可能需要透過不同的端點來路由請求 — 例如,當使用代理服務來集中管理 API 金鑰、實施速率限制,或透過企業閘道路由流量時。

您可以透過在服務商設定中加入 url 參數來設定自定義基礎 URL:

php
'providers' => [
    'openai' => [
        'driver' => 'openai',
        'key' => env('OPENAI_API_KEY'),
        'url' => env('OPENAI_BASE_URL'),
    ],

    'anthropic' => [
        'driver' => 'anthropic',
        'key' => env('ANTHROPIC_API_KEY'),
        'url' => env('ANTHROPIC_BASE_URL'),
    ],
],

這在透過代理服務(如 LiteLLM 或 Azure OpenAI Gateway)路由請求或使用替代端點時非常有用。

以下服務商支援自定義基礎 URL:OpenAI、Anthropic、Gemini、Groq、Cohere、DeepSeek、xAI 以及 OpenRouter。

服務商支援

AI SDK 的各項功能支援多種服務商。下表總結了每項功能可用的服務商:

功能服務商
文字OpenAI, Anthropic, Gemini, Azure, Groq, xAI, DeepSeek, Mistral, Ollama
圖片OpenAI, Gemini, xAI
TTSOpenAI, ElevenLabs
STTOpenAI, ElevenLabs, Mistral
嵌入OpenAI, Gemini, Azure, Cohere, Mistral, Jina, VoyageAI
重排Cohere, Jina
檔案OpenAI, Anthropic, Gemini

Laravel\Ai\Enums\Lab 列舉 (Enum) 可用於在整個程式碼中引用服務商,而不需要使用純字串:

php
use Laravel\Ai\Enums\Lab;

Lab::Anthropic;
Lab::OpenAI;
Lab::Gemini;
// ...

Agents

Agents 是在 Laravel AI SDK 中與 AI 服務商互動的基本構建塊。每個 Agent 都是一個專用的 PHP 類別,封裝了與大型語言模型互動所需的指令、對話上下文、工具和輸出架構 (Schema)。將 Agent 視為一個專業助理 —— 例如銷售教練、文件分析師、支援機器人 —— 您只需設定一次,便可在整個應用程式中根據需要進行提示 (Prompt)。

您可以透過 make:agent Artisan 指令建立 Agent:

shell
php artisan make:agent SalesCoach

php artisan make:agent SalesCoach --structured

在產生的 Agent 類別中,您可以定義系統提示 / 指令、訊息上下文、可用工具以及輸出架構(如果適用):

php
<?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) {}

    /**
     * Get the instructions that the agent should follow.
     */
    public function instructions(): Stringable|string
    {
        return 'You are a sales coach, analyzing transcripts and providing feedback and an overall sales strength score.';
    }

    /**
     * Get the list of messages comprising the conversation so far.
     */
    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();
    }

    /**
     * Get the tools available to the agent.
     *
     * @return Tool[]
     */
    public function tools(): iterable
    {
        return [
            new RetrievePreviousTranscripts,
        ];
    }

    /**
     * Get the agent's structured output schema definition.
     */
    public function schema(JsonSchema $schema): array
    {
        return [
            'feedback' => $schema->string()->required(),
            'score' => $schema->integer()->min(1)->max(10)->required(),
        ];
    }
}

提示 (Prompting)

要提示 Agent,請先使用 make 方法或標準實例化建立一個實例,然後呼叫 prompt

php
$response = (new SalesCoach)
    ->prompt('Analyze this sales transcript...');

$response = SalesCoach::make()
    ->prompt('Analyze this sales transcript...');

return (string) $response;

make 方法會從容器中解析您的 Agent,從而允許自動依賴注入。您也可以向 Agent 的建構函式傳遞參數:

php
$agent = SalesCoach::make(user: $user);

藉由向 prompt 方法傳遞額外的參數,您可以在提示時覆寫預設的服務商、模型或 HTTP 逾時時間:

php
$response = (new SalesCoach)->prompt(
    'Analyze this sales transcript...',
    provider: Lab::Anthropic,
    model: 'claude-haiku-4-5-20251001',
    timeout: 120,
);

對話上下文

如果您的 Agent 實作了 Conversational 介面,您可以使用 messages 方法來回傳先前的對話上下文(如果適用):

php
use App\Models\History;
use Laravel\Ai\Messages\Message;

/**
 * Get the list of messages comprising the conversation so far.
 */
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();
}

記住對話

注意: 在使用 RemembersConversations trait 之前,您應該使用 vendor:publish Artisan 指令發布並執行 AI SDK 遷移。這些遷移將建立儲存對話所需的資料庫資料表。

如果您希望 Laravel 自動為您的 Agent 儲存和檢索對話記錄,您可以使用 RemembersConversations trait。此 trait 提供了一種簡單的方法,可以將對話訊息持久化到資料庫中,而無需手動實作 Conversational 介面:

php
<?php

namespace App\Ai\Agents;

use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Promptable;

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

    /**
     * Get the instructions that the agent should follow.
     */
    public function instructions(): string
    {
        return 'You are a sales coach...';
    }
}

要為使用者開始新的對話,請在提示前呼叫 forUser 方法:

php
$response = (new SalesCoach)->forUser($user)->prompt('Hello!');

$conversationId = $response->conversationId;

對話 ID 會包含在回應中並可儲存以供日後參考,或者您可以直接從 agent_conversations 資料表中檢索使用者的所有對話。

要繼續現有的對話,請使用 continue 方法:

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

當使用 RemembersConversations trait 時,先前的訊息會在提示時自動載入並包含在對話上下文中。新的訊息(包括使用者和助理)會在每次互動後自動儲存。

結構化輸出

如果您希望您的 Agent 回傳結構化輸出,請實作 HasStructuredOutput 介面,這要求您的 Agent 定義一個 schema 方法:

php
<?php

namespace App\Ai\Agents;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasStructuredOutput;
use Laravel\Ai\Promptable;

class SalesCoach implements Agent, HasStructuredOutput
{
    use Promptable;

    // ...

    /**
     * Get the agent's structured output schema definition.
     */
    public function schema(JsonSchema $schema): array
    {
        return [
            'score' => $schema->integer()->required(),
        ];
    }
}

當提示一個回傳結構化輸出的 Agent 時,您可以像存取陣列一樣存取回傳的 StructuredAgentResponse

php
$response = (new SalesCoach)->prompt('Analyze this sales transcript...');

return $response['score'];

附件

提示時,您也可以隨提示傳遞附件,讓模型檢查圖片和文件:

php
use App\Ai\Agents\SalesCoach;
use Laravel\Ai\Files;

$response = (new SalesCoach)->prompt(
    'Analyze the attached sales transcript...',
    attachments: [
        Files\Document::fromStorage('transcript.pdf') // Attach a document from a filesystem disk...
        Files\Document::fromPath('/home/laravel/transcript.md') // Attach a document from a local path...
        $request->file('transcript'), // Attach an uploaded file...
    ]
);

同樣地,Laravel\Ai\Files\Image 類別可用於將圖片附加到提示中:

php
use App\Ai\Agents\ImageAnalyzer;
use Laravel\Ai\Files;

$response = (new ImageAnalyzer)->prompt(
    'What is in this image?',
    attachments: [
        Files\Image::fromStorage('photo.jpg') // Attach an image from a filesystem disk...
        Files\Image::fromPath('/home/laravel/photo.jpg') // Attach an image from a local path...
        $request->file('photo'), // Attach an uploaded file...
    ]
);

串流

您可以透過呼叫 stream 方法來串流 Agent 的回應。回傳的 StreamableAgentResponse 可以從路由中回傳,以自動向客戶端發送串流回應 (SSE):

php
use App\Ai\Agents\SalesCoach;

Route::get('/coach', function () {
    return (new SalesCoach)->stream('Analyze this sales transcript...');
});

then 方法可用於提供一個閉包 (Closure),該閉包將在整個回應都已串流至客戶端時被呼叫:

php
use App\Ai\Agents\SalesCoach;
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...
        });
});

或者,您可以手動遍歷串流事件:

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

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

使用 Vercel AI SDK 協定進行串流

您可以透過在可串流回應上呼叫 usingVercelDataProtocol 方法,來使用 Vercel AI SDK 串流協定 串流事件:

php
use App\Ai\Agents\SalesCoach;

Route::get('/coach', function () {
    return (new SalesCoach)
        ->stream('Analyze this sales transcript...')
        ->usingVercelDataProtocol();
});

廣播

您可以透過幾種不同的方式來廣播串流事件。首先,您可以簡單地對串流事件呼叫 broadcastbroadcastNow 方法:

php
use App\Ai\Agents\SalesCoach;
use Illuminate\Broadcasting\Channel;

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

foreach ($stream as $event) {
    $event->broadcast(new Channel('channel-name'));
}

或者,您可以呼叫 Agent 的 broadcastOnQueue 方法來將 Agent 操作排入佇列,並在串流事件可用時進行廣播:

php
(new SalesCoach)->broadcastOnQueue(
    'Analyze this sales transcript...'
    new Channel('channel-name'),
);

佇列

使用 Agent 的 queue 方法,您可以對 Agent 進行提示,但允許它在背景處理回應,從而保持您的應用程式反應迅速。thencatch 方法可用於註冊閉包,這些閉包將在回應可用或發生例外狀況時被呼叫:

php
use Illuminate\Http\Request;
use Laravel\Ai\Responses\AgentResponse;
use Throwable;

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

    return back();
});

工具

工具可用於賦予 Agent 額外的功能,讓它們在回應提示時可以使用。可以使用 make:tool Artisan 指令建立工具:

shell
php artisan make:tool RandomNumberGenerator

生成的工具將被放置在應用程式的 app/Ai/Tools 目錄中。每個工具都包含一個 handle 方法,當 Agent 需要使用該工具時會呼叫此方法:

php
<?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
{
    /**
     * Get the description of the tool's purpose.
     */
    public function description(): Stringable|string
    {
        return 'This tool may be used to generate cryptographically secure random numbers.';
    }

    /**
     * Execute the tool.
     */
    public function handle(Request $request): Stringable|string
    {
        return (string) random_int($request['min'], $request['max']);
    }

    /**
     * Get the tool's schema definition.
     */
    public function schema(JsonSchema $schema): array
    {
        return [
            'min' => $schema->integer()->min(0)->required(),
            'max' => $schema->integer()->required(),
        ];
    }
}

定義好工具後,您可以從任何 Agent 的 tools 方法中回傳它:

php
use App\Ai\Tools\RandomNumberGenerator;

/**
 * Get the tools available to the agent.
 *
 * @return Tool[]
 */
public function tools(): iterable
{
    return [
        new RandomNumberGenerator,
    ];
}

相似度搜尋

SimilaritySearch 工具允許 Agent 使用儲存在資料庫中的向量嵌入 (Vector Embeddings) 搜尋與給定查詢相似的文檔。當您想讓 Agent 存取並搜尋應用程式的資料以進行檢索增強生成 (RAG) 時,這非常有用。

建立相似度搜尋工具最簡單的方法是搭配具有向量嵌入的 Eloquent 模型使用 usingModel 方法:

php
use App\Models\Document;
use Laravel\Ai\Tools\SimilaritySearch;

public function tools(): iterable
{
    return [
        SimilaritySearch::usingModel(Document::class, 'embedding'),
    ];
}

第一個參數是 Eloquent 模型類別,第二個參數是包含向量嵌入的欄位。

您也可以提供介於 0.01.0 之間的最低相似度門檻,以及一個用於自定義查詢的閉包:

php
SimilaritySearch::usingModel(
    model: Document::class,
    column: 'embedding',
    minSimilarity: 0.7,
    limit: 10,
    query: fn ($query) => $query->where('published', true),
),

若要進行更多控制,您可以建立一個帶有自定義閉包的相似度搜尋工具,該閉包會回傳搜尋結果:

php
use App\Models\Document;
use Laravel\Ai\Tools\SimilaritySearch;

public function tools(): iterable
{
    return [
        new SimilaritySearch(using: function (string $query) {
            return Document::query()
                ->where('user_id', $this->user->id)
                ->whereVectorSimilarTo('embedding', $query)
                ->limit(10)
                ->get();
        }),
    ];
}

您可以使用 withDescription 方法來自定義工具的描述:

php
SimilaritySearch::usingModel(Document::class, 'embedding')
    ->withDescription('Search the knowledge base for relevant articles.'),

服務商工具

服務商工具是由 AI 服務商原生提供的特殊工具,具有網頁搜尋、URL 擷取和檔案搜尋等功能。與一般工具不同,服務商工具是由服務商本身執行,而非由您的應用程式執行。

服務商工具可以透過您的 Agent 的 tools 方法回傳。

網頁搜尋

WebSearch 服務商工具允許 Agents 搜尋網路以獲取即時資訊。這對於回答有關時事、近期數據或在模型訓練截止後可能已變更的主題非常有用。

支援的服務商: Anthropic, OpenAI, Gemini

php
use Laravel\Ai\Providers\Tools\WebSearch;

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

您可以設定網頁搜尋工具,以限制搜尋次數或將結果限制在特定網域:

php
(new WebSearch)->max(5)->allow(['laravel.com', 'php.net']),

若要根據使用者位置精確化搜尋結果,請使用 location 方法:

php
(new WebSearch)->location(
    city: 'New York',
    region: 'NY',
    country: 'US'
);

網頁擷取

WebFetch 服務商工具允許 Agents 擷取並讀取網頁內容。當您需要 Agent 分析特定的 URL 或從已知網頁獲取詳細資訊時,這非常有用。

支援的服務商: Anthropic, Gemini

php
use Laravel\Ai\Providers\Tools\WebFetch;

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

您可以設定網頁擷取工具,以限制擷取次數或限制在特定網域:

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

檔案搜尋

FileSearch 服務商工具允許 Agents 搜尋儲存在向量儲存 (vector stores)中的檔案。這透過允許 Agent 在您上傳的檔案中搜尋相關資訊,來實現檢索增強生成 (RAG)。

支援的服務商: OpenAI, Gemini

php
use Laravel\Ai\Providers\Tools\FileSearch;

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

您可以提供多個向量儲存 ID 以在多個儲存空間中搜尋:

php
new FileSearch(stores: ['store_1', 'store_2']);

如果您的檔案具有 metadata,您可以透過提供 where 參數來篩選搜尋結果。對於簡單的等值篩選,請傳遞一個陣列:

php
new FileSearch(stores: ['store_id'], where: [
    'author' => 'Taylor Otwell',
    'year' => 2026,
]);

對於更複雜的篩選條件,您可以傳遞一個接收 FileSearchQuery 實例的閉包:

php
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'])
);

中介層

Agents 支援中介層,允許您在提示 (Prompt) 發送到服務商之前攔截並修改它們。若要為 Agent 新增中介層,請實作 HasMiddleware 介面並定義一個回傳中介層類別陣列的 middleware 方法:

php
<?php

namespace App\Ai\Agents;

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

class SalesCoach implements Agent, HasMiddleware
{
    use Promptable;

    // ...

    /**
     * Get the agent's middleware.
     */
    public function middleware(): array
    {
        return [
            new LogPrompts,
        ];
    }
}

每個中介層類別都應定義一個 handle 方法,該方法接收 AgentPrompt 和一個用於將提示傳遞給下一個中介層的 Closure

php
<?php

namespace App\Ai\Middleware;

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

class LogPrompts
{
    /**
     * Handle the incoming prompt.
     */
    public function handle(AgentPrompt $prompt, Closure $next)
    {
        Log::info('Prompting agent', ['prompt' => $prompt->prompt]);

        return $next($prompt);
    }
}

您可以在回應上使用 then 方法,在 Agent 完成處理後執行程式碼。這適用於同步和串流回應:

php
public function handle(AgentPrompt $prompt, Closure $next)
{
    return $next($prompt)->then(function (AgentResponse $response) {
        Log::info('Agent responded', ['text' => $response->text]);
    });
}

匿名 Agents

有時您可能想快速與模型互動,而不想建立專用的 Agent 類別。您可以使用 agent 函式建立一個臨時的匿名 Agent:

php
use function Laravel\Ai\{agent};

$response = agent(
    instructions: 'You are an expert at software development.',
    messages: [],
    tools: [],
)->prompt('Tell me about Laravel')

匿名 Agents 也可以產生結構化輸出:

php
use Illuminate\Contracts\JsonSchema\JsonSchema;

use function Laravel\Ai\{agent};

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

Agent 設定

您可以使用 PHP 屬性 (Attributes) 為 Agent 設定文字生成選項。以下是可用的屬性:

  • MaxSteps: Agent 使用工具時可以執行的最大步驟數。
  • MaxTokens: 模型可以生成的最大 Token 數量。
  • Model: Agent 應使用的模型。
  • Provider: Agent 使用的 AI 服務商 (或用於故障轉移的服務商)。
  • Temperature: 用於生成的取樣溫度 (0.0 到 1.0)。
  • Timeout: Agent 請求的 HTTP 超時秒數 (預設:60)。
  • UseCheapestModel: 使用服務商最便宜的文字模型以進行成本優化。
  • UseSmartestModel: 使用服務商能力最強的文字模型以處理複雜任務。
php
<?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\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)]
class SalesCoach implements Agent
{
    use Promptable;

    // ...
}

UseCheapestModelUseSmartestModel 屬性允許您自動為特定服務商選擇最具成本效益或能力最強的模型,而無需指定模型名稱。當您想要在不同的服務商之間優化成本或能力時,這非常有用:

php
use Laravel\Ai\Attributes\UseCheapestModel;
use Laravel\Ai\Attributes\UseSmartestModel;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Promptable;

#[UseCheapestModel]
class SimpleSummarizer implements Agent
{
    use Promptable;

    // Will use the cheapest model (e.g., Haiku)...
}

#[UseSmartestModel]
class ComplexReasoner implements Agent
{
    use Promptable;

    // Will use the most capable model (e.g., Opus)...
}

圖片

Laravel\Ai\Image 類別可用於透過 openaigeminixai 服務商來產生圖片:

php
use Laravel\Ai\Image;

$image = Image::of('A donut sitting on the kitchen counter')->generate();

$rawContent = (string) $image;

squareportraitlandscape 方法可用於控制圖片的長寬比,而 quality 方法則可用於引導模型決定最終圖片的品質 (highmediumlow)。timeout 方法可用於指定 HTTP 超時時間(以秒為單位):

php
use Laravel\Ai\Image;

$image = Image::of('A donut sitting on the kitchen counter')
    ->quality('high')
    ->landscape()
    ->timeout(120)
    ->generate();

您可以使用 attachments 方法附加參考圖片:

php
use Laravel\Ai\Files;
use Laravel\Ai\Image;

$image = Image::of('Update this photo of me to be in the style of an impressionist painting.')
    ->attachments([
        Files\Image::fromStorage('photo.jpg'),
        // Files\Image::fromPath('/home/laravel/photo.jpg'),
        // Files\Image::fromUrl('https://example.com/photo.jpg'),
        // $request->file('photo'),
    ])
    ->landscape()
    ->generate();

產生的圖片可以輕鬆儲存在應用程式 config/filesystems.php 設定檔中設定的預設磁碟:

php
$image = Image::of('A donut sitting on the kitchen counter');

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

圖片產生也可以加入佇列:

php
use Laravel\Ai\Image;
use Laravel\Ai\Responses\ImageResponse;

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

        // ...
    });

音訊 (TTS)

Laravel\Ai\Audio 類別可用於從指定的文字產生音訊:

php
use Laravel\Ai\Audio;

$audio = Audio::of('I love coding with Laravel.')->generate();

$rawContent = (string) $audio;

malefemalevoice 方法可用於決定所產生音訊的聲音:

php
$audio = Audio::of('I love coding with Laravel.')
    ->female()
    ->generate();

$audio = Audio::of('I love coding with Laravel.')
    ->voice('voice-id-or-name')
    ->generate();

同樣地,instructions 方法可用於動態地指導模型所產生的音訊聽起來應該如何:

php
$audio = Audio::of('I love coding with Laravel.')
    ->female()
    ->instructions('Said like a pirate')
    ->generate();

產生的音訊可以輕鬆儲存在應用程式 config/filesystems.php 設定檔中設定的預設磁碟:

php
$audio = Audio::of('I love coding with Laravel.')->generate();

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

音訊產生也可以加入佇列:

php
use Laravel\Ai\Audio;
use Laravel\Ai\Responses\AudioResponse;

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

        // ...
    });

轉錄 (STT)

Laravel\Ai\Transcription 類別可用於為指定的音訊產生轉錄文字:

php
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;

diarize 方法可用於指示您希望回應除了包含原始文字轉錄外,還包含語音標記 (Diarized) 轉錄,讓您可以根據說話者來存取分段後的轉錄內容:

php
$transcript = Transcription::fromStorage('audio.mp3')
    ->diarize()
    ->generate();

轉錄產生也可以加入佇列:

php
use Laravel\Ai\Transcription;
use Laravel\Ai\Responses\TranscriptionResponse;

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

嵌入 (Embeddings)

您可以使用 Laravel 的 Stringable 類別中新增的 toEmbeddings 方法,輕鬆地為任何給定的字串生成向量嵌入 (Vector Embeddings):

php
use Illuminate\Support\Str;

$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();

或者,您也可以使用 Embeddings 類別一次為多個輸入生成嵌入:

php
use Laravel\Ai\Embeddings;

$response = Embeddings::for([
    'Napa Valley has great wine.',
    'Laravel is a PHP framework.',
])->generate();

$response->embeddings; // [[0.123, 0.456, ...], [0.789, 0.012, ...]]

您可以為嵌入指定維度 (Dimensions) 與服務商:

php
$response = Embeddings::for(['Napa Valley has great wine.'])
    ->dimensions(1536)
    ->generate(Lab::OpenAI, 'text-embedding-3-small');

查詢嵌入

生成嵌入後,您通常會將它們儲存在資料庫的 vector 欄位中,以便稍後查詢。Laravel 透過 pgvector 擴充功能為 PostgreSQL 的向量欄位提供原生支援。要開始使用,請在您的遷移 (Migration) 中定義一個 vector 欄位,並指定維度數量:

php
Schema::ensureVectorExtensionExists();

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

您還可以新增向量索引以加速相似度搜尋。當在向量欄位上呼叫 index 時,Laravel 會自動建立一個使用餘弦距離 (Cosine Distance) 的 HNSW 索引:

php
$table->vector('embedding', dimensions: 1536)->index();

在您的 Eloquent 模型上,您應該將向量欄位轉換為 array

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

要查詢相似的記錄,請使用 whereVectorSimilarTo 方法。此方法會根據最小餘弦相似度(介於 0.01.0 之間,1.0 為完全相同)過濾結果,並按相似度排序結果:

php
use App\Models\Document;

$documents = Document::query()
    ->whereVectorSimilarTo('embedding', $queryEmbedding, minSimilarity: 0.4)
    ->limit(10)
    ->get();

$queryEmbedding 可以是浮點數陣列或純字串。當提供字串時,Laravel 將自動為其生成嵌入:

php
$documents = Document::query()
    ->whereVectorSimilarTo('embedding', 'best wineries in Napa Valley')
    ->limit(10)
    ->get();

如果您需要更多控制,可以獨立使用底層的 whereVectorDistanceLessThanselectVectorDistance 以及 orderByVectorDistance 方法:

php
$documents = Document::query()
    ->select('*')
    ->selectVectorDistance('embedding', $queryEmbedding, as: 'distance')
    ->whereVectorDistanceLessThan('embedding', $queryEmbedding, maxDistance: 0.3)
    ->orderByVectorDistance('embedding', $queryEmbedding)
    ->limit(10)
    ->get();

如果您想讓 Agent 能夠執行相似度搜尋作為一項工具,請查看 相似度搜尋 (Similarity Search) 工具文件。

📌 備註

向量查詢目前僅支援使用 pgvector 擴充功能的 PostgreSQL 連線。

快取嵌入

嵌入生成可以進行快取,以避免對相同輸入進行多餘的 API 呼叫。要啟用快取,請將 ai.caching.embeddings.cache 設定選項設為 true

php
'caching' => [
    'embeddings' => [
        'cache' => true,
        'store' => env('CACHE_STORE', 'database'),
        // ...
    ],
],

啟用快取時,嵌入將會被快取 30 天。快取鍵 (Cache Key) 是根據服務商、模型、維度和輸入內容生成的,確保相同的請求會回傳快取的結果,而不同的設定則會生成新的嵌入。

即使全域快取已停用,您也可以使用 cache 方法為特定請求啟用快取:

php
$response = Embeddings::for(['Napa Valley has great wine.'])
    ->cache()
    ->generate();

您可以指定自定義的快取持續時間(以秒為單位):

php
$response = Embeddings::for(['Napa Valley has great wine.'])
    ->cache(seconds: 3600) // Cache for 1 hour
    ->generate();

toEmbeddings Stringable 方法也接受一個 cache 引數:

php
// Cache with default duration...
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: true);

// Cache for a specific duration...
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: 3600);

重排 (Reranking)

重排 (Reranking) 允許您根據文件與給定查詢的相關性重新排序文件列表。這對於透過語義理解來改善搜尋結果非常有用:

Laravel\Ai\Reranking 類別可用於重排文件:

php
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');

// Access the top result...
$response->first()->document; // "Laravel is a PHP web application framework."
$response->first()->score;    // 0.95
$response->first()->index;    // 1 (original position)

limit 方法可用於限制回傳的結果數量:

php
$response = Reranking::of($documents)
    ->limit(5)
    ->rerank('search query');

重排集合 (Collections)

為了方便起見,可以使用 rerank 巨集對 Laravel 集合 (Collections) 進行重排。第一個引數指定用於重排的欄位,第二個引數則是查詢:

php
// Rerank by a single field...
$posts = Post::all()
    ->rerank('body', 'Laravel tutorials');

// Rerank by multiple fields (sent as JSON)...
$reranked = $posts->rerank(['title', 'body'], 'Laravel tutorials');

// Rerank using a closure to build the document...
$reranked = $posts->rerank(
    fn ($post) => $post->title.': '.$post->body,
    'Laravel tutorials'
);

您也可以限制結果數量並指定服務商:

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

檔案

Laravel\Ai\Files 類別或個別的檔案類別可用於將檔案儲存在您的 AI 服務商中,以便稍後在對話中使用。這對於大型文件或您想要多次引用而不想重複上傳的檔案非常有用:

php
use Laravel\Ai\Files\Document;
use Laravel\Ai\Files\Image;

// Store a file from a local path...
$response = Document::fromPath('/home/laravel/document.pdf')->put();
$response = Image::fromPath('/home/laravel/photo.jpg')->put();

// Store a file that is stored on a filesystem disk...
$response = Document::fromStorage('document.pdf', disk: 'local')->put();
$response = Image::fromStorage('photo.jpg', disk: 'local')->put();

// Store a file that is stored on a remote URL...
$response = Document::fromUrl('https://example.com/document.pdf')->put();
$response = Image::fromUrl('https://example.com/photo.jpg')->put();

return $response->id;

您也可以儲存原始內容或上傳的檔案:

php
use Laravel\Ai\Files;
use Laravel\Ai\Files\Document;

// Store raw content...
$stored = Document::fromString('Hello, World!', 'text/plain')->put();

// Store an uploaded file...
$stored = Document::fromUpload($request->file('document'))->put();

檔案儲存後,您可以在透過 Agents 生成文字時引用該檔案,而不需要重新上傳:

php
use App\Ai\Agents\SalesCoach;
use Laravel\Ai\Files;

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

若要擷取先前儲存的檔案,請在檔案實例上使用 get 方法:

php
use Laravel\Ai\Files\Document;

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

$file->id;
$file->mimeType();

若要從服務商刪除檔案,請使用 delete 方法:

php
Document::fromId('file-id')->delete();

預設情況下,Files 類別會使用您應用程式的 config/ai.php 設定檔中所設定的預設 AI 服務商。對於大多數操作,您可以使用 provider 引數指定不同的服務商:

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

在對話中使用儲存的檔案

檔案儲存在服務商後,您可以在 Agent 對話中使用 DocumentImage 類別的 fromId 方法來引用它:

php
use App\Ai\Agents\DocumentAnalyzer;
use Laravel\Ai\Files;
use Laravel\Ai\Files\Document;

$stored = Document::fromPath('/path/to/report.pdf')->put();

$response = (new DocumentAnalyzer)->prompt(
    'Summarize this document.',
    attachments: [
        Document::fromId($stored->id),
    ],
);

同樣地,儲存的圖片可以使用 Image 類別來引用:

php
use Laravel\Ai\Files;
use Laravel\Ai\Files\Image;

$stored = Image::fromPath('/path/to/photo.jpg')->put();

$response = (new ImageAnalyzer)->prompt(
    'What is in this image?',
    attachments: [
        Image::fromId($stored->id),
    ],
);

向量儲存 (Vector Stores)

向量儲存允許您建立可搜尋的檔案集合,這些集合可用於檢索增強生成 (RAG)。Laravel\Ai\Stores 類別提供了建立、擷取和刪除向量儲存的方法:

php
use Laravel\Ai\Stores;

// Create a new vector store...
$store = Stores::create('Knowledge Base');

// Create a store with additional options...
$store = Stores::create(
    name: 'Knowledge Base',
    description: 'Documentation and reference materials.',
    expiresWhenIdleFor: days(30),
);

return $store->id;

若要透過 ID 擷取現有的向量儲存,請使用 get 方法:

php
use Laravel\Ai\Stores;

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

$store->id;
$store->name;
$store->fileCounts;
$store->ready;

若要刪除向量儲存,請在 Stores 類別或儲存實例上使用 delete 方法:

php
use Laravel\Ai\Stores;

// Delete by ID...
Stores::delete('store_id');

// Or delete via a store instance...
$store = Stores::get('store_id');

$store->delete();

將檔案新增至儲存空間

擁有向量儲存後,您可以使用 add 方法將 檔案 新增至其中。新增到儲存空間的檔案會自動建立索引,以便使用 服務商檔案搜尋工具 進行語義搜尋:

php
use Laravel\Ai\Files\Document;
use Laravel\Ai\Stores;

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

// Add a file that has already been stored with the provider...
$document = $store->add('file_id');
$document = $store->add(Document::fromId('file_id'));

// Or, store and add a file in one step...
$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;

注意: 通常,在將先前儲存的檔案新增到向量儲存時,回傳的文件 ID 會與檔案先前分配的 ID 一致;然而,某些向量儲存服務商可能會回傳一個新的、不同的「文件 ID」。因此,建議您始終在資料庫中儲存這兩個 ID 以供將來引用。

將檔案新增到儲存空間時,您可以為其附加元資料。稍後使用 服務商檔案搜尋工具 時,這些元資料可用於過濾搜尋結果:

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

若要從儲存空間中移除檔案,請使用 remove 方法:

php
$store->remove('file_id');

從向量儲存中移除檔案並不會從服務商的 檔案儲存 中移除它。若要從向量儲存中移除檔案並從檔案儲存中永久刪除它,請使用 deleteFile 引數:

php
$store->remove('file_abc123', deleteFile: true);

故障轉移 (Failover)

當進行提示或生成其他媒體時,您可以提供一個服務商 / 模型的陣列,以便在主要服務商遇到服務中斷或速率限制時,自動故障轉移到備用服務商 / 模型:

php
use App\Ai\Agents\SalesCoach;
use Laravel\Ai\Image;

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

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

測試

Agents

若要在測試期間模擬 Agent 的回應,請在 Agent 類別上呼叫 fake 方法。您可以選擇性地提供一個回應陣列或一個閉包 (Closure):

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

// Automatically generate a fixed response for every prompt...
SalesCoach::fake();

// Provide a list of prompt responses...
SalesCoach::fake([
    'First response',
    'Second response',
]);

// Dynamically handle prompt responses based on the incoming prompt...
SalesCoach::fake(function (AgentPrompt $prompt) {
    return 'Response for: '.$prompt->prompt;
});

注意: 當在回傳結構化輸出的 Agent 上呼叫 Agent::fake() 時,Laravel 將會自動產生符合您 Agent 定義的輸出結構 (Schema) 的假資料。

在對 Agent 進行提示後,您可以對收到的提示進行斷言:

php
use Laravel\Ai\Prompts\AgentPrompt;

SalesCoach::assertPrompted('Analyze this...');

SalesCoach::assertPrompted(function (AgentPrompt $prompt) {
    return $prompt->contains('Analyze');
});

SalesCoach::assertNotPrompted('Missing prompt');

SalesCoach::assertNeverPrompted();

對於已排入佇列的 Agent 調用,請使用佇列斷言方法:

php
use Laravel\Ai\QueuedAgentPrompt;

SalesCoach::assertQueued('Analyze this...');

SalesCoach::assertQueued(function (QueuedAgentPrompt $prompt) {
    return $prompt->contains('Analyze');
});

SalesCoach::assertNotQueued('Missing prompt');

SalesCoach::assertNeverQueued();

為了確保所有 Agent 調用都有對應的模擬回應,您可以使用 preventStrayPrompts。如果調用 Agent 時沒有定義模擬回應,系統將會拋出一個例外狀況:

php
SalesCoach::fake()->preventStrayPrompts();

圖片

可以透過在 Image 類別上呼叫 fake 方法來模擬圖片生成。一旦圖片被模擬後,就可以針對記錄的圖片生成提示進行各種斷言:

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

// Automatically generate a fixed response for every prompt...
Image::fake();

// Provide a list of prompt responses...
Image::fake([
    base64_encode($firstImage),
    base64_encode($secondImage),
]);

// Dynamically handle prompt responses based on the incoming prompt...
Image::fake(function (ImagePrompt $prompt) {
    return base64_encode('...');
});

在產生圖片後,您可以對收到的提示進行斷言:

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

Image::assertNotGenerated('Missing prompt');

Image::assertNothingGenerated();

對於已排入佇列的圖片生成,請使用佇列斷言方法:

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

Image::assertNotQueued('Missing prompt');

Image::assertNothingQueued();

為了確保所有產生的圖片都有對應的模擬回應,您可以使用 preventStrayImages。如果生成圖片時沒有定義模擬回應,系統將會拋出一個例外狀況:

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

音訊

可以透過在 Audio 類別上呼叫 fake 方法來模擬音訊生成。一旦音訊被模擬後,就可以針對記錄的音訊生成提示進行各種斷言:

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

// Automatically generate a fixed response for every prompt...
Audio::fake();

// Provide a list of prompt responses...
Audio::fake([
    base64_encode($firstAudio),
    base64_encode($secondAudio),
]);

// Dynamically handle prompt responses based on the incoming prompt...
Audio::fake(function (AudioPrompt $prompt) {
    return base64_encode('...');
});

在產生音訊後,您可以對收到的提示進行斷言:

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

Audio::assertNotGenerated('Missing prompt');

Audio::assertNothingGenerated();

對於已排入佇列的音訊生成,請使用佇列斷言方法:

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

Audio::assertNotQueued('Missing prompt');

Audio::assertNothingQueued();

為了確保所有產生的音訊都有對應的模擬回應,您可以使用 preventStrayAudio。如果生成音訊時沒有定義模擬回應,系統將會拋出一個例外狀況:

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

轉錄

可以透過在 Transcription 類別上呼叫 fake 方法來模擬轉錄產生。一旦轉錄被模擬後,就可以針對記錄的轉錄產生提示進行各種斷言:

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

// Automatically generate a fixed response for every prompt...
Transcription::fake();

// Provide a list of prompt responses...
Transcription::fake([
    'First transcription text.',
    'Second transcription text.',
]);

// Dynamically handle prompt responses based on the incoming prompt...
Transcription::fake(function (TranscriptionPrompt $prompt) {
    return 'Transcribed text...';
});

在產生轉錄後,您可以對收到的提示進行斷言:

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

Transcription::assertNotGenerated(
    fn (TranscriptionPrompt $prompt) => $prompt->language === 'fr'
);

Transcription::assertNothingGenerated();

對於已排入佇列的轉錄生成,請使用佇列斷言方法:

php
Transcription::assertQueued(
    fn (QueuedTranscriptionPrompt $prompt) => $prompt->isDiarized()
);

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

Transcription::assertNothingQueued();

為了確保所有產生的轉錄都有對應的模擬回應,您可以使用 preventStrayTranscriptions。如果產生轉錄時沒有定義模擬回應,系統將會拋出一個例外狀況:

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

嵌入

嵌入生成可以透過在 Embeddings 類別上呼叫 fake 方法來模擬。一旦模擬了嵌入,就可以對記錄的嵌入生成提示進行各種斷言:

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

// Automatically generate fake embeddings of the proper dimensions for every prompt...
Embeddings::fake();

// Provide a list of prompt responses...
Embeddings::fake([
    [$firstEmbeddingVector],
    [$secondEmbeddingVector],
]);

// Dynamically handle prompt responses based on the incoming prompt...
Embeddings::fake(function (EmbeddingsPrompt $prompt) {
    return array_map(
        fn () => Embeddings::fakeEmbedding($prompt->dimensions),
        $prompt->inputs
    );
});

在生成嵌入之後,您可以對收到的提示進行斷言:

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

Embeddings::assertNotGenerated(
    fn (EmbeddingsPrompt $prompt) => $prompt->contains('Other')
);

Embeddings::assertNothingGenerated();

對於進入佇列的嵌入生成,請使用佇列斷言方法:

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

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

Embeddings::assertNothingQueued();

為了確保所有嵌入生成都有對應的模擬回應,您可以使用 preventStrayEmbeddings。如果生成嵌入時沒有定義模擬回應,則會拋出異常:

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

重排

重排操作可以透過在 Reranking 類別上呼叫 fake 方法來模擬:

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

// Automatically generate a fake reranked responses...
Reranking::fake();

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

在重排之後,您可以對執行的操作進行斷言:

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

Reranking::assertNotReranked(
    fn (RerankingPrompt $prompt) => $prompt->contains('Django')
);

Reranking::assertNothingReranked();

檔案

檔案操作可以透過在 Files 類別上呼叫 fake 方法來模擬:

php
use Laravel\Ai\Files;

Files::fake();

一旦模擬了檔案操作,您就可以對發生的上傳與刪除進行斷言:

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

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

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

Files::assertNotStored(fn (StorableFile $file) =>
    (string) $file === 'Hello, World!'
);

Files::assertNothingStored();

若要針對檔案刪除進行斷言,您可以傳遞一個檔案 ID:

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

向量儲存

向量儲存操作可以透過在 Stores 類別上呼叫 fake 方法來模擬。模擬儲存也會自動模擬 檔案操作

php
use Laravel\Ai\Stores;

Stores::fake();

一旦模擬了儲存操作,您就可以對建立或刪除的儲存空間進行斷言:

php
use Laravel\Ai\Stores;

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

// Make assertions...
Stores::assertCreated('Knowledge Base');

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

Stores::assertNotCreated('Other Store');

Stores::assertNothingCreated();

若要針對儲存空間刪除進行斷言,您可以提供儲存空間 ID:

php
Stores::assertDeleted('store_id');
Stores::assertNotDeleted('other_store_id');
Stores::assertNothingDeleted();

若要斷言檔案是否已新增至儲存空間或從中移除,請在給定的 Store 執行個體上使用斷言方法:

php
Stores::fake();

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

// Add / remove files...
$store->add('added_id');
$store->remove('removed_id');

// Make assertions...
$store->assertAdded('added_id');
$store->assertRemoved('removed_id');

$store->assertNotAdded('other_file_id');
$store->assertNotRemoved('other_file_id');

如果檔案儲存在服務商的 檔案儲存 中,並在同一個請求中新增到向量儲存,您可能不知道檔案的服務商 ID。在這種情況下,您可以將一個閉包 (Closure) 傳遞給 assertAdded 方法,以針對新增檔案的內容進行斷言:

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

$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)

Laravel AI SDK 會發送多種 事件 (events),包含:

  • AddingFileToStore
  • AgentPrompted
  • AgentStreamed
  • AudioGenerated
  • CreatingStore
  • EmbeddingsGenerated
  • FileAddedToStore
  • FileDeleted
  • FileRemovedFromStore
  • FileStored
  • GeneratingAudio
  • GeneratingEmbeddings
  • GeneratingImage
  • GeneratingTranscription
  • ImageGenerated
  • InvokingTool
  • PromptingAgent
  • RemovingFileFromStore
  • Reranked
  • Reranking
  • StoreCreated
  • StoringFile
  • StreamingAgent
  • ToolInvoked
  • TranscriptionGenerated

您可以監聽這些事件中的任何一個,以記錄或儲存 AI SDK 的使用資訊。