본문 바로가기

Laravel AI SDK

번역일: 2026년 6월 20일

Laravel AI SDK

소개

Laravel AI SDK는 OpenAI, Anthropic, Gemini 등 다양한 AI 프로바이더와 일관된 방식으로 상호작용할 수 있는 통합 API를 제공합니다. 이 SDK를 사용하면 툴과 구조화된 출력을 갖춘 지능형 에이전트를 구축하고, 이미지를 생성하고, 오디오를 합성 및 변환하고, 벡터 임베딩을 생성하는 등 다양한 작업을 Laravel 친화적인 인터페이스 하나로 처리할 수 있습니다.

설치

Composer를 통해 Laravel AI SDK를 설치합니다:

composer require laravel/ai

다음으로, vendor:publish Artisan 명령어를 사용해 AI SDK의 설정 파일과 마이그레이션 파일을 퍼블리시합니다:

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

마지막으로, 데이터베이스 마이그레이션을 실행합니다. 이 마이그레이션은 AI SDK가 대화 내역을 저장하는 데 사용하는 agent_conversationsagent_conversation_messages 테이블을 생성합니다:

php artisan migrate

설정

AI 프로바이더 인증 정보는 config/ai.php 파일 또는 .env 파일의 환경 변수로 설정할 수 있습니다:

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 파일에서 설정할 수 있습니다.

커스텀 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
TTSOpenAI, ElevenLabs
STTOpenAI, ElevenLabs, Mistral
임베딩OpenAI, Gemini, Azure, Cohere, Mistral, Jina, VoyageAI
리랭킹Cohere, Jina
파일OpenAI, Anthropic, Gemini

코드에서 프로바이더를 문자열 대신 Laravel\Ai\Enums\Lab 열거형으로 참조할 수 있습니다:

use Laravel\Ai\Enums\Lab; Lab::Anthropic; Lab::OpenAI; Lab::Gemini; // ...

에이전트

에이전트는 Laravel AI SDK에서 AI 프로바이더와 상호작용하는 기본 단위입니다. 각 에이전트는 대형 언어 모델과 상호작용하는 데 필요한 지시사항, 대화 컨텍스트, 툴, 출력 스키마를 하나의 PHP 클래스로 캡슐화합니다. 에이전트는 영업 코치, 문서 분석기, 고객 지원 봇처럼 한 번 정의하면 애플리케이션 전체에서 재사용할 수 있는 전문화된 어시스턴트로 생각하면 됩니다.

make:agent Artisan 명령어로 에이전트를 생성할 수 있습니다:

php artisan make:agent SalesCoachphp 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) {} /** * 에이전트가 따라야 할 지시사항을 반환합니다. */ public function instructions(): Stringable|string { return '당신은 영업 코치입니다. 통화 내용을 분석하고 피드백과 전반적인 영업 역량 점수를 제공합니다.'; } /** * 지금까지의 대화를 구성하는 메시지 목록을 반환합니다. */ 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(); } /** * 에이전트가 사용할 수 있는 툴 목록을 반환합니다. * * @return Tool[] */ public function tools(): iterable { return [ new RetrievePreviousTranscripts, ]; } /** * 에이전트의 구조화된 출력 스키마를 정의합니다. */ public function schema(JsonSchema $schema): array { return [ 'feedback' => $schema->string()->required(), 'score' => $schema->integer()->min(1)->max(10)->required(), ]; } }

프롬프트

에이전트에 프롬프트를 전달하려면 make 메서드 또는 일반 인스턴스화로 에이전트를 생성한 후 prompt를 호출합니다:

$response = (new SalesCoach) ->prompt('이 영업 통화 내용을 분석해 주세요...'); return (string) $response;

make 메서드는 컨테이너에서 에이전트를 resolve하므로 의존성 자동 주입이 가능합니다. 생성자 인수를 함께 전달할 수도 있습니다:

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

prompt 메서드에 추가 인수를 전달하면 기본 프로바이더, 모델, HTTP 타임아웃을 재정의할 수 있습니다:

$response = (new SalesCoach)->prompt( '이 영업 통화 내용을 분석해 주세요...', provider: Lab::Anthropic, model: 'claude-haiku-4-5-20251001', timeout: 120, );

대화 컨텍스트

