Vercel AI SDK 실전
Next.js/TS 앱에서 여러 LLM 프로바이더를 한 API 로 붙일 때 연다. 함수 시그니처, 툴 호출, 스트리밍 UI, 프로바이더 교체, 그리고 메이저 버전 간 breaking change 지뢰밭.
신선도 경고. 메이저가 빠르게 오르고 함수·필드 이름이 자주 바뀐다. 버전·API 이름은 전부
(verified 2026-07)기준 — 다음 세션에서npm view ai version으로 재확인하라. Anthropic 모델 ID 는 SDK 문서 예시가 아니라 claude-family 를 정본으로 삼는다.
패키지 구조와 버전 핀
코어 ai 와 프로바이더/UI 패키지는 버전 번호가 따로 논다. 코어가 7.x 라고 @ai-sdk/react 도 7 이라 넘겨짚지 마라.
| 패키지 | import | 최신 (verified 2026-07) | 역할 |
|---|---|---|---|
ai |
'ai' |
7.0.37 | Core: generateText, tools, agents |
@ai-sdk/anthropic |
'@ai-sdk/anthropic' |
4.0.20 | Anthropic 프로바이더 |
@ai-sdk/openai |
'@ai-sdk/openai' |
4.0.20 | OpenAI 프로바이더 |
@ai-sdk/google |
'@ai-sdk/google' |
4.0.24 | Google 프로바이더 |
@ai-sdk/react |
'@ai-sdk/react' |
4.0.40 | UI 훅 (useChat 등) |
ai 는 v5·v6·v7 세 메이저 라인 동시 유지보수 중이다 (dist-tags: latest 7.0.37, ai-v6 6.0.235, ai-v5 5.0.220 — verified 2026-07). pnpm add ai@latest @ai-sdk/react @ai-sdk/anthropic 로 v7 를 깔되 package.json 에 정확히 핀하라. 세 surface: Core('ai'), UI(@ai-sdk/react|vue|svelte|angular), Harnesses(v7 신규, Claude Code/Codex 하네스를 HarnessAgent 로 감쌈).
핵심 함수 4개
전부 import { ... } from 'ai'. 텍스트는 generateText/streamText, 임베딩은 embed/embedMany.
import { generateText, streamText, embed, embedMany } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
// 1) 한 방에 텍스트
const { text, usage, finishReason } = await generateText({
model: anthropic('claude-opus-5'),
prompt: '3문장 요약해줘',
});
// 2) 스트리밍 — result 는 즉시 반환, textStream 을 순회
const result = streamText({ model: anthropic('claude-opus-5'), prompt: '...' });
for await (const delta of result.textStream) process.stdout.write(delta);
const total = await result.usage; // Promise
// 3)/4) 임베딩 — 단일 / 배치
const { embedding } = await embed({ model: 'openai/text-embedding-3-small', value: 'sunny day' });
const { embeddings } = await embedMany({ model: 'openai/text-embedding-3-small', values: ['a', 'b'] });
result.stream 은 텍스트뿐 아니라 툴콜·reasoning 포함 전체 이벤트 스트림 (v7 에서 fullStream → stream 개명). 콜백은 onEnd/onError/onChunk.
툴 호출
tool() 로 정의하고 이름을 key 로 하는 객체로 넘긴다. 스키마 필드는 inputSchema 다 (parameters 아님).
import { tool, generateText, isStepCount } from 'ai';
import { z } from 'zod';
const weather = tool({
description: 'Get the weather in a location',
inputSchema: z.object({ location: z.string() }),
execute: async ({ location }) => ({ location, temperature: 72 }),
});
const { text, steps } = await generateText({
model: anthropic('claude-opus-5'),
tools: { weather },
stopWhen: isStepCount(5), // 멀티스텝 정지조건 (v7: stepCountIs → isStepCount)
prompt: 'SF 날씨 알려줘',
});
에이전트 루프가 필요하면 ToolLoopAgent 를 쓴다 (new ToolLoopAgent({ model, tools }).generate({ prompt }); v6 에서 Experimental_Agent 안정화, 기본 stopWhen step count 20). Anthropic SDK 자체의 tool runner 와는 별개다 → agent-frameworks.
구조화 출력
v7 권장은 generateText/streamText 에 output 옵션 + Output.* 헬퍼. generateObject/streamObject 는 v6 부터 deprecated (export 는 잔존 — 완전 제거 여부는 재확인 필요).
import { generateText, Output } from 'ai';
const { output } = await generateText({
model: anthropic('claude-opus-5'),
output: Output.object({ schema: z.object({ name: z.string(), age: z.number().nullable() }) }),
prompt: '인물 정보를 뽑아줘',
});
Output.object|array|choice|json|text 가 있고 스키마는 Zod, 스트리밍은 result.partialOutputStream. Anthropic 네이티브 방식은 structured-output 참고.
스트리밍 UI — Next.js 라우트 핸들러
클라이언트는 useChat(@ai-sdk/react), 서버는 라우트 핸들러에서 streamText. 메시지는 v6 부터 parts 배열 모델이다.
// app/api/chat/route.ts
import { streamText, convertToModelMessages, createUIMessageStreamResponse, toUIMessageStream, type UIMessage } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
export const runtime = 'edge';
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: anthropic('claude-opus-5'),
messages: await convertToModelMessages(messages), // v6부터 async
});
return createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }) });
}
// 클라이언트
const { messages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({ api: '/api/chat' }),
});
// status: 'submitted' | 'streaming' | 'ready' | 'error'
// 렌더: message.parts.map(p => p.type === 'text' ? p.text : null)
프로바이더 교체 (Anthropic ↔ 타사)
| 방식 | 코드 | 언제 |
|---|---|---|
| 문자열 ID + AI Gateway (v7 기본) | model: 'anthropic/claude-...' |
코드 안 고치고 프로바이더/모델 스왑, Gateway 라우팅·비용집계 |
| 프로바이더 인스턴스 | anthropic('claude-...') |
프로바이더 고정, providerOptions 로 벤더 기능 접근 |
createProviderRegistry / customProvider |
registry.languageModel('anthropic:opus') |
별칭·폴백 프리컨피그 (v7: experimental_customProvider → customProvider) |
Anthropic 은 pnpm add @ai-sdk/anthropic, import { anthropic }, env ANTHROPIC_API_KEY. extended thinking 은 providerOptions.anthropic.thinking 로 켠다.
모델 ID 는 SDK 문서를 믿지 마라. AI SDK Anthropic 문서 예시(
claude-opus-4-20250514등)와 Gateway 예시(anthropic/claude-opus-4.1등)는 오래됐다. 현행 ID(claude-opus-5기본, 날짜 접미사 금지)는 claude-family 를 정본으로 써라.
함정 (gotcha)
- 버전 이름 드리프트. v6→v7 만 해도:
system→instructions(messages 내 system 은 기본 거부),experimental_*접두사 대거 제거(output/telemetry/activeTools/generateImage),result.fullStream→result.stream,stepCountIs→isStepCount,onFinish→onEnd. 코드젠·구버전 스니펫이 조용히 틀린다.npx @ai-sdk/codemod v7로 마이그레이션. - 토큰 사용량 집계 위치가 바뀐다. v7 에서 top-level
usage/content가 모든 step 합산으로 바뀌고, 마지막 step 전용값은finalStep로 이동. 캐시 필드는usage.cachedInputTokens→usage.inputTokenDetails.cacheReadTokens. 비용 계산 코드가 여기서 깨진다. - 런타임 요건. v7 은 Node.js 22+ 필수, ESM only (CommonJS
require()불가). edge runtime 에서는export const runtime = 'edge'를 라우트에 명시하고, 노드 전용 API(fs 등)를 execute 안에서 부르지 마라. - OpenTelemetry 분리. v7 텔레메트리는
@ai-sdk/otel별도 설치 +registerTelemetry(). 기존experimental_telemetry자동 켜짐을 기대하면 계측이 사라진다. 그리고convertToModelMessages는 async(v6부터) —await빼먹으면 Promise 가 messages 로 들어간다. - 프로바이더 버전 불일치. 코어만 올리고
@ai-sdk/react/프로바이더를 안 올리면 wire format 불일치로 스트리밍이 깨진다. 세트로 올려라.
참고
- anthropic-messages-api — SDK 를 벗기고 Anthropic 네이티브 API 를 직접 칠 때
- claude-family — 여기 넣을 현행 Claude 모델 ID·컨텍스트·가격 정본
- structured-output — 구조화 출력 전략 비교 (SDK output vs 네이티브 json_schema)
- agent-frameworks — ToolLoopAgent vs Anthropic Agent SDK vs 타 프레임워크
- embeddings-and-vector-search — embed/embedMany 로 만든 벡터를 RAG 에 태우기
- build-a-rag-pipeline — 임베딩·검색·생성 파이프라인 전체
출처: 버전은 npm registry 실측 [HIGH], API 형태는 ai-sdk.dev 공식 docs [HIGH]. 비Anthropic 프로바이더 모델명·GA 날짜는 미검증. 원본 → 2026-07-25-vercel-ai-sdk