OpenAI, Anthropic Claude, Mistral, Cohere AI 서비스 통합을 위한 Laravel 패키지 Sidekick
요약
OpenAI, Anthropic Claude, Mistral, Cohere 등 주요 AI 서비스들을 통합적으로 사용할 수 있는 Laravel 패키지 'Sidekick'이 소개되었습니다. 이 패키지는 빌더 API, 스트리밍 지원, 툴 호출, 구조화된 출력 등 현대적인 LLM 기능을 PHP 환경에서 쉽게 구현할 수 있도록 설계되었습니다.
핵심 포인트
- OpenAI, Anthropic Claude 등 다수 AI 모델 통합 지원
- Laravel 기반으로 개발 편의성 극대화 (PHP 8.2+)
- 빌더 패턴을 통해 프롬프트 및 설정 관리 용이
- 스트리밍, 툴 호출, 구조화된 출력 등 고급 기능 제공
OpenAI, Anthropic Claude, Mistral, 그리고 Cohere AI 서비스를 통합하기 위한 유연한 Laravel 패키지입니다. 현대적인 빌더 API, 타입이 지정된 응답(typed responses), 스트리밍 지원(streaming support), 툴 호출(tool calling), 구조화된 출력(structured output), 데이터베이스 기반 대화 기록(database-backed conversations), 임베드 가능한 채팅 위젯(embeddable chat widget), 그리고 최고 수준의 테스트 지원을 특징으로 합니다.
PHP 8.2+
- Laravel 10, 11, 또는 12
composer require paparascaldev/sidekick
php artisan sidekick:install
또는 수동으로 설치할 수 있습니다:
composer require paparascaldev/sidekick
php artisan vendor:publish --tag=sidekick-config
php artisan migrate
.env 파일에 API 키를 추가하세요
(사용하는 제공업체만 추가하세요):
SIDEKICK_OPENAI_TOKEN=your-openai-key
SIDEKICK_CLAUDE_TOKEN=your-anthropic-key
SIDEKICK_MISTRAL_TOKEN=your-mistral-key
...
설정 파일을 게시하고 사용자 정의하세요:
php artisan vendor:publish --tag=sidekick-config
config/sidekick.php 파일에는 다음이 포함됩니다:
return [
// 명시된 기본 제공업체(provider)가 없을 때의 기본값
'default' => env('SIDEKICK_DEFAULT_PROVIDER', 'openai'),
...
Sidekick 파사드(facade) 또는 sidekick() 헬퍼 함수를 사용할 수 있습니다:
use PapaRascalDev\Sidekick\Facades\Sidekick;
// 파사드를 사용하는 경우
$response = Sidekick::text()->withPrompt('Hello')->generate();
...
$response = Sidekick::text()
->using('openai', 'gpt-4o')
->withSystemPrompt('You are a helpful assistant.')
...
모든 TextBuilder 메서드:
| Method | Description |
|---|---|
using(string $provider, ?string $model) | 제공자 및 모델 설정 |
withPrompt(string $prompt) | 사용자 메시지 추가 |
withSystemPrompt(string $prompt) | 시스템 프롬프트 설정 |
withMessages(array $messages) | 전체 메시지 기록 설정 (Message 객체 또는 배열의 배열) |
addMessage(Role $role, string $content) | 특정 역할을 가진 단일 메시지 추가 |
withMaxTokens(int $maxTokens) | 최대 토큰 수 설정 (기본값: 1024) |
withTemperature(float $temp) | 온도 설정 (기본값: 1.0) |
generate(): TextResponse | 실행 및 TextResponse 반환 |
stream(): StreamResponse | 실행 및 스트리밍 가능한 StreamResponse 반환 |
$stream = Sidekick::text()
->using('anthropic', 'claude-sonnet-4-20250514')
->withPrompt('Write a haiku about coding')
...
모델이 호출할 수 있는 도구를 제공하면, Sidekick이 이를 대신 실행합니다. 도구는 이름, 설명, 인자용 JSON Schema, 그리고 핸들러로 정의합니다. Sidekick은 모델에게 도구를 보내고, 모델이 요청할 때 핸들러를 실행하며, 그 결과를 다시 전달하고, 모델이 최종 답변을 반환할 때까지 루프를 반복합니다.
OpenAI, Anthropic, Mistral에서 지원됩니다.
use PapaRascalDev\\\Sidekick\\\Facades\\\Sidekick;
use PapaRascalDev\\\Sidekick\\\ValueObjects\\Tool;
$response = Sidekick::text()
...
핸들러는 모델의 인자를 배열로 받고 문자열을 반환합니다 (배열 및 객체는 자동으로 JSON 인코딩됩니다). 그 결과는 모델에게 다시 전송되므로, 최종 $response->text는 도구가 실행된 후의 답변입니다.
만약 도구에 핸들러가 없다면, Sidekick은 모델이 요청할 때 멈추고 호출을 사용자에게 돌려주어 직접 실행하도록 합니다:
$response = Sidekick::text()
->using('openai', 'gpt-4o')
->withPrompt('What is the weather in London?')
...
기본적으로 Sidekick은 제어권을 반환하기 전에 최대 5번의 자동 도구 라운드를 실행합니다. withMaxToolCalls()로 조정할 수 있습니다:
Sidekick::text()
->using('anthropic', 'claude-sonnet-4-20250514')
->withPrompt('Plan my trip.')
...
Tool 메서드:
| Method | Description |
|---|---|
withTools(array $tools) | 도구 추가 (Tool 객체 또는 배열) |
withTool(Tool $tool) | 단일 도구 추가 |
withMaxToolCalls(int $max) | 최대 자동 도구 호출 횟수 (기본값: 5) |
Tool::make()
은 name, description, parameters (JSON Schema 객체), 그리고 선택적 handler callable을 받습니다. Cohere는 아직 도구 호출을 지원하지 않으며, 도구가 전달되면 명확한 예외를 발생시킵니다.
자유 텍스트 대신 모델로부터 유형화되고 검증된 JSON을 받으려면 JSON Schema를 전달하고 Sidekick이 응답을 TextResponse::$structured에 디코드합니다.
OpenAI, Anthropic, Mistral에서 지원됩니다.
$response = Sidekick::text()
->using('openai', 'gpt-4o')
->withPrompt('Extract the person: John Doe, age 42, lives in London.')
...
기본적으로 Sidekick은 엄격한 스키마(이름 response, strict true)를 요청합니다. OpenAI와 Mistral에서 엄격 모드는 모든 객체가 additionalProperties: false를 설정하고 required에 모든 키를 나열하도록 요구합니다. 사용자 지정 이름으로 전달하거나 엄격 모드를 완화해야 할 때는 다음을 사용하세요:
use PapaRascalDev\Sidekick\ValueObjects\Schema;
// 인라인
->withSchema($schema, name: 'person', strict: false)
...
각 제공업체별 구현 방식: OpenAI와 Mistral은 네이티브 json_schema 응답 형식을 사용합니다. Anthropic에는 네이티브 동등물이 없기 때문에 Sidekick은 스키마와 일치하는 단일 도구를 강제하고, 구조화된 결과를 그로부터 읽어옵니다. 어느 쪽이든 $response->structured에서 동일한 디코드된 배열을 얻게 됩니다. Cohere는 아직 지원되지 않으며 명확한 예외를 발생시킵니다.
구조화 메서드:
| Method | Description |
|---|---|
| `withSchema(array | Schema $schema, string $name = 'response', bool $strict = true)` |
// 대화 시작
$convo = Sidekick::conversation()
->using('openai', 'gpt-4o')
...
모든 ConversationBuilder 메서드:
| 메서드 | 설명 |
|---|---|
using(string $provider, ?string $model) | 제공자 및 모델 설정 |
withSystemPrompt(string $prompt) | 시스템 프롬프트 설정 |
withMaxTokens(int $maxTokens) | 최대 토큰 수 설정 (기본값: 1024) |
begin(): self | 새로운 대화 시작 (DB에 영속화됨) |
resume(string $id): self | UUID를 사용하여 기존 대화 재개 |
send(string $message): TextResponse | 메시지 전송 및 응답 받기 |
delete(): bool | 대화 및 메시지 삭제 |
getConversation(): ?Conversation | 기본 Eloquent 모델 가져오기 |
$response = Sidekick::image()
->using('openai', 'dall-e-3')
->withPrompt('A sunset over mountains')
...
모든 ImageBuilder 메서드:
| 메서드 | 설명 |
|---|---|
using(string $provider, ?string $model) | 제공자 및 모델 설정 |
withPrompt(string $prompt) | 이미지 프롬프트 설정 |
withSize(string $size) | 크기 설정 (기본값: 1024x1024 ) |
withQuality(string $quality) | 품질 설정: standard 또는 hd (기본값: standard ) |
count(int $count) | 생성할 이미지 개수 (기본값: 1) |
generate(): ImageResponse | 실행 및 ImageResponse 반환 |
$response = Sidekick::audio()
->using('openai', 'tts-1')
->withText('Hello, welcome to Sidekick!')
...
모든 AudioBuilder 메서드:
| 메서드 | 설명 |
|---|---|
using(string $provider, ?string $model) | 제공자 및 모델 설정 |
withText(string $text) | 음성으로 말할 텍스트 설정 |
withVoice(string $voice) | 목소리 설정 (기본값: alloy ) |
withFormat(string $format) | 오디오 형식 설정 (기본값: mp3 ) |
generate(): AudioResponse | 실행 및 AudioResponse 반환 |
$response = Sidekick::transcription()
->using('openai', 'whisper-1')
->withFile('/path/to/audio.mp3')
...
모든 TranscriptionBuilder 메서드:
| 메서드 | 설명 |
|---|---|
using(string $provider, ?string $model) | 제공업체 및 모델 설정 |
withFile(string $filePath) | 오디오 파일 경로 |
withLanguage(string $language) | 언어 힌트 (선택 사항) |
generate(): TranscriptionResponse | 실행하고 TranscriptionResponse 반환 |
$response = Sidekick::embedding()
->using('openai', 'text-embedding-3-small')
->withInput('Laravel is a great framework')
...
모든 EmbeddingBuilder 메서드:
| 메서드 | 설명 |
|---|---|
using(string $provider, ?string $model) | 제공업체 및 모델 설정 |
| `withInput(string | array $input)` |
generate(): EmbeddingResponse | 실행하고 EmbeddingResponse 반환 |
$response = Sidekick::moderation()
->using('openai', 'text-moderation-latest')
->withContent('Some text to moderate')
...
모든 ModerationBuilder 메서드:
| 메서드 | 설명 |
|---|---|
using(string $provider, ?string $model) | 제공업체 및 모델 설정 |
withContent(string $content) | 검열할 텍스트 |
generate(): ModerationResponse | 실행하고 ModerationResponse 반환 |
기본 텍스트 제공업체를 사용하는 간편 메서드:
// 텍스트 요약 (문자열 반환)
$summary = Sidekick::summarize('Long text here...', maxLength: 500);
// 텍스트 번역 (문자열 반환)
...
Sidekick은 비즈니스 지식을 저장하고 실제 데이터에 AI 응답을 근거지어 답변함으로써, 반품 정책, 가격 책정, 지원 시간 등에 대한 환각(hallucinations)을 방지할 수 있는 내장 RAG (Retrieval-Augmented Generation, 검색 증강 생성) 시스템을 포함합니다.
RAG는 기본 설정으로 바로 작동합니다. config/sidekick.php의 knowledge 섹션에서 임베딩 제공업체, 청크 크기 및 검색 설정을 제어합니다:
'knowledge' => [
'embedding' => ['provider' => 'openai', 'model' => 'text-embedding-3-small'],
'chunking' => ['chunk_size' => 2000, 'overlap' => 200],
...
또는 Artisan 명령어를 사용합니다:
# 파일 인제스트(Ingest)하기
php artisan sidekick:ingest my-kb --file=/path/to/faq.md
# 인라인 텍스트 인제스트하기
...
// 관련 청크 검색하기
$results = Sidekick::knowledge('my-kb')->search('What is your return policy?');
foreach ($results as $chunk) {
...
// 원샷(One-liner): KB를 검색하고 근거 기반 답변 생성하기
$answer = Sidekick::knowledge('my-kb')->ask('What is your return policy?');
챗 위젯을 지식 기반에 연결하여 사용자 데이터로부터 답변하도록 설정합니다:
SIDEKICK_WIDGET_ENABLED=true
SIDEKICK_WIDGET_KNOWLEDGE_BASE=my-kb
또는 config/sidekick.php에서
:
'widget' => [
'knowledge_base' => 'my-kb',
'rag_context_chunks' => 5,
...
설정되면 위젯은 각 사용자 메시지에 대해 자동으로 지식 기반을 검색하고 관련 컨텍스트를 시스템 프롬프트에 주입합니다. RAG가 실패할 경우(API 오류, 빈 KB), 원래의 시스템 프롬프트로 우아하게 폴백(fallback)됩니다.
기본 VectorSearch 드라이버는 PHP에서 코사인 유사도(cosine similarity)를 계산합니다. 프로덕션 워크로드의 경우 사용자 정의 드라이버(예: pgvector, Pinecone)로 교체할 수 있습니다:
// SearchesKnowledge 계약 구현하기
use PapaRascalDev\\\Sidekick\Contracts\SearchesKnowledge;
class PgVectorSearch implements SearchesKnowledge
...
$kb = Sidekick::knowledge('my-kb');
$kb->chunkCount(); // 저장된 청크 개수
$kb->purge(); // 모든 청크 삭제하기
...
Sidekick은 Alpine.js 기반의 챗 위젯을 제공하며, 이를 모든 Blade 템플릿에 임베드할 수 있습니다. Livewire는 필요하지 않습니다.
.env 파일에서:
SIDEKICK_WIDGET_ENABLED=true
SIDEKICK_WIDGET_PROVIDER=openai
SIDEKICK_WIDGET_MODEL=gpt-4o
...
<x-sidekick::chat-widget
position="bottom-right"
theme="dark"
...
Props:
| Prop | 기본값 (Default) | 옵션 (Options) |
|---|---|---|
position | bottom-right | bottom-right, bottom-left, top-right, top-left |
theme | light | light, dark |
title | Chat Assistant | 모든 문자열 (Any string) |
placeholder | Type a message... | 모든 문자열 (Any string) |
button-label | Chat | 모든 문자열 (Any string) |
Alpine.js를 포함하고 CSRF 메타 태그를 갖도록 레이아웃을 구성하세요:
<meta name="csrf-token" content="{{ csrf_token() }}">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
런타임 또는 설정을 통해 사용자 정의 Provider를 등록하세요:
// 런타임 등록 (Runtime registration)
Sidekick::registerProvider('ollama', function ($app) {
return new OllamaProvider(config('sidekick.providers.ollama'));
...
사용자 정의 Provider는 ProviderContract와 관련 기능 인터페이스(ProvidesText, ProvidesImages, ProvidesAudio, ProvidesTranscription, ProvidesEmbeddings, ProvidesModeration)를 구현해야 합니다.
Sidekick은 Sidekick::fake()을 통해 최고 수준의 테스트 지원을 제공합니다:
use PapaRascalDev\Sidekick\Facades\Sidekick;
use PapaRascalDev\Sidekick\Responses\TextResponse;
use PapaRascalDev\Sidekick\ValueObjects\Meta;
...
Sidekick은 구독할 수 있는 Laravel 이벤트를 디스패치합니다:
AI 자동 생성 콘텐츠
본 콘텐츠는 GitHub AI Tools의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기