본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 07. 02:26

Next.js로 100줄 만에 만든 ChatGPT 클론 (Streaming + Tools + 한 줄로 끝나는 Provider 교체)

요약

Vercel AI SDK를 사용하여 Next.js 환경에서 단 100줄의 코드로 스트리밍과 도구 호출(Tool calls) 기능이 포함된 ChatGPT 클론을 만드는 방법을 소개합니다. 다양한 LLM 제공자를 단 한 줄의 코드로 교체할 수 있는 Provider 중립적 아키텍처를 강조합니다.

핵심 포인트

  • Vercel AI SDK의 useChat 훅을 통한 간편한 스트리밍 구현
  • Gemini, Claude 등 다양한 모델을 단 한 줄로 교체 가능한 중립성
  • 모델의 도구 호출(Tool calls)과 실행 결과를 스트림 내에서 처리
  • TypeScript와 Zod를 활용한 엔드 투 엔드 타입 안정성 확보

ai-sdk-from-zero.vercel.app을 여세요. _"도쿄는 지금 몇 시인가요?"_라고 입력해 보세요.

토큰 (tokens)이 스트리밍되는 것을 지켜보세요. 메시지 중간에 작은 🔧 get_current_time 알약 모양의 UI가 나타납니다. 그런 다음 어시스턴트는 학습 데이터에서 지어낸 것이 아니라, 제가 직접 작성한 실제 함수를 통해 계산된 실제 도쿄의 시간을 알려줍니다.

지난 3년 동안 "이건 어렵다"라고 느꼈던 것들이 약 100줄의 Next.js 코드로 사라졌습니다.

Vercel AI SDK가 해결하는 문제

3년 전, "브라우저로 LLM 토큰을 스트리밍하기"란 WebSocket 서버를 구축하고, SSE 프레임을 직접 디코딩하며, StrictMode에서 프레임 누락이나 이중 렌더링 없이 React ref에 텍스트를 추가하기 위해 정교한 상태 머신 (state machine)을 작성해야 함을 의미했습니다.

오늘날에는 useChat 하나면 충분합니다. 훅 (hook) 하나로 모든 것이 해결됩니다.

Vercel AI SDK는 AI 채팅을 위한 배포 모델의 해결책입니다:

  • Provider 중립성 (Provider-neutral). Gemini, Claude, GPT-4, Mistral, Groq, Ollama를 지원합니다. src/lib/ai.ts에서 단 한 줄만 수정하면 전체 백엔드를 교체할 수 있습니다.
  • 기본 스트리밍 (Streaming by default). 토큰 단위의 가시성은 부가 기능이 아닌 일급 시민 (first-class feature) 기능입니다.
  • 도구 호출 (Tool calls) 포함. 모델이 호출을 방출하면, SDK가 핸들러를 실행하고, 모델이 그 결과를 확인하여 최종 답변을 구성합니다. 이 모든 과정이 동일한 응답 스트림 (response stream) 상에서 이루어집니다.
  • TypeScript 우선 (TypeScript-first). Zod를 통한 스키마 (schemas) 정의를 지원합니다. 타입이 엔드 투 엔드 (end-to-end)로 흐릅니다.

고객 지원 에이전트, 내부 Q&A, 개발 도구, AI 튜터 등 어떤 종류의 채팅 인터페이스를 구축하더라도 이것이 바로 추상화 (abstraction) 모델입니다.

1단계: 서버 (15줄)

// src/app/api/chat/route.ts
import { streamText, convertToModelMessages, type UIMessage } from 'ai'
import { model } from '@/lib/ai'
...

이것이 스트리밍 채팅 백엔드입니다. streamText()는 모델 청크 (model chunks)의 비동기 스트림을 반환합니다. .toUIMessageStreamResponse()는 이를 useChat이 기대하는 프레이밍 (framing)을 갖춘 HTTP 응답으로 감쌉니다. 시스템 프롬프트 (system prompt)는 사용자 턴 (user turn)을 소모하지 않고 모델의 조건을 설정합니다.

2단계: Provider (3줄)

// src/lib/ai.ts
import { google } from '@ai-sdk/google'
export const model = google('gemini-2.5-flash')

Claude로 교체하려면:

import { anthropic } from '@ai-sdk/anthropic'
export const model = anthropic('claude-sonnet-4-5')

스트리밍 엔드포인트(streaming endpoint)와 채팅 UI는 이를 신경 쓰지 않습니다. SDK가 모든 제공자(provider)의 와이어 포맷(wire format)을 정규화(normalise)하기 때문입니다. 단 한 줄로 교체 가능합니다. 이것은 마케팅 문구가 아니라 아키텍처(architecture)의 특징입니다.

