LLM 驅動聊天介面的興起造成了一個獨特的使用者體驗問題:看著文字逐字元出現令人興奮,但看著部分渲染的 Markdown 閃爍和跳動卻令人沮喪。當 LLM 生成程式碼區塊、表格或巢狀清單時,標準的 Markdown 渲染器無法處理 Token 的增量到達。它們等待完整的輸出,然後一次性渲染全部——這違背了串流的目的。使用者在串流完成之前盯著原始文字,然後頁面在一切同時重新格式化時跳動。
Streamdown 是 Vercel 對這個問題的優雅解決方案。它是一個專為 LLM 生成內容設計的開源串流 Markdown 渲染器。關鍵洞察在於 Markdown 渲染必須漸進地進行:每個 Token 應立即渲染,元素應在變得明確時出現,DOM 應逐步更新而不會出現版面不穩定。
該函式庫是專為 AI 時代打造的。傳統的 Markdown 渲染器假設完整、靜態的輸入。Streamdown 假設不完整、串流的輸入,並對如何渲染部分內容做出智慧決策。當 LLM 開始生成程式碼區塊時,Streamdown 立即渲染一個開啟的程式碼區塊容器。當它開始一個表格時,它渲染開放的表格標籤並在儲存格到達時填充。這創造了一個流暢、漸進的視覺體驗,與 LLM 回應的串流性質相匹配。
核心架構
Streamdown 的內部管線透過四個階段處理傳入的 Token:
| 階段 | 元件 | 功能 |
|---|---|---|
| 詞法分析 | 增量詞法分析器 | 在 Token 到達時解析部分 Markdown Token |
| 建構器 | 部分 AST 建構器 | 建構可表示不完整元素的 AST |
| 渲染器 | 漸進式 DOM 渲染器 | 隨著每次 AST 變更更新即時 DOM |
| 完成器 | 串流後解析器 | 最終化任何剩餘的不完整元素 |
渲染管線
下圖說明了 Streamdown 如何處理來自 LLM 的串流回應:
sequenceDiagram
participant LLM as LLM 串流
participant Buffer as Token 緩衝區
participant Lexer as 增量詞法分析器
participant AST as 部分 AST
participant DOM as DOM 渲染器
participant Worker as 高亮工作線程
LLM->>Buffer: Token "## "
Buffer->>Lexer: 刷新部分區塊
Lexer->>AST: "h2 標題"
AST->>DOM: 開啟標題標籤
LLM->>Buffer: Token "Installation"
Buffer->>Lexer: 刷新
Lexer->>AST: "文字節點"
AST->>DOM: 附加 "Installation"
LLM->>Buffer: Token "\n\n```python\n"
Buffer->>Lexer: 刷新
Lexer->>AST: "開啟程式碼區塊"
AST->>DOM: 渲染程式碼區塊外殼
LLM->>Buffer: Token "print('hello')"
Buffer->>Lexer: 刷新
Lexer->>AST: "程式碼行"
AST->>DOM: 附加程式碼行(純文字)
LLM->>Buffer: Token "\n```"
Buffer->>Lexer: 刷新
Lexer->>AST: "關閉程式碼區塊"
AST->>DOM: 關閉程式碼區塊
Worker-->>AST: 請求高亮
AST->>DOM: 使用高亮內容更新LLM 串流中的每個 Token 即時通過此管線。增量詞法分析器是關鍵元件:它必須在 Token 到達之間維護狀態,以便正確識別部分序列(如 [Click h 可能是連結 [Click here](url) 的開頭)並適當地渲染它。
渲染品質比較
下表將 Streamdown 與渲染 LLM 輸出的替代方法進行了比較:
| 方法 | 串流? | 部分語法 | 程式碼高亮 | 表格渲染 | 套件大小 |
|---|---|---|---|---|---|
| Streamdown | 是,逐個 Token | 優雅降級 | 背景工作線程 | 增量 | 12 KB (gzip) |
| react-markdown | 否(等待完整) | 不適用 | 基於外掛 | 僅完整 | 15 KB |
| marked | 否 | 不適用 | 基於外掛 | 僅完整 | 10 KB |
| 原生 innerHTML | 是,但不安全 | 渲染中斷 | 手動 | 中斷 | 0 KB(無依賴) |
| 自訂串流渲染器 | 部分 | 通常中斷 | 手動 | 通常中斷 | 視情況而定 |
使用範例
使用 Streamdown 與 React 和 Vercel AI SDK 非常簡單:
import { Streamdown } from '@vercel/streamdown/react';
export function ChatMessage({ content }) {
return <Streamdown content={content} />;
}
該元件自動處理串流輸入、漸進式渲染和最終解析。對於更高階的使用案例,Streamdown 提供用於自訂樣式、主題整合和互動處理器的鉤子。
開始使用
請造訪 Streamdown GitHub 儲存庫 取得安裝說明、API 文件和範例。該函式庫以 @vercel/streamdown 形式在 npm 上提供,並支援所有主要前端框架。Vercel AI SDK 文件 提供將 Streamdown 與 AI SDK 串流回應結合的整合指南。
常見問題
什麼是 Streamdown?
Streamdown 是 Vercel 的開源串流 Markdown 渲染器,可在 LLM 生成的文字逐個 Token 到達時顯示,並對表格、程式碼區塊、清單和標題等 Markdown 元素進行漸進式渲染。
為什麼串流 Markdown 渲染很困難?
標準的 Markdown 解析器假設輸入是完整的。串流 Markdown 會逐步渲染 Token,因此渲染器必須處理部分語法——例如在表頭之前到達的表格行,或未閉合的程式碼區塊——並逐步更新 DOM,而不會出現閃爍或版面位移。
Streamdown 如何在串流期間處理程式碼語法高亮?
Streamdown 使用多遍渲染策略。程式碼區塊在 Token 到達時首先顯示為無樣式的純文字,然後後台工作線程在區塊完成後應用語法高亮。這確保了零感知延遲,同時最終顯示完全高亮的程式碼。
我可以在沒有 React 的情況下使用 Streamdown 嗎?
可以。Streamdown 與框架無關,並匯出一個適用於任何前端堆疊的純 JavaScript API。還有針對 React、Vue、Svelte 和 Solid.js 的專用整合,提供串流友善的鉤子和元件。
Streamdown 與標準 React Markdown 有何不同?
標準的 React Markdown 函式庫(如 react-markdown)需要在渲染之前提供完整的 Markdown 輸入。Streamdown 專為增量渲染設計:它逐個 Token 更新即時 DOM,優雅地處理部分語法,並在串流完成時解析為正確渲染的 Markdown。
延伸閱讀
- Streamdown GitHub 儲存庫 – 原始碼、API 文件和範例
- Vercel AI SDK 文件 – 將 Streamdown 與 AI SDK 串流整合
- Vercel 部落格:AI 應用中的串流 – Vercel 對 AI 串流使用者體驗的觀點
- CommonMark 規範 – Streamdown 實作的 Markdown 標準
無程式碼也能輕鬆打造專業LINE官方帳號!一鍵導入模板,讓AI助你行銷加分!