본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 09. 17:39

Vercel AI SDK를 사용한 AI 에이전트 구축하기

요약

Vercel AI SDK를 활용하여 도구 호출 루프(tool-calling loops) 기반의 AI 에이전트를 구축하는 방법을 설명합니다. 다중 도구 사용, stopWhen 및 stepCountIs 설정을 통해 지원 분류 에이전트의 실행 흐름을 제어하는 기술적 가이드를 제공합니다.

핵심 포인트

  • Vercel AI SDK의 도구 호출 루프 메커니즘 이해
  • stopWhen과 stepCountIs를 이용한 에이전트 중단 조건 제어
  • Zod를 활용한 다중 도구 정의 및 입력 스키마 설정
  • 고객 조회부터 티켓 생성까지의 실전 지원 에이전트 워크플로우

Vercel AI SDK는 에이전트를 **도구 호출 루프 (tool-calling loops)**로 취급합니다. 모델이 텍스트를 생성하거나 도구를 호출하면, SDK가 해당 도구들을 실행하며, 모델이 답변을 하거나 **중단 조건 (stop condition)**이 발생할 때까지 루프가 계속됩니다.

이 포스트에서는 고객과 송장(invoice)을 조회하고, 내부 지식 베이스를 검색하며, 티켓을 생성하거나 상담원에게 에스컬레이션(escalate)하는 **지원 분류 에이전트 (support triage agent)**를 구축합니다. 이 내용은 Vercel AI SDK를 활용한 LLM 통합 포스트를 기반으로 하며, 다중 도구 (multiple tools), stopWhen, 그리고 **stepCountIs**에 초점을 맞춥니다.

SDK 네이티브 tool() 핸들러 대신 MCP를 통해 노출된 외부 도구에 대해서는 Node.js를 사용한 MCP 서버 포스트를 참조하세요.

사전 요구 사항

  • OpenAI 계정
  • 생성된 API 키
  • 결제 활성화
  • Node.js 버전 26
  • ai, @ai-sdk/openai, zod 설치 (npm i ai @ai-sdk/openai zod)
  • Vercel AI SDK 통합 포스트를 통한 클라이언트 설정

멘탈 모델 - 단계(steps)와 도구 루프

**단계 (step)**는 한 번의 모델 생성(generation)을 의미합니다. 해당 단계에서 모델은 다음 중 하나를 수행합니다:

  • 텍스트 (text) 반환 (루프 종료)
  • 도구 호출 (tool calls) 반환 (SDK가 이를 실행하고 결과를 가지고 다음 단계를 시작)

지원 분류 에이전트의 전형적인 흐름: 사용자 질문 → 모델이 조회 도구 호출 (getCustomer, getInvoice, searchKnowledgeBase) → 모델이 티켓을 생성하거나 에스컬레이션 → 최종 답변. stopWhen은 쓰기 도구(write tools)가 실행되기 전이나 후에 루프를 종료할 수 있습니다.

stepCountIs(5)는 5개의 개별 도구 호출이 아니라, "5단계 (5 steps)"(5번의 모델 생성) 후에 중단하라는 의미입니다. 단일 단계에는 여러 개의 병렬 도구 호출이 포함될 수 있습니다.

stopWhen 없이 tools를 전달하면, SDK는 안전 장치로서 기본값으로 stepCountIs(20)를 설정합니다.

지원 분류 시나리오

프롬프트 예시:

고객 cus_1042가 송장 inv_8891에 대해 두 번 청구되었다고 합니다. 어떻게 해야 할까요?

현실적인 체인:

  1. getCustomer - 플랜 등급 (plan tier), 열린 티켓 수 (open ticket count)
  2. getInvoice - 금액 (amount), 상태 (status), 결제 ID (payment IDs)
  3. searchKnowledgeBase - 중복 청구 및 환불 정책 (duplicate-charge and refund policy)
  4. createSupportTicket 또는 escalateToHuman - 실행 액션 또는 감시 중단 (sentinel stop)

데모는 인메모리 피스처 (in-memory fixtures: 고객, 송장, 지식 베이스 문서)를 사용하므로 데이터베이스 없이도 스크립트가 실행됩니다.

여러 도구 정의하기 (Defining multiple tools)

tool()과 Zod의 inputSchema를 사용하여 도구를 등록합니다. 명확한 description 값은 모델이 올바른 도구를 선택하는 데 도움을 줍니다.

import { tool } from 'ai';
import { z } from 'zod';

...

결과를 도출하기 위한 쓰기 도구 (write tools)를 추가합니다:

