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_conversations 및 agent_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 |
| TTS | OpenAI, ElevenLabs |
| STT | OpenAI, 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 메서드를 사용하면 에이전트에 프롬프트를 보내되 응답 처리는 백그라운드에서 진행할 수 있어, 애플리케이션의 응답성을 유지할 수 있습니다. then 및 catch 메서드로 응답이 준비됐을 때 또는 예외가 발생했을 때 호출될 클로저를 등록할 수 있습니다:
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