Laravel 앱에 Claude/OpenAI API 통합하기: 실전 가이드
요약
Laravel 애플리케이션에 Claude와 OpenAI API를 통합하는 실전 가이드를 제공합니다. 드라이버 패턴을 사용하여 설정 변경만으로 AI 모델을 쉽게 전환할 수 있는 깔끔한 아키텍처 설계 방법을 다룹니다.
핵심 포인트
- Laravel의 config 시스템과 .env를 활용한 안전한 API 키 관리
- 드라이버 패턴을 적용한 ReportSummaryService 설계 방식
- Claude와 OpenAI API의 인증 헤더 및 구조적 차이점 비교
- PHP 환경에서 AI 기능을 프로덕션 수준으로 구현하는 방법
12년 이상 PHP 애플리케이션을 구축해 온 저는, 최근 프로덕션 환경의 Laravel 대시보드에 AI 기반 기능인 '원시 분석 데이터로부터 생성되는 자동 보고서 요약' 기능을 추가했습니다. 저를 놀라게 했던 것은 구현의 난이도가 아니라, 이 주제에 대해 PHP 중심의 양질의 콘텐츠가 얼마나 적은가 하는 점이었습니다. 거의 모든 LLM 튜토리얼은 당신이 Python을 작성하고 있다고 가정합니다.
그래서 제가 간절히 원했던 가이드를 여기에 준비했습니다. 바로 실제 프로덕션에 배포할 수 있는 깔끔한 아키텍처를 사용하여 Claude API와 OpenAI API를 Laravel 앱에 통합하는 방법입니다.
우리가 만들 것: 원시 데이터를 입력받아 사람이 읽을 수 있는 요약본을 반환하는 ReportSummaryService입니다. 설정 변경 한 번으로 Claude와 OpenAI 사이를 전환할 수 있도록 드라이버 패턴 (driver pattern)을 적용할 것입니다.
1단계: API 키 가져오기
- Claude: Claude Console에 가입하고, Account Settings에서 키를 생성하세요.
- OpenAI: OpenAI Platform에서 키를 가져오세요.
.env 파일에 다음을 추가하세요:
AI_PROVIDER=claude
ANTHROPIC_API_KEY=sk-ant-xxxxx
...
⚠️ API 키를 절대 코드에 직접 입력(hardcode)하지 마세요. 절대 커밋하지 마세요. 만약 Git에 키를 푸시한 적이 있다면 즉시 교체(rotate)하세요. (이미 알고 계시겠지만, 그래도 말씀드립니다.)
이제 config/services.php에 등록하세요. 이것이 Laravel 방식이며, 이를 통해 어디서든 config()를 사용할 수 있고 설정 캐싱 (config caching)의 이점을 누릴 수 있습니다:
'anthropic' => [
'key' => env('ANTHROPIC_API_KEY'),
'model' => env('ANTHROPIC_MODEL', 'claude-sonnet-4-6'),
...
2단계: 두 API 이해하기 (95% 유사함)
두 API 모두 단순한 REST API입니다. JSON을 POST하면 JSON을 돌려받습니다.
Claude (Messages API):
POST https://api.anthropic.com/v1/messages
Headers:
x-api-key: YOUR_KEY
...
OpenAI (Chat Completions API):
POST https://api.openai.com/v1/chat/completions
Headers:
Authorization: Bearer YOUR_KEY
...
사람들을 헷갈리게 만드는 주요 차이점은 다음과 같습니다:
| Claude | OpenAI | |
|---|---|---|
| 인증 헤더 (Auth header) | x-api-key | Authorization: Bearer |
| ... |
그게 전부입니다. 이 다섯 가지 차이점만 알면 두 API를 모두 파악한 것입니다.
Step 3: 계약 (Contract) + 드라이버 (Drivers) 구축
컨트롤러 곳곳에 Http::post() 호출을 흩뿌리는 대신 (우리 모두 그런 코드베이스를 본 적이 있죠), 계약 (Contract)을 정의해 보겠습니다:
// app/Services/AI/AiClientInterface.php
...
Claude 드라이버
Laravel의 HTTP 클라이언트는 이를 매우 깔끔하게 만들어 줍니다. cURL 보일러플레이트 (boilerplate)가 필요 없습니다:
// app/Services/AI/ClaudeClient.php
...
OpenAI 드라이버
// app/Services/AI/OpenAiClient.php
...
Laravel이 여기서 얼마나 많은 작업을 대신 처리해 주는지 주목하세요: timeout(), 조건부 콜백을 포함한 retry(), withToken(), 그리고 JSON 응답에 대한 점 표기법 (dot-notation) 접근까지. 이것이 제가 이 프레임워크를 사랑하는 이유입니다.
Step 4: 서비스 프로바이더 (Service Provider)에서 드라이버 바인딩하기
이제 마법이 일어납니다. 단 하나의 설정 값으로 앱 전체가 어떤 프로바이더를 사용할지 결정합니다:
// app/Providers/AppServiceProvider.php
...
.env 파일의 한 줄만 변경하여 프로바이더를 전환할 수 있습니다. 코드 변경은 필요 없습니다. 만약 한 프로바이더에 장애가 발생하거나 가격이 변동된다면, 스위치만 바꾸면 됩니다. 이 추상화만으로도 충분한 가치가 있습니다.
Step 5: 실제 기능 구축하기
제 실제 업무에서 가져온 현실적인 유스케이스(use case)를 소개합니다: 일일 분석 데이터를 경영진이 읽기 쉬운 보고서로 요약하는 기능입니다.
// app/Services/ReportSummaryService.php
...
그리고 컨트롤러는 마땅히 그래야 하듯 가볍게 작성합니다:
// app/Http/Controllers/ReportController.php
...
Laravel의 컨테이너 (container)가 모든 것을 주입 (inject)합니다. 컨트롤러는 요약을 작성한 것이 Claude인지 OpenAI인지 알 필요도, 신경 쓸 필요도 없습니다.
Step 6: 프로덕션 강화 (튜토리얼에서 생략되는 부분)
공격적인 캐싱 (Cache aggressively)
LLM 호출은 느리고 (1~10초) 비용이 발생합니다. 입력값이 변경되지 않았다면 API를 다시 호출하지 마세요:
use Illuminate\Support\Facades\Cache;
public function summarize(array $reportData): string
...
제 경우에는 이 방식이 API 비용을 약 70% 정도 절감해 주었습니다. 대부분의 사용자가 하루에도 같은 보고서를 여러 번 요청하기 때문입니다.
긴 작업은 큐(Queues)로 이동하기
사용자의 HTTP 요청이 LLM을 기다리며 10초 동안 멈춰 있게 하지 마세요. 큐에 작업(queued job)을 디스패치(dispatch)하고, 결과를 저장한 뒤, 준비가 되면 알림을 보내도록 하세요:
GenerateReportSummary::dispatch($reportId);
이미 Laravel 큐(Redis/database 드라이버)를 사용 중이라면, 이 작업은 15분이면 충분합니다.
실패를 우아하게 처리하기 (Handle failures gracefully)
LLM API는 때때로 실패합니다. 속도 제한(rate limits), 서버 과부하, 타임아웃 등이 발생할 수 있습니다. 저희 드라이버의 retry() 호출은 일시적인 오류를 처리하지만, 앱이 우아하게 성능을 저하시킬(degrade gracefully) 수 있도록 항상 해당 기능을 래핑(wrap)하세요:
try {
$summary = $summaryService->summarize($data);
} catch (RuntimeException $e) {
...
AI 기능은 부가적인 강화 요소여야 하며, 단일 장애점(single point of failure)이 되어서는 안 됩니다.
비용 제어하기
max_tokens를 의도적으로 설정하세요. 이는 요청당 출력 비용의 상한선을 정해줍니다.- 단순한 작업에는 더 작은 모델을 사용하세요. 요약, 분류(classification), 추출(extraction) 작업에는 플래그십 모델이 거의 필요하지 않습니다. Claude Haiku나 OpenAI의 mini 티어 모델은 종종 10배 더 저렴하면서도 충분히 훌륭한 성능을 보여줍니다.
- 배포 전 제공업체 대시보드에서 지출 한도(spend limits)를 설정하세요. 이 점은 꼭 믿으셔도 좋습니다.
- 토큰 사용량을 기록(Log)하세요. 두 API 모두 응답에
usage객체를 반환합니다. 이를 저장하여 각 기능에 정확히 얼마의 비용이 드는지 파악하세요.
공식 SDK는 어떤가요?
위의 모든 내용은 Laravel의 HTTP 클라이언트를 사용하므로 네트워크상에서 정확히 어떤 일이 일어나는지 확인할 수 있습니다. 더 큰 프로젝트라면 다음을 고려해 보세요:
- Anthropic의 공식 PHP SDK:
composer require anthropic-ai/sdk guzzlehttp/guzzle(PHP 8.1 이상 필요) — 스트리밍(streaming), 페이지네이션(pagination), 재시도(retries)를 대신 처리해 줍니다. - openai-php/laravel: Laravel 네이티브 파사드(facade)를 제공하는 인기 있는 커뮤니티 패키지입니다.
저는 여전히 여기서 했던 것처럼 원시(raw) 버전을 한 번 작성해 보는 것을 추천합니다. 실제 API를 이해하면 나중에 SDK 문제를 디버깅하기가 훨씬 쉬워집니다.
마무리
전체적인 그림은 다음과 같습니다:
.env파일의 키를config/services.php를 통해 참조- 제공자(provider)별 드라이버를 포함하는
AiClientInterface계약(contract) - 환경 변수 하나로 제공자를 전환할 수 있는 컨테이너 바인딩(Container binding)
- 얇은 컨트롤러(Thin controllers)와 서비스(services)에 위치한 로직
- 프로덕션 환경을 위한 캐시(Cache) + 큐(Queues) + 우아한 실패(Graceful failure) 처리
이 중 어느 것도 생소한 것이 아닙니다. 여러분이 이미 사용하고 있는 깔끔한 Laravel 아키텍처를 새로운 종류의 API에 적용한 것뿐입니다. 이것이 진짜 핵심입니다: AI 기능을 구축하기 위해 Python을 배울 필요는 없습니다. 여러분의 PHP 기술은 그대로 적용됩니다.
다음 포스트에서는 Laravel과 서버 전송 이벤트(Server-Sent Events, SSE)를 사용하여 브라우저로 스트리밍 응답을 전달하는 방법(ChatGPT 스타일로 요약이 한 단어씩 나타나도록 하는 방법)을 다룰 예정입니다. 해당 내용을 놓치고 싶지 않다면 저를 팔로우해 주세요.
PHP 앱에 AI 기능을 추가해 보셨나요? 무엇을 사용하셨나요 — 순수 HTTP, SDK, 아니면 다른 무언가였나요? 댓글로 여러분의 이야기를 들려주세요. 👇
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기