Vercel AI SDK 사용법: 초보자 가이드

Rebecca Kovács

Rebecca Kovács

10 June 2025

Vercel AI SDK 사용법: 초보자 가이드

Vercel AI SDK 초보자를 위한 확실한 가이드에 오신 것을 환영합니다. 인공지능이 디지털 환경을 빠르게 변화시키는 세상에서, 웹 애플리케이션에 AI를 통합하는 능력은 틈새 전문 분야에서 현대 개발자의 핵심 역량으로 변화했습니다. 이 가이드는 호기심 많은 초보자부터 유능한 AI 애플리케이션 개발자로 여러분을 이끌도록 설계되었습니다.

오랫동안 강력한 대규모 언어 모델(LLM)과 사용자 친화적인 웹 인터페이스 사이의 간극을 메우는 것은 복잡한 작업이었습니다. 개발자는 서로 다른 제공업체의 API와 씨름하고, 복잡한 상태를 관리하며, 응답 스트리밍과 같은 기능을 수동으로 구현해야 했습니다. Vercel AI SDK는 바로 이러한 문제들을 해결하기 위해 만들어졌습니다. 이는 AI 기반 경험을 구축하는 복잡성 위에 통합되고 우아한 추상화 계층을 제공하는 TypeScript 우선 툴킷입니다.

이것은 단순히 퀵스타트 가이드가 아닙니다. 이 튜토리얼을 통해 Next.js와 Google의 Gemini 모델을 사용하여 처음부터 완전하고 기능이 풍부한 AI 챗봇을 구축할 것입니다. 우리는 간단한 "Hello World" 예제를 훨씬 뛰어넘을 것입니다. 여러분은 다음을 배우게 됩니다:

이 종합 가이드의 끝에 도달하면, 작동하는 고급 챗봇뿐만 아니라 Vercel AI SDK를 사용하여 자신만의 독특하고 강력한 AI 기반 애플리케이션을 자신 있게 구축하는 데 필요한 깊은 개념적 지식도 갖게 될 것입니다.

💡
멋진 API 문서를 생성하는 훌륭한 API 테스트 도구를 원하십니까?

개발 팀이 최대 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?

Apidog는 귀하의 모든 요구 사항을 충족하며, Postman을 훨씬 저렴한 가격으로 대체합니다!
button

챕터 1: 기초 및 설정

모든 위대한 구조물에는 견고한 기초가 필요합니다. 이 챕터에서는 개발 환경을 설정하고, 필요한 도구를 설치하며, API 키를 준비할 것입니다. 또한 우리가 내리는 각 선택의 "왜"를 이해하는 시간도 가질 것입니다.

사전 준비 사항

코드를 한 줄도 작성하기 전에 도구 상자가 준비되었는지 확인합시다.

  1. Google AI Studio로 이동합니다.
  2. Google 계정으로 로그인합니다.
  3. "API 키 가져오기"를 클릭한 다음 "새 프로젝트에서 API 키 만들기"를 클릭합니다.
  4. 생성된 키를 복사하여 지금은 안전한 곳에 보관하십시오. 이 키는 비밀번호처럼 취급하십시오. 절대로 공개적으로 노출하지 마십시오.

1단계: Next.js 프로젝트 초기화

프로덕션 수준 애플리케이션 구축을 위한 최고의 React 프레임워크인 Next.js를 사용할 것입니다. Next.js의 App Router 패러다임은 AI 애플리케이션의 서버 중심적인 특성과 완벽하게 통합됩니다.

터미널을 열고 다음 명령을 실행하여 새 프로젝트를 생성하십시오.

npx create-next-app@latest vercel-ai-tutorial

설치 프로그램이 몇 가지 질문을 할 것입니다. 다음 설정을 사용하여 원활하게 따라오십시오.

설치가 완료되면 새로 생성된 프로젝트 디렉토리로 이동하십시오.

cd vercel-ai-tutorial

2단계: Vercel AI SDK 설치

이제 AI SDK 패키지를 프로젝트에 추가해 봅시다.

npm install ai @ai-sdk/react @ai-sdk/google zod

