Panduan Vercel AI SDK 5: Chat Type-Safe, Tool & Agen

Foto oleh Markus Spiske on Pexels
Vercel AI SDK 5 adalah toolkit TypeScript untuk membangun aplikasi AI, dirilis 31 Juli 2025. Ia menyediakan fungsi provider-agnostic seperti streamText dan generateText, chat type-safe dengan UIMessage dan ModelMessage, kontrol loop agen, serta hook UI framework seperti useChat untuk React, Vue, Svelte, dan Angular.
UIMessage adalah sumber kebenaran bagi state aplikasi Anda — ia menyimpan array parts lengkap, metadata, serta input dan output tool, dan inilah yang Anda persist. ModelMessage adalah bentuk ringkas yang dioptimalkan untuk token dan dikonsumsi model. Anda mengubah satu ke lainnya dengan convertToModelMessages tepat sebelum pemanggilan model.
AI SDK 5 menggantikan maxSteps sisi-klien yang lama dengan kendali sisi-server. stopWhen menentukan kapan loop berhenti — misalnya stepCountIs untuk batas keras atau hasToolCall untuk berhenti saat sebuah tool terpicu. prepareStep berjalan sebelum tiap langkah sehingga Anda bisa mengubah model, pesan, system prompt, atau memaksa tool tertentu untuk giliran itu.
useChat tidak lagi mengelola kolom input, jadi Anda memegang sendiri state input. Fungsi append digantikan sendMessage, dan backend disambungkan lewat transport seperti DefaultChatTransport, yang bisa diganti dengan WebSocket atau transport langsung-ke-provider. Pesan kembali sebagai objek UIMessage yang dirender dengan memetakan parts-nya.
Bisa. Setiap provider — OpenAI, Anthropic, Google, dan banyak lainnya — menerapkan spesifikasi model bahasa V2 yang sama, sehingga berpindah biasanya cukup mengubah satu baris pada argumen model. Namun perilaku tidak dijamin identik antarprovider, jadi jalankan ulang evaluasi dan periksa keandalan tool calling setelah berpindah.

