發布日期:2026 年 7 月 16 日
在「使用 Vercel AI SDK 搭配內建的 Prompt API」中,您已瞭解四個核心生成基本類型,也就是 generateText()、streamText()、混合程式碼,以及使用 Output.object() 的結構化輸出內容,這些都是由 @browser-ai/core 提供支援。這次您要建構更具互動性的內容:完整的串流聊天使用者介面,完全在瀏覽器中執行,且在 Prompt API 無法使用時,會自動改用雲端模型。
要建構的內容
React 即時通訊介面,可執行下列操作:
- 使用 Vercel AI SDK 的
useChathook 串流多輪對話。 - 在瀏覽器中執行模型迴圈,不需後端伺服器。
- 如果 Prompt API 無法使用,系統會自動改用 Gemini 2.5 Flash。
- 以 GitHub 風格的 Markdown 格式算繪助理回覆,並在串流期間處理不完整的權杖。
- 等待第一個權杖時,顯示「思考中…」微光。
- 自動捲動至新訊息,並在您向上捲動時顯示捲動至底部的按鈕。
其他依附元件
除了 ai、@browser-ai/core 和 @ai-sdk/google 之外,即時通訊 UI 還需要 React、AI SDK 的 React 繫結,以及幾個 Markdown 套件:
npm install react react-dom @ai-sdk/react
npm install react-markdown remark-gfm harden-react-markdown
npm install -D @types/react @types/react-dom
此外,請為 UI 新增 Tailwind CSS、一些元件公用程式,以及 Lucide 圖示:
npm install -D tailwindcss postcss autoprefixer
npm install clsx tailwind-merge lucide-react
投票設定:多項建構作業
專案已有 index.html。新增 chat.html 做為第二個進入點,並設定 Vite 建構這兩個進入點:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
export default defineConfig({
plugins: [react()],
resolve: { alias: { '@': resolve(__dirname, './src') } },
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
chat: resolve(__dirname, 'chat.html'),
},
},
},
});
chat.html 相當簡單,只有 <div id="root"> 和指令碼標記:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Built-in AI Chatbot</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/chat.tsx"></script>
</body>
</html>
自動選取模型
在聊天機器人中,應用程式會自動做出選擇:先嘗試使用內建模型,如果 Prompt API 無法使用,則會改用雲端模型。
這項作業會在模組載入時執行,也就是在 React 掛接之前,因此當使用者輸入第一則訊息時,代理程式已準備就緒:
const agentPromise: Promise<ToolLoopAgent> = (async () => {
const builtIn = browserAI();
let model: any = builtIn;
if (typeof builtIn.availability === 'function') {
const availability = await builtIn.availability();
if (availability === 'unavailable') {
const { createGoogleGenerativeAI } = await import('@ai-sdk/google');
model = createGoogleGenerativeAI({ apiKey })('gemini-2.5-flash');
} else if (availability === 'downloadable') {
await builtIn.createSessionWithProgress(() => {});
}
}
return new ToolLoopAgent({ model, instructions: 'You are a helpful assistant.' });
})();
這個新元件是 ToolLoopAgent,也就是 AI SDK 抽象化,可管理任何模型的多輪對話迴圈。這個方法會採用模型和系統提示,並在內部處理來回通訊。
連結代理程式以使用 Chat
@ai-sdk/react 套件的 useChat 勾點通常會與 HTTP 端點通訊。
如要在瀏覽器端進行推論,請改用 DirectChatTransport。這個迴圈完全在瀏覽器中執行,不涉及任何伺服器:ToolLoopAgent
const transport = useMemo(() => new DirectChatTransport({ agent }), [agent]);
const { messages, sendMessage, status, stop } = useChat({ transport });
useMemo 很重要,因為 DirectChatTransport 會保留對話狀態,因此必須是穩定的參照。每次算繪時重新建立,都會重設對話。
useChat 的優點包括:
Messages:完整對話 (UIMessage[]),每個對話都包含role和parts陣列sendMessage({ text }):傳送新的使用者回合,並開始串流回應Status:'idle'|'submitted'|'streaming'|'error'Stop:取消正在進行的生成作業
顯示訊息
每則訊息都有 parts 陣列。這個聊天機器人只會用到 type:
'text' 部分。使用者訊息會以靠右對齊的泡泡顯示;助理訊息則會靠左對齊,並顯示圖示:
const ChatMessage = ({ message, isStreaming }: { message: UIMessage; isStreaming: boolean }) => {
const isUser = message.role === 'user';
const textParts = message.parts.map((part, i) => {
if (part.type !== 'text') return null;
if (isUser) return <span key={i}>{part.text}</span>;
return <Response key={i} parseIncompleteMarkdown={isStreaming}>{part.text}</Response>;
});
if (isUser) {
return (
<div className="flex flex-col items-end gap-2 animate-fade-up">
<MessageContent className="w-fit max-w-[min(80%,56ch)] ...">
{textParts}
</MessageContent>
</div>
);
}
return (
<div className="flex items-start gap-3">
<AIIcon />
<MessageContent className="text-[13px] leading-[1.65]">{textParts}</MessageContent>
</div>
);
};
MessageContent 和 Response 是 AI 元素。這些是 shadcn 樣式的來源元件,您會複製到專案中,而不是從 npm 安裝。Response 會以 react-markdown 包裝 remark-gfm,用於 GitHub 風格的 Markdown (表格、工作清單、刪除線),並以 harden-react-markdown 清理 AI 輸出內容中的連結和圖片。
訊息仍在串流時,parseIncompleteMarkdown 屬性為 true。在串流期間,模型可能會寫入 **bold,但尚未關閉 **,留下會以星號顯示的懸空符記。parseIncompleteMarkdown 會關閉所有開啟的 **、__、`、~~,並截斷懸而未決的 [ 連結開頭,確保每個增量區塊的輸出內容都乾淨整齊。
「思考中…」狀態
從傳送訊息到收到第一個權杖之間,status是
'submitted'。在此期間,應用程式會顯示閃爍動畫:
{status === 'submitted' && messages.at(-1)?.role !== 'assistant' && (
<ThinkingMessage />
)}
條件 messages.at(-1)?.role !== 'assistant' 可防止在助理訊息開始串流後,微光效果再次出現。
ThinkingMessage 使用 Shimmer 元件:<span>,其中包含使用 background-clip: text 的移動漸層,可為「思考中…」文字提供掃掠式醒目顯示效果。
自動捲動
有新內容時,應用程式會捲動至底部,但前提是使用者已在底部。如果他們正在閱讀某篇文章或與人對話,捲動畫面會打斷他們,令人感到不悅。
const [isAtBottom, setIsAtBottom] = useState(true);
useEffect(() => {
if (isAtBottom) endRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages, status, isAtBottom]);
const handleScroll = () => {
const el = containerRef.current;
if (!el) return;
setIsAtBottom(el.scrollHeight - el.scrollTop - el.clientHeight < 50);
};
當 isAtBottom 為 false 時,系統會顯示浮動的捲動至底部按鈕,使用者返回底部時,按鈕會淡出。
輸入區域
當您輸入內容時,文字區域會將高度重設為 auto,然後設為 scrollHeight,藉此自動調整大小。按下 Enter 鍵 (而非 Shift+Enter 鍵) 即可提交,且在串流回覆時,「傳送」按鈕會替換為「停止」按鈕,呼叫 stop():
<textarea
onInput={(e) => {
const el = e.currentTarget;
el.style.height = 'auto';
el.style.height = `${el.scrollHeight}px`;
}}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
if (input.trim() && !isStreaming) {
sendMessage({ text: input });
setInput('');
}
}
}}
/>;
{
isStreaming ? (
<Button variant="outline" onClick={stop}>
Stop
</Button>
) : (
<Button type="submit" disabled={!input.trim()}>
Send
</Button>
);
}
以載入狀態掛接
由於 agentPromise 是非同步,請先等待,再算繪 Chat。App 包裝函式會解析 Promise,並在這段期間顯示微調器:
function App() {
const [agent, setAgent] = (useState < ToolLoopAgent) | (null > null);
useEffect(() => {
agentPromise.then(setAgent);
}, []);
if (!agent) {
return (
<div className="flex h-dvh items-center justify-center">
<Loader size={20} />
</div>
);
}
return <Chat agent={agent} />;
}
代理程式解決問題後 (無論是立即啟動內建模型,還是等待模型下載),微調器就會消失,並掛載對話使用者介面。
示範
這個 即時示範 是功能齊全的聊天機器人,完全在瀏覽器中執行。輸入訊息,然後按下 Enter 鍵。如果可以使用 Prompt API,回覆內容會直接從裝置端模型串流傳輸,無須發出網路要求。如果瀏覽器不支援 Prompt API,系統會自動改用 Gemini 2.5 Flash。你可以要求它以清單形式說明某件事、撰寫程式碼片段,或使用 Markdown 格式。回覆內容會直接以格式化程式碼區塊、表格和內嵌程式碼呈現。

結論
在這兩篇文章中,您已瞭解 Vercel AI SDK 如何透過瀏覽器的內建 Prompt API,實現各種功能,從原始的生成基本項目,到完善的串流聊天介面,應有盡有。
在「搭配使用內建提示 API 和 Vercel AI SDK」中,您已瞭解如何使用 generateText() 和 streamText() 生成非串流和串流文字、如何使用 Output.object() 要求結構化 JSON 輸出內容,以及如何編寫混合程式碼,在執行階段選取內建模型和雲端供應商,且生成邏輯不會變更。
在這份文件中,您採用了相同的建構區塊,並將其包裝在完整的 React UI 中:ToolLoopAgent 用於管理對話迴圈、useChat 用於在瀏覽器中直接串流回應,以及 AI Elements 元件,用於在收到 Markdown 回應時,以清楚的方式呈現;當 Prompt API 無法使用時,所有這些都會自動回復到雲端。DirectChatTransport
結果是兩個完全透過瀏覽器運作的試用版,不需要後端:
- 使用內建的 Prompt API 和 Vercel AI SDK 試用版:並排顯示文字生成、串流和結構化輸出內容
- 使用 Vercel AI SDK UI 和 AI 元素,搭配 Prompt API 示範:提供完整串流功能的聊天機器人,可轉譯 Markdown 和使用深色模式