如何在Web终端实时渲染LLM流式Markdown:wterm markdown包教程
【免费下载链接】wtermA terminal emulator for the web项目地址: https://gitcode.com/gh_mirrors/wterm1/wterm
wterm 是一个面向 Web 的终端模拟器,其中的@wterm/markdown包能实时将 LLM 流式输出的 Markdown 逐块转换成终端 ANSI 文本。本教程带你快速掌握 Web 终端实时渲染 LLM 流式 Markdown 的完整方法:从一行命令安装,到把 AI 回复流接入浏览器终端,新手也能照着做出来。
为什么 Web 终端要实时渲染 LLM 流式 Markdown?
在大模型应用中,回复是一次次以小块文本(chunk)的形式返回的。传统做法是:
- 等全部文本接收完毕;
- 用 Markdown 库渲染成 HTML。
这在网页聊天框里没问题,但如果你用的是Web 终端(比如 AI 编程助手嵌在终端里),等全文接收完再渲染会有明显的"空白等待期",而且 Markdown 库产出的是 HTML,终端根本不认。
@wterm/markdown解决的就是这个问题:它是一个流式 Markdown 转 ANSI 渲染器,文本一到就立刻转成带样式的终端输出,用户在终端里看到回答"打字机式"逐行浮现,体验与本地 TUI 一致。
💡 一句话理解:
push()喂进流式文本,终端立刻拿到可显示的 ANSI 内容;flush()在流结束时兜底收尾。
一键安装:如何快速上手 wterm markdown 包
安装只需一条命令:
npm install @wterm/markdown核心用法极简,只需三步:
import { MarkdownRenderer } from "@wterm/markdown"; const md = new MarkdownRenderer({ width: 80 }); // 流式过程中,每收到一段文本就调用一次 const ansi = md.push("# 标题\n\n这是 **加粗** 内容。\n"); terminal.write(ansi); // 流结束后收尾 terminal.write(md.flush());完整 API 说明见官方文档 markdown.mdx 与包内 README。
核心 API 讲解:push 与 flush 如何工作?
MarkdownRenderer类的实现非常紧凑,源码仅约 200 行,值得了解其工作机制:
| 方法 | 作用 |
|---|---|
push(delta: string): string | 喂入一段 Markdown 文本,返回已完整行的 ANSI 输出 |
flush(): string | 流结束时刷出缓冲区剩余内容,并关闭未结束的代码块 |
构造参数width | 终端列宽(默认 80),用于生成分隔线长度 |
关键点:内部按行缓冲。push()会把不完整的一行留在内部缓冲区,只有遇到换行符、确认一行完整时才渲染输出。这个设计正是为流式场景准备的——LLM 的 chunk 边界是随机的,可能正好把一行切成两半,而渲染器会自动拼接,不会出现半行闪烁或格式错乱。
实现细节可以阅读源码 index.ts,其中push方法(第 32-44 行)展示了缓冲逻辑,flush方法(第 46-56 行)负责收尾。
支持哪些 Markdown 语法?渲染效果一览
@wterm/markdown覆盖了 LLM 回复中最常用的语法,渲染效果如下:
| 语法 | 终端渲染效果 |
|---|---|
#~######标题 | H1/H2 粗体亮白色,H3+ 粗体,并自动留白行 |
**粗体**/__粗体__ | 加粗 |
*斜体*/_斜体_ | 斜体 |
`行内代码` | 青色高亮 |
文字 | 绿色下划线 + 灰色淡显的 URL |
围栏代码块``` | 缩进展示,上下带暗淡分隔线 |
- item无序列表 | 缩进圆点列表 |
1. item有序列表 | 带序号列表 |
> 引用 | 带暗淡竖线的引用块 |
---分隔线 | 暗淡横线 |
每种渲染都有对应的单元测试保障,例如 H1 渲染为粗体亮白色的断言见 markdown.test.ts。
实战:3 步把 LLM 流接入 Web 终端
wterm 官方提供了一个完整可运行的示例项目markdown-streaming,使用@wterm/react+ AI SDK 演示了全流程,项目说明见 examples/markdown-streaming/README.md。
第 1 步:服务端流式返回
API 路由使用 AI SDK 的streamText发起流式请求,通过toTextStreamResponse()把文本流原样推给前端:
const result = streamText({ model: "openai/gpt-4o-mini", messages }); return result.toTextStreamResponse();参考实现:route.ts
第 2 步:前端逐块读取并渲染
这是整个方案的核心循环——用ReadableStream的 reader 逐块读取,每块立即push进渲染器并写入终端:
const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const rendered = md.push(decoder.decode(value, { stream: true })); if (rendered) write(rendered); } write(md.flush());完整页面实现(含用户输入、会话历史、错误处理)见 page.tsx。
第 3 步:体验与细节
- 回答边生成边渲染,标题、粗体、代码块等样式随内容实时出现;
- 生成过程中按
Ctrl+C可中断流(示例中用AbortController实现,见 page.tsx); - 每次新回答建议创建新的
MarkdownRenderer实例,避免上一轮的缓冲状态残留。
新手避坑:4 个最佳实践
- 流结束务必调用
flush()—— 否则最后一行文本和未闭合的代码块不会被渲染,这是最常见的遗漏。 - 忽略返回的空字符串——
push()在收到不完整的行时返回空串,if (rendered)判空后再写入终端即可。 - 按需设置
width—— 该参数只影响分隔线长度,一般跟随终端实际列宽设置。 - 不要对整段文本重复 push—— 渲染器是状态式的,每个 chunk 只能喂一次,重复喂会导致内容翻倍。
小结:wterm markdown 包适合谁?
@wterm/markdown用极小的体积(核心实现不足 300 行)解决了「Web 终端里 LLM 流式输出」这一真实痛点:
- 做AI 终端助手 / 编程 Agent 产品:终端 UI + 流式 Markdown 是理想形态;
- 做浏览器内演示 / 文档站点:几行代码即可让 AI 回复在真终端里打字机式呈现。
结合 wterm 的 React / Vue / Svelte 框架绑定(源码位于 packages/@wterm/react/ 等目录),你可以快速把实时渲染 LLM 流式 Markdown 的能力嵌入任何前端项目。
【免费下载链接】wtermA terminal emulator for the web项目地址: https://gitcode.com/gh_mirrors/wterm1/wterm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考