跳转至内容

Laravel AI SDK

简介

Laravel AI SDK 提供了一个统一且富有表现力的 API,用于与 OpenAI、Anthropic、Gemini 等 AI 提供商进行交互。利用 AI SDK,你可以构建具备工具调用和结构化输出能力的智能体、生成图像、合成及转录音频、创建向量嵌入等等——所有这些都通过一个统一且符合 Laravel 习惯的接口实现。

安装

你可以通过 Composer 安装 Laravel AI SDK:

1composer require laravel/ai

接下来,你应该使用 vendor:publish Artisan 命令发布 AI SDK 的配置文件和迁移文件:

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

最后,你应该运行应用程序的数据库迁移。这将创建 agent_conversationsagent_conversation_messages 数据表,AI SDK 使用它们来驱动其对话存储功能。

1php artisan migrate

配置

你可以在应用程序的 config/ai.php 配置文件中定义 AI 提供商凭据,或者将其作为环境变量存放在应用程序的 .env 文件中。

1ANTHROPIC_API_KEY=
2COHERE_API_KEY=
3ELEVENLABS_API_KEY=
4GEMINI_API_KEY=
5MISTRAL_API_KEY=
6OLLAMA_API_KEY=
7OPENAI_API_KEY=
8JINA_API_KEY=
9VOYAGEAI_API_KEY=
10XAI_API_KEY=

用于文本、图像、音频、转录和嵌入的默认模型也可以在应用程序的 config/ai.php 配置文件中进行配置。

自定义基础 URL

默认情况下,Laravel AI SDK 直接连接到每个提供商的公共 API 端点。然而,你可能需要通过不同的端点路由请求——例如,当使用代理服务来集中管理 API 密钥、实施速率限制或通过企业网关路由流量时。

你可以通过在提供商配置中添加 url 参数来配置自定义基础 URL。

1'providers' => [
2 'openai' => [
3 'driver' => 'openai',
4 'key' => env('OPENAI_API_KEY'),
5 'url' => env('OPENAI_BASE_URL'),
6 ],
7 
8 'anthropic' => [
9 'driver' => 'anthropic',
10 'key' => env('ANTHROPIC_API_KEY'),
11 'url' => env('ANTHROPIC_BASE_URL'),
12 ],
13],

