Vercel AI SDK란?
Vercel AI SDK는 Next.js(및 Node.js) 앱에 AI 기능을 붙이는 가장 빠른 방법입니다. OpenAI, Anthropic, Google 등 주요 AI 공급자를 통합 인터페이스로 다룰 수 있고, 스트리밍·채팅·구조화 출력을 위한 React Hook과 서버 유틸리티를 제공합니다.
pnpm add ai @ai-sdk/openai @ai-sdk/anthropic
3
0초 만에 스트리밍 채팅 만들기
서버 (app/api/chat/route.ts)
import { openai } from '@ai-sdk/openai'
import { streamText } from 'ai'
export async function POST(req: Request) {
const { messages } = await req.json()
const result = streamText({
model: openai('gpt-4o-mini'),
system: '당신은 친절한 AI 어시스턴트입니다.',
messages,
})
return result.toDataStreamResponse()
}
클라이언트 (app/chat/page.tsx)
'use client'
import { useChat } from 'ai/react'
export default function ChatPage() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat()
return (
<div className="flex flex-col h-screen max-w-2xl mx-auto p-4">
<div className="flex-1 overflow-y-auto space-y-4">
{messages.map(m => (
<div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
<span className="inline-block bg-gray-100 rounded-lg px-4 py-2">
{m.content}
</span>
</div>
))}
{isLoading && <div className="text-gray-400">생각 중...</div>}
</div>
<form onSubmit={handleSubmit} className="flex gap-2 mt-4">
<input
value={input}
onChange={handleInputChange}
placeholder="메시지를 입력하세요..."
className="flex-1 border rounded-lg px-4 py-2"
/>
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded-lg">
전송
</button>
</form>
</div>
)
}
이게 전부입니다. useChat 훅 하나로 메시지 상태, 스트리밍, 로딩 상태를 모두 관리합니다.
모델 교체: 코드 변경 최소화
AI SDK의 핵심 장점은 공급자 교체가 쉽다는 것입니다:
// OpenAI → Claude로 교체: 딱 2줄
import { anthropic } from '@ai-sdk/anthropic'
// import { openai } from '@ai-sdk/openai'
const result = streamText({
model: anthropic('claude-sonnet-4-6-20251001'),
// model: openai('gpt-4o'),
messages,
})
구조화 출력 (Structured Output)
JSON 형식으로 안정적인 데이터를 받아야 할 때:
import { generateObject } from 'ai'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
// Zod 스키마로 출력 형식 정의
const ProductSchema = z.object({
name: z.string().describe('상품명'),
category: z.enum(['전자제품', '의류', '식품', '기타']),
sentiment: z.enum(['긍정', '부정', '중립']),
keyIssues: z.array(z.string()).describe('주요 문제점 목록'),
rating: z.number().min(1).max(5),
})
export async function analyzeReview(reviewText: string) {
const { object } = await generateObject({
model: openai('gpt-4o-mini'),
schema: ProductSchema,
prompt: `다음 리뷰를 분석하세요: ${reviewText}`,
})
return object
// { name: "...", category: "전자제품", sentiment: "부정", keyIssues: [...], rating: 2 }
}
generateText 대신 generateObject를 쓰면 파싱 코드 없이 타입 안전한 JSON을 받을 수 있습니다.
Tool Use (함수 호출)
AI가 도구를 사용해 실제 작업을 수행하게 합니다:
import { streamText, tool } from 'ai'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
const result = streamText({
model: openai('gpt-4o'),
tools: {
getWeather: tool({
description: '특정 도시의 날씨를 조회합니다',
parameters: z.object({
city: z.string().describe('도시명'),
}),
execute: async ({ city }) => {
// 실제 날씨 API 호출
const response = await fetch(`https://api.weather.com/${city}`)
return response.json()
},
}),
searchDatabase: tool({
description: '제품 데이터베이스에서 검색합니다',
parameters: z.object({
query: z.string(),
limit: z.number().default(5),
}),
execute: async ({ query, limit }) => {
return await db.products.search(query, limit)
},
}),
},
messages,
maxSteps: 5, // 최대 도구 호출 횟수
})
useCompletion: 단발성 텍스트 생성
채팅이 아닌 단발성 생성(문서 요약, 번역 등)에는 useCompletion을 사용합니다:
'use client'
import { useCompletion } from 'ai/react'
export function SummaryButton({ article }: { article: string }) {
const { completion, complete, isLoading } = useCompletion({
api: '/api/summarize',
})
return (
<div>
<button
onClick={() => complete(article)}
disabled={isLoading}
className="bg-blue-500 text-white px-4 py-2 rounded"
>
{isLoading ? '요약 중...' : '요약하기'}
</button>
{completion && (
<div className="mt-4 p-4 bg-gray-50 rounded">
{completion}
</div>
)}
</div>
)
}
미들웨어와 에러 처리
프로덕션에서는 레이트 리밋과 에러 처리가 필수입니다:
// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai'
import { streamText } from 'ai'
import { NextResponse } from 'next/server'
export async function POST(req: Request) {
try {
const { messages, userId } = await req.json()
// 레이트 리밋 확인
const allowed = await checkRateLimit(userId)
if (!allowed) {
return NextResponse.json(
{ error: '요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요.' },
{ status: 429 }
)
}
const result = streamText({
model: openai('gpt-4o'),
messages,
onFinish: async ({ usage, text }) => {
// 사용량 로깅
await logUsage({ userId, tokens: usage.totalTokens, chars: text.length })
},
})
return result.toDataStreamResponse()
} catch (error) {
console.error('AI API 에러:', error)
return NextResponse.json({ error: '서버 오류가 발생했습니다.' }, { status: 500 })
}
}
주요 Hook 정리
| Hook | 용도 | 반환값 |
|---|---|---|
useChat | 멀티턴 채팅 | messages, input, handleSubmit |
useCompletion | 단발성 생성 | completion, complete, isLoading |
useAssistant | OpenAI Assistants API | messages, submitMessage |
useObject | 실시간 구조화 출력 | object, submit, isLoading |
결론
Vercel AI SDK는 Next.js 개발자에게 최적화된 AI 통합 도구입니다. 핵심 장점:
- 통합 인터페이스: OpenAI, Claude, Gemini를 동일한 코드로 교체
- React 최적화: 스트리밍, 로딩 상태, 에러 처리를 Hook으로 추상화
- 타입 안전: TypeScript + Zod로 AI 출력을 안전하게 처리
- 서버 컴포넌트 지원: Next.js App Router와 완벽 통합
AI 기능을 처음 Next.js에 붙여보고 싶다면 공식 문서(sdk.vercel.ai)의 예제부터 시작하세요.