각 패키지가 무엇을 하는지 살펴보겠습니다.

3단계: API 키 보안

애플리케이션 코드에 API 키를 하드코딩하지 마십시오. 이는 주요 보안 위험입니다. 전문가 표준은 환경 변수를 사용하는 것입니다. Next.js는 .env.local 파일을 통해 이를 위한 내장 지원을 제공합니다.

프로젝트 루트에 파일을 생성하십시오.

touch .env.local

이제 이 새 파일을 열고 Google AI 키를 추가하십시오.

# .env.local
# This file is for local development and should NOT be committed to git.
GOOGLE_GENERATIVE_AI_API_KEY=YOUR_GOOGLE_AI_API_KEY

YOUR_GOOGLE_AI_API_KEY를 이전에 복사한 키로 바꾸십시오. Next.js는 이 파일을 자동으로 로드하여 서버에서 키를 사용할 수 있게 하는데, 이는 우리가 정확히 필요한 곳입니다.

챕터 2: 챗봇의 핵심 구조 구축

프로젝트 설정이 완료되었으므로, 이제 애플리케이션의 핵심 구성 요소인 AI와 통신하는 서버 측 API 엔드포인트와 사용자가 상호작용할 클라이언트 측 UI를 구축할 차례입니다.

AI 앱의 클라이언트-서버 아키텍처

우리 챗봇은 두 가지 주요 부분으로 구성됩니다.

  1. 서버 측 API 라우트 (/api/chat/route.ts): 서버에서 실행되는 보안 환경입니다. 주요 역할은 사용자의 브라우저로부터 채팅 기록을 받아 비밀 API 키를 추가하고, Google AI 서비스로 요청을 전달한 다음, 응답을 사용자에게 스트리밍하는 것입니다. 이 로직을 서버에 유지하는 것은 보안에 매우 중요합니다. 이는 API 키가 공개적으로 노출되지 않도록 보장합니다.
  2. 클라이언트 측 UI (page.tsx): 사용자의 브라우저에서 실행되는 React 컴포넌트입니다. 채팅 기록을 렌더링하고, 사용자 입력을 캡처하며, 해당 입력을 API 라우트로 보내는 역할을 합니다.

이러한 분리는 안전하고 성능이 뛰어난 웹 애플리케이션을 구축하는 데 필수적입니다.

4단계: API 라우트 핸들러 생성

서버 측 엔드포인트를 만들어 봅시다. src/app 디렉토리에 새 폴더 api를 만들고, 그 안에 또 다른 폴더 chat을 만드십시오. 마지막으로 chat 폴더 안에 route.ts라는 파일을 생성하십시오.

최종 경로는 src/app/api/chat/route.ts가 되어야 합니다.

이 파일에 다음 코드를 채워 넣으십시오.

// src/app/api/chat/route.ts

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

// Vercel-specific configuration to allow streaming responses for up to 30 seconds
export const maxDuration = 30;

// The main API route handler
export async function POST(req: Request) {
  try {
    // Extract the `messages` array from the request body
    const { messages } = await req.json();

    // Call the AI provider with the conversation history
    const result = await streamText({
      model: google('models/gemini-1.5-pro-latest'),
      // The `messages` array provides the model with context for the conversation
      messages,
    });

    // Respond with a streaming response
    return result.toDataStreamResponse();
  } catch (error) {
    // It's a good practice to handle potential errors
    if (error instanceof Error) {
      return new Response(JSON.stringify({ error: error.message }), { status: 500 });
    }
    return new Response(JSON.stringify({ error: 'An unknown error occurred' }), { status: 500 });
  }
}

이 중요한 파일을 분석해 봅시다.

5단계: 사용자 인터페이스 제작

이제 재미있는 부분입니다. UI를 구축해 봅시다. @ai-sdk/react 패키지 덕분에 이것은 놀라울 정도로 간단합니다. src/app/page.tsx에 있는 메인 페이지 파일을 열고 전체 내용을 다음 코드로 바꾸십시오.

// src/app/page.tsx