这在通过代理服务(如 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
TTS OpenAI, ElevenLabs
STT OpenAI, ElevenLabs, Mistral
嵌入 (Embeddings) OpenAI, Gemini, Azure, Cohere, Mistral, Jina, VoyageAI
重排序 (Reranking) Cohere, Jina
文件 OpenAI, Anthropic, Gemini

Laravel\Ai\Enums\Lab 枚举可以在代码中引用提供商,而无需直接使用字符串。

1use Laravel\Ai\Enums\Lab;
2 
3Lab::Anthropic;
4Lab::OpenAI;
5Lab::Gemini;
6// ...

智能体 (Agents)

智能体(Agents)是 Laravel AI SDK 中与 AI 提供商交互的基础构建块。每个智能体都是一个专门的 PHP 类,封装了与大语言模型交互所需的指令、对话上下文、工具和输出模式。可以将智能体视为一个专业助手——如销售教练、文档分析师或客服机器人——你在应用程序中配置一次,即可根据需要随时调用。

你可以通过 make:agent Artisan 命令创建智能体。

1php artisan make:agent SalesCoach
2 
3php artisan make:agent SalesCoach --structured

在生成的智能体类中,你可以定义系统提示词(指令)、消息上下文、可用工具以及输出模式(如果适用)。

1<?php
2 
3namespace App\Ai\Agents;
4 
5use App\Ai\Tools\RetrievePreviousTranscripts;
6use App\Models\History;
7use App\Models\User;
8use Illuminate\Contracts\JsonSchema\JsonSchema;
9use Laravel\Ai\Contracts\Agent;
10use Laravel\Ai\Contracts\Conversational;
11use Laravel\Ai\Contracts\HasStructuredOutput;
12use Laravel\Ai\Contracts\HasTools;
13use Laravel\Ai\Messages\Message;
14use Laravel\Ai\Promptable;
15use Stringable;
16 
17class SalesCoach implements Agent, Conversational, HasTools, HasStructuredOutput
18{
19 use Promptable;
20 
21 public function __construct(public User $user) {}
22 
23 /**
24 * Get the instructions that the agent should follow.
25 */
26 public function instructions(): Stringable|string
27 {
28 return 'You are a sales coach, analyzing transcripts and providing feedback and an overall sales strength score.';
29 }
30 
31 /**
32 * Get the list of messages comprising the conversation so far.
33 */
34 public function messages(): iterable
35 {
36 return History::where('user_id', $this->user->id)
37 ->latest()
38 ->limit(50)
39 ->get()
40 ->reverse()
41 ->map(function ($message) {
42 return new Message($message->role, $message->content);
43 })->all();
44 }
45 
46 /**
47 * Get the tools available to the agent.
48 *
49 * @return Tool[]
50 */
51 public function tools(): iterable
52 {
53 return [
54 new RetrievePreviousTranscripts,
55 ];
56 }
57 
58 /**
59 * Get the agent's structured output schema definition.
60 */
61 public function schema(JsonSchema $schema): array
62 {
63 return [
64 'feedback' => $schema->string()->required(),
65 'score' => $schema->integer()->min(1)->max(10)->required(),
66 ];
67 }
68}

提示词 (Prompting)

要向智能体发送提示词,首先使用 make 方法或常规实例化创建一个实例,然后调用 prompt 方法。

1$response = (new SalesCoach)
2 ->prompt('Analyze this sales transcript...');
3 
4return (string) $response;

make 方法从容器中解析你的智能体,允许自动依赖注入。你也可以向智能体的构造函数传递参数。

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

通过向 prompt 方法传递额外参数,你可以在发送提示词时覆盖默认的提供商、模型或 HTTP 超时设置。

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

对话上下文

如果你的智能体实现了 Conversational 接口,你可以使用 messages 方法返回之前的对话上下文(如果适用)。

1use App\Models\History;
2use Laravel\Ai\Messages\Message;
3 
4/**
5 * Get the list of messages comprising the conversation so far.
6 */
7public function messages(): iterable
8{
9 return History::where('user_id', $this->user->id)
10 ->latest()
11 ->limit(50)
12 ->get()
13 ->reverse()
14 ->map(function ($message) {
15 return new Message($message->role, $message->content);
16 })->all();
17}

记忆对话

在使用 RemembersConversations trait 之前,你应该使用 vendor:publish Artisan 命令发布并运行 AI SDK 的迁移。这些迁移将创建存储对话所需的数据库表。

如果你希望 Laravel 自动为你的智能体存储和检索对话历史,可以使用 RemembersConversations trait。此 trait 提供了一种简单的方法将对话消息持久化到数据库中,而无需手动实现 Conversational 接口。

1<?php
2 
3namespace App\Ai\Agents;
4 
5use Laravel\Ai\Concerns\RemembersConversations;
6use Laravel\Ai\Contracts\Agent;
7use Laravel\Ai\Contracts\Conversational;
8use Laravel\Ai\Promptable;
9 
10class SalesCoach implements Agent, Conversational
11{
12 use Promptable, RemembersConversations;
13 
14 /**
15 * Get the instructions that the agent should follow.
16 */
17 public function instructions(): string
18 {
19 return 'You are a sales coach...';
20 }
21}

要为用户开始新的对话,请在发送提示词前调用 forUser 方法。

1$response = (new SalesCoach)->forUser($user)->prompt('Hello!');
2 
3$conversationId = $response->conversationId;

对话 ID 会在响应中返回,可以存储以备日后参考;或者你也可以直接从 agent_conversations 表中检索用户的所有对话。

要继续现有的对话,请使用 continue 方法。

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

使用 RemembersConversations trait 时,之前的消息会自动加载并包含在提示词的对话上下文中。新消息(无论是用户还是助手)会在每次交互后自动存储。

结构化输出

如果你希望智能体返回结构化输出,请实现 HasStructuredOutput 接口,该接口要求智能体定义一个 schema 方法。

1<?php
2 
3namespace App\Ai\Agents;
4 
5use Illuminate\Contracts\JsonSchema\JsonSchema;
6use Laravel\Ai\Contracts\Agent;
7use Laravel\Ai\Contracts\HasStructuredOutput;
8use Laravel\Ai\Promptable;
9 
10class SalesCoach implements Agent, HasStructuredOutput
11{
12 use Promptable;
13 
14 // ...
15 
16 /**
17 * Get the agent's structured output schema definition.
18 */
19 public function schema(JsonSchema $schema): array
20 {
21 return [
22 'score' => $schema->integer()->required(),
23 ];
24 }
25}

当提示一个返回结构化输出的智能体时,你可以像访问数组一样访问返回的 StructuredAgentResponse

1$response = (new SalesCoach)->prompt('Analyze this sales transcript...');
2 
3return $response['score'];

附件

发送提示词时,你也可以随附附件,以便模型检查图像和文档。

1use App\Ai\Agents\SalesCoach;
2use Laravel\Ai\Files;
3 
4$response = (new SalesCoach)->prompt(
5 'Analyze the attached sales transcript...',
6 attachments: [
7 Files\Document::fromStorage('transcript.pdf') // Attach a document from a filesystem disk...
8 Files\Document::fromPath('/home/laravel/transcript.md') // Attach a document from a local path...
9 $request->file('transcript'), // Attach an uploaded file...
10 ]
11);

同样,Laravel\Ai\Files\Image 类可用于将图像附加到提示词中。

1use App\Ai\Agents\ImageAnalyzer;
2use Laravel\Ai\Files;
3 
4$response = (new ImageAnalyzer)->prompt(
5 'What is in this image?',
6 attachments: [
7 Files\Image::fromStorage('photo.jpg') // Attach an image from a filesystem disk...
8 Files\Image::fromPath('/home/laravel/photo.jpg') // Attach an image from a local path...
9 $request->file('photo'), // Attach an uploaded file...
10 ]
11);

流式传输

你可以通过调用 stream 方法流式传输智能体的响应。返回的 StreamableAgentResponse 可以从路由返回,从而自动向客户端发送流式响应 (SSE)。

1use App\Ai\Agents\SalesCoach;
2 
3Route::get('/coach', function () {
4 return (new SalesCoach)->stream('Analyze this sales transcript...');
5});

可以使用 then 方法提供一个闭包,该闭包将在整个响应流式传输到客户端后被调用。

1use App\Ai\Agents\SalesCoach;
2use Laravel\Ai\Responses\StreamedAgentResponse;
3 
4Route::get('/coach', function () {
5 return (new SalesCoach)
6 ->stream('Analyze this sales transcript...')
7 ->then(function (StreamedAgentResponse $response) {
8 // $response->text, $response->events, $response->usage...
9 });
10});

或者,你可以手动遍历流式事件。

1$stream = (new SalesCoach)->stream('Analyze this sales transcript...');
2 
3foreach ($stream as $event) {
4 // ...
5}

使用 Vercel AI SDK 协议进行流式传输

你可以通过在可流式响应上调用 usingVercelDataProtocol 方法,使用 Vercel AI SDK 流协议来流式传输事件。

1use App\Ai\Agents\SalesCoach;
2 
3Route::get('/coach', function () {
4 return (new SalesCoach)
5 ->stream('Analyze this sales transcript...')
6 ->usingVercelDataProtocol();
7});

广播

你可以通过几种不同的方式广播流式事件。首先,可以直接在流式事件上调用 broadcastbroadcastNow 方法。

1use App\Ai\Agents\SalesCoach;
2use Illuminate\Broadcasting\Channel;
3 
4$stream = (new SalesCoach)->stream('Analyze this sales transcript...');
5 
6foreach ($stream as $event) {
7 $event->broadcast(new Channel('channel-name'));
8}

或者,你可以调用智能体的 broadcastOnQueue 方法,将智能体操作放入队列,并在流式事件可用时进行广播。

1(new SalesCoach)->broadcastOnQueue(
2 'Analyze this sales transcript...'
3 new Channel('channel-name'),
4);

队列处理 (Queueing)

使用智能体的 queue 方法,你可以发送提示词并允许其在后台处理响应,从而保持应用程序的快速响应。thencatch 方法可用于注册闭包,分别在响应可用或发生异常时被调用。

1use Illuminate\Http\Request;
2use Laravel\Ai\Responses\AgentResponse;
3use Throwable;
4 
5Route::post('/coach', function (Request $request) {
6 return (new SalesCoach)
7 ->queue($request->input('transcript'))
8 ->then(function (AgentResponse $response) {
9 // ...
10 })
11 ->catch(function (Throwable $e) {
12 // ...
13 });
14 
15 return back();
16});

工具

工具可以赋予智能体额外的功能,以便在响应提示词时使用。可以使用 make:tool Artisan 命令创建工具。

1php artisan make:tool RandomNumberGenerator

生成的工具将放置在应用程序的 app/Ai/Tools 目录中。每个工具都包含一个 handle 方法,当智能体需要使用该工具时,它会被调用。

1<?php
2 
3namespace App\Ai\Tools;
4 
5use Illuminate\Contracts\JsonSchema\JsonSchema;
6use Laravel\Ai\Contracts\Tool;
7use Laravel\Ai\Tools\Request;
8use Stringable;
9 
10class RandomNumberGenerator implements Tool
11{
12 /**
13 * Get the description of the tool's purpose.
14 */
15 public function description(): Stringable|string
16 {
17 return 'This tool may be used to generate cryptographically secure random numbers.';
18 }
19 
20 /**
21 * Execute the tool.
22 */
23 public function handle(Request $request): Stringable|string
24 {
25 return (string) random_int($request['min'], $request['max']);
26 }
27 
28 /**
29 * Get the tool's schema definition.
30 */
31 public function schema(JsonSchema $schema): array
32 {
33 return [
34 'min' => $schema->integer()->min(0)->required(),
35 'max' => $schema->integer()->required(),
36 ];
37 }
38}

一旦定义了工具,就可以在任何智能体的 tools 方法中返回它。

1use App\Ai\Tools\RandomNumberGenerator;
2 
3/**
4 * Get the tools available to the agent.
5 *
6 * @return Tool[]
7 */
8public function tools(): iterable
9{
10 return [
11 new RandomNumberGenerator,
12 ];
13}

SimilaritySearch 工具允许智能体使用数据库中存储的向量嵌入来搜索与给定查询相似的文档。这对于检索增强生成 (RAG) 非常有用,当你希望智能体能够搜索应用程序的数据时。

创建相似度搜索工具最简单的方法是使用 usingModel 方法,并传入一个具有向量嵌入的 Eloquent 模型。

1use App\Models\Document;
2use Laravel\Ai\Tools\SimilaritySearch;
3 
4public function tools(): iterable
5{
6 return [
7 SimilaritySearch::usingModel(Document::class, 'embedding'),
8 ];
9}

第一个参数是 Eloquent 模型类,第二个参数是包含向量嵌入的列名。

你还可以提供 0.01.0 之间的最小相似度阈值,以及一个自定义查询的闭包。

1SimilaritySearch::usingModel(
2 model: Document::class,
3 column: 'embedding',
4 minSimilarity: 0.7,
5 limit: 10,
6 query: fn ($query) => $query->where('published', true),
7),

为了获得更多控制权,你可以通过一个返回搜索结果的自定义闭包来创建相似度搜索工具。

1use App\Models\Document;
2use Laravel\Ai\Tools\SimilaritySearch;
3 
4public function tools(): iterable
5{
6 return [
7 new SimilaritySearch(using: function (string $query) {
8 return Document::query()
9 ->where('user_id', $this->user->id)
10 ->whereVectorSimilarTo('embedding', $query)
11 ->limit(10)
12 ->get();
13 }),
14 ];
15}

你可以使用 withDescription 方法自定义工具的描述。

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

提供商工具

提供商工具是 AI 提供商原生实现的特殊工具,提供诸如网页搜索、URL 获取和文件搜索等功能。与常规工具不同,提供商工具由提供商本身执行,而不是由你的应用程序执行。

提供商工具可以通过智能体的 tools 方法返回。

WebSearch 提供商工具允许智能体搜索网页以获取实时信息。这对于回答关于时事、最新数据或在模型训练截止日期后发生变化的主题非常有用。

支持的提供商: Anthropic, OpenAI, Gemini

1use Laravel\Ai\Providers\Tools\WebSearch;
2 
3public function tools(): iterable
4{
5 return [
6 new WebSearch,
7 ];
8}

你可以配置网页搜索工具以限制搜索次数或将结果限制在特定域名内。

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

若要根据用户位置优化搜索结果,请使用 location 方法。

1(new WebSearch)->location(
2 city: 'New York',
3 region: 'NY',
4 country: 'US'
5);

网页获取

WebFetch 提供商工具允许智能体获取并读取网页内容。当你需要智能体分析特定 URL 或从已知网页检索详细信息时,这非常有用。

支持的提供商: Anthropic, Gemini

1use Laravel\Ai\Providers\Tools\WebFetch;
2 
3public function tools(): iterable
4{
5 return [
6 new WebFetch,
7 ];
8}

你可以配置网页获取工具以限制获取数量或限制在特定域名内。

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

FileSearch 提供商工具允许智能体搜索存储在 向量存储 中的 文件。这通过允许智能体搜索上传的文档以获取相关信息,从而实现检索增强生成 (RAG)。

支持的提供商: OpenAI, Gemini

1use Laravel\Ai\Providers\Tools\FileSearch;
2 
3public function tools(): iterable
4{
5 return [
6 new FileSearch(stores: ['store_id']),
7 ];
8}

你可以提供多个向量存储 ID 以跨多个存储进行搜索。

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

如果你的文件具有 元数据,你可以通过提供 where 参数来过滤搜索结果。对于简单的相等过滤,传递一个数组即可。

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

对于更复杂的过滤,你可以传递一个接收 FileSearchQuery 实例的闭包。

1use Laravel\Ai\Providers\Tools\FileSearchQuery;
2 
3new FileSearch(stores: ['store_id'], where: fn (FileSearchQuery $query) =>
4 $query->where('author', 'Taylor Otwell')
5 ->whereNot('status', 'draft')
6 ->whereIn('category', ['news', 'updates'])
7);

中间件

智能体支持中间件,允许你在提示词发送给提供商之前对其进行拦截和修改。可以使用 make:agent-middleware Artisan 命令创建中间件。

1php artisan make:agent-middleware LogPrompts

生成的中间件将放置在应用程序的 app/Ai/Middleware 目录中。要将中间件添加到智能体,需实现 HasMiddleware 接口并定义一个 middleware 方法,该方法返回中间件类数组。

1<?php
2 
3namespace App\Ai\Agents;
4 
5use App\Ai\Middleware\LogPrompts;
6use Laravel\Ai\Contracts\Agent;
7use Laravel\Ai\Contracts\HasMiddleware;
8use Laravel\Ai\Promptable;
9 
10class SalesCoach implements Agent, HasMiddleware
11{
12 use Promptable;
13 
14 // ...
15 
16 /**
17 * Get the agent's middleware.
18 */
19 public function middleware(): array
20 {
21 return [
22 new LogPrompts,
23 ];
24 }
25}

每个中间件类应定义一个 handle 方法,该方法接收 AgentPrompt 和一个用于将提示词传递给下一个中间件的 Closure

1<?php
2 
3namespace App\Ai\Middleware;
4 
5use Closure;
6use Laravel\Ai\Prompts\AgentPrompt;
7 
8class LogPrompts
9{
10 /**
11 * Handle the incoming prompt.
12 */
13 public function handle(AgentPrompt $prompt, Closure $next)
14 {
15 Log::info('Prompting agent', ['prompt' => $prompt->prompt]);
16 
17 return $next($prompt);
18 }
19}

你可以在响应上使用 then 方法,在智能体完成处理后执行代码。这适用于同步和流式响应。

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

匿名智能体

有时你可能想在不创建专门智能体类的情况下快速与模型交互。你可以使用 agent 函数创建一个临时(匿名)智能体。

1use function Laravel\Ai\{agent};
2 
3$response = agent(
4 instructions: 'You are an expert at software development.',
5 messages: [],
6 tools: [],
7)->prompt('Tell me about Laravel')

匿名智能体也可以产生结构化输出。

1use Illuminate\Contracts\JsonSchema\JsonSchema;
2 
3use function Laravel\Ai\{agent};
4 
5$response = agent(
6 schema: fn (JsonSchema $schema) => [
7 'number' => $schema->integer()->required(),
8 ],
9)->prompt('Generate a random number less than 100')

智能体配置

你可以使用 PHP 属性配置智能体的文本生成选项。以下是可用属性:

  • MaxSteps:使用工具时智能体可以采取的最大步骤数。
  • MaxTokens:模型可以生成的最大 Token 数。
  • Model:智能体应使用的模型。
  • Provider:智能体使用的 AI 提供商(或用于故障转移的提供商列表)。
  • Temperature:用于生成的采样温度(0.0 到 1.0)。
  • Timeout:智能体请求的 HTTP 超时时间(秒,默认:60)。
  • UseCheapestModel:使用提供商最便宜的文本模型以进行成本优化。
  • UseSmartestModel:使用提供商最强大的文本模型以处理复杂任务。
1<?php
2 
3namespace App\Ai\Agents;
4 
5use Laravel\Ai\Attributes\MaxSteps;
6use Laravel\Ai\Attributes\MaxTokens;
7use Laravel\Ai\Attributes\Model;
8use Laravel\Ai\Attributes\Provider;
9use Laravel\Ai\Attributes\Temperature;
10use Laravel\Ai\Attributes\Timeout;
11use Laravel\Ai\Contracts\Agent;
12use Laravel\Ai\Enums\Lab;
13use Laravel\Ai\Promptable;
14 
15#[Provider(Lab::Anthropic)]
16#[Model('claude-haiku-4-5-20251001')]
17#[MaxSteps(10)]
18#[MaxTokens(4096)]
19#[Temperature(0.7)]
20#[Timeout(120)]
21class SalesCoach implements Agent
22{
23 use Promptable;
24 
25 // ...
26}

UseCheapestModelUseSmartestModel 属性允许你无需指定模型名称,即可自动为特定提供商选择最具成本效益或最强大的模型。当你希望在不同提供商之间优化成本或能力时,这非常有用。

1use Laravel\Ai\Attributes\UseCheapestModel;
2use Laravel\Ai\Attributes\UseSmartestModel;
3use Laravel\Ai\Contracts\Agent;
4use Laravel\Ai\Promptable;
5 
6#[UseCheapestModel]
7class SimpleSummarizer implements Agent
8{
9 use Promptable;
10 
11 // Will use the cheapest model (e.g., Haiku)...
12}
13 
14#[UseSmartestModel]
15class ComplexReasoner implements Agent
16{
17 use Promptable;
18 
19 // Will use the most capable model (e.g., Opus)...
20}

提供商选项

如果你的智能体需要传递提供商特定的选项(如 OpenAI 的推理工作量或惩罚设置),请实现 HasProviderOptions 契约并定义 providerOptions 方法。

1<?php
2 
3namespace App\Ai\Agents;
4 
5use Laravel\Ai\Contracts\Agent;
6use Laravel\Ai\Contracts\HasProviderOptions;
7use Laravel\Ai\Enums\Lab;
8use Laravel\Ai\Promptable;
9 
10class SalesCoach implements Agent, HasProviderOptions
11{
12 use Promptable;
13 
14 // ...
15 
16 /**
17 * Get provider-specific generation options.
18 */
19 public function providerOptions(Lab|string $provider): array
20 {
21 return match ($provider) {
22 Lab::OpenAI => [
23 'reasoning' => ['effort' => 'low'],
24 'frequency_penalty' => 0.5,
25 'presence_penalty' => 0.3,
26 ],
27 Lab::Anthropic => [
28 'thinking' => ['budget_tokens' => 1024],
29 ],
30 default => [],
31 };
32 }
33}

providerOptions 方法接收当前使用的提供商(Lab 枚举或字符串),允许你按提供商返回不同的选项。在使用 故障转移 时,这尤其有用,因为每个备用提供商都可以接收其各自的配置。

图像

Laravel\Ai\Image 类可用于使用 openaigeminixai 提供商生成图像。

1use Laravel\Ai\Image;
2 
3$image = Image::of('A donut sitting on the kitchen counter')->generate();
4 
5$rawContent = (string) $image;

squareportraitlandscape 方法可用于控制图像的长宽比,quality 方法可用于引导模型实现最终图像质量(highmediumlow)。timeout 方法可用于指定 HTTP 超时时间(秒)。

1use Laravel\Ai\Image;
2 
3$image = Image::of('A donut sitting on the kitchen counter')
4 ->quality('high')
5 ->landscape()
6 ->timeout(120)
7 ->generate();

你可以使用 attachments 方法附加参考图像。

1use Laravel\Ai\Files;
2use Laravel\Ai\Image;
3 
4$image = Image::of('Update this photo of me to be in the style of an impressionist painting.')
5 ->attachments([
6 Files\Image::fromStorage('photo.jpg'),
7 // Files\Image::fromPath('/home/laravel/photo.jpg'),
8 // Files\Image::fromUrl('https://example.com/photo.jpg'),
9 // $request->file('photo'),
10 ])
11 ->landscape()
12 ->generate();

生成的图像可以轻松存储在应用程序 config/filesystems.php 配置文件中配置的默认磁盘上。

1$image = Image::of('A donut sitting on the kitchen counter');
2 
3$path = $image->store();
4$path = $image->storeAs('image.jpg');
5$path = $image->storePublicly();
6$path = $image->storePubliclyAs('image.jpg');

图像生成也可以放入队列。

1use Laravel\Ai\Image;
2use Laravel\Ai\Responses\ImageResponse;
3 
4Image::of('A donut sitting on the kitchen counter')
5 ->portrait()
6 ->queue()
7 ->then(function (ImageResponse $image) {
8 $path = $image->store();
9 
10 // ...
11 });

音频

Laravel\Ai\Audio 类可用于根据给定的文本生成音频。

1use Laravel\Ai\Audio;
2 
3$audio = Audio::of('I love coding with Laravel.')->generate();
4 
5$rawContent = (string) $audio;

malefemalevoice 方法可用于确定生成音频的音色。

1$audio = Audio::of('I love coding with Laravel.')
2 ->female()
3 ->generate();
4 
5$audio = Audio::of('I love coding with Laravel.')
6 ->voice('voice-id-or-name')
7 ->generate();

类似地,instructions 方法可用于动态指导模型生成音频的听感效果。

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

生成的音频可以轻松存储在应用程序 config/filesystems.php 配置文件中配置的默认磁盘上。

1$audio = Audio::of('I love coding with Laravel.')->generate();
2 
3$path = $audio->store();
4$path = $audio->storeAs('audio.mp3');
5$path = $audio->storePublicly();
6$path = $audio->storePubliclyAs('audio.mp3');

音频生成也可以放入队列。

1use Laravel\Ai\Audio;
2use Laravel\Ai\Responses\AudioResponse;
3 
4Audio::of('I love coding with Laravel.')
5 ->queue()
6 ->then(function (AudioResponse $audio) {
7 $path = $audio->store();
8 
9 // ...
10 });

转录

Laravel\Ai\Transcription 类可用于根据给定的音频生成转录文本。

1use Laravel\Ai\Transcription;
2 
3$transcript = Transcription::fromPath('/home/laravel/audio.mp3')->generate();
4$transcript = Transcription::fromStorage('audio.mp3')->generate();
5$transcript = Transcription::fromUpload($request->file('audio'))->generate();
6 
7return (string) $transcript;

diarize 方法可用于指示你希望响应包含带有说话人识别的转录,从而使你能够按说话人访问分段转录。

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

转录生成也可以放入队列。

1use Laravel\Ai\Transcription;
2use Laravel\Ai\Responses\TranscriptionResponse;
3 
4Transcription::fromStorage('audio.mp3')
5 ->queue()
6 ->then(function (TranscriptionResponse $transcript) {
7 // ...
8 });

嵌入 (Embeddings)

你可以使用 Laravel Stringable 类中新增的 toEmbeddings 方法,轻松为任何给定的字符串生成向量嵌入。

1use Illuminate\Support\Str;
2 
3$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();

或者,你可以使用 Embeddings 类一次性为多个输入生成嵌入。

1use Laravel\Ai\Embeddings;
2 
3$response = Embeddings::for([
4 'Napa Valley has great wine.',
5 'Laravel is a PHP framework.',
6])->generate();
7 
8$response->embeddings; // [[0.123, 0.456, ...], [0.789, 0.012, ...]]

你可以指定嵌入的维度和提供商。

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

查询嵌入

生成嵌入后,通常会将它们存储在数据库的 vector 列中以备后续查询。Laravel 通过 pgvector 扩展对 PostgreSQL 上的向量列提供了原生支持。开始之前,请在迁移中定义一个 vector 列,并指定维度数。

1Schema::ensureVectorExtensionExists();
2 
3Schema::create('documents', function (Blueprint $table) {
4 $table->id();
5 $table->string('title');
6 $table->text('content');
7 $table->vector('embedding', dimensions: 1536);
8 $table->timestamps();
9});

你还可以添加向量索引以加速相似度搜索。当在向量列上调用 index 时,Laravel 会自动创建一个带有余弦距离的 HNSW 索引。

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

在 Eloquent 模型上,你应该将向量列转换为 array

1protected function casts(): array
2{
3 return [
4 'embedding' => 'array',
5 ];
6}

要查询相似记录,请使用 whereVectorSimilarTo 方法。该方法通过最小余弦相似度(0.01.0,其中 1.0 表示完全相同)过滤结果,并按相似度对结果进行排序。

1use App\Models\Document;
2 
3$documents = Document::query()
4 ->whereVectorSimilarTo('embedding', $queryEmbedding, minSimilarity: 0.4)
5 ->limit(10)
6 ->get();

$queryEmbedding 可以是浮点数数组或纯字符串。当给定字符串时,Laravel 会自动为其生成嵌入。

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

如果需要更多控制权,你可以独立使用底层方法:whereVectorDistanceLessThanselectVectorDistanceorderByVectorDistance

1$documents = Document::query()
2 ->select('*')
3 ->selectVectorDistance('embedding', $queryEmbedding, as: 'distance')
4 ->whereVectorDistanceLessThan('embedding', $queryEmbedding, maxDistance: 0.3)
5 ->orderByVectorDistance('embedding', $queryEmbedding)
6 ->limit(10)
7 ->get();

如果你希望赋予智能体作为工具执行相似度搜索的能力,请查阅 相似度搜索 工具文档。

向量查询目前仅在支持 pgvector 扩展的 PostgreSQL 连接上受支持。

缓存嵌入

嵌入生成可以被缓存,以避免对相同输入进行冗余 API 调用。要启用缓存,请将 ai.caching.embeddings.cache 配置选项设置为 true

1'caching' => [
2 'embeddings' => [
3 'cache' => true,
4 'store' => env('CACHE_STORE', 'database'),
5 // ...
6 ],
7],

启用缓存后,嵌入会被缓存 30 天。缓存键基于提供商、模型、维度和输入内容,确保相同的请求返回缓存结果,而不同的配置会生成新的嵌入。

即使全局缓存被禁用,你也可以使用 cache 方法为特定请求启用缓存。

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

你可以指定自定义的缓存时长(秒)。

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

toEmbeddings Stringable 方法也接受一个 cache 参数。

1// Cache with default duration...
2$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: true);
3 
4// Cache for a specific duration...
5$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: 3600);