에이전트가 Conversational 인터페이스를 구현하는 경우, messages 메서드에서 이전 대화 컨텍스트를 반환할 수 있습니다:

use App\Models\History; use Laravel\Ai\Messages\Message; /** * 지금까지의 대화를 구성하는 메시지 목록을 반환합니다. */ 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(); }

대화 기억하기

NOTE

RemembersConversations 트레잇을 사용하기 전에, vendor:publish Artisan 명령어로 AI SDK 마이그레이션을 퍼블리시하고 실행해야 합니다. 이 마이그레이션은 대화 내역을 저장하는 데 필요한 데이터베이스 테이블을 생성합니다.

Laravel이 에이전트의 대화 내역을 자동으로 저장하고 불러오도록 하려면 RemembersConversations 트레잇을 사용하세요. 이 트레잇은 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; /** * 에이전트가 따라야 할 지시사항을 반환합니다. */ public function instructions(): string { return '당신은 영업 코치입니다...'; } }

사용자를 위한 새 대화를 시작하려면 프롬프트 전에 forUser 메서드를 호출합니다:

$response = (new SalesCoach)->forUser($user)->prompt('안녕하세요!'); $conversationId = $response->conversationId;

대화 ID는 응답에서 반환되며, 이후 참조를 위해 저장해 두거나 agent_conversations 테이블에서 직접 사용자의 모든 대화를 조회할 수 있습니다.

기존 대화를 이어가려면 continue 메서드를 사용합니다:

$response = (new SalesCoach) ->continue($conversationId, as: $user) ->prompt('그 부분에 대해 더 자세히 설명해 주세요.');

RemembersConversations 트레잇을 사용하면 프롬프트 시 이전 메시지가 자동으로 불러와져 대화 컨텍스트에 포함됩니다. 각 상호작용 후 새 메시지(사용자 및 어시스턴트 모두)도 자동으로 저장됩니다.

구조화된 출력

에이전트가 구조화된 데이터를 반환하도록 하려면 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; // ... /** * 에이전트의 구조화된 출력 스키마를 정의합니다. */ public function schema(JsonSchema $schema): array { return [ 'score' => $schema->integer()->required(), ]; } }

구조화된 출력을 반환하는 에이전트에 프롬프트하면 반환된 StructuredAgentResponse를 배열처럼 접근할 수 있습니다:

$response = (new SalesCoach)->prompt('이 영업 통화 내용을 분석해 주세요...'); return $response['score'];

첨부 파일

프롬프트 시 이미지나 문서를 첨부하여 모델이 해당 파일을 검토할 수 있도록 할 수 있습니다:

