Laravel AI SDK (Laravel AI SDK)
소개 (Introduction)
Laravel AI SDK는 OpenAI, Anthropic, Gemini 등 다양한 AI 프로바이더와 상호작용할 수 있는 통합되고 표현력 있는 API를 제공합니다. AI SDK를 사용하면 일관된 Laravel 친화적 인터페이스만으로 도구와 구조화된 출력을 갖춘 지능형 에이전트를 만들고, 이미지를 생성하며, 오디오를 합성하고 전사하고, 벡터 임베딩을 생성하는 등 다양한 작업을 수행할 수 있습니다.
설치 (Installation)
Composer를 통해 Laravel AI SDK를 설치할 수 있습니다.
composer require laravel/ai
다음으로, vendor:publish Artisan 명령어를 사용하여 AI SDK 설정 파일과 마이그레이션 파일을 게시해야 합니다.
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
마지막으로 애플리케이션의 데이터베이스 마이그레이션을 실행해야 합니다. 이 작업은 AI SDK가 대화 저장 기능을 제공하는 데 사용하는 agent_conversations 및 agent_conversation_messages 테이블을 생성합니다.
php artisan migrate
설정
AI 프로바이더 자격 증명은 애플리케이션의 config/ai.php 설정 파일 또는 애플리케이션의 .env 파일에 환경 변수로 정의할 수 있습니다.
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=
텍스트, 이미지, 오디오, 전사, 임베딩에 사용할 기본 모델도 애플리케이션의 config/ai.php 설정 파일에서 구성할 수 있습니다.
사용자 지정 Base URL
기본적으로 Laravel AI SDK는 각 프로바이더의 공개 API 엔드포인트에 직접 연결합니다. 하지만 다른 엔드포인트를 통해 요청을 라우팅해야 할 수도 있습니다. 예를 들어 API 키 관리를 중앙화하거나, 속도 제한을 구현하거나, 회사 게이트웨이를 통해 트래픽을 라우팅하기 위해 프록시 서비스를 사용할 때가 그렇습니다.
프로바이더 설정에 url 매개변수를 추가하여 사용자 지정 Base URL을 구성할 수 있습니다.
'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와 같은 프록시 서비스를 통해 요청을 라우팅하거나 대체 엔드포인트를 사용할 때 유용합니다.
사용자 지정 Base 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 |
| 임베딩 | OpenAI, Gemini, Azure, Cohere, Mistral, Jina, VoyageAI |
| 재순위 지정 | Cohere, Jina |
| 파일 | OpenAI, Anthropic, Gemini |
코드 전체에서 일반 문자열 대신 Laravel\Ai\Enums\Lab enum을 사용하여 프로바이더를 참조할 수 있습니다.
use Laravel\Ai\Enums\Lab;
Lab::Anthropic;
Lab::OpenAI;
Lab::Gemini;
// ...
에이전트 (Agents)
에이전트는 Laravel AI SDK에서 AI 프로바이더와 상호작용하기 위한 기본 구성 요소입니다. 각 에이전트는 대규모 언어 모델과 상호작용하는 데 필요한 지침, 대화 컨텍스트, 도구, 출력 스키마를 캡슐화하는 전용 PHP 클래스입니다. 에이전트를 영업 코치, 문서 분석기, 지원 봇처럼 애플리케이션 전반에서 한 번 구성해 두고 필요할 때 프롬프트할 수 있는 특화된 어시스턴트라고 생각하면 됩니다.
make:agent Artisan 명령어를 통해 에이전트를 만들 수 있습니다.
php artisan make:agent SalesCoach
php artisan make:agent SalesCoach --structured
생성된 에이전트 클래스 안에서 시스템 프롬프트 / 지침, 메시지 컨텍스트, 사용 가능한 도구, 출력 스키마(해당하는 경우)를 정의할 수 있습니다.
<?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(),
];
}
}
프롬프트 작성
에이전트에 프롬프트하려면 먼저 make 메서드 또는 일반적인 인스턴스 생성 방식으로 인스턴스를 만든 다음 prompt를 호출합니다.
$response = (new SalesCoach)
->prompt('Analyze this sales transcript...');
return (string) $response;
make 메서드는 컨테이너에서 에이전트를 해석하므로 자동 의존성 주입을 사용할 수 있습니다. 에이전트 생성자에 인수를 전달할 수도 있습니다.
$agent = SalesCoach::make(user: $user);
prompt 메서드에 추가 인수를 전달하면 프롬프트할 때 기본 프로바이더, 모델 또는 HTTP 제한 시간을 재정의할 수 있습니다.
$response = (new SalesCoach)->prompt(
'Analyze this sales transcript...',
provider: Lab::Anthropic,
model: 'claude-haiku-4-5-20251001',
timeout: 120,
);
대화 컨텍스트
에이전트가 Conversational 인터페이스를 구현하는 경우, 해당된다면 messages 메서드를 사용하여 이전 대화 컨텍스트를 반환할 수 있습니다.
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();
}
대화 기억하기
참고:
RemembersConversationstrait를 사용하기 전에vendor:publishArtisan 명령어를 사용하여 AI SDK 마이그레이션을 게시하고 실행해야 합니다. 이 마이그레이션은 대화를 저장하는 데 필요한 데이터베이스 테이블을 생성합니다.
Laravel이 에이전트의 대화 기록을 자동으로 저장하고 가져오도록 하려면 RemembersConversations trait를 사용할 수 있습니다. 이 trait는 Conversational 인터페이스를 직접 구현하지 않아도 대화 메시지를 데이터베이스에 유지할 수 있는 간단한 방법을 제공합니다.
<?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 메서드를 호출합니다.
$response = (new SalesCoach)->forUser($user)->prompt('Hello!');
$conversationId = $response->conversationId;
대화 ID는 응답에서 반환되며 나중에 참조할 수 있도록 저장할 수 있습니다. 또는 agent_conversations 테이블에서 사용자의 모든 대화를 직접 조회할 수도 있습니다.
기존 대화를 이어가려면 continue 메서드를 사용합니다.
$response = (new SalesCoach)
->continue($conversationId, as: $user)
->prompt('Tell me more about that.');
RemembersConversations trait를 사용할 때는 프롬프트할 때 이전 메시지가 자동으로 로드되어 대화 컨텍스트에 포함됩니다. 새 메시지(사용자와 어시스턴트 모두)는 각 상호작용 후 자동으로 저장됩니다.
구조화된 출력
에이전트가 구조화된 출력을 반환하도록 하려면 HasStructuredOutput 인터페이스를 구현합니다. 이 인터페이스는 에이전트가 schema 메서드를 정의하도록 요구합니다.
<?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(),
];
}
}
구조화된 출력을 반환하는 에이전트에 프롬프트할 때는 반환된 StructuredAgentResponse를 배열처럼 접근할 수 있습니다.
$response = (new SalesCoach)->prompt('Analyze this sales transcript...');
return $response['score'];
중첩 객체
중첩된 구조화된 출력을 정의하려면 클로저와 함께 object 메서드를 사용합니다.
<?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(),
'metadata' => $schema->object(fn ($schema) => [
'confidence' => $schema->string()->enum(['low', 'medium', 'high'])->required(),
'language' => $schema->string()->required(),
])->required(),
];
}
}
객체 배열
에이전트가 구조화된 항목 목록을 반환해야 한다면, array와 object 메서드를 함께 사용합니다.
public function schema(JsonSchema $schema): array
{
return [
'feedback' => $schema->array()
->items(
$schema->object(fn ($schema) => [
'comment' => $schema->string()->required(),
'score' => $schema->integer()->required(),
])
)
->required(),
];
}
첨부 파일
프롬프트를 보낼 때, 모델이 이미지와 문서를 살펴볼 수 있도록 프롬프트와 함께 첨부 파일을 전달할 수도 있습니다.
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 클래스를 사용하여 프롬프트에 이미지를 첨부할 수 있습니다.
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 메서드를 호출하여 에이전트의 응답을 스트리밍할 수 있습니다. 반환되는 StreamableAgentResponse는 라우트에서 그대로 반환할 수 있으며, 그러면 클라이언트에 스트리밍 응답(SSE)이 자동으로 전송됩니다.
use App\Ai\Agents\SalesCoach;
Route::get('/coach', function () {
return (new SalesCoach)->stream('Analyze this sales transcript...');
});
then 메서드를 사용하면 전체 응답이 클라이언트에 스트리밍된 뒤 호출될 클로저를 제공할 수 있습니다.
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...
});
});
또는 스트리밍된 이벤트를 직접 순회할 수도 있습니다.
$stream = (new SalesCoach)->stream('Analyze this sales transcript...');
foreach ($stream as $event) {
// ...
}
Vercel AI SDK 프로토콜을 사용한 스트리밍
스트리밍 가능한 응답에서 usingVercelDataProtocol 메서드를 호출하여 Vercel AI SDK 스트림 프로토콜을 사용해 이벤트를 스트리밍할 수 있습니다.
use App\Ai\Agents\SalesCoach;
Route::get('/coach', function () {
return (new SalesCoach)
->stream('Analyze this sales transcript...')
->usingVercelDataProtocol();
});
브로드캐스팅
스트리밍된 이벤트는 몇 가지 방식으로 브로드캐스트할 수 있습니다. 먼저, 스트리밍된 이벤트에서 broadcast 또는 broadcastNow 메서드를 간단히 호출할 수 있습니다.
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'));
}
또는 에이전트의 broadcastOnQueue 메서드를 호출하여 에이전트 작업을 큐에 넣고, 스트리밍된 이벤트가 준비되는 대로 브로드캐스트할 수 있습니다.
(new SalesCoach)->broadcastOnQueue(
'Analyze this sales transcript...'
new Channel('channel-name'),
);
큐 처리
에이전트의 queue 메서드를 사용하면 에이전트에 프롬프트를 보내되, 응답 처리는 백그라운드에서 수행하도록 할 수 있습니다. 이렇게 하면 애플리케이션을 빠르고 반응성 있게 유지할 수 있습니다. then과 catch 메서드를 사용하여 응답을 사용할 수 있게 되었을 때 또는 예외가 발생했을 때 호출될 클로저를 등록할 수 있습니다.
use Illuminate\Http\Request;
use Laravel\Ai\Responses\AgentResponse;
use Throwable;
Route::post('/coach', function (Request $request) {
(new SalesCoach)
->queue($request->input('transcript'))
->then(function (AgentResponse $response) {
// ...
})
->catch(function (Throwable $e) {
// ...
});
return back();
});
도구
도구는 에이전트가 프롬프트에 응답하는 동안 활용할 수 있는 추가 기능을 제공하는 데 사용됩니다. 도구는 make:tool Artisan 명령어를 사용하여 만들 수 있습니다.
php artisan make:tool RandomNumberGenerator
생성된 도구는 애플리케이션의 app/Ai/Tools 디렉터리에 배치됩니다. 각 도구에는 에이전트가 해당 도구를 사용해야 할 때 호출되는 handle 메서드가 포함됩니다.
<?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(),
];
}
}
도구를 정의한 뒤에는 에이전트의 tools 메서드에서 해당 도구를 반환할 수 있습니다.
use App\Ai\Tools\RandomNumberGenerator;
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [
new RandomNumberGenerator,
];
}
유사도 검색
SimilaritySearch 도구를 사용하면 에이전트가 데이터베이스에 저장된 벡터 임베딩을 사용하여 주어진 쿼리와 유사한 문서를 검색할 수 있습니다. 이는 에이전트가 애플리케이션 데이터에 접근하여 검색할 수 있게 하려는 경우, 검색 증강 생성(RAG)에 유용합니다.
유사도 검색 도구를 만드는 가장 간단한 방법은 벡터 임베딩을 가진 Eloquent 모델과 함께 usingModel 메서드를 사용하는 것입니다.
use App\Models\Document;
use Laravel\Ai\Tools\SimilaritySearch;
public function tools(): iterable
{
return [
SimilaritySearch::usingModel(Document::class, 'embedding'),
];
}
첫 번째 인수는 Eloquent 모델 클래스이고, 두 번째 인수는 벡터 임베딩을 포함하는 컬럼입니다.
0.0에서 1.0 사이의 최소 유사도 임계값과 쿼리를 사용자 정의하기 위한 클로저도 제공할 수 있습니다.
SimilaritySearch::usingModel(
model: Document::class,
column: 'embedding',
minSimilarity: 0.7,
limit: 10,
query: fn ($query) => $query->where('published', true),
),
더 세밀하게 제어하려면, 검색 결과를 반환하는 사용자 정의 클로저로 유사도 검색 도구를 만들 수 있습니다.
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 메서드를 사용하여 도구의 설명을 사용자 정의할 수 있습니다.
SimilaritySearch::usingModel(Document::class, 'embedding')
->withDescription('Search the knowledge base for relevant articles.'),
제공자 도구
제공자 도구는 AI 제공자가 기본적으로 구현한 특별한 도구로, 웹 검색, URL 가져오기, 파일 검색과 같은 기능을 제공합니다. 일반 도구와 달리 제공자 도구는 애플리케이션이 아니라 제공자 자체에서 실행됩니다.
제공자 도구는 에이전트의 tools 메서드에서 반환할 수 있습니다.
웹 검색
WebSearch 제공자 도구를 사용하면 에이전트가 실시간 정보를 얻기 위해 웹을 검색할 수 있습니다. 모델의 학습 기준 시점 이후 변경되었을 수 있는 최신 사건, 최근 데이터, 또는 주제에 관한 질문에 답할 때 유용합니다.
지원 제공자: Anthropic, OpenAI, Gemini
use Laravel\Ai\Providers\Tools\WebSearch;
public function tools(): iterable
{
return [
new WebSearch,
];
}
웹 검색 도구는 검색 횟수를 제한하거나 결과를 특정 도메인으로 제한하도록 설정할 수 있습니다.
(new WebSearch)->max(5)->allow(['laravel.com', 'php.net']),
사용자 위치를 기준으로 검색 결과를 더 정교하게 조정하려면 location 메서드를 사용합니다.
(new WebSearch)->location(
city: 'New York',
region: 'NY',
country: 'US'
);
웹 가져오기
WebFetch 제공자 도구를 사용하면 에이전트가 웹 페이지의 내용을 가져와 읽을 수 있습니다. 에이전트가 특정 URL을 분석하거나 알려진 웹 페이지에서 자세한 정보를 가져와야 할 때 유용합니다.
지원 제공자: Anthropic, Gemini
use Laravel\Ai\Providers\Tools\WebFetch;
public function tools(): iterable
{
return [
new WebFetch,
];
}
웹 가져오기 도구는 가져오기 횟수를 제한하거나 특정 도메인으로 제한하도록 설정할 수 있습니다.
(new WebFetch)->max(3)->allow(['docs.laravel.com']),
파일 검색
FileSearch 제공자 도구를 사용하면 에이전트가 vector stores에 저장된 files를 검색할 수 있습니다. 이를 통해 에이전트가 업로드된 문서에서 관련 정보를 검색할 수 있으므로 검색 증강 생성(RAG)을 사용할 수 있습니다.
지원 제공자: OpenAI, Gemini
use Laravel\Ai\Providers\Tools\FileSearch;
public function tools(): iterable
{
return [
new FileSearch(stores: ['store_id']),
];
}
여러 저장소를 대상으로 검색하려면 여러 vector store ID를 제공할 수 있습니다.
new FileSearch(stores: ['store_1', 'store_2']);
파일에 metadata가 있다면, where 인수를 제공하여 검색 결과를 필터링할 수 있습니다. 단순 동등 조건 필터에는 배열을 전달합니다.
new FileSearch(stores: ['store_id'], where: [
'author' => 'Taylor Otwell',
'year' => 2026,
]);
더 복잡한 필터에는 FileSearchQuery 인스턴스를 받는 클로저를 전달할 수 있습니다.
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'])
);
Middleware
Agents는 Middleware를 지원하므로, 프롬프트가 provider로 전송되기 전에 이를 가로채고 수정할 수 있습니다. Middleware는 make:agent-middleware Artisan 명령어로 만들 수 있습니다.
php artisan make:agent-middleware LogPrompts
생성된 Middleware는 애플리케이션의 app/Ai/Middleware 디렉터리에 배치됩니다. 에이전트에 Middleware를 추가하려면 HasMiddleware 인터페이스를 구현하고, Middleware 클래스 배열을 반환하는 middleware 메서드를 정의합니다.
<?php
namespace App\Ai\Agents;
use App\Ai\Middleware\LogPrompts;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasMiddleware;
use Laravel\Ai\Promptable;
class SalesCoach implements Agent, HasMiddleware
{
use Promptable;
// ...
/**
* Get the agent's middleware.
*/
public function middleware(): array
{
return [
new LogPrompts,
];
}
}
각 Middleware 클래스는 AgentPrompt와 프롬프트를 다음 Middleware로 전달하기 위한 Closure를 받는 handle 메서드를 정의해야 합니다.
<?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 메서드를 사용할 수 있습니다. 이 방식은 동기 응답과 스트리밍 응답 모두에서 동작합니다.
public function handle(AgentPrompt $prompt, Closure $next)
{
return $next($prompt)->then(function (AgentResponse $response) {
Log::info('Agent responded', ['text' => $response->text]);
});
}
익명 에이전트
때로는 전용 에이전트 클래스를 만들지 않고 모델과 빠르게 상호작용하고 싶을 수 있습니다. agent 함수를 사용하면 임시 익명 에이전트를 만들 수 있습니다.
use function Laravel\Ai\{agent};
$response = agent(
instructions: 'You are an expert at software development.',
messages: [],
tools: [],
)->prompt('Tell me about Laravel')
익명 에이전트도 구조화된 출력을 생성할 수 있습니다.
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')
에이전트 설정
PHP 속성을 사용하여 에이전트의 텍스트 생성 옵션을 설정할 수 있습니다. 사용할 수 있는 속성은 다음과 같습니다.
MaxSteps: 도구를 사용할 때 에이전트가 수행할 수 있는 최대 단계 수입니다.MaxTokens: 모델이 생성할 수 있는 최대 토큰 수입니다.Model: 에이전트가 사용할 모델입니다.Provider: 에이전트가 사용할 AI provider입니다. failover를 위해 여러 provider를 지정할 수도 있습니다.Temperature: 생성에 사용할 샘플링 온도입니다(0.0부터 1.0까지).Timeout: 에이전트 요청의 HTTP 제한 시간(초)입니다(기본값: 60).UseCheapestModel: 비용 최적화를 위해 provider의 가장 저렴한 텍스트 모델을 사용합니다.UseSmartestModel: 복잡한 작업을 위해 provider의 가장 성능이 뛰어난 텍스트 모델을 사용합니다.
<?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;
// ...
}
UseCheapestModel 및 UseSmartestModel 속성을 사용하면 모델 이름을 지정하지 않아도 지정된 provider에서 가장 비용 효율적인 모델이나 가장 성능이 뛰어난 모델을 자동으로 선택할 수 있습니다. 여러 provider에서 비용 또는 성능을 기준으로 최적화하고 싶을 때 유용합니다.
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)...
}
Provider 옵션
에이전트가 OpenAI의 추론 노력 수준이나 패널티 설정처럼 provider별 옵션을 전달해야 한다면, HasProviderOptions contract를 구현하고 providerOptions 메서드를 정의합니다.
<?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;
// ...
/**
* Get provider-specific generation options.
*/
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 => [],
};
}
}
providerOptions 메서드는 현재 사용 중인 provider(Lab enum 또는 문자열)를 받으므로, provider별로 서로 다른 옵션을 반환할 수 있습니다. 이는 failover(장애 조치)를 사용할 때 특히 유용합니다. 각 fallback provider가 고유한 설정을 받을 수 있기 때문입니다.
이미지 (Images)
Laravel\Ai\Image 클래스는 openai, gemini, xai provider를 사용하여 이미지를 생성할 때 사용할 수 있습니다.
use Laravel\Ai\Image;
$image = Image::of('A donut sitting on the kitchen counter')->generate();
$rawContent = (string) $image;
image의 종횡비를 제어하려면 square, portrait, landscape 메서드를 사용할 수 있으며, 최종 이미지 품질(high, medium, low)을 모델에 안내하려면 quality 메서드를 사용할 수 있습니다. HTTP 제한 시간을 초 단위로 지정하려면 timeout 메서드를 사용할 수 있습니다.
use Laravel\Ai\Image;
$image = Image::of('A donut sitting on the kitchen counter')
->quality('high')
->landscape()
->timeout(120)
->generate();
attachments 메서드를 사용하여 참고 이미지를 첨부할 수 있습니다.
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 설정 파일에 구성된 기본 disk에 쉽게 저장할 수 있습니다.
$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');
이미지 생성은 큐에 넣을 수도 있습니다.
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();
// ...
});
오디오 (Audio)
Laravel\Ai\Audio 클래스는 주어진 텍스트로부터 오디오를 생성하는 데 사용할 수 있습니다.
use Laravel\Ai\Audio;
$audio = Audio::of('I love coding with Laravel.')->generate();
$rawContent = (string) $audio;
male, female, voice 메서드는 생성되는 오디오의 음성을 결정하는 데 사용할 수 있습니다.
$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 메서드를 사용하면 생성되는 오디오가 어떻게 들려야 하는지 모델에 동적으로 지시할 수 있습니다.
$audio = Audio::of('I love coding with Laravel.')
->female()
->instructions('Said like a pirate')
->generate();
생성된 오디오는 애플리케이션의 config/filesystems.php 설정 파일에 구성된 기본 disk에 쉽게 저장할 수 있습니다.
$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');
오디오 생성은 큐에 넣을 수도 있습니다.
use Laravel\Ai\Audio;
use Laravel\Ai\Responses\AudioResponse;
Audio::of('I love coding with Laravel.')
->queue()
->then(function (AudioResponse $audio) {
$path = $audio->store();
// ...
});
전사 (Transcriptions)
Laravel\Ai\Transcription 클래스는 주어진 오디오의 전사본을 생성하는 데 사용할 수 있습니다.
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 메서드는 원본 텍스트 전사본에 더해 화자 분리 전사본도 응답에 포함하고 싶다는 뜻을 나타낼 때 사용할 수 있습니다. 이를 통해 화자별로 나뉜 전사본에 접근할 수 있습니다.
$transcript = Transcription::fromStorage('audio.mp3')
->diarize()
->generate();
전사 생성은 큐에 넣을 수도 있습니다.
use Laravel\Ai\Transcription;
use Laravel\Ai\Responses\TranscriptionResponse;
Transcription::fromStorage('audio.mp3')
->queue()
->then(function (TranscriptionResponse $transcript) {
// ...
});
임베딩 (Embeddings)
Laravel의 Stringable 클래스를 통해 사용할 수 있는 새로운 toEmbeddings 메서드를 사용하면, 주어진 문자열에 대한 벡터 임베딩을 쉽게 생성할 수 있습니다.
use Illuminate\Support\Str;
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();
또는 Embeddings 클래스를 사용하여 여러 입력에 대한 임베딩을 한 번에 생성할 수 있습니다.
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, ...]]
임베딩에 사용할 차원 수와 프로바이더를 지정할 수 있습니다:
$response = Embeddings::for(['Napa Valley has great wine.'])
->dimensions(1536)
->generate(Lab::OpenAI, 'text-embedding-3-small');
임베딩 쿼리하기
임베딩을 생성한 뒤에는 보통 나중에 쿼리할 수 있도록 데이터베이스의 vector 컬럼에 저장합니다. Laravel은 pgvector 확장을 통해 PostgreSQL의 벡터 컬럼을 네이티브로 지원합니다. 시작하려면 마이그레이션에서 차원 수를 지정하여 vector 컬럼을 정의합니다:
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이 코사인 거리를 사용하는 HNSW 인덱스를 자동으로 생성합니다:
$table->vector('embedding', dimensions: 1536)->index();
Eloquent 모델에서는 벡터 컬럼을 array로 캐스팅해야 합니다:
protected function casts(): array
{
return [
'embedding' => 'array',
];
}
유사한 레코드를 쿼리하려면 whereVectorSimilarTo 메서드를 사용합니다. 이 메서드는 최소 코사인 유사도(0.0에서 1.0 사이이며, 1.0은 동일함을 의미합니다)를 기준으로 결과를 필터링하고, 유사도 순서로 결과를 정렬합니다:
use App\Models\Document;
$documents = Document::query()
->whereVectorSimilarTo('embedding', $queryEmbedding, minSimilarity: 0.4)
->limit(10)
->get();
$queryEmbedding은 부동소수점 숫자 배열이거나 일반 문자열일 수 있습니다. 문자열이 주어지면 Laravel이 해당 문자열의 임베딩을 자동으로 생성합니다:
$documents = Document::query()
->whereVectorSimilarTo('embedding', 'best wineries in Napa Valley')
->limit(10)
->get();
더 세밀하게 제어해야 한다면 하위 수준의 whereVectorDistanceLessThan, selectVectorDistance, orderByVectorDistance 메서드를 각각 사용할 수 있습니다:
$documents = Document::query()
->select('*')
->selectVectorDistance('embedding', $queryEmbedding, as: 'distance')
->whereVectorDistanceLessThan('embedding', $queryEmbedding, maxDistance: 0.3)
->orderByVectorDistance('embedding', $queryEmbedding)
->limit(10)
->get();
에이전트가 도구로 유사도 검색을 수행할 수 있게 하려면 유사도 검색 도구 문서를 확인하십시오.
벡터 쿼리는 현재
pgvector확장을 사용하는 PostgreSQL 연결에서만 지원됩니다.
임베딩 캐싱
동일한 입력에 대해 중복 API 호출을 피하기 위해 임베딩 생성을 캐싱할 수 있습니다. 캐싱을 활성화하려면 ai.caching.embeddings.cache 설정 옵션을 true로 설정합니다:
'caching' => [
'embeddings' => [
'cache' => true,
'store' => env('CACHE_STORE', 'database'),
// ...
],
],
캐싱이 활성화되면 임베딩은 30일 동안 캐시됩니다. 캐시 키는 프로바이더, 모델, 차원 수, 입력 내용을 기반으로 생성되므로, 동일한 요청은 캐시된 결과를 반환하고 설정이 다른 요청은 새 임베딩을 생성합니다.
전역 캐싱이 비활성화되어 있어도 cache 메서드를 사용하여 특정 요청에 대해 캐싱을 활성화할 수도 있습니다:
$response = Embeddings::for(['Napa Valley has great wine.'])
->cache()
->generate();
초 단위로 사용자 지정 캐시 기간을 지정할 수 있습니다:
$response = Embeddings::for(['Napa Valley has great wine.'])
->cache(seconds: 3600) // Cache for 1 hour
->generate();
toEmbeddings Stringable 메서드도 cache 인수를 받습니다:
// 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)
재순위화는 주어진 쿼리와의 관련성을 기준으로 문서 목록의 순서를 다시 정렬할 수 있게 해줍니다. 이는 의미적 이해를 활용해 검색 결과를 개선하는 데 유용합니다:
Laravel\Ai\Reranking 클래스를 사용하여 문서를 재순위화할 수 있습니다:
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 메서드를 사용하여 반환되는 결과 수를 제한할 수 있습니다:
$response = Reranking::of($documents)
->limit(5)
->rerank('search query');
컬렉션 재순위화
편의를 위해 Laravel 컬렉션은 rerank 매크로를 사용하여 재순위화할 수 있습니다. 첫 번째 인수는 재순위화에 사용할 필드를 지정하고, 두 번째 인수는 쿼리입니다:
// 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'
);
결과 수를 제한하고 프로바이더를 지정할 수도 있습니다:
$reranked = $posts->rerank(
by: 'content',
query: 'Laravel tutorials',
limit: 10,
provider: Lab::Cohere
);
파일 (Files)
Laravel\Ai\Files 클래스 또는 개별 파일 클래스를 사용하여 나중에 대화에서 사용할 파일을 AI 프로바이더에 저장할 수 있습니다. 다시 업로드하지 않고 여러 번 참조하려는 큰 문서나 파일에 유용합니다:
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;
원시 콘텐츠나 업로드된 파일도 저장할 수 있습니다:
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();
파일이 저장되면, 해당 파일을 다시 업로드하는 대신 에이전트를 통해 텍스트를 생성할 때 파일을 참조할 수 있습니다:
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 메서드를 사용합니다:
use Laravel\Ai\Files\Document;
$file = Document::fromId('file-id')->get();
$file->id;
$file->mimeType();
프로바이더에서 파일을 삭제하려면 delete 메서드를 사용합니다:
Document::fromId('file-id')->delete();
기본적으로 Files 클래스는 애플리케이션의 config/ai.php 설정 파일에 구성된 기본 AI 프로바이더를 사용합니다. 대부분의 작업에서는 provider 인수를 사용하여 다른 프로바이더를 지정할 수 있습니다:
$response = Document::fromPath(
'/home/laravel/document.pdf'
)->put(provider: Lab::Anthropic);
대화에서 저장된 파일 사용하기
파일이 프로바이더에 저장되면 Document 또는 Image 클래스의 fromId 메서드를 사용하여 에이전트 대화에서 해당 파일을 참조할 수 있습니다:
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 클래스를 사용하여 참조할 수 있습니다:
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 클래스는 벡터 저장소를 생성하고, 가져오고, 삭제하는 메서드를 제공합니다:
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 메서드를 사용합니다:
use Laravel\Ai\Stores;
$store = Stores::get('store_id');
$store->id;
$store->name;
$store->fileCounts;
$store->ready;
벡터 저장소를 삭제하려면 Stores 클래스 또는 저장소 인스턴스에서 delete 메서드를 사용합니다:
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 메서드를 사용하여 파일을 추가할 수 있습니다. 저장소에 추가된 파일은 파일 검색 프로바이더 도구를 사용한 의미 검색을 위해 자동으로 인덱싱됩니다:
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를 모두 데이터베이스에 저장하는 것이 좋습니다.
파일을 저장소에 추가할 때 메타데이터를 첨부할 수 있습니다. 이 메타데이터는 나중에 파일 검색 프로바이더 도구를 사용할 때 검색 결과를 필터링하는 데 사용할 수 있습니다:
$store->add(Document::fromPath('/path/to/document.pdf'), metadata: [
'author' => 'Taylor Otwell',
'department' => 'Engineering',
'year' => 2026,
]);
저장소에서 파일을 제거하려면 remove 메서드를 사용합니다:
$store->remove('file_id');
벡터 저장소에서 파일을 제거해도 프로바이더의 파일 저장소에서는 제거되지 않습니다. 벡터 저장소에서 파일을 제거하고 파일 저장소에서도 영구적으로 삭제하려면 deleteFile 인수를 사용합니다:
$store->remove('file_abc123', deleteFile: true);
장애 조치 (Failover)
프롬프트를 보내거나 다른 미디어를 생성할 때 기본 프로바이더에서 서비스 중단이나 사용량 제한을 만나면 백업 프로바이더 / 모델로 자동 장애 조치할 수 있도록 프로바이더 / 모델 배열을 제공할 수 있습니다:
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]);
테스트 (Testing)
에이전트
테스트 중에 에이전트의 응답을 가짜로 처리하려면 에이전트 클래스에서 fake 메서드를 호출합니다. 선택적으로 응답 배열이나 클로저를 제공할 수 있습니다.
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::fake()가 호출되면, Laravel은 에이전트에 정의된 출력 스키마와 일치하는 가짜 데이터를 자동으로 생성합니다.
에이전트에 프롬프트를 전달한 후에는 수신된 프롬프트에 대해 검증할 수 있습니다.
use Laravel\Ai\Prompts\AgentPrompt;
SalesCoach::assertPrompted('Analyze this...');
SalesCoach::assertPrompted(function (AgentPrompt $prompt) {
return $prompt->contains('Analyze');
});
SalesCoach::assertNotPrompted('Missing prompt');
SalesCoach::assertNeverPrompted();
큐에 등록된 에이전트 호출에는 큐용 검증 메서드를 사용합니다.
use Laravel\Ai\QueuedAgentPrompt;
SalesCoach::assertQueued('Analyze this...');
SalesCoach::assertQueued(function (QueuedAgentPrompt $prompt) {
return $prompt->contains('Analyze');
});
SalesCoach::assertNotQueued('Missing prompt');
SalesCoach::assertNeverQueued();
모든 에이전트 호출에 대응하는 가짜 응답이 있는지 확인하려면 preventStrayPrompts를 사용할 수 있습니다. 정의된 가짜 응답 없이 에이전트가 호출되면 예외가 발생합니다.
SalesCoach::fake()->preventStrayPrompts();
이미지
이미지 생성은 Image 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다. 이미지가 가짜로 처리되면, 기록된 이미지 생성 프롬프트에 대해 다양한 검증을 수행할 수 있습니다.
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('...');
});
이미지를 생성한 후에는 수신된 프롬프트에 대해 검증할 수 있습니다.
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();
모든 이미지 생성에 대응하는 가짜 응답이 있는지 확인하려면 preventStrayImages를 사용할 수 있습니다. 정의된 가짜 응답 없이 이미지가 생성되면 예외가 발생합니다.
Image::fake()->preventStrayImages();
오디오
오디오 생성은 Audio 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다. 오디오가 가짜로 처리되면, 기록된 오디오 생성 프롬프트에 대해 다양한 검증을 수행할 수 있습니다.
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('...');
});
오디오를 생성한 후에는 수신된 프롬프트에 대해 검증할 수 있습니다.
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();
모든 오디오 생성에 대응하는 가짜 응답이 있는지 확인하려면 preventStrayAudio를 사용할 수 있습니다. 정의된 가짜 응답 없이 오디오가 생성되면 예외가 발생합니다.
Audio::fake()->preventStrayAudio();
전사
전사 생성은 Transcription 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다. 전사가 가짜로 처리되면, 기록된 전사 생성 프롬프트에 대해 다양한 검증을 수행할 수 있습니다.
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...';
});
전사를 생성한 후에는 수신된 프롬프트에 대해 검증할 수 있습니다.
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();
모든 전사 생성에 대응하는 가짜 응답이 있는지 확인하려면 preventStrayTranscriptions를 사용할 수 있습니다. 정의된 가짜 응답 없이 전사가 생성되면 예외가 발생합니다.
Transcription::fake()->preventStrayTranscriptions();
임베딩
임베딩 생성은 Embeddings 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다. 임베딩이 가짜로 처리되면, 기록된 임베딩 생성 프롬프트에 대해 다양한 검증을 수행할 수 있습니다.
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
);
});
임베딩을 생성한 후에는 수신된 프롬프트에 대해 검증할 수 있습니다.
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();
모든 임베딩 생성에 대응하는 가짜 응답이 있는지 확인하려면 preventStrayEmbeddings를 사용할 수 있습니다. 정의된 가짜 응답 없이 임베딩이 생성되면 예외가 발생합니다.
Embeddings::fake()->preventStrayEmbeddings();
재순위화
재순위화 작업은 Reranking 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다.
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),
],
]);
재순위화를 수행한 후에는 실행된 작업에 대해 검증할 수 있습니다.
Reranking::assertReranked(function (RerankingPrompt $prompt) {
return $prompt->contains('Laravel') && $prompt->limit === 5;
});
Reranking::assertNotReranked(
fn (RerankingPrompt $prompt) => $prompt->contains('Django')
);
Reranking::assertNothingReranked();
파일
파일 작업은 Files 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다.
use Laravel\Ai\Files;
Files::fake();
파일 작업이 가짜로 처리되면, 발생한 업로드와 삭제에 대해 검증할 수 있습니다.
use Laravel\Ai\Contracts\Files\StorableFile;
use Laravel\Ai\Files\Document;
// Store files...
Document::fromString('Hello, Laravel!', mimeType: '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를 전달할 수 있습니다.
Files::assertDeleted('file-id');
Files::assertNotDeleted('file-id');
Files::assertNothingDeleted();
벡터 스토어
벡터 스토어 작업은 Stores 클래스에서 fake 메서드를 호출하여 가짜로 처리할 수 있습니다. 스토어를 가짜로 처리하면 파일 작업도 자동으로 가짜 처리됩니다.
use Laravel\Ai\Stores;
Stores::fake();
스토어 작업이 가짜로 처리되면, 생성되거나 삭제된 스토어에 대해 검증할 수 있습니다.
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를 제공할 수 있습니다:
Stores::assertDeleted('store_id');
Stores::assertNotDeleted('other_store_id');
Stores::assertNothingDeleted();
저장소에 파일이 추가되었거나 제거되었는지 어설션하려면, 지정된 Store 인스턴스의 어설션 메서드를 사용합니다:
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를 알 수 없을 수 있습니다. 이 경우 assertAdded 메서드에 클로저를 전달하여 추가된 파일의 내용에 대해 어설션할 수 있습니다:
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는 다음을 포함한 다양한 이벤트를 디스패치합니다:
AddingFileToStoreAgentPromptedAgentStreamedAudioGeneratedCreatingStoreEmbeddingsGeneratedFileAddedToStoreFileDeletedFileRemovedFromStoreFileStoredGeneratingAudioGeneratingEmbeddingsGeneratingImageGeneratingTranscriptionImageGeneratedInvokingToolPromptingAgentRemovingFileFromStoreRerankedRerankingStoreCreatedStoringFileStreamingAgentToolInvokedTranscriptionGenerated
이 이벤트 중 어느 것이든 리스닝하여 AI SDK 사용 정보를 로그로 남기거나 저장할 수 있습니다.