Laravel AI SDK는 OpenAI, Anthropic, Gemini 등의 AI 프로바이더와 상호작용하기 위한 통합적이고 표현력 있는 API를 제공합니다. AI SDK를 사용하면 도구 및 구조화된 출력을 갖춘 지능형 에이전트 구축, 이미지 생성, 음성 합성 및 음성 인식, 벡터 임베딩 생성 등 다양한 AI 기능을 일관된 Laravel다운 인터페이스로 구현할 수 있습니다.
Laravel AI SDK는 Laravel 13에서 추가된 공식 패키지입니다. laravel/ai로 제공되며, 여러 AI 프로바이더를 통합 API로 다룰 수 있습니다.
LM Studio, vLLM, Together, Fireworks, 로컬 게이트웨이 등 OpenAI 호환 API를 사용하는 경우 openai-compatible 드라이버로 프로바이더를 설정할 수 있습니다. url은 필수이며, key를 지정하면 Bearer 토큰으로 전송됩니다.
Conversational 인터페이스를 구현하고 messages() 메서드를 정의하면 과거 대화 이력을 AI에 전달할 수 있습니다.RemembersConversations 트레이트를 사용하면 대화 이력을 데이터베이스에 자동으로 저장 및 조회할 수 있습니다.
use Laravel\Ai\Concerns\RemembersConversations;class SalesCoach implements Agent, Conversational{ use Promptable, RemembersConversations; public function instructions(): string { return 'You are a sales coach...'; }}
forUser()로 대화를 시작하고, 반환된 conversationId를 사용해 continue()로 이어지는 대화를 할 수 있습니다.
$response = (new SalesCoach)->forUser($user)->prompt('Hello!');$conversationId = $response->conversationId;$response = (new SalesCoach)->continue($conversationId, as: $user)->prompt('Tell me more about that.');
HasStructuredOutput 인터페이스를 구현하고 schema() 메서드로 JSON 스키마를 정의하면, AI의 응답을 구조화된 데이터로 받을 수 있습니다.
public function schema(JsonSchema $schema): array{ return ['score' => $schema->integer()->required()];}$response = (new SalesCoach)->prompt('Analyze this...');return $response['score'];
use Laravel\Ai\Files;$response = (new SalesCoach)->prompt( 'Analyze the attached sales transcript...', attachments: [ Files\Document::fromStorage('transcript.pdf'), Files\Document::fromPath('/home/laravel/transcript.md'), $request->file('transcript'), ]);
이미지 첨부도 동일하게 할 수 있습니다.
$response = (new ImageAnalyzer)->prompt('What is in this image?', attachments: [ Files\Image::fromStorage('photo.jpg'), Files\Image::fromPath('/home/laravel/photo.jpg'), $request->file('photo'),]);
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'),);
브로드캐스트 플랫폼에 따라 WebSocket 메시지를 약 10KB로 제한하는 경우가 있습니다. 큰 도구 결과 등 데이터 양이 많은 스트림 이벤트가 이 상한을 초과해 브로드캐스트에 실패할 수 있습니다. WithoutBroadcasting Attribute를 사용해 특정 이벤트 유형을 브로드캐스트에서 제외할 수 있습니다.
제외된 이벤트는 브로드캐스트되지 않지만, agent_conversation_messages 테이블에 저장은 계속됩니다. 따라서 프런트엔드는 스트림 완료 후에 도구의 전체 데이터를 가져올 수 있습니다. 이는 큐 경유(broadcastOnQueue)와 동기(broadcast / broadcastNow) 모두에서 동작합니다.
도구를 사용하면 AI가 코드 내의 함수를 호출할 수 있게 됩니다. make:tool 명령어로 도구 클래스를 생성할 수 있습니다.
php artisan make:tool RandomNumberGenerator
<?phpnamespace App\Ai\Tools;use Illuminate\Contracts\JsonSchema\JsonSchema;use Laravel\Ai\Contracts\Tool;use Laravel\Ai\Tools\Request;use Stringable;class RandomNumberGenerator implements Tool{ public function description(): Stringable|string { return 'This tool may be used to generate cryptographically secure random numbers.'; } public function handle(Request $request): Stringable|string { return (string) random_int($request['min'], $request['max']); } public function schema(JsonSchema $schema): array { return [ 'min' => $schema->integer()->min(0)->required(), 'max' => $schema->integer()->required(), ]; }}
에이전트의 tools() 메서드로 도구를 등록합니다.
public function tools(): iterable{ return [new RandomNumberGenerator];}
use App\Ai\Tools\RandomNumberGenerator;use Laravel\Mcp\Client;/** * Get the tools available to the agent. * * @return Tool[] */public function tools(): iterable{ return [ ...Client::web('https://mcp.example.com') ->withToken($token) ->tools(), new RandomNumberGenerator, ];}
AI SDK는 각 MCP 도구를 자동으로 래핑해 에이전트가 다른 도구와 동일하게 호출할 수 있게 합니다. 이름 있는 MCP 클라이언트를 사용할 수도 있습니다.
use Laravel\Mcp\Facades\Mcp;public function tools(): iterable{ return [ ...Mcp::client('github')->tools(), ];}
에이전트는 다른 에이전트의 tools() 메서드에서 반환할 수도 있습니다. 에이전트를 도구로서 등록하면, 부모 에이전트가 특정 작업을 서브 에이전트에 위임하고 그 결과를 원래 응답에 통합할 수 있습니다. 범용 에이전트가 전문화된 지시, 도구, 모델 설정, 프로바이더 설정을 가진 특화형 에이전트에 접근할 때 편리합니다.예를 들어 고객 지원 에이전트가 환불 정책 질문을 환불 전문 에이전트에 위임하는 예시입니다.
<?phpnamespace App\Ai\Agents;use Laravel\Ai\Contracts\Agent;use Laravel\Ai\Contracts\HasTools;use Laravel\Ai\Promptable;class CustomerSupportAgent implements Agent, HasTools{ use Promptable; public function instructions(): string { return 'You help customers with account, order, and billing questions. Delegate refund policy questions to the refunds specialist.'; } public function tools(): iterable { return [ new RefundsAgent, ]; }}
부모 에이전트에게 서브 에이전트를 보이는 방법을 커스터마이즈하려면, 서브 에이전트에 CanActAsTool 인터페이스를 구현하고 도구용 이름과 설명을 정의합니다.
<?phpnamespace App\Ai\Agents;use App\Ai\Tools\LookupOrder;use Laravel\Ai\Attributes\Provider;use Laravel\Ai\Contracts\Agent;use Laravel\Ai\Contracts\CanActAsTool;use Laravel\Ai\Contracts\HasTools;use Laravel\Ai\Enums\Lab;use Laravel\Ai\Promptable;#[Provider(Lab::Anthropic)]class RefundsAgent implements Agent, CanActAsTool, HasTools{ use Promptable; public function instructions(): string { return 'You are a refunds specialist. Use order details and the refund policy to give concise eligibility guidance.'; } public function name(): string { return 'refunds_specialist'; } public function description(): string { return 'Determine whether an order is eligible for a refund and explain the next step.'; } public function tools(): iterable { return [ new LookupOrder, ]; }}
CanActAsTool을 구현하지 않은 서브 에이전트의 경우, Laravel은 클래스 이름을 도구 이름으로 사용하고 범용적인 설명문을 자동으로 생성합니다. 각 서브 에이전트의 호출은 독립적으로 이루어지며, 부모 에이전트의 대화 이력은 이어받지 않습니다.
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;$response = agent( schema: fn (JsonSchema $schema) => ['number' => $schema->integer()->required()],)->prompt('Generate a random number less than 100');
// 가장 저렴한 모델 사용#[UseCheapestModel]class SimpleSummarizer implements Agent{ use Promptable;}// 가장 고성능인 모델 사용#[UseSmartestModel]class ComplexReasoner implements Agent{ use Promptable;}
Image 클래스로 이미지를 생성할 수 있습니다. OpenAI, Gemini, xAI 프로바이더가 지원합니다.
use Laravel\Ai\Image;$image = Image::of('A donut sitting on the kitchen counter')->generate();$rawContent = (string) $image;
품질이나 종횡비, 타임아웃을 지정할 수 있습니다.
$image = Image::of('A donut sitting on the kitchen counter') ->quality('high') ->landscape() ->timeout(120) ->generate();
참조 이미지를 첨부해 가공할 수도 있습니다.
use Laravel\Ai\Files;$image = Image::of('Update this photo to be in the style of an impressionist painting.') ->attachments([Files\Image::fromStorage('photo.jpg')]) ->landscape() ->generate();
Audio 클래스로 텍스트를 음성으로 변환할 수 있습니다. OpenAI, ElevenLabs 프로바이더가 지원합니다.
use Laravel\Ai\Audio;$audio = Audio::of('I love coding with Laravel.')->generate();$rawContent = (string) $audio;
음성의 성별이나 구체적인 보이스 ID, 말투의 지시도 지정할 수 있습니다.
$audio = Audio::of('I love coding with Laravel.')->female()->generate();$audio = Audio::of('I love coding with Laravel.')->voice('voice-id-or-name')->generate();$audio = Audio::of('I love coding with Laravel.')->female()->instructions('Said like a pirate')->generate();
use Laravel\Ai\Responses\AudioResponse;Audio::of('I love coding with Laravel.') ->queue() ->then(function (AudioResponse $audio) { $path = $audio->store(); });
use Illuminate\Support\Str;// Stringable 사용 방법$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();
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');
$response = Embeddings::for(['Napa Valley has great wine.'])->cache()->generate();$response = Embeddings::for(['Napa Valley has great wine.'])->cache(seconds: 3600)->generate();// Stringable에서도 동일$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: true);$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings(cache: 3600);
검색 결과를 쿼리와의 관련도로 리랭크(정렬)할 수 있습니다. Cohere, Jina 프로바이더가 지원합니다.
use Laravel\Ai\Reranking;$response = Reranking::of([ 'Django is a Python web framework.', 'Laravel is a PHP web application framework.', 'React is a JavaScript library for building user interfaces.',])->rerank('PHP frameworks');$response->first()->document; // "Laravel is a PHP web application framework."$response->first()->score; // 0.95$response->first()->index; // 1
use Laravel\Ai\Files;$response = (new SalesCoach)->prompt( 'Analyze the attached sales transcript...', attachments: [Files\Document::fromId('file-id')]);
여러 프로바이더를 배열로 지정하면 첫 번째 프로바이더가 실패한 경우 다음 프로바이더로 자동 폴백됩니다.
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]);