use App\Ai\Agents\SalesCoach; use Laravel\Ai\Files; $response = (new SalesCoach)->prompt( '첨부된 영업 통화 내용을 분석해 주세요...', attachments: [ Files\Document::fromStorage('transcript.pdf'), // 파일시스템 디스크의 문서 첨부 Files\Document::fromPath('/home/laravel/transcript.md'), // 로컬 경로의 문서 첨부 $request->file('transcript'), // 업로드된 파일 첨부 ] );

이미지를 첨부하려면 Laravel\Ai\Files\Image 클래스를 사용합니다:

use App\Ai\Agents\ImageAnalyzer; use Laravel\Ai\Files; $response = (new ImageAnalyzer)->prompt( '이 이미지에는 무엇이 있나요?', attachments: [ Files\Image::fromStorage('photo.jpg'), // 파일시스템 디스크의 이미지 첨부 Files\Image::fromPath('/home/laravel/photo.jpg'), // 로컬 경로의 이미지 첨부 $request->file('photo'), // 업로드된 파일 첨부 ] );

스트리밍

에이전트의 응답을 스트리밍하려면 stream 메서드를 호출합니다. 반환된 StreamableAgentResponse를 라우트에서 반환하면 SSE(Server-Sent Events) 스트리밍 응답이 자동으로 클라이언트에 전송됩니다:

use App\Ai\Agents\SalesCoach; Route::get('/coach', function () { return (new SalesCoach)->stream('이 영업 통화 내용을 분석해 주세요...'); });

then 메서드를 사용하면 응답 스트리밍이 완료된 후 호출될 클로저를 등록할 수 있습니다:

use App\Ai\Agents\SalesCoach; use Laravel\Ai\Responses\StreamedAgentResponse; Route::get('/coach', function () { return (new SalesCoach) ->stream('이 영업 통화 내용을 분석해 주세요...') ->then(function (StreamedAgentResponse $response) { // $response->text, $response->events, $response->usage... }); });

스트리밍 이벤트를 직접 순회할 수도 있습니다:

$stream = (new SalesCoach)->stream('이 영업 통화 내용을 분석해 주세요...'); foreach ($stream as $event) { // ... }

Vercel AI SDK 프로토콜을 사용한 스트리밍

스트리밍 응답에 usingVercelDataProtocol 메서드를 호출하면 Vercel AI SDK 스트림 프로토콜을 사용하여 이벤트를 스트리밍할 수 있습니다:

use App\Ai\Agents\SalesCoach; Route::get('/coach', function () { return (new SalesCoach) ->stream('이 영업 통화 내용을 분석해 주세요...') ->usingVercelDataProtocol(); });

브로드캐스팅

스트리밍 이벤트를 브로드캐스팅하는 방법은 몇 가지가 있습니다. 먼저, 스트리밍 이벤트에서 직접 broadcast 또는 broadcastNow 메서드를 호출할 수 있습니다:

use App\Ai\Agents\SalesCoach; use Illuminate\Broadcasting\Channel; $stream = (new SalesCoach)->stream('이 영업 통화 내용을 분석해 주세요...'); foreach ($stream as $event) { $event->broadcast(new Channel('channel-name')); }

또는 에이전트의 broadcastOnQueue 메서드를 호출하여 에이전트 작업을 큐에 추가하고 스트리밍 이벤트가 준비되는 대로 브로드캐스팅할 수 있습니다:

(new SalesCoach)->broadcastOnQueue( '이 영업 통화 내용을 분석해 주세요...', new Channel('channel-name'), );

큐잉

에이전트의 queue 메서드를 사용하면 에이전트에 프롬프트를 보내되 응답 처리는 백그라운드에서 진행할 수 있어, 애플리케이션의 응답성을 유지할 수 있습니다. thencatch 메서드로 응답이 준비됐을 때 또는 예외가 발생했을 때 호출될 클로저를 등록할 수 있습니다:

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(); });

툴을 사용하면 에이전트가 프롬프트에 응답하는 과정에서 활용할 수 있는 추가 기능을 제공할 수 있습니다. 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 { /** * 툴의 목적에 대한 설명을 반환합니다. */ public function description(): Stringable|string { return '이 툴은 암호학적으로 안전한 난수를 생성하는 데 사용할 수 있습니다.'; } /** * 툴을 실행합니다. */ 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 메서드에서 반환합니다:

use App\Ai\Tools\RandomNumberGenerator; /** * 에이전트가 사용할 수 있는 툴 목록을 반환합니다. * * @return Tool[] */ public function tools(): iterable { return [ new RandomNumberGenerator, ]; }

SimilaritySearch 툴은 데이터베이스에 저장된 벡터 임베딩을 사용하여 주어진 쿼리와 유사한 문서를 검색할 수 있게 해줍니다. 이는 에이전트가 애플리케이션 데이터를 검색할 수 있도록 하는 RAG(Retrieval-Augmented Generation) 구현에 유용합니다.

벡터 임베딩이 있는 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('지식 베이스에서 관련 문서를 검색합니다.'),

프로바이더 툴

프로바이더 툴은 AI 프로바이더가 자체적으로 구현한 특수 툴로, 웹 검색, URL 가져오기, 파일 검색 등의 기능을 제공합니다. 일반 툴과 달리 프로바이더 툴은 애플리케이션이 아닌 프로바이더가 직접 실행합니다.

프로바이더 툴은 에이전트의 tools 메서드에서 반환할 수 있습니다.

WebSearch 프로바이더 툴은 에이전트가 실시간 정보를 검색할 수 있게 합니다. 최신 뉴스, 최근 데이터, 또는 모델의 학습 이후 변경된 정보에 대한 질문에 답하는 데 유용합니다.

지원 프로바이더: Anthropic, OpenAI, Gemini

use Laravel\Ai\Providers\Tools\WebSearch; public function tools(): it

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 20일