重排序 (Reranking)

重排序(Reranking)允许你根据文档与给定查询的相关性对其进行重新排序。这对于通过语义理解改进搜索结果非常有用。

Laravel\Ai\Reranking 类可用于重排序文档。

1use Laravel\Ai\Reranking;
2 
3$response = Reranking::of([
4 'Django is a Python web framework.',
5 'Laravel is a PHP web application framework.',
6 'React is a JavaScript library for building user interfaces.',
7])->rerank('PHP frameworks');
8 
9// Access the top result...
10$response->first()->document; // "Laravel is a PHP web application framework."
11$response->first()->score; // 0.95
12$response->first()->index; // 1 (original position)

limit 方法可用于限制返回的结果数量。

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

重排序集合

为方便起见,可以使用 rerank 宏对 Laravel 集合进行重排序。第一个参数指定用于重排序的字段,第二个参数是查询语句。

1// Rerank by a single field...
2$posts = Post::all()
3 ->rerank('body', 'Laravel tutorials');
4 
5// Rerank by multiple fields (sent as JSON)...
6$reranked = $posts->rerank(['title', 'body'], 'Laravel tutorials');
7 
8// Rerank using a closure to build the document...
9$reranked = $posts->rerank(
10 fn ($post) => $post->title.': '.$post->body,
11 'Laravel tutorials'
12);

