把 LLM 接进编辑器:流式输出的前后端实现细节
给我们的 Markdown 编辑器加了一个「AI 续写」功能,最麻烦的不是模型调用,而是流式输出的全链路设计。
后端:SSE 逐块推送
return new Response(
new ReadableStream({
async start(controller) {
for await (const chunk of llmStream) {
controller.enqueue(`data: ${JSON.stringify(chunk)}\n\n`);
}
controller.close();
},
}),
{ headers: { "Content-Type": "text/event-stream" } }
);
前端:Reader 打字机渲染
const reader = response.body!.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
appendText(decode(value)); // 增量追加,不做全量替换
}
经验
- 增量渲染时不要每次重新解析完整 Markdown,按块 append 纯文本,结束后再整体渲染一次
- 一定要处理客户端中断:
reader.cancel()要传导到上游模型调用,省 token - SSE 比 WebSocket 简单得多,单向生成场景够用