969 字
约 3 分钟
0
markstream-vue 入门:AI 流式 Markdown 渲染

markstream-vue 入门:AI 流式 Markdown 渲染

AI 对话的回复是一段一段「流」出来的,普通的 Markdown 渲染器在这种场景下会闪烁、抖动、代码块错乱。markstream-vue 专为这个场景而生。

问题:流式输出为什么难渲染

AI 聊天的返回不是一次给全,而是逐 token 推送——你看到的「打字机效果」。这对渲染是巨大挑战:

半截语法问题。流到一半的 Markdown 是不合法的:代码块只有开头 ``` 没有结尾、表格只流到第二行、数学公式只有一半 $。传统渲染器拿到这种「残缺文本」会渲染错乱,等下一段来了又重渲染,用户看到的就是闪烁和布局跳动。

性能问题。每来一段就要整体重新解析渲染全文,回复长了(几千 token)越到后面每帧的重渲染开销越大,低端设备肉眼可见地卡。

markstream-vue 针对这两点做了专项处理:增量解析(只处理新增的部分)+ 未闭合语法容错(代码块没闭合就先按代码块渲染,等闭合了自然完整)。本站 AI 对话页用的就是它配合 Vue 做流式渲染。

基本用法

pnpm add markstream-vue
<script setup>
import { ref } from 'vue';
import { MarkStream } from 'markstream-vue';

const content = ref('');

// 典型的 SSE 流式请求
async function ask(question) {
  const response = await fetch('/api/ai/chat', {
    method: 'POST',
    body: JSON.stringify({ question }),
  });
  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    content.value += decoder.decode(value);   // 不断追加到同一个字符串
  }
}
</script>

<template>
  <MarkStream :content="content" />
</template>

接法的心智模型简单到离谱:不管流从哪来(SSE、WebSocket、fetch reader),只要持续往一个字符串 ref 里追加,组件就会把它渲染成稳定的 Markdown。组件自己处理增量与容错。

WebSocket 流的接法

本站 AI 对话走 WebSocket(后端 Spring WebSocket 推流),接法同理:

ws.onmessage = (event) => {
  const chunk = JSON.parse(event.data);
  if (chunk.type === 'delta') {
    content.value += chunk.text;     // 追加增量
  } else if (chunk.type === 'done') {
    loading.value = false;           // 流结束
  }
};

一个建议:流结束后不要再整段重渲染。有的实现收尾时把最终文本重新 parse 一遍「求干净」,反而引入一次全量重渲染的闪烁——markstream 的增量方式下,最后一个 chunk 渲染完自然就是终态。

与打字机效果的配合

有的产品想在「拿到全部回复」后做匀速打字机(本地模拟流),markstream 也适用:

const full = await fetchFullAnswer();
const timer = setInterval(() => {
  content.value = full.slice(0, content.value.length + 2);
  if (content.value.length >= full.length) clearInterval(timer);
}, 30);

不过真实流式(真逐 token)的体验优于模拟打字机——用户等待首 token 的时间才是体感关键,能真流式就别模拟。

样式与代码高亮

组件支持自定义渲染样式(代码块、表格、引用等 CSS 类都可覆盖)。代码高亮默认可用,按需配置主题:

<MarkStream :content="content" class="ai-message" />
/* 覆盖代码块风格示例 */
.ai-message pre {
  border-radius: 10px;
  background: #0d1117;
}

AI 回复里最重的内容就是代码块(AI 特别爱贴代码),代码块渲染的稳定性基本决定了对话区 80% 的观感——这也是选专用流式渲染器而不是普通 markdown-it 的最大理由。

小结

markstream-vue 解决的是「AI 流式输出 × Markdown」这对组合的特殊问题:增量解析保证性能不衰减,未闭合语法容错保证不闪烁。接入成本几乎为零——往一个 ref 里追加文本,剩下的交给它。做 AI 对话界面,这是基础设施级的组件。

markstream-vue 入门:AI 流式 Markdown 渲染
http://www.clxhxhhr.top/posts/3719/
作者
clxstart
发布于
2026-09-25
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。