你还可以限制结果数量并指定提供商。

1$reranked = $posts->rerank(
2 by: 'content',
3 query: 'Laravel tutorials',
4 limit: 10,
5 provider: Lab::Cohere
6);

文件

Laravel\Ai\Files 类或单独的文件类可用于将文件存储在你的 AI 提供商处,以供后续对话使用。这对于大文件或你希望多次引用而不必重新上传的文件非常有用。

1use Laravel\Ai\Files\Document;
2use Laravel\Ai\Files\Image;
3 
4// Store a file from a local path...
5$response = Document::fromPath('/home/laravel/document.pdf')->put();
6$response = Image::fromPath('/home/laravel/photo.jpg')->put();
7 
8// Store a file that is stored on a filesystem disk...
9$response = Document::fromStorage('document.pdf', disk: 'local')->put();
10$response = Image::fromStorage('photo.jpg', disk: 'local')->put();
11 
12// Store a file that is stored on a remote URL...
13$response = Document::fromUrl('https://example.com/document.pdf')->put();
14$response = Image::fromUrl('https://example.com/photo.jpg')->put();
15 
16return $response->id;

你也可以存储原始内容或上传的文件。

1use Laravel\Ai\Files;
2use Laravel\Ai\Files\Document;
3 
4// Store raw content...
5$stored = Document::fromString('Hello, World!', 'text/plain')->put();
6 
7// Store an uploaded file...
8$stored = Document::fromUpload($request->file('document'))->put();