저는 Gemini 2.5 Flash를 기본값으로 사용합니다. Google의 무료 티어(분당 15회 요청, 일일 100만 회 요청) 덕분에 독자들이 비용 지불 없이 리포지토리(repo)를 클론하여 실행해 볼 수 있기 때문입니다. Anthropic은 2024년에 무료 체험을 중단했으며, 새 계정은 5달러의 유료 크레딧이 필요합니다.

3단계: 클라이언트 (~50줄)

'use client'

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

useChat이 핵심 기능(killer feature)입니다. 이 함수는 입력을 수집하고, /api/chat을 호출하며, SSE(Server-Sent Events) 스트림을 프레임 단위로 디코딩하고, 최신 어시스턴트(assistant) 메시지에 토큰(token)을 점진적으로 추가합니다. 도착하는 모든 토큰은 리렌더링(re-render)을 트리거합니다. WebSockets, 수동 SSE 파싱, 토큰 배치(batching) 로직, 이중 렌더링 방지 로직이 전혀 필요 없습니다.

단 50줄로 작동하는 채팅 UI를 완성할 수 있습니다.

4단계: 도구 (진정한 초능력)

챗봇은 재미있습니다. 하지만 **여러분이 직접 작성한 함수(functions)**를 호출할 수 있는 챗봇은 진짜 제품(product)입니다.

import { streamText, tool, stepCountIs } from 'ai'
import { z } from 'zod'

...

SDK가 전체 요청/응답 루프(request/response loop)를 처리합니다:

  1. 모델이 현재 시간이 필요하다고 결정합니다.
  2. { timezone: "Asia/Tokyo" }와 함께 도구 호출(tool call)을 방출합니다.
  3. SDK가 여러분의 execute 핸들러를 실행합니다.
  4. SDK가 결과를 모델에 다시 전달합니다.
  5. 모델이 실제 시간을 포함하여 최종 답변을 작성합니다.

이 모든 과정이 동일한 응답 스트림(response stream) 상에서 이루어집니다. 클라이언트는 이를 하나의 연속적인 어시스턴트 턴(assistant turn)으로 인식하며, 도구가 호출되었음을 나타내는 작은 마커만 표시됩니다.

stopWhen: stepCountIs(3)를 사용하면 모델이 단일 사용자 턴 내에서 도구 호출을 체이닝(chaining)할 수 있습니다. 이는 여러 작업을 구성하는 에이전트(agents)에게 매우 유용합니다.

이것이 변화시킨 것

3년 전이라면 OpenAI API를 감싸는 Slack 봇을 작성했을 것입니다. 2년 전이라면 ChatGPT 플러그인(2024년 지원 중단)을 작성했을 것입니다. 1년 전이라면 SSE 디코더, useEffect를 활용한 복잡한 처리, 토큰 배치 로직을 직접 구현(hand-roll)해야 했을 것입니다.

오늘날 여러분은 useChat({ transport: ... })를 작성하고, streamText() 라우트 핸들러(route handler)를 배치하며, 선택적으로 Zod로 검증된 도구(tool)를 등록하기만 하면 바로 배포할 수 있습니다.

Vercel AI SDK는 단순히 영리하게 만들어진 래퍼(wrapper)가 아닙니다. 이것은 **3년 전에 이미 존재했어야 할 추상화 (abstraction)**입니다. 스트리밍 (streaming) + 도구 호출 (tool-call) + 프로바이더 교체 (provider-swap)의 복잡성을 프레임워크 내부로 사라지게 하여, 여러분이 봇이 실제로 수행하는 기능에만 집중할 수 있게 해주는 추상화 말입니다.

만약 여러분이 "배관 작업(plumbing)이 너무 무섭게 생겨서" 실제 AI 채팅 제품을 만드는 것을 미뤄왔다면, 이제 그 변명은 통하지 않습니다.

이 데모를 위한 코드는 GitHub에 있으며, 따라 할 수 있는 8개의 단계별 커밋 (commit)이 준비되어 있습니다. 라이브 버전은 ai-sdk-from-zero.vercel.app에서 확인할 수 있습니다. 접속해서 도쿄의 시간을 물어보세요. 도구가 실행되는 것을 확인하십시오.

이것이 바로 Vercel AI SDK입니다.

🔗 코드: github.com/dev48v/ai-sdk-from-zero
🌐 라이브 데모: ai-sdk-from-zero.vercel.app
📚 시리즈: TechFromZero — 매일 새로운 기술을 모두 무료로, 모두 오픈 소스로 제공합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0