const createSupportTicket = tool({
  description: '고객 및 정책 컨텍스트를 수집한 후 지원 티켓을 생성합니다',
  inputSchema: z.object({
...

execute에서 구조화된 객체 (structured objects)를 반환하세요. SDK는 이를 다음 단계를 위한 도구 결과 (tool results)로 직렬화합니다. 모델이 예외를 던지는 대신 복구할 수 있도록 명시적인 에러 (예: { found: false, error: '...' })를 반환하세요.

generateText를 이용한 다단계 분류 (Multi-step triage)

모든 도구와 분류 규칙이 포함된 system 프롬프트를 전달합니다:

import { generateText, stepCountIs } from 'ai';

const { text, steps } = await generateText({
...

도구 호출 (tool calling)을 지원하는 모델을 사용하세요 (Vercel AI SDK 포스트의 웹 검색과 동일한 요구 사항입니다).

stopWhen - 루프가 중단되는 시점

stopWhen은 도구 루프 (tool loop)의 중단 조건을 정의합니다. 조건은 마지막 단계에 도구 결과가 포함되어 있을 때만 평가됩니다.

  • 단일 조건은 해당 조건이 true를 반환할 때 중단됩니다.
  • 배열은 어느 하나라도 조건이 true를 반환할 때 중단됩니다 (OR 로직).
  • stopWhen이 없으면 SDK는 stepCountIs(20)를 적용합니다.

모델이 추가적인 도구 호출 없이 텍스트를 반환하면 루프는 자연스럽게 종료됩니다.

stepCountIs - 단계 수 제한

stepCountIs(n)steps.lengthn에 도달하면 중단합니다. 제어되지 않는 루프와 무제한적인 API 비용 발생을 방지하기 위해 모든 프로덕션 에이전트에 이를 사용하세요.

유스케이스 (Use case)권장 제한 (Suggested cap)
단일 도구 사용 후 답변2 (도구 단계 + 텍스트 단계)
...

동일한 프롬프트에 대한 엄격한 제한(Tight) vs 완화된 제한(Relaxed):

import { generateText, stepCountIs } from 'ai';

// 모델이 더 많은 컨텍스트를 원하더라도 3단계 후에 중단합니다
...

hasToolCallstepCountIs 결합하기

hasToolCall('toolName')은 모델이 최신 단계에서 특정 도구를 호출할 때 중단됩니다. 이를 stepCountIs와 결합하면 하드 캡(hard cap)과 감시 도구(sentinel tool)를 동시에 사용할 수 있습니다:

import { generateText, stepCountIs, hasToolCall } from 'ai';

const { text, steps } = await generateText({
...

escalateToHuman은 감시 도구로서 잘 작동합니다. 모델이 해당 케이스에 사람이 필요하다고 결정하는 즉시, 최종 텍스트 전용 단계를 기다리지 않고 루프가 중단됩니다.

steps 및 사용량 조사하기

결과값의 steps 배열에는 단계별 도구 호출(tool calls), 도구 결과(tool results), 종료 사유(finish reason) 및 사용량(usage)이 포함되어 있습니다. 이를 디버깅 및 비용 추적에 사용하세요:

const { text, steps, totalUsage } = await generateText({
  model: openai('gpt-5.5'),
  tools: supportTools,
...

streamText를 사용할 때는 onStepFinish를 전달하여 각 단계가 완료될 때마다 로그를 남길 수 있습니다.

ToolLoopAgent - 재사용 가능한 에이전트 정의

ToolLoopAgent는 스크립트와 API 라우트 전반에서 재사용할 수 있도록 동일한 루프를 래핑(wrap)합니다. generateText와 동일한 설정(tools, stopWhen, instructions)을 수용합니다.

import { ToolLoopAgent, stepCountIs } from 'ai';

const supportTriageAgent = new ToolLoopAgent({
...

스트리밍을 위해서는 .stream()을 사용하세요. Next.js 채팅 UI의 경우, AI SDK 에이전트 문서createAgentUIStreamResponse를 참조하세요.

도구를 사용한 스트리밍

streamText는 동일한 toolsstopWhen 설정을 지원합니다:

import { streamText, stepCountIs } from 'ai';

const result = streamText({
...

텍스트는 점진적으로 스트리밍됩니다. 도구 호출은 루프가 진행됨에 따라 텍스트 세그먼트 사이에서 실행됩니다.

프로덕션 참고 사항

  • 항상 stopWhen을 설정하세요 - 모니터링 없이 프로덕션 환경에서 기본값인 stepCountIs(20)에 의존하지 마세요.
  • 비용 (Cost) - 각 단계(step)는 추가적인 모델 호출입니다. steps 또는 onStepFinish 사용량을 로그로 남기세요.
  • 도구 오류 (Tool errors) - 모델이 재시도하거나 상위 단계로 에스컬레이션(escalate)해야 하는 경우, 예외를 던지는 대신 execute에서 구조화된 에러를 반환하세요.
  • 지침 (Instructions) - 정책 규칙은 사용자 프롬프트(user prompt)뿐만 아니라 system / instructions에 유지하세요.
  • 다른 곳에서의 동일한 패턴 - PR 리뷰 (listPRsgetCheckssubmitReview) 또는 직무 적합성 점수 산정(job-fit scoring)은 서로 다른 도구를 사용하지만 동일한 루프 메커니즘을 사용합니다.

데모 (Demo)

각 섹션에 대한 실행 가능한 스크립트는 vercel-ai-sdk-agents-demo 폴더에 있습니다. 코드 데모를 통해 접속할 수 있습니다.

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0