一旦文件存储完毕,在通过智能体生成文本时,可以直接引用该文件,而无需重新上传。

1use App\Ai\Agents\SalesCoach;
2use Laravel\Ai\Files;
3 
4$response = (new SalesCoach)->prompt(
5 'Analyze the attached sales transcript...'
6 attachments: [
7 Files\Document::fromId('file-id') // Attach a stored document...
8 ]
9);

要检索之前存储的文件,请在文件实例上使用 get 方法。

1use Laravel\Ai\Files\Document;
2 
3$file = Document::fromId('file-id')->get();
4 
5$file->id;
6$file->mimeType();

要从提供商处删除文件,请使用 delete 方法。

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

默认情况下,Files 类使用应用程序 config/ai.php 配置文件中配置的默认 AI 提供商。对于大多数操作,你可以使用 provider 参数指定不同的提供商。

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

在对话中使用存储的文件

一旦文件存储在提供商处,你就可以使用 DocumentImage 类上的 fromId 方法在智能体对话中引用它。

1use App\Ai\Agents\DocumentAnalyzer;
2use Laravel\Ai\Files;
3use Laravel\Ai\Files\Document;
4 
5$stored = Document::fromPath('/path/to/report.pdf')->put();
6 
7$response = (new DocumentAnalyzer)->prompt(
8 'Summarize this document.',
9 attachments: [
10 Document::fromId($stored->id),
11 ],
12);