'use client';

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

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading, error } = useChat();

  // A ref to the scrollable container of messages
  const messagesContainerRef = useRef<HTMLDivElement>(null);

  // Effect to scroll to the bottom of the messages container whenever messages change
  useEffect(() => {
    if (messagesContainerRef.current) {
      messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
    }
  }, [messages]);

  return (
    <div className="flex flex-col h-screen bg-gray-50">
      {/* Messages container */}
      <div ref={messagesContainerRef} className="flex-1 overflow-y-auto p-8 space-y-4">
        {messages.map(m => (
          <div
            key={m.id}
            className={`flex gap-3 ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}
          >
            {/* Display user's avatar */}
            {m.role === 'user' && (
              <div className="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">U</div>
            )}

            {/* Message bubble */}
            <div
              className={`max-w-xl p-3 rounded-2xl shadow-md whitespace-pre-wrap ${
                m.role === 'user'
                  ? 'bg-blue-500 text-white rounded-br-none'
                  : 'bg-white text-black rounded-bl-none'
              }`}
            >
              <span className="font-bold block">{m.role === 'user' ? 'You' : 'AI Assistant'}</span>
              {m.content}
            </div>

            {/* Display AI's avatar */}
            {m.role !== 'user' && (
              <div className="w-10 h-10 rounded-full bg-gray-700 flex items-center justify-center text-white font-bold">AI</div>
            )}
          </div>
        ))}
      </div>

      {/* Input form */}
      <div className="p-4 bg-white border-t">
        <form onSubmit={handleSubmit} className="flex items-center gap-4 max-w-4xl mx-auto">
          <input
            className="flex-1 p-3 border rounded-full focus:outline-none focus:ring-2 focus:ring-blue-500"
            value={input}
            placeholder="Ask me anything..."
            onChange={handleInputChange}
            disabled={isLoading}
          />
          <button
            type="submit"
            className="px-6 py-3 bg-blue-500 text-white rounded-full font-semibold hover:bg-blue-600 disabled:bg-blue-300 disabled:cursor-not-allowed"
            disabled={isLoading}
          >
            Send
          </button>
        </form>
        {error && (
          <p className="text-red-500 mt-2 text-center">{error.message}</p>
        )}
      </div>
    </div>
  );
}

상당한 양의 코드이지만, 대부분은 Tailwind CSS로 세련된 UI를 만드는 데 사용됩니다. 로직에 초점을 맞춰봅시다.

6단계: 애플리케이션 실행

이제 완전하고 잘 구조화된 AI 챗봇을 구축했습니다. 실행해 봅시다!

npm run dev

브라우저에서 http://localhost:3000으로 이동하십시오. 세련된 채팅 인터페이스가 여러분을 맞이할 것입니다. 질문을 해보세요. 메시지가 즉시 나타나고, AI의 응답이 토큰 단위로 스트리밍되는 것을 볼 수 있습니다.

챕터 3: 고급 기능 - 챗봇에 초능력 부여하기

우리 챗봇은 똑똑하지만, 지식은 훈련 데이터에 국한됩니다. 실시간 정보에 액세스하거나 현실 세계에서 행동을 수행할 수 없습니다. 이 챕터에서는 이러한 한계를 극복하기 위해 "도구(Tools)"를 제공할 것입니다.

도구(Tools)란 무엇인가요?

도구(Tool)는 LLM이 실행하도록 선택할 수 있는 여러분이 정의한 함수입니다. 모델에게 도구를 설명하면, 모델은 사용자 쿼리에 답변하기 위해 도구가 필요하다고 판단될 때 텍스트 생성을 일시 중지하고 대신 특별한 "도구 호출(tool call)" 객체를 출력합니다. 그러면 여러분의 코드는 모델이 제공한 인수를 사용하여 함수를 실행하고, 결과는 다시 모델에게 전송됩니다. 모델은 이 새로운 정보를 사용하여 최종적이고 더 정확한 응답을 생성합니다.

두 가지 도구로 챗봇의 기능을 강화해 봅시다.

  1. 특정 위치의 현재 날씨를 가져오는 도구.
  2. 화씨 온도를 섭씨 온도로 변환하는 도구.

이를 통해 봇은 "런던의 날씨는 섭씨로 얼마인가요?"와 같은 질문에 답할 수 있게 됩니다. 이는 여러 단계와 외부 데이터가 필요한 작업입니다.

7단계: 도구를 지원하도록 API 업그레이드

서버의 streamText 호출에서 도구를 정의해야 합니다. src/app/api/chat/route.ts 파일을 열고 새 tools 정의를 포함하도록 수정하십시오.

// src/app/api/chat/route.ts
import { google } from '@ai-sdk/google';
import { streamText, tool } from 'ai';
import { z } from 'zod';

export const maxDuration = 30;

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

  const result = await streamText({
    model: google('models/gemini-1.5-pro-latest'),
    messages,
    // Define the tools the model can use
    tools: {
      getWeather: tool({
        description: 'Get the current weather for a specific location. Always returns temperature in Fahrenheit.',
        parameters: z.object({
          location: z.string().describe('The city and state, e.g., San Francisco, CA'),
        }),
        execute: async ({ location }) => {
          // In a real app, you would fetch from a real weather API
          console.log(`Fetching weather for ${location}`);
          return {
            temperature: Math.floor(Math.random() * (100 - 30 + 1) + 30),
            high: Math.floor(Math.random() * (100 - 80 + 1) + 80),
            low: Math.floor(Math.random() * (50 - 30 + 1) + 30),
            conditions: ['Sunny', 'Cloudy', 'Rainy'][Math.floor(Math.random() * 3)],
          };
        },
      }),
      convertFahrenheitToCelsius: tool({
        description: 'Convert a temperature from Fahrenheit to Celsius.',
        parameters: z.object({
          temperature: z.number().describe('The temperature in Fahrenheit'),
        }),
        execute: async ({ temperature }) => {
          console.log(`Converting ${temperature}°F to Celsius`);
          return {
            celsius: Math.round((temperature - 32) * (5 / 9)),
          };
        },
      }),
    },
  });

  return result.toDataStreamResponse();
}

tools 객체를 분석해 봅시다.

8단계: UI에서 다단계 도구 호출 활성화

서버에 도구를 정의하는 것만으로는 충분하지 않습니다. 기본적으로 모델이 도구 호출을 하면 대화가 중단됩니다. useChat 훅에게 해당 도구 호출 결과를 자동으로 모델에게 다시 보내도록 알려야 모델이 추론을 계속하고 최종 답변을 공식화할 수 있습니다.

이것은 믿을 수 없을 정도로 간단합니다. src/app/page.tsx에서 useChat 훅 초기화를 업데이트하십시오.

// src/app/page.tsx

// ...
export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading, error } = useChat({
    // Tell the hook to automatically send tool results back to the model
    experimental_sendExtraToolMessages: true,
  });
  // ... rest of the component
}

그게 전부입니다. experimental_sendExtraToolMessages: true 속성은 다단계 도구 사용 흐름을 활성화합니다.

9단계: 도구 호출을 위한 더 나은 UI

현재 UI는 m.content만 표시합니다. 도구가 호출될 때 흥미로운 정보는 메시지 객체의 다른 속성에 있습니다. 도구 호출을 보기 좋게 렌더링하는 전용 컴포넌트를 만들어 봅시다.

먼저, src/app/page.tsx의 메인 메시지 루프를 업데이트하여 이러한 호출을 렌더링하도록 하겠습니다.

// src/app/page.tsx

// ... inside the Chat component's return statement
<div ref={messagesContainerRef} className="flex-1 overflow-y-auto p-8 space-y-4">
  {messages.map(m => (
    <div
      key={m.id}
      className={`flex gap-3 ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}
    >
      {/* ... avatars ... */}
      <div
        className={`max-w-xl p-3 rounded-2xl shadow-md whitespace-pre-wrap ${
          m.role === 'user'
            ? 'bg-blue-500 text-white rounded-br-none'
            : 'bg-white text-black rounded-bl-none'
        }`}
      >
        <span className="font-bold block">{m.role === 'user' ? 'You' : 'AI Assistant'}</span>

        {/* Render tool invocations */}
        {m.toolInvocations?.map(tool => (
          <div key={tool.toolCallId} className="my-2 p-2 bg-gray-100 rounded text-sm text-gray-700">
            <p className="font-semibold">Tool Call: `{tool.toolName}`</p>
            <pre className="mt-1 p-1 bg-gray-200 rounded text-xs">
              {JSON.stringify(tool.args, null, 2)}
            </pre>
          </div>
        ))}

        {m.content}
      </div>
      {/* ... avatars ... */}
    </div>
  ))}
  {isLoading && messages[messages.length - 1]?.role === 'assistant' && (
      <div className="flex justify-start p-8 space-x-3">
          <div className="w-10 h-10 rounded-full bg-gray-700 flex items-center justify-center text-white font-bold">AI</div>
          <div className="p-3 rounded-2xl shadow-md bg-white">
              <div className="typing-indicator">
                  <span></span><span></span><span></span>
              </div>
          </div>
      </div>
  )}
</div>
// ...

또한 어시스턴트가 생각하는 동안 나타나는 간단한 타이핑 표시기도 추가했습니다. 이를 위해 약간의 CSS를 추가해야 합니다. src/app/globals.css 파일에 다음을 추가하십시오.

/* src/app/globals.css */

.typing-indicator span {
  height: 8px;
  width: 8px;
  background-color: #9E9EA1;
  border-radius: 50%;
  display: inline-block;
  animation: a 1.2s infinite ease-in-out;
}
.typing-indicator span:nth-child(1) { animation-delay: -0.4s; }
.typing-indicator span:nth-child(2) { animation-delay: -0.2s; }
@keyframes a {
  0%, 60%, 100% { transform: scale(0.2); }
  30% { transform: scale(1); }
}

이제 애플리케이션을 다시 실행하십시오. "뉴욕의 날씨는 섭씨로 얼마인가요?"라고 물어보십시오. UI에서 펼쳐지는 흥미로운 일련의 사건을 보게 될 것입니다.

  1. 모델은 먼저 getWeather 도구를 호출합니다. UI에서 렌더링된 도구 호출을 볼 수 있습니다.
  2. 결과 (화씨 무작위 온도)가 모델에게 다시 전송됩니다.
  3. 섭씨 온도가 필요하다는 것을 아는 모델은 첫 번째 도구 결과의 온도를 입력으로 사용하여 convertFahrenheitToCelsius 도구를 호출합니다.
  4. 마지막으로, 섭씨 온도를 얻은 모델은 원래 질문에 답변하는 자연어 응답을 생성합니다.

이것이 AI 에이전트를 구축하는 힘이며, Vercel AI SDK는 이러한 복잡한 조율을 놀라울 정도로 간단하게 만듭니다.

챕터 4: 다음 단계는?

고급 AI 기반 챗봇을 성공적으로 구축했습니다. 백지 상태에서 시작하여 응답을 스트리밍하고, 로딩 및 오류 상태를 처리하며, 도구를 활용하여 외부 데이터와 다단계 방식으로 상호작용할 수 있는 기능이 풍부한 애플리케이션을 만들었습니다.

이 가이드는 여러분에게 강력한 기초를 제공했지만, 이는 시작에 불과합니다. Vercel AI SDK는 더 많은 것을 제공합니다. 계속해서 탐색할 수 있는 몇 가지 경로가 있습니다.

웹 개발의 미래는 지능적이고, 인터랙티브하며, 개인화될 것입니다. Vercel AI SDK를 통해 여러분은 이제 이러한 혁명의 선두에 설 도구와 지식을 갖게 되었습니다. 즐거운 개발 되세요!

💡
멋진 API 문서를 생성하는 훌륭한 API 테스트 도구를 원하십니까?

개발 팀이 최대 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?

Apidog는 귀하의 모든 요구 사항을 충족하며, Postman을 훨씬 저렴한 가격으로 대체합니다!
button

Apidog에서 API 설계-첫 번째 연습

API를 더 쉽게 구축하고 사용하는 방법을 발견하세요