Foto oleh Markus Spiske on Pexels
Ringkasan Utama
Vercel AI SDK 5 adalah toolkit TypeScript untuk membangun aplikasi AI, dirilis Juli 2025. Ia memisahkan state chat menjadi UIMessage untuk UI dan ModelMessage untuk model, menambah kontrol loop agen lewat stopWhen dan prepareStep, mengganti parameters tool menjadi inputSchema, melakukan streaming lewat Server-Sent Events, dan tetap provider-agnostic di OpenAI, Anthropic, serta Google.
Saya sudah cukup sering merilis fitur LLM untuk tahu di mana letak kesulitannya: tidak pernah pada prompt pertama, melainkan pada semua yang datang sesudahnya. Menyimpan percakapan, memutarnya ulang, menambah pemanggilan tool, mengganti model saat satu provider kena rate-limit, dan menjaga agar klien dan server sepakat tentang bentuk sebuah pesan. Vercel AI SDK 5, dirilis 31 Juli 2025, adalah versi pertama yang membuat masalah-masalah itu terasa memang dirancang untuk diselesaikan, bukan diakali.
Ini bukan changelog. Ini model berpikir yang saya harap saya miliki sebelum bermigrasi: untuk apa tipe pesan baru itu, bagaimana loop agen benar-benar berhenti, mengapa definisi tool dipindahkan, dan apa yang diharapkan useChat baru untuk Anda kelola sendiri. Setiap klaim di sini merujuk pada pengumuman resmi dan panduan migrasi yang ditautkan di akhir.
Dua fungsi yang paling sering Anda pakai tidak berpindah: streamText untuk respons token demi token dan generateText untuk satu hasil. Yang berubah di sekelilingnya adalah kosakatanya. Tool kini mendeklarasikan inputSchema alih-alih parameters, Anda membatasi loop agen dengan stopWhen alih-alih maxSteps, dan Anda memberi makan model dengan convertToModelMessages. Berikut route handler lengkap yang melakukan streaming balasan dan bisa memanggil tool cuaca.
import { streamText, tool, convertToModelMessages, stepCountIs } from "ai"
import { openai } from "@ai-sdk/openai"
import { z } from "zod"
export async function POST(req: Request) {
const { messages } = await req.json()
const result = streamText({
model: openai("gpt-4o"),
messages: convertToModelMessages(messages),
stopWhen: stepCountIs(5),
tools: {
getWeather: tool({
description: "Get the current weather for a city",
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => {
const res = await fetch("https://api.example.com/weather?city=" + city)
return res.json()
},
}),
},
})
return result.toUIMessageStreamResponse()
}Inilah perubahan yang menata ulang segalanya. AI SDK 5 memecah sebuah pesan menjadi dua tipe. UIMessage adalah sumber kebenaran bagi state aplikasi Anda: ia membawa array parts yang terurut penuh, metadata, input dan output tool, serta data typed kustom apa pun yang Anda stream ke browser. ModelMessage adalah bentuk ringkas yang dioptimalkan untuk token dan itulah yang benar-benar dikonsumsi model bahasa. Anda menyimpan UIMessage, lalu memanggil convertToModelMessages tepat sebelum pemanggilan model. String content datar yang lama sudah hilang, digantikan array parts yang typed, sehingga teks, reasoning, pemanggilan tool, dan file masing-masing menjadi part yang terpisah dan bisa diperiksa.
Simpan UIMessage, jangan pernah ModelMessage. UIMessage menjaga setiap detail — hasil tool, metadata, bagian reasoning — sedangkan ModelMessage sengaja membuang apa yang tidak dibutuhkan model. Menyimpan bentuk model berarti Anda kehilangan data secara permanen dan tidak bisa membangunnya kembali nanti.
Hook React ini dibangun ulang di sekitar sebuah transport. Ia tidak lagi mengelola kolom input untuk Anda, dan append sudah tiada — Anda memanggil sendMessage sebagai gantinya. Anda menyambungkan backend lewat DefaultChatTransport, yang bisa Anda ganti dengan WebSocket atau transport langsung-ke-provider untuk aplikasi khusus klien. Pesan kembali sebagai objek UIMessage, jadi Anda merender tiap pesan dengan memetakan parts-nya, bukan membaca satu string.
"use client"
import { useChat } from "@ai-sdk/react"
import { DefaultChatTransport } from "ai"
import { useState } from "react"
export function Chat() {
const [input, setInput] = useState("")
const { messages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({ url: "/api/chat" }),
})
return (
<div>
{messages.map((m) => (
<div key={m.id}>
<strong>{m.role}</strong>
{m.parts.map((part, i) =>
part.type === "text" ? <span key={i}>{part.text}</span> : null
)}
</div>
))}
<form
onSubmit={(e) => {
e.preventDefault()
sendMessage({ text: input })
setInput("")
}}
>
<input value={input} onChange={(e) => setInput(e.target.value)} />
</form>
</div>
)
}Sebuah agen hanyalah model yang terus memanggil tool sampai selesai, dan AI SDK 5 memberi Anda dua kendali jujur atas loop itu. stopWhen menentukan kapan berhenti — berikan stepCountIs untuk batas keras, hasToolCall untuk berhenti saat tool tertentu terpicu, atau sebuah array untuk menggabungkannya. prepareStep berjalan sebelum tiap langkah sehingga Anda bisa mengubah model, pesan, system prompt, atau memaksa sebuah tool untuk satu giliran itu. Bersama-sama keduanya menggantikan maxSteps sisi-klien yang tumpul dengan kendali sisi-server yang sesungguhnya.
const result = streamText({
model: openai("gpt-4o"),
messages: convertToModelMessages(messages),
tools,
// Keep looping until the model calls finalAnswer OR we hit 8 steps
stopWhen: [stepCountIs(8), hasToolCall("finalAnswer")],
// Reshape each step: force a planning tool on the first turn
prepareStep: async ({ stepNumber }) => {
if (stepNumber === 0) {
return { toolChoice: { type: "tool", toolName: "planTask" } }
}
return {}
},
})Setiap provider — OpenAI, Anthropic, Google, dan puluhan lainnya — menerapkan spesifikasi model bahasa V2 yang sama, sehingga berpindah cukup dengan mengubah satu baris pada argumen model; sisa kode Anda tidak tersentuh. Itulah yang membuat SDK ini benar-benar portabel: Anda bisa memulai di gpt-4o, memindahkan jalur yang sensitif biaya ke model lebih murah, dan mengarahkan langkah yang berat reasoning ke Claude tanpa menulis ulang tool, streaming, atau UI Anda.
Pergantian model satu baris tidak membuat perilaku identik. Provider berbeda dalam keandalan tool calling, kepatuhan JSON, batas konteks, dan cara mereka memformat reasoning. Perlakukan pergantian provider sebagai perubahan nyata: jalankan ulang eval Anda dan periksa rasio tool call sebelum mempercayainya di produksi.
| Konsep | AI SDK 4 | AI SDK 5 |
|---|---|---|
| Bentuk pesan | Satu string content | Array parts typed pada UIMessage |
| Input model | convertToCoreMessages | convertToModelMessages |
| Input useChat | Dikelola untuk Anda | Anda memegang state input |
| Mengirim pesan | append() | sendMessage() |
| Sambungan backend | opsi api | transport (DefaultChatTransport) |
| Batas loop | maxSteps (sisi-klien) | stopWhen (sisi-server) |
| Skema tool | parameters dan result | inputSchema dan output |
Saran saya setelah memindahkan kode nyata: mulailah dari model pesan, bukan dari hook. Begitu Anda meresapi bahwa UIMessage adalah yang Anda simpan dan ModelMessage adalah yang Anda kirim, perubahan useChat dan tool berhenti terasa sembarang dan mulai terasa sebagai konsekuensi. Jalankan codemod resmi untuk menyapu penggantian nama yang mekanis, lalu perbaiki manual lapisan penyimpanan, karena di situlah satu-satunya tempat codemod tidak bisa menalar data Anda.