同样,存储的图像可以使用 Image 类进行引用。

1use Laravel\Ai\Files;
2use Laravel\Ai\Files\Image;
3 
4$stored = Image::fromPath('/path/to/photo.jpg')->put();
5 
6$response = (new ImageAnalyzer)->prompt(
7 'What is in this image?',
8 attachments: [
9 Image::fromId($stored->id),
10 ],
11);

向量存储

向量存储允许你创建可搜索的文件集合,可用于检索增强生成 (RAG)。Laravel\Ai\Stores 类提供了创建、检索和删除向量存储的方法。

1use Laravel\Ai\Stores;
2 
3// Create a new vector store...
4$store = Stores::create('Knowledge Base');
5 
6// Create a store with additional options...
7$store = Stores::create(
8 name: 'Knowledge Base',
9 description: 'Documentation and reference materials.',
10 expiresWhenIdleFor: days(30),
11);
12 
13return $store->id;

要按 ID 检索现有的向量存储,请使用 get 方法。

1use Laravel\Ai\Stores;
2 
3$store = Stores::get('store_id');
4 
5$store->id;
6$store->name;
7$store->fileCounts;
8$store->ready;

要删除向量存储,请在 Stores 类或存储实例上使用 delete 方法。

1use Laravel\Ai\Stores;
2 
3// Delete by ID...
4Stores::delete('store_id');
5 
6// Or delete via a store instance...
7$store = Stores::get('store_id');
8 
9$store->delete();

向存储中添加文件

拥有向量存储后,可以使用 add 方法向其中添加 文件。添加到存储中的文件会自动索引,以便使用 文件搜索提供商工具 进行语义搜索。

1use Laravel\Ai\Files\Document;
2use Laravel\Ai\Stores;
3 
4$store = Stores::get('store_id');
5 
6// Add a file that has already been stored with the provider...
7$document = $store->add('file_id');
8$document = $store->add(Document::fromId('file_id'));
9 
10// Or, store and add a file in one step...
11$document = $store->add(Document::fromPath('/path/to/document.pdf'));
12$document = $store->add(Document::fromStorage('manual.pdf'));
13$document = $store->add($request->file('document'));
14 
15$document->id;
16$document->fileId;

通常,当向向量存储添加之前存储的文件时,返回的文档 ID 会与文件之前分配的 ID 匹配;但某些向量存储提供商可能会返回一个新的、不同的“文档 ID”。因此,建议你在数据库中同时存储这两个 ID 以供日后参考。

添加文件到存储时,可以为其附加元数据。这些元数据稍后可在使用 文件搜索提供商工具 时用于过滤搜索结果。

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

要从存储中移除文件,请使用 remove 方法。

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

从向量存储中移除文件不会将其从提供商的 文件存储 中移除。要从向量存储中移除文件并将其从文件存储中永久删除,请使用 deleteFile 参数。

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

