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

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

2026년 3월 2일 45 views by 코드벤터

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

AI 챗봇을 만들 때 가장 중요한 사용자 경험 중 하나는 실시간 스트리밍입니다. 응답 전체가 오기를 기다리는 대신, 글자가 하나씩 나타나는 방식은 체감 속도를 크게 향상시킵니다. Vercel AI SDK는 이를 쉽게 구현할 수 있도록 설계된 TypeScript 기반의 오픈소스 라이브러리입니다.

이 글에서는 Next.js App Router + Vercel AI SDK를 활용해 실시간 스트리밍 챗봇을 처음부터 끝까지 구현하는 방법을 살펴봅니다.


Vercel AI SDK란?

Vercel AI SDK는 OpenAI, Google Gemini, Anthropic Claude 등 다양한 AI 모델 제공업체와의 통합을 추상화해주는 라이브러리입니다. 핵심 기능은 두 가지입니다.

  • AI SDK Core: 서버 사이드에서 LLM 호출 및 스트리밍 처리 (streamText, generateText 등)
  • AI SDK UI: 클라이언트 사이드에서 채팅 상태 관리 (useChat, useCompletion 훅)

주요 패키지 비교

패키지역할사용 위치
`ai`Core SDK - streamText, generateText서버 (API Route)
`@ai-sdk/react`useChat, useCompletion 훅클라이언트 (React)
`@ai-sdk/openai`OpenAI 모델 어댑터서버
`@ai-sdk/google`Google Gemini 어댑터서버
`@ai-sdk/anthropic`Anthropic Claude 어댑터서버

1단계: 프로젝트 설정

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

.env.local 파일에 API 키를 추가합니다.

bash
OPENAI_API_KEY=sk-your-openai-api-key

2단계: API 라우트 생성 (서버 사이드)

app/api/chat/route.ts 파일을 생성합니다. 이 라우트는 클라이언트로부터 메시지를 받아 AI 모델에 전달하고 스트리밍 응답을 반환합니다.

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

export const maxDuration = 30;

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

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

  return result.toUIMessageStreamResponse();
}

핵심 포인트:

  • streamText: LLM 응답을 청크 단위로 스트리밍
  • convertToModelMessages: useChat 형식의 메시지를 모델용으로 변환
  • toUIMessageStreamResponse(): React 클라이언트와 호환되는 스트림 응답 포맷
  • maxDuration = 30: Vercel 서버리스 함수의 최대 실행 시간 (스트리밍 필수)

3단계: 채팅 UI 구현 (클라이언트 사이드)

tsx
// app/page.tsx
"use client";

import { useChat } from "@ai-sdk/react";
import { useEffect, useRef } from "react";

export default function ChatPage() {
  const { messages, input, handleInputChange, handleSubmit, isLoading, error } =
    useChat({ api: "/api/chat" });

  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages]);

  return (
    <div className="flex flex-col h-screen max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">AI 챗봇</h1>
      <div className="flex-1 overflow-y-auto space-y-4 mb-4">
        {messages.map((message) => (
          <div key={message.id} className={message.role === "user" ? "text-right" : "text-left"}>
            <span className={message.role === "user"
              ? "bg-blue-500 text-white rounded-lg px-4 py-2 inline-block"
              : "bg-gray-100 rounded-lg px-4 py-2 inline-block"}>
              {typeof message.content === "string" ? message.content : null}
            </span>
          </div>
        ))}
        {isLoading && (
          <div className="text-left">
            <span className="bg-gray-100 rounded-lg px-4 py-2 inline-block animate-pulse">
              답변 생성 중...
            </span>
          </div>
        )}
        {error && <div className="text-red-500">오류: {error.message}</div>}
        <div ref={bottomRef} />
      </div>
      <form onSubmit={handleSubmit} className="flex gap-2">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="메시지를 입력하세요..."
          disabled={isLoading}
          className="flex-1 border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
        />
        <button
          type="submit"
          disabled={isLoading || !input.trim()}
          className="bg-blue-500 text-white rounded-lg px-6 py-2 disabled:opacity-50">
          전송
        </button>
      </form>
    </div>
  );
}

4단계: 고급 기능 추가

smoothStream으로 부드러운 스트리밍

typescript
import { streamText, smoothStream } from "ai";

const result = streamText({
  model: openai("gpt-4o-mini"),
  messages: convertToModelMessages(messages),
  experimental_transform: smoothStream({ delayInMs: 20 }),
});

smoothStream은 청크 단위의 텍스트 출력을 더 자연스럽게 만들어 사용자 경험을 향상시킵니다.

도구(Tool) 호출 추가

typescript
import { streamText, tool } from "ai";
import { z } from "zod";

const result = streamText({
  model: openai("gpt-4o"),
  messages: convertToModelMessages(messages),
  tools: {
    getCurrentTime: tool({
      description: "현재 시간을 반환합니다",
      parameters: z.object({}),
      execute: async () => new Date().toLocaleString("ko-KR"),
    }),
  },
});

도구 호출을 통해 챗봇이 외부 데이터나 실시간 정보에 접근할 수 있습니다.


AI SDK 버전별 주요 변경점

버전주요 변경사항
v3.x기본 streamText, useChat 도입
v4.xtoUIMessageStreamResponse() 추가, RSC 지원 강화
v5.xconvertToModelMessages() 도입, 에이전트 추상화 계층
v6.x도구 실행 승인, 개발자 도구, 에이전트 중심 설계

베스트 프랙티스 요약

서버 사이드:

  • API 키는 반드시 서버 사이드에서만 사용 (.env.local, process.env)
  • maxDuration 설정으로 스트리밍 타임아웃 방지
  • try/catch로 에러 처리 및 클라이언트 친화적 메시지 반환

클라이언트 사이드:

  • isLoading 상태로 중복 요청 방지
  • useEffect + ref로 자동 스크롤 구현
  • 에러 상태 UI 처리 필수

성능 최적화:

  • 개발 환경엔 gpt-4o-mini, 프로덕션엔 gpt-4o 같은 모델 분리 전략
  • smoothStream으로 체감 응답 속도 개선
  • Rate limiting과 인증 미들웨어 적용

코드벤터는 Vercel AI SDK와 같은 최신 AI 개발 도구를 적극 활용해 빠르고 실용적인 제품을 만드는 것을 지향합니다. 복잡한 AI 인프라를 추상화하고 비즈니스 가치에 집중하는 것, 그것이 코드벤터와 함께하는 개발의 방향입니다. 스트리밍 챗봇 구현에 관해 궁금한 점이 있다면 언제든지 코드픽 커뮤니티에서 질문해 주세요.

개발 의뢰 상담

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

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

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

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

AI Development Studio

코드픽 by 코드벤터

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

© 2025 코드벤터. All rights reserved.