Vercel AI SDK로 스트리밍 챗봇 구현하기 - 코드픽 블로그
Vercel AI SDK로 스트리밍 챗봇 구현하기
기술 가이드

Vercel AI SDK로 스트리밍 챗봇 구현하기

2026년 2월 28일 62 views by 코드벤터

Vercel AI SDK로 스트리밍 챗봇 구현하기

AI 챗봇을 만들 때 가장 중요한 사용자 경험 중 하나는 실시간 스트리밍 응답입니다. ChatGPT처럼 텍스트가 한 글자씩 흘러나오는 방식은 응답 완료를 기다리는 지루함을 없애고, 실제로 AI가 생각하고 있다는 느낌을 줍니다. Vercel AI SDK는 이 복잡한 스트리밍 로직을 몇 줄의 코드로 해결해줍니다.

Vercel AI SDK란?

Vercel AI SDK는 TypeScript 기반의 오픈소스 툴킷으로, LLM(Large Language Model) 연동과 스트리밍 응답 처리를 추상화해줍니다. OpenAI, Google Gemini, Anthropic Claude 등 주요 AI 공급자를 단일 인터페이스로 지원하며, React/Next.js와 긴밀하게 통합됩니다.

주요 패키지 구성

패키지역할주요 기능
`ai`코어 SDKstreamText, generateText, tool 정의
`@ai-sdk/react`React 훅useChat, useCompletion, useAssistant
`@ai-sdk/openai`OpenAI 어댑터GPT-4o, o1 등 모델 연결
`@ai-sdk/google`Google 어댑터Gemini Pro, Flash 등 모델 연결
`@ai-sdk/anthropic`Anthropic 어댑터Claude 3.5 등 모델 연결

프로젝트 설정

1단계: Next.js 프로젝트 생성 및 패키지 설치

bash
npx create-next-app@latest ai-chatbot --typescript --app --eslint
cd ai-chatbot
npm install ai @ai-sdk/react @ai-sdk/openai

2단계: 환경 변수 설정

프로젝트 루트에 .env.local 파일을 생성합니다.

bash
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx

이 파일은 절대 Git에 커밋하지 마세요. .gitignore.env.local이 포함되어 있는지 확인하세요.


백엔드: API Route Handler 구현

Next.js App Router 기반의 스트리밍 API 라우트를 작성합니다.

typescript
// app/api/chat/route.ts
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';

export const runtime = 'edge';
export const maxDuration = 30;

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = await streamText({
    model: openai('gpt-4o'),
    system: '당신은 친절하고 유능한 AI 어시스턴트입니다. 한국어로 답변하세요.',
    messages,
  });

  return result.toDataStreamResponse();
}

streamText는 LLM의 응답을 청크 단위로 스트리밍하며, toDataStreamResponse()는 이를 클라이언트 측 useChat 훅이 이해할 수 있는 형식으로 변환합니다. runtime = edge를 설정하면 Vercel Edge Network에서 실행되어 더 빠른 응답을 기대할 수 있습니다.


프론트엔드: useChat 훅으로 UI 구성

useChat 훅은 채팅 상태 관리, 메시지 전송, 스트리밍 응답 수신을 모두 처리합니다.

typescript
// app/page.tsx
'use client';

import { useChat } from '@ai-sdk/react';

export default function ChatPage() {
  const {
    messages,
    input,
    handleInputChange,
    handleSubmit,
    isLoading,
    error,
    reload,
    stop,
  } = useChat({
    api: '/api/chat',
    onError: (err) => console.error('Chat error:', err),
  });

  return (
    <div className="flex flex-col h-screen max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4 text-sky-400">AI 챗봇</h1>

      <div className="flex-1 overflow-y-auto space-y-4 mb-4">
        {messages.map((msg) => (
          <div
            key={msg.id}
            className={msg.role === 'user' ? 'bg-sky-100 ml-8' : 'bg-gray-100 mr-8'}
          >
            <span className="text-xs text-gray-500">{msg.role === 'user' ? '나' : 'AI'}</span>
            <p className="whitespace-pre-wrap">{msg.content}</p>
          </div>
        ))}

        {isLoading && (
          <div className="bg-gray-100 mr-8 p-3 rounded-lg">
            <p className="text-gray-400 animate-pulse">응답 생성 중...</p>
          </div>
        )}
      </div>

      {error && (
        <div className="mb-2 p-2 bg-red-100 text-red-600 rounded text-sm">
          오류가 발생했습니다.
          <button onClick={() => reload()} className="underline ml-1">다시 시도</button>
        </div>
      )}

      <form onSubmit={handleSubmit} className="flex gap-2">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="메시지를 입력하세요..."
          disabled={isLoading}
          className="flex-1 border border-gray-300 rounded-lg px-4 py-2"
        />
        {isLoading ? (
          <button type="button" onClick={() => stop()} className="px-4 py-2 bg-red-500 text-white rounded-lg">중단</button>
        ) : (
          <button type="submit" disabled={!input.trim()} className="px-4 py-2 bg-sky-500 text-white rounded-lg">전송</button>
        )}
      </form>
    </div>
  );
}