故障转移 (Failover)

在发送提示词或生成其他媒体时,你可以提供一个提供商/模型数组,以便在主要提供商遇到服务中断或速率限制时,自动故障转移到备份提供商/模型。

1use App\Ai\Agents\SalesCoach;
2use Laravel\Ai\Image;
3 
4$response = (new SalesCoach)->prompt(
5 'Analyze this sales transcript...',
6 provider: [Lab::OpenAI, Lab::Anthropic],
7);
8 
9$image = Image::of('A donut sitting on the kitchen counter')
10 ->generate(provider: [Lab::Gemini, Lab::xAI]);

测试

智能体 (Agents)

要在测试中伪造智能体的响应,请在智能体类上调用 fake 方法。你可以选择提供响应数组或闭包。

1use App\Ai\Agents\SalesCoach;
2use Laravel\Ai\Prompts\AgentPrompt;
3 
4// Automatically generate a fixed response for every prompt...
5SalesCoach::fake();
6 
7// Provide a list of prompt responses...
8SalesCoach::fake([
9 'First response',
10 'Second response',
11]);
12 
13// Dynamically handle prompt responses based on the incoming prompt...
14SalesCoach::fake(function (AgentPrompt $prompt) {
15 return 'Response for: '.$prompt->prompt;
16});

当对返回结构化输出的智能体调用 Agent::fake() 时,Laravel 会自动生成符合你定义的输出模式的伪造数据。

发送提示词后,你可以对接收到的提示词进行断言。

1use Laravel\Ai\Prompts\AgentPrompt;
2 
3SalesCoach::assertPrompted('Analyze this...');
4 
5SalesCoach::assertPrompted(function (AgentPrompt $prompt) {
6 return $prompt->contains('Analyze');
7});
8 
9SalesCoach::assertNotPrompted('Missing prompt');
10 
11SalesCoach::assertNeverPrompted();

对于队列化的智能体调用,请使用队列断言方法。

1use Laravel\Ai\QueuedAgentPrompt;
2 
3SalesCoach::assertQueued('Analyze this...');
4 
5SalesCoach::assertQueued(function (QueuedAgentPrompt $prompt) {
6 return $prompt->contains('Analyze');
7});
8 
9SalesCoach::assertNotQueued('Missing prompt');
10 
11SalesCoach::assertNeverQueued();

要确保所有智能体调用都有对应的伪造响应,你可以使用 preventStrayPrompts。如果调用了没有定义伪造响应的智能体,将抛出异常。

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

图像

图像生成可以通过在 Image 类上调用 fake 方法进行伪造。一旦伪造,就可以对记录的图像生成提示词执行各种断言。

1use Laravel\Ai\Image;
2use Laravel\Ai\Prompts\ImagePrompt;
3use Laravel\Ai\Prompts\QueuedImagePrompt;
4 
5// Automatically generate a fixed response for every prompt...
6Image::fake();
7 
8// Provide a list of prompt responses...
9Image::fake([
10 base64_encode($firstImage),
11 base64_encode($secondImage),
12]);
13 
14// Dynamically handle prompt responses based on the incoming prompt...
15Image::fake(function (ImagePrompt $prompt) {
16 return base64_encode('...');
17});

生成图像后,你可以对接收到的提示词进行断言。

1Image::assertGenerated(function (ImagePrompt $prompt) {
2 return $prompt->contains('sunset') && $prompt->isLandscape();
3});
4 
5Image::assertNotGenerated('Missing prompt');
6 
7Image::assertNothingGenerated();

对于队列化的图像生成,请使用队列断言方法。

1Image::assertQueued(
2 fn (QueuedImagePrompt $prompt) => $prompt->contains('sunset')
3);
4 
5Image::assertNotQueued('Missing prompt');
6 
7Image::assertNothingQueued();

要确保所有图像生成都有对应的伪造响应,你可以使用 preventStrayImages。如果生成图像时没有定义伪造响应,将抛出异常。

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

音频

音频生成可以通过在 Audio 类上调用 fake 方法进行伪造。一旦伪造,就可以对记录的音频生成提示词执行各种断言。

1use Laravel\Ai\Audio;
2use Laravel\Ai\Prompts\AudioPrompt;
3use Laravel\Ai\Prompts\QueuedAudioPrompt;
4 
5// Automatically generate a fixed response for every prompt...
6Audio::fake();
7 
8// Provide a list of prompt responses...
9Audio::fake([
10 base64_encode($firstAudio),
11 base64_encode($secondAudio),
12]);
13 
14// Dynamically handle prompt responses based on the incoming prompt...
15Audio::fake(function (AudioPrompt $prompt) {
16 return base64_encode('...');
17});

生成音频后,你可以对接收到的提示词进行断言。

1Audio::assertGenerated(function (AudioPrompt $prompt) {
2 return $prompt->contains('Hello') && $prompt->isFemale();
3});
4 
5Audio::assertNotGenerated('Missing prompt');
6 
7Audio::assertNothingGenerated();

对于队列化的音频生成,请使用队列断言方法。

1Audio::assertQueued(
2 fn (QueuedAudioPrompt $prompt) => $prompt->contains('Hello')
3);
4 
5Audio::assertNotQueued('Missing prompt');
6 
7Audio::assertNothingQueued();

要确保所有音频生成都有对应的伪造响应,你可以使用 preventStrayAudio。如果生成音频时没有定义伪造响应,将抛出异常。

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

转录

转录生成可以通过在 Transcription 类上调用 fake 方法进行伪造。一旦伪造,就可以对记录的转录生成提示词执行各种断言。

1use Laravel\Ai\Transcription;
2use Laravel\Ai\Prompts\TranscriptionPrompt;
3use Laravel\Ai\Prompts\QueuedTranscriptionPrompt;
4 
5// Automatically generate a fixed response for every prompt...
6Transcription::fake();
7 
8// Provide a list of prompt responses...
9Transcription::fake([
10 'First transcription text.',
11 'Second transcription text.',
12]);
13 
14// Dynamically handle prompt responses based on the incoming prompt...
15Transcription::fake(function (TranscriptionPrompt $prompt) {
16 return 'Transcribed text...';
17});

生成转录后,你可以对接收到的提示词进行断言。

1Transcription::assertGenerated(function (TranscriptionPrompt $prompt) {
2 return $prompt->language === 'en' && $prompt->isDiarized();
3});
4 
5Transcription::assertNotGenerated(
6 fn (TranscriptionPrompt $prompt) => $prompt->language === 'fr'
7);
8 
9Transcription::assertNothingGenerated();

对于队列化的转录生成,请使用队列断言方法。

1Transcription::assertQueued(
2 fn (QueuedTranscriptionPrompt $prompt) => $prompt->isDiarized()
3);
4 
5Transcription::assertNotQueued(
6 fn (QueuedTranscriptionPrompt $prompt) => $prompt->language === 'fr'
7);
8 
9Transcription::assertNothingQueued();

要确保所有转录生成都有对应的伪造响应,你可以使用 preventStrayTranscriptions。如果生成转录时没有定义伪造响应,将抛出异常。

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

嵌入 (Embeddings)

嵌入生成可以通过在 Embeddings 类上调用 fake 方法进行伪造。一旦伪造,就可以对记录的嵌入生成提示词执行各种断言。

1use Laravel\Ai\Embeddings;
2use Laravel\Ai\Prompts\EmbeddingsPrompt;
3use Laravel\Ai\Prompts\QueuedEmbeddingsPrompt;
4 
5// Automatically generate fake embeddings of the proper dimensions for every prompt...
6Embeddings::fake();
7 
8// Provide a list of prompt responses...
9Embeddings::fake([
10 [$firstEmbeddingVector],
11 [$secondEmbeddingVector],
12]);
13 
14// Dynamically handle prompt responses based on the incoming prompt...
15Embeddings::fake(function (EmbeddingsPrompt $prompt) {
16 return array_map(
17 fn () => Embeddings::fakeEmbedding($prompt->dimensions),
18 $prompt->inputs
19 );
20});

生成嵌入后,你可以对接收到的提示词进行断言。

1Embeddings::assertGenerated(function (EmbeddingsPrompt $prompt) {
2 return $prompt->contains('Laravel') && $prompt->dimensions === 1536;
3});
4 
5Embeddings::assertNotGenerated(
6 fn (EmbeddingsPrompt $prompt) => $prompt->contains('Other')
7);
8 
9Embeddings::assertNothingGenerated();

对于队列化的嵌入生成,请使用队列断言方法。

1Embeddings::assertQueued(
2 fn (QueuedEmbeddingsPrompt $prompt) => $prompt->contains('Laravel')
3);
4 
5Embeddings::assertNotQueued(
6 fn (QueuedEmbeddingsPrompt $prompt) => $prompt->contains('Other')
7);
8 
9Embeddings::assertNothingQueued();

要确保所有嵌入生成都有对应的伪造响应,你可以使用 preventStrayEmbeddings。如果生成嵌入时没有定义伪造响应,将抛出异常。

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

重排序 (Reranking)

重排序操作可以通过在 Reranking 类上调用 fake 方法进行伪造。

1use Laravel\Ai\Reranking;
2use Laravel\Ai\Prompts\RerankingPrompt;
3use Laravel\Ai\Responses\Data\RankedDocument;
4 
5// Automatically generate a fake reranked responses...
6Reranking::fake();
7 
8// Provide custom responses...
9Reranking::fake([
10 [
11 new RankedDocument(index: 0, document: 'First', score: 0.95),
12 new RankedDocument(index: 1, document: 'Second', score: 0.80),
13 ],
14]);

重排序后,你可以对执行的操作进行断言。

1Reranking::assertReranked(function (RerankingPrompt $prompt) {
2 return $prompt->contains('Laravel') && $prompt->limit === 5;
3});
4 
5Reranking::assertNotReranked(
6 fn (RerankingPrompt $prompt) => $prompt->contains('Django')
7);
8 
9Reranking::assertNothingReranked();

文件

文件操作可以通过在 Files 类上调用 fake 方法进行伪造。

1use Laravel\Ai\Files;
2 
3Files::fake();

一旦文件操作被伪造,你就可以对发生的上传和删除操作进行断言。

1use Laravel\Ai\Contracts\Files\StorableFile;
2use Laravel\Ai\Files\Document;
3 
4// Store files...
5Document::fromString('Hello, Laravel!', mimeType: 'text/plain')
6 ->as('hello.txt')
7 ->put();
8 
9// Make assertions...
10Files::assertStored(fn (StorableFile $file) =>
11 (string) $file === 'Hello, Laravel!' &&
12 $file->mimeType() === 'text/plain';
13);
14 
15Files::assertNotStored(fn (StorableFile $file) =>
16 (string) $file === 'Hello, World!'
17);
18 
19Files::assertNothingStored();

对于删除文件的断言,可以传递一个文件 ID。

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

向量存储

向量存储操作可以通过在 Stores 类上调用 fake 方法进行伪造。伪造存储时,也会自动伪造 文件操作

1use Laravel\Ai\Stores;
2 
3Stores::fake();

一旦存储操作被伪造,你就可以对创建或删除的存储进行断言。

1use Laravel\Ai\Stores;
2 
3// Create store...
4$store = Stores::create('Knowledge Base');
5 
6// Make assertions...
7Stores::assertCreated('Knowledge Base');
8 
9Stores::assertCreated(fn (string $name, ?string $description) =>
10 $name === 'Knowledge Base'
11);
12 
13Stores::assertNotCreated('Other Store');
14 
15Stores::assertNothingCreated();

对于删除存储的断言,可以提供存储 ID。

1Stores::assertDeleted('store_id');
2Stores::assertNotDeleted('other_store_id');
3Stores::assertNothingDeleted();

要断言文件已添加到存储或从存储中移除,请在给定的 Store 实例上使用断言方法。

1Stores::fake();
2 
3$store = Stores::get('store_id');
4 
5// Add / remove files...
6$store->add('added_id');
7$store->remove('removed_id');
8 
9// Make assertions...
10$store->assertAdded('added_id');
11$store->assertRemoved('removed_id');
12 
13$store->assertNotAdded('other_file_id');
14$store->assertNotRemoved('other_file_id');

如果文件存储在提供商的 文件存储 中,并在同一请求中添加到向量存储,你可能不知道该文件的提供商 ID。在这种情况下,你可以向 assertAdded 方法传递一个闭包,以根据添加文件的内容进行断言。

1use Laravel\Ai\Contracts\Files\StorableFile;
2use Laravel\Ai\Files\Document;
3 
4$store->add(Document::fromString('Hello, World!', 'text/plain')->as('hello.txt'));
5 
6$store->assertAdded(fn (StorableFile $file) => $file->name() === 'hello.txt');
7$store->assertAdded(fn (StorableFile $file) => $file->content() === 'Hello, World!');

活动

Laravel AI SDK 分发了多种 事件,包括:

  • 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 的使用信息。