고급 기능: Tool Calling

단순한 대화를 넘어, Tool Calling을 활용하면 AI가 외부 API를 호출하거나 특정 작업을 수행하도록 할 수 있습니다.

typescript
// app/api/chat/route.ts (Tool Calling 버전)
import { streamText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = await streamText({
    model: openai('gpt-4o'),
    messages,
    tools: {
      getWeather: tool({
        description: '특정 도시의 현재 날씨를 조회합니다.',
        parameters: z.object({
          city: z.string().describe('날씨를 조회할 도시명'),
        }),
        execute: async ({ city }) => {
          return { city, temperature: 22, condition: '맑음' };
        },
      }),
    },
    maxSteps: 5,
  });

  return result.toDataStreamResponse();
}

멀티 모델 지원: 공급자 전환하기

Vercel AI SDK의 강점은 공급자를 손쉽게 바꿀 수 있다는 것입니다.

typescript
import { google } from '@ai-sdk/google';
import { anthropic } from '@ai-sdk/anthropic';

// Google Gemini로 전환
const result = await streamText({
  model: google('gemini-2.0-flash-exp'),
  messages,
});

// Anthropic Claude로 전환
const result2 = await streamText({
  model: anthropic('claude-3-5-sonnet-20241022'),
  messages,
});

코어 로직은 동일하게 유지하면서 모델만 바꿀 수 있어, A/B 테스트나 비용 최적화에 유리합니다.


대화 기록 영구 저장

기본 useChat은 페이지 새로고침 시 대화 기록이 사라집니다. 영구 저장을 위해 initialMessages와 서버 저장 로직을 결합합니다.

typescript
const { messages } = useChat({
  initialMessages: previousMessages,
  onFinish: async (message) => {
    await fetch('/api/save-message', {
      method: 'POST',
      body: JSON.stringify({ message }),
    });
  },
});

정리: 왜 Vercel AI SDK인가?

Vercel AI SDK는 스트리밍 챗봇 구현의 복잡도를 획기적으로 낮춰줍니다. streamText로 백엔드 스트리밍을 처리하고, useChat으로 프론트엔드 상태를 관리하면, 수백 줄이 필요했던 작업을 수십 줄로 해결할 수 있습니다. Tool Calling, 멀티 모델 지원, Edge Runtime 최적화까지 갖춰져 있어 프로덕션 수준의 AI 애플리케이션을 빠르게 구축할 수 있습니다.

코드벤터는 Vercel AI SDK와 같은 최신 AI 개발 도구를 적극 활용해 실용적인 AI 서비스를 빠르게 만들어냅니다. 복잡한 기술을 단순하게, 아이디어를 현실로 바꾸는 것이 코드벤터가 추구하는 방향입니다. 함께 만들어가는 여정에 동참하고 싶다면 codepick.kr을 찾아주세요.

개발 의뢰 상담

AI 서비스나 플랫폼 개발을
고민 중이신가요?

CodePick에서는
기획 → 개발 → 운영까지 함께합니다.
아이디어만 있어도 상담 가능합니다.

CodeVenter 개발팀이 직접 담당 · 1~2 영업일 내 회신

✓ 스타트업 MVP 개발✓ AI 서비스 개발✓ 웹 플랫폼 개발✓ 기업 시스템 구축✓ 모바일 앱 개발

AI Development Studio

코드픽 by 코드벤터

  • 대표: 윤승환 · 사업자등록번호: 121-57-64983
  • 대구광역시 중구 국채보상로 586, 16층 · info@codeventer.com

© 2025 코드벤터. All rights reserved.