AI 流式渲染

共 29 题
📑 题目列表 29 题
#
★★★

1. AI SDK(ai/@ai-sdk/openai/Vercel AI SDK)

请介绍 Vercel AI SDK 的整体架构与核心能力,说明 ai 包与 @ai-sdk/openai 等 Provider 包的分工,以及它如何统一不同 LLM 提供商的流式响应?

  • ai 核心包与 provider 包的分层设计
  • useChat/streamText 等流式 API 的抽象
  • 框架无关与 React/Vue/Svelte 集成的取舍

Vercel AI SDK 采用"核心 + Provider"分层:核心包 ai 定义统一的模型抽象(generateText/streamText)与 UI 工具(useChat/useCompletion/useObject),各提供商通过 @ai-sdk/openai、@ai-sdk/anthropic、@ai-sdk/google 等适配层接入,前端业务代码不直接依赖厂商 SDK。服务端 streamText 返回可流式传输的响应(支持 SSE),客户端 useChat 接收文本增量并维护完整消息状态。其工程价值在于:模型切换只改 provider 配置、统一处理流式解析与错误格式、内置 tool call 与 structured output 支持,同时保持框架无关,可嵌入任何框架。

本题考察对 AI SDK 生态的分层认知:先讲清核心包与 provider 包的分工,再落到流式渲染与 hooks 的工程价值,最后点出"统一抽象、可替换 provider"这一核心卖点,避免只背 API 名。

#
★★★

2. OpenAI/Anthropic/Google 流式响应(text/event-stream + fetch)

OpenAI、Anthropic 与 Google 三家厂商的流式响应如何基于 text/event-stream 与 fetch 实现?三家在流式协议上有什么差异?

  • SSE(text/event-stream)在 LLM 流式响应的应用
  • 三家厂商流式数据的格式差异(data 行、事件类型)
  • fetch 流式读取(ReadableStream + getReader)的实现要点

三家厂商都支持 HTTP SSE 流式返回,Content-Type 为 text/event-stream,客户端用 fetch 发起请求后通过 response.body.getReader() 逐块读取。OpenAI 每个 data 块是 JSON 的 choices[0].delta.content 增量;Anthropic 采用事件类型化设计(content_block_delta、message_delta 等事件携带不同类型负载);Google Gemini 的 streamGenerateContent 则以流式 JSON 数组返回 candidates 增量。共同点:空数据行作为心跳、done 标志或流结束标记各不相同,需要按厂商解析器处理;工程上建议统一封装一个"厂商适配器",把各家增量归一化为 {type, text, toolCalls, usage} 事件再交给渲染层。

先回答"都是 SSE + fetch 流式"的共性,再分述三家格式差异,最后落到统一适配层的工程实践,体现"知其然并知统一抽象"的水平。

#
★★★

3. Assistant UI 协议、Streamdown、Marquee 渲染节流

什么是 Assistant UI 协议与 Streamdown?在 AI 流式渲染中它们如何与渲染节流(如 Marquee 思想)配合提升用户体验?

  • Assistant UI 协议对消息类型化结构(text/tool/attachment)的约定
  • Streamdown 对 Markdown 分块增量渲染的规范化
  • 渲染节流与"先稳定再渲染"的权衡

Assistant UI 是一套社区约定的消息协议,把 AI 消息规范化为可序列化的类型化结构(system/assistant/user/tool 角色,内容为 text、toolCall、attachment 等块的数组),便于多端复用与持久化。Streamdown 是"增量 Markdown"约定:把流式 token 增量按 Markdown 语义累积为增量块,渲染器只重绘新增部分,避免整篇重解析。Marquee 渲染节流则借鉴"先预览后稳定"的思路,对高频 token 流做时间片批量提交。三者结合:协议层规范化数据,Streamdown 做增量解析,渲染层节流合并,形成流畅且可恢复的流式渲染管线。

考察对流式渲染"协议、解析、渲染"三层的理解:协议解决数据形状、Streamdown 解决增量语义、节流解决渲染性能,能分层作答即体现系统性认知。

#
★★★

4. Vercel AI SDK 的 useChat/useCompletion/useObject 流式 hooks

Vercel AI SDK 的 useChat、useCompletion、useObject 三个流式 hooks 各自解决什么问题?它们与 streamText 服务端 API 如何配合?

  • 三个 hooks 的适用场景差异(对话/补全/结构化对象)
  • 与服务端 streamText 的流式管道
  • useChat 维护消息数组与流式状态的方式

useChat 面向多轮对话,内部维护 messages 数组与 input 状态,自动把服务端增量合并进最后一条 assistant 消息,并暴露 isLoading、error 与 stop();useCompletion 面向单次补全,只维护 completion 字符串,适合"续写"类场景;useObject 面向结构化输出,把流式增量实时按 JSON Schema 解析为部分对象,适合表单填充、代码生成等场景。三者都要求服务端用 streamText 返回可流式管道(Next.js 的 AI SDK Route Handler 或任意框架的流式响应),客户端通过统一协议拿到增量并渲染。工程上按"对话、续写、结构化"三种交互形态选型,避免把所有场景都塞进 useChat。

先分清三个 hooks 的场景定位,再讲服务端 streamText 的配合,最后给出"按交互形态选型"的工程判断,展示对 SDK 能力的准确边界认知。

#
★★★

5. SSE、WebSocket、fetch 流的增量解析与渲染

SSE、WebSocket 与 fetch 流在 AI 流式输出的增量解析与渲染上各有什么特点?工程上如何选择?

  • 三种传输方式的连接模型与断线行为差异
  • 单向推送 vs 双向通信的适用场景
  • 增量解析与浏览器兼容性(EventSource 不支持 POST/header)

SSE 基于 HTTP 长连接单向推送,EventSource 自动重连且带 Last-Event-ID 断点续传,但只支持 GET;若要 POST 请求体、自定义 header(如 API Key)需用 fetch + ReadableStream 手写解析。WebSocket 是双向全双工,适合需要客户端中途插话、多轮工具调用或服务端主动推送的复杂会话,但要自己实现心跳、重连与消息协议。fetch 流(response.body.getReader())灵活可控,能同时拿到响应头状态码,便于错误处理与 AbortController 取消。选择建议:纯单向流式输出首选 SSE;需要双向交互选 WebSocket;需要 POST/header 与精细控制时用 fetch 流自行解析,并封装统一的增量事件管道给渲染层。

从连接模型、能力边界、工程配套(重连/心跳/取消)三个维度对比三种方式,并给出按场景选型的建议,是本题得分的核心。

#
★★★

6. Markdown 未闭合状态处理、代码块语法高亮、复制按钮

AI 流式输出 Markdown 时,未闭合的代码块、列表等中间状态如何处理?语法高亮与复制按钮在流式场景下有哪些工程要点?

  • 流式未闭合 Markdown 的容错解析策略
  • 代码块语法高亮在增量场景的防抖与重算
  • 复制按钮的交互与剪贴板权限

流式场景下 Markdown 常处于未闭合状态(如 ``` 出现但语言与内容未完),解析器必须容错:react-markdown/remark 对未闭合代码块默认按已闭合处理,渲染时保持代码块容器稳定、内容增量追加,避免整块闪烁。语法高亮在每次增量时重算成本高,工程上用"节流 + 只对完成的代码块高亮、进行中的块暂用纯文本"的策略,或用 shiki 的流式缓存与 Web Worker 异步高亮,保证不阻塞渲染。复制按钮只对已闭合代码块显示,点击时用 navigator.clipboard.writeText 写入,注意 HTTPS 安全上下文要求与失败降级(execCommand 兜底)。

分别处理"解析容错、高亮性能、复制交互"三个问题,突出"增量渲染下的稳定容器 + 延迟高亮 + 完成态操作"这一条主线,体现流式工程的细节意识。

#
★★★

7. text/event-stream 与 text/plain 在流式响应的工程取舍

LLM 流式响应中 text/event-stream 与 text/plain 两种 Content-Type 各有什么工程取舍?什么时候适合用 text/plain?

  • SSE 的格式约定(data/event/id/retry 字段)
  • text/plain 的简单直出与长度限制问题
  • 与代理、缓存、兼容性的关系

text/event-stream 是规范化的 SSE 格式:按行解析 data:、event:、id:、retry: 字段,空行分隔事件,支持断点续传(Last-Event-ID)与自定义事件类型,适合承载 JSON 增量、工具调用事件、用量统计等多类消息;代价是解析复杂、一些中间代理和 CDN 对长连接与分块缓冲处理不一致。text/plain 直接输出原始文本增量,客户端按 chunk 累积即可,实现最简单、兼容性最好,但无法携带结构化元数据、没有标准重连协议,且一旦客户端/代理缓冲整段响应就失去流式意义。工程取舍:需要结构化事件、断线恢复选 text/event-stream;纯文本直出、追求极简与最大兼容性(如极轻量服务、简单代理环境)可选 text/plain,前端仍可复用同一增量渲染管线。

从"数据表达能力、断点续传、代理兼容"三个维度对比两种类型,并给出"简单场景 text/plain、复杂场景 SSE"的取舍结论,避免绝对化。

#
★★★

8. Server-Sent Events(SSE)在 LLM 流输出的工程价值与现代浏览器支持

Server-Sent Events(SSE)在 LLM 流式输出中有哪些工程价值?现代浏览器对其支持现状如何?

  • SSE 的自动重连、Last-Event-ID 与事件类型机制
  • 单向长连接对 LLM 流输出的适配性
  • 浏览器支持范围与 HTTP/1.1 连接数限制、代理缓冲问题

SSE 的工程价值:基于 HTTP 长连接单向推送,天然适配 LLM"服务端持续生成、客户端被动接收"的模型;EventSource 内置自动重连与 Last-Event-ID 断点续传,省去手写重连逻辑;支持命名事件(message/error/usage 等)做多类型分发;文本协议便于调试与代理透传。现代浏览器(Chrome、Firefox、Safari、Edge)均原生支持 EventSource;注意点:HTTP/1.1 下同域并发连接数有限(约 6 个),多会话场景需 HTTP/2 多路复用或复用单连接;EventSource 不支持 POST 与自定义 header,需携带 token 时改用 fetch 流或 query 参数方案;中间代理若缓冲响应会导致流式延迟,需配置 X-Accel-Buffering: no 等禁用缓冲。

先讲 SSE 的协议价值(自动重连、事件类型、单向适配),再讲浏览器支持与连接数、代理缓冲等工程约束,展现"价值 + 边界"的完整认知。

#
★★★

9. 打字机效果的渲染节流(批量更新/requestAnimationFrame)如何兼顾流畅与滚动性能?

AI 流式输出中,打字机效果的渲染节流(批量更新/requestAnimationFrame)如何兼顾视觉流畅与滚动性能?

  • 高频 token 增量与渲染成本的矛盾
  • rAF 帧节流与 React 批量更新的配合
  • 滚动位置锚定与内容高度变化的处理

LLM 每帧可能到达多个 token,逐 token 同步 setState 会造成高频重渲染,工程上用节流聚合:以 requestAnimationFrame 为节拍,把一帧内到达的所有增量合并为一次状态更新(React 18 的自动批处理也可把同一帧内的 setState 合并),保证每秒最多约 60 次渲染。渲染时只更新新增文本节点或让 Markdown 组件做增量 diff,避免整棵子树重建。滚动性能方面:自动滚动用"内容接近底部才跟随"策略,通过检测 scrollTop + clientHeight 与 scrollHeight 的差值阈值判断用户是否在阅读旧内容,跟随滚动用 scrollTo 并配合 ResizeObserver 在内容高度变化时微调,防止抖动;长对话配合虚拟列表只渲染可视区间。

核心是"节流合并 + 增量更新 + 智能滚动",先讲渲染侧节流,再讲滚动侧策略,两条线都落到性能指标上,体现流式 UI 的系统工程思维。

#
★★

10. ReadableStream API 在 AI 流式输出的工程实现与边界

ReadableStream API 在 AI 流式输出中如何实现增量读取?它有哪些工程边界?

  • response.body 与 getReader() 的读取模型
  • 文本解码(TextDecoder)与字节分块的边界
  • cancel/abort 与背压处理

fetch 返回的 response.body 是 ReadableStream,通过 getReader() 拿到 reader,循环调用 reader.read() 逐块读取 Uint8Array,用 TextDecoder(stream: true)把跨块的 UTF-8 字节安全解码为字符串增量,再按 SSE 或厂商协议解析成文本事件交给渲染层。工程边界:字节流本身是任意的,UTF-8 多字节字符可能被块边界截断,必须用 TextDecoder 流式解码而不能直接 toString;异常/断流通过 reader.read() 返回 done 或抛错感知,需要捕获后触发重连;取消请求应调用 reader.cancel() 或 AbortController.abort() 让连接真正关闭,防止资源泄漏;背压方面,若渲染跟不上,可暂缓下一次 read 或在合适位置节流,避免内存无限堆积。

先讲"字节流 → TextDecoder → 增量文本"的实现链路,再讲 UTF-8 截断、取消与背压三个边界,展示对流的底层理解而非只背 API。

#
★★

11. Vercel AI SDK 在 React 流式 UI(Chat、Completion)

Vercel AI SDK 如何在 React 中构建 Chat 与 Completion 流式 UI?它的消息状态管理与增量渲染是怎么组织的?

  • useChat 的消息数组结构与流式追加
  • useCompletion 的补全文本管理
  • 与 React 渲染模型(并发、批处理)的配合

在 React 中,Chat 场景用 useChat:它维护 messages 数组(每条含 id、role、content),发送消息后服务端 streamText 的增量经协议回传,SDK 内部把增量追加到最后一条 assistant 消息的 content 上,组件只需按 messages 渲染列表,配合 useEffect 处理自动滚动即可;isLoading 驱动"生成中"指示,stop() 暴露给用户取消。Completion 场景用 useCompletion:仅维护 completion 字符串与 input,适合单次续写。两者都依赖服务端暴露流式 API(如 Next.js Route Handler 中调 streamText 并把 result.toUIMessageStreamResponse() 或 stream 返回),前端通过内置的 fetch 流解析增量。工程要点:消息数组用稳定的 id 做 key;流式期间避免整列表重排序;长对话结合虚拟滚动;将消息持久化与恢复放在 hooks 之外,保持 UI 层纯净。

先讲两个 hooks 各自的状态模型,再讲服务端到前端的流式管道与渲染注意点,突出"状态由 SDK 管理、渲染由组件负责"的分工。

#
★★

12. AI 流式响应中的 Markdown 渲染(react-markdown)

AI 流式响应中的 Markdown 渲染为什么常用 react-markdown?流式场景下有哪些性能与安全要点?

  • react-markdown 的解析渲染模型(AST、零 dangerouslySetInnerHTML)
  • 流式增量下的重渲染成本控制
  • XSS 防护与自定义渲染器的扩展

react-markdown 基于 unified/remark 把 Markdown 解析为 AST 再渲染为 React 元素,默认输出文本节点而非 HTML 字符串,不引入 dangerouslySetInnerHTML,天然规避大部分注入面;同时通过 components 属性可自定义渲染(如把代码块换成带高亮与复制按钮的组件)。流式场景下,每次增量都会触发全量解析,工程上用 memo 化、把渲染器抽离为只对增量区间的重解析,或结合节流批量提交增量来摊薄成本;对超长内容可用分片渲染或虚拟化。安全方面,除了解析器本身转义外,仍需对链接协议白名单(过滤 javascript: 等)、对自定义组件注入的内容做二次校验,并把用户输入与模型输出区分对待。

核心答出两点:react-markdown 的 AST 渲染模型带来的安全性,以及流式下"增量节流 + 组件定制 + 协议白名单"的工程实践。

#
★★

13. AI 流式响应中的 Token 计数与成本预估的工程实践

AI 流式响应中的 Token 计数与成本预估有哪些工程实践?客户端如何估算 token 数量?

  • tiktoken 等 tokenizer 在客户端的应用
  • 流式场景下增量计数的时机与精度
  • 成本预估与用量可视化

Token 计数在客户端常用 OpenAI 开源的 tiktoken(提供 WASM/JS 版本),按模型对应的编码器(如 cl100k_base)对文本编码统计,注意不同厂商/模型的 tokenizer 不同(Anthropic、Google 各有实现),需按 provider 选择。流式场景下,可在每次增量提交时累加该段文本的 token 数,或仅在流结束时精确统计;为降低高频计算成本,可对短增量做近似估算(如中文约 1 字 1-2 token)并在空闲时校准。成本预估结合单价表(输入/输出分开计价)实时展示当前会话消耗,配合用量图表与预算上限(cost limit),在接近阈值时提示或降级到小模型。注意:token 数会随上下文重算(缓存命中)变化,展示需注明"估算"而非精确计费。

从"用什么统计、何时统计、怎么算钱"三层展开,突出按 provider 选 tokenizer、增量节流统计与成本可视化,并点明估算与计费的差异。

#
★★

14. AI 流式响应中的 XSS 风险(HTML、URL)与安全防御

AI 流式响应中的 XSS 风险有哪些(HTML、URL)?前端如何防御?

  • 模型输出 HTML/链接的注入面
  • Markdown 渲染库的转义边界与协议白名单
  • DOMPurify 等 sanitize 管线的配置

模型输出不可信,若直接注入 innerHTML 或让渲染库输出原始 HTML 就会引入 XSS:恶意输出可包含

先枚举风险面(HTML 注入、URL 协议),再给出"渲染层转义 + DOMPurify 白名单 + 链接协议校验"三层防御,强调模型输出按不可信数据处理。

#
★★

15. AI 流式响应中的增量解析(JSON Streaming、NDJSON)

AI 流式响应中的增量解析如何实现?JSON Streaming 与 NDJSON 各有什么工程取舍?

  • 流式 JSON 的部分解析(partial parse)
  • NDJSON 按行解析的简单性与边界
  • 流结束后的最终校验与回退

增量解析指在流未结束时从部分数据中提取可用信息。NDJSON(Newline-Delimited JSON)把每个完整 JSON 对象放在一行,客户端按 \n 切分后逐行 JSON.parse,实现简单、天然支持增量,但要求服务端保证一行一个对象且不出现跨行字符串(JSON 字符串含换行会被转义为 \n,一般可控)。JSON Streaming(如部分 JSON、json-schema 驱动的 partial parse)则用专门的流式解析器(如 partial-json、JSON.parse 配合状态机)在任意字节处解析出部分对象,配合 schema 可实时渲染字段,但实现复杂、异常处理多。工程上:能按行输出优先 NDJSON;需要任意位置的实时字段(如流式表单)用 partial JSON 解析器;无论哪种,流结束时都要对最终数据做完整校验,解析失败时回退显示原始文本并重试。

对比"按行切分"与"任意位置部分解析"两种方案的使用场景与复杂度,并强调结束后的完整性校验与降级,体现工程严谨性。

#
★★

16. AI 流式响应中的乐观 UI(Optimistic UI)与回滚的工程价值

AI 流式响应中的乐观 UI(Optimistic UI)是什么?失败回滚如何设计?

  • 乐观更新与流式响应的结合(立即展示占位内容)
  • 请求失败/中断时的回滚策略
  • 消息状态一致性(pending/success/error)

乐观 UI 指在用户发送后不等待网络,立即在界面上展示"预期的中间态":如把用户消息立即上屏并附加 pending 状态、展示"生成中"的光标/骨架屏,让交互零延迟。AI 场景中,客户端先写入用户消息与空的 assistant 占位,再在流式增量到达时填充占位,形成"先渲染后填充"的体验。回滚设计:请求失败、超时或用户取消时,把 assistant 占位标记为 error 态(保留部分文本或显示重试按钮),必要时把已提交的本地状态恢复为发送前快照;幂等上给每次生成分配 requestId,重试时用同一 id 覆盖而非追加,避免重复消息。状态机(pending/success/error)驱动 UI 与持久化,保证刷新后仍可恢复。

答出"立即展示 + 流式填充 + 失败回滚"的完整链路,并强调 requestId 幂等与状态机,展示对乐观更新边界的理解。

#
★★

17. AI 流式响应中的多模态(图片、音频、视频)的工程应用

AI 流式响应中的多模态(图片、音频、视频)有哪些工程应用?前端如何渲染与流式呈现?

  • 多模态输出的类型(文本/图片/音频/视频/文件)
  • 流式渲染图片与音频的时机与体验
  • 输入侧多模态上传的约束(大小、类型、配额)

多模态输出指模型在文本之外返回图片(如 DALL·E/Imagen 生成的图)、音频(TTS 生成的语音)、视频或文件。前端工程上:文本与工具调用仍走流式增量,图片/音频等非文本块通常在消息结构中作为独立块(block)出现,图片用 URL 或 data URL 懒加载渲染并给出 loading 占位,音频用 播放并可边下边播(流式音频),视频类似。渲染时机上,图文混合的消息按块顺序排列,图片就位后逐步插入,配合"生成中"提示。输入侧多模态上传需检查 MIME 类型、文件大小与配额(如单文件上限、会话总量),预览时注意 EXIF 方向与解码内存,超大图先压缩再上传;不支持的模态要在调用前探测(如检查模型能力)并降级提示。

分"输出侧块式渲染"与"输入侧上传约束"两面作答,突出按消息块组织多模态内容、流式音频边下边播、上传前能力/大小/配额探测三个要点。

#
★★

18. AI 流式响应中的 SSE 长连接在 nginx 反向代理的工程配置

AI 流式响应中的 SSE 长连接在 nginx 反向代理下有哪些工程配置要点?

  • proxy_buffering 与缓冲导致的流式延迟
  • 响应头(X-Accel-Buffering)与超时配置
  • 连接数、读超时与断线重连的配合

nginx 反代 SSE 最常见的坑是缓冲:默认 proxy_buffering on 会把上游响应攒满缓冲再转发,导致流式输出一坨坨或卡死,需关闭缓冲(proxy_buffering off)并设置 X-Accel-Buffering: no 响应头让 nginx 对该响应跳过缓冲;同时设置 proxy_read_timeout(默认 60s)足够大或配合 SSE 心跳事件防空闲断连,proxy_cache off 避免缓存流式响应。SSE 是长连接,还需注意 worker_connections 与 keepalive 配置支撑并发连接,HTTP/1.1 下客户端同域连接数有限,可配置 HTTP/2 或引导多个连接。另外关闭 gzip 对流式响应的压缩或按需配置(压缩会引入缓冲),保证字节尽快到达客户端。

抓住"缓冲"与"超时"两个核心:proxy_buffering off + X-Accel-Buffering: no、加大 read_timeout、配心跳,再谈连接数与压缩,覆盖 SSE 反代的主要坑。

#
★★

19. AI 流式响应中的错误恢复(断网、超时)的现代实践

AI 流式响应中遇到断网、超时如何做错误恢复?现代实践有哪些?

  • 断网检测(navigator.onLine/online 事件)与恢复策略
  • 超时(AbortSignal.timeout)与重试的配合
  • 断点续传与本地补包(IndexedDB 缓存已收内容)

错误恢复分三个层面:一是感知,监听 online/offline 事件与 fetch 失败,用 AbortSignal.timeout 或自建定时器识别超时,区分"网络中断"与"服务端错误"(429/5xx);二是恢复,断网时暂停自动滚动并提示,网络恢复后对未完成请求自动重试,重试遵循指数退避与 jitter,且用 requestId 保证幂等避免重复插入消息;三是数据保全,把已收到的增量实时写入 IndexedDB(或内存快照),断线重连后从 Last-Event-ID 或本地已收内容继续,而不是整段重新生成——对超长回答这是体验关键。工程上把"错误分类 → 退避重试 → 本地续传"封装成统一的流式客户端,UI 只消费状态。

按"感知错误、重试恢复、数据保全"三层作答,突出幂等重试与本地补包续传两个现代实践,体现工程完整性。

#
★★

20. AI 流式响应中的响应式布局(流式内容不抖动)的工程应用

AI 流式响应中如何保证响应式布局下流式内容不抖动?

  • 流式内容高度动态变化对布局的影响
  • 容器稳定策略(min-height、占位、aspect-ratio)
  • 滚动锚定(scroll anchoring)与内容插入位置控制

流式内容逐字增长会造成容器高度频繁变化,引发页面跳动、滚动位置漂移与重排。工程实践:消息容器设置最小高度或按块预留占位(如代码块按行数估算高度),图片/视频用 aspect-ratio 与占位符固定尺寸,避免加载瞬间撑开布局;插入新内容统一发生在消息流末尾,用 scroll anchoring(CSS overflow-anchor)让浏览器锚定可视区域,减少因上方内容变化导致的跳动;自动滚动时只在"接近底部"时跟随,并借助 content-visibility 对屏幕外消息跳过渲染,降低长对话的重排成本。响应式上,代码块用横向滚动或自适应换行、表格容器内滚动,配合 max-width 与断点保持不同屏幕宽度下的稳定阅读体验。

围绕"高度稳定 + 滚动锚定 + 按需渲染"展开:占位与 aspect-ratio 稳定尺寸、overflow-anchor 稳定视口、content-visibility 与条件跟随滚动稳定长列表,构成不抖动的流式布局。

#
★★

21. AI 流式响应中的字体切换(等宽到比例字体的工程价值)

AI 流式响应中为什么常见"等宽字体到比例字体"的字体切换?其工程价值是什么?

  • 等宽字体在流式打字阶段的布局稳定性
  • 切换到比例字体的时机与避免回退跳动
  • 字体度量差异与布局抖动的关系

等宽字体(monospace)每个字符宽度一致,流式打字阶段用等宽字体可以让增量字符稳定推进、光标位置可预测,避免文字宽度随机变化造成的视觉跳动;而比例字体(proportional)阅读体验更好、信息密度更高。工程价值:在"生成中"用等宽字体展示、生成完成后切换到比例字体,把"不稳定渲染"与"最终阅读"分离。切换时机需谨慎:若在流式中途切换,字宽变化会造成整段重排跳动,常见做法是流结束后统一切换,或为两种字体设置相同的度量参数(font-feature-settings 对齐)使切换时布局差异最小;也可用 CSS 的尺寸适配(如调整行高、宽度补偿)平滑过渡。这一实践体现了"以布局稳定性优先的流式渲染"思想。

答出等宽字体的度量稳定优势、比例字体的阅读优势,以及"完成后切换 + 度量对齐"的工程细节,体现对排版与流式体验结合的理解。

#
★★

22. AI 流式响应中的语言切换(中文、英文)与本地化的现代实践

AI 流式响应中如何处理中文、英文等语言切换与本地化?有哪些现代实践?

  • 多语言内容的渲染与字体栈配置
  • 语言检测(lang 属性)与断词差异(中文无空格分词)
  • 本地化文案(i18n)与数字/日期格式

AI 输出可能混合中英文(甚至代码、emoji),工程实践:为容器设置包含中英文字体的字体栈(font-family: 系统中文 + Latin 字体),利用 font fallback 保证两种语言都渲染正常;按内容片段标注 lang 属性(如 lang="zh" / lang="en"),利于屏幕阅读器发音与浏览器排版(换行、连字符);中文没有空格分词,换行依赖浏览器断字算法,必要时用 word-break: break-word 防溢出。本地化方面,应用自身的 UI 文案用 i18n 框架(如 i18next)管理,流式内容本身不翻译,但对"生成中/重试/复制"等状态文案做多语言;数字、日期、时间用 Intl API 按 locale 格式化,避免硬编码。现代实践还包括按用户语言偏好调整提示词(prompt 本地化)与模型参数。

分"内容渲染的语言处理"与"应用自身本地化"两层,答出字体栈、lang 属性、中文断词与 Intl/i18n 实践,体现多语言工程的完整性。

#
★★

23. AI 流式响应中的 Tool Calls(Function Calling)

AI 流式响应中的 Tool Calls(Function Calling)如何工作?前端如何渲染工具调用的流式状态?

  • 工具调用在流式协议中的表示(tool_call 增量块)
  • 前端对工具调用的执行流程(参数完整后再执行)
  • 工具结果回传与多轮调用的状态 UI

Function Calling 是模型输出"调用某个工具"的结构化指令:流式响应中,模型先输出 tool_call 块的增量(工具名与参数 JSON 逐步到达),前端或代理层需等参数 JSON 完整后再执行工具,而非边收边执行。执行后把结果作为 tool 角色消息回传给模型,模型基于结果继续生成文本或发起下一个工具调用,形成多轮循环。前端 UI 上,工具调用过程有明确状态:发起中(显示工具名与参数摘要)、执行中(进度动画)、成功(展示结果摘要与可展开详情)、失败(错误提示与重试)。工程要点:参数用 schema 校验后再执行(防注入);执行超时与并发限制;流式过程中把 tool_call 与文本增量都渲染出来,让用户看到"模型正在做什么";安全上高风险工具需用户确认。

讲清"流式参数增量 → 完整后执行 → 结果回传多轮"的循环,并给出四态工具调用 UI,体现对 Agent 交互模式的完整理解。

#
★★

24. AI 流式响应中的 Context Window 限制与上下文压缩的工程应用

AI 流式响应中的 Context Window 限制如何应对?上下文压缩有哪些工程应用?

  • 上下文窗口超限的表现(截断、报错)
  • 压缩策略:摘要、裁剪、结构化保留
  • 客户端 token 计数与发送前检查

上下文窗口是模型单次能处理的最大 token 数,超出后请求会报错或模型"遗忘"早期内容。工程应对分事前与事后:事前,客户端用 tokenizer 对会话历史实时计数,接近上限时触发处理(提示用户开新会话、自动裁剪最旧消息、或进入压缩流程);事后(流式中发现内容超限)则截断早期消息并重试。上下文压缩的现代实践:对最旧的消息做摘要(用模型把多轮对话压缩为要点),保留最近 N 条原始消息与关键事实;结构化保留(如把搜索结果、工具结果提取为结构化记录而非原文);裁剪工具调用细节、只保留结果摘要。注意摘要会丢失细节,工程上把"原始全文本地保留 + 压缩版本送模型"结合,用户仍可回溯。

先讲超限表现,再按"事前计数检查、事后摘要压缩、结构化保留"分层给方案,并点出本地保留全文与模型侧压缩配合的关键。

#

25. AI 流式响应中的 SSE Polyfill(EventSource polyfill)

AI 流式响应中的 SSE Polyfill(EventSource polyfill)解决什么问题?它有哪些实现方式与边界?

  • EventSource 的能力限制(GET、无自定义 header)与 polyfill 动机
  • 基于 fetch + ReadableStream 的 polyfill 实现
  • polyfill 的边界(重连、事件解析、取消)

原生 EventSource 只支持 GET 且无法自定义请求头,而 LLM 服务常需 POST(长 prompt)与 Authorization 头,故需 polyfill:用 fetch(POST + headers)发起请求,读取 response.body 的 ReadableStream,按 SSE 规范逐行解析(data/event/id/retry 字段、空行分隔事件),在解析到完整事件时派发 message/自定义事件。成熟的 polyfill(如 @microsoft/fetch-event-source)还实现自动重连(含 Last-Event-ID 回传)、自定义事件分发、AbortController 取消与错误分类。边界:polyfill 不提供原生的自动重连语义时需自行处理;无法百分百模拟 EventSource 的浏览器内部行为(如 retry 退避细节);需注意 CORS 与 credentials 配置,以及流中途 HTTP 错误(如 401)时对错误 body 的读取。

先讲"为什么需要 polyfill"(POST/header 限制),再讲"基于 fetch 流的实现要点",最后列边界(重连、取消、错误处理),体现对协议级实现的理解。

#

26. Prompt API 接受图片或音频等多模态输入时,前端应如何在调用前检查模态能力、MIME 类型、尺寸与配额,并处理 EXIF、解码内存、流式输入及不支持模态的降级

Prompt API 接受图片或音频等多模态输入时,前端如何在调用前检查模态能力、MIME 类型、尺寸与配额,并处理 EXIF、解码内存、流式输入及不支持模态的降级?

  • 调用前能力探测(模态支持、模型配额)
  • MIME 类型、尺寸与配额的前置校验
  • EXIF 方向修正、解码内存与降级策略

前置检查分四步:一是能力探测,通过模型能力接口确认当前模型支持图片/音频等模态(不支持则直接降级为纯文本提示或提示用户);二是格式校验,检查文件 MIME 类型是否在白名单内(如 image/jpeg、image/png、audio/mp3),用 file.type 与魔数双重确认,避免伪造扩展名;三是尺寸与配额校验,图片检查宽高像素与文件大小(超大图压缩后再传,避免解码内存峰值),音频检查时长与大小,并核对会话配额(单次与累计上限);四是内容预处理,图片用 createImageBitmap 或 文章配图 加载后按 EXIF orientation 修正方向、必要时 canvas 降采样,音频校验编码格式与码率。流式输入场景下分批校验与上传;不支持的模态(如某模型不支持视频)在前端隐藏或禁用入口并给出说明,避免请求失败。降级原则是"fail closed":校验不通过就不发请求,而不是尝试后静默失败。

按"能力探测 → 格式/尺寸/配额校验 → EXIF 与解码内存处理 → 不支持降级"的流水线作答,突出"先校验后调用、降级而非报错"的工程原则。

#

27. 同一端侧 LLM 分别用 WebNN MLGraphBuilder 和 WebGPU Compute Shader 实现时,算子融合、图编译、显存管理、KV Cache 与浏览器驱动差异会如何影响首 Token 延迟和 tokens/s

同一端侧 LLM 分别用 WebNN MLGraphBuilder 和 WebGPU Compute Shader 实现时,算子融合、图编译、显存管理、KV Cache 与浏览器驱动差异会如何影响首 Token 延迟和 tokens/s?

  • WebNN 的图编译与算子融合机制 vs WebGPU 手工 shader
  • 显存管理与 KV Cache 策略对吞吐的影响
  • 浏览器/驱动差异对端侧推理稳定性的影响

WebNN 走"声明式图"路径:MLGraphBuilder 构建计算图,由浏览器/底层 ML 后端(如 DirectML、oneDNN、XNNPACK)编译优化,自动做算子融合(如 QKV 投影合并、激活融合)与内存复用,图编译一次后反复执行,对 Transformer 这类固定结构模型能显著降低首 Token 延迟;但图编译的自动优化依赖后端能力,不同浏览器/平台(Chrome on Windows vs Android)后端实现不同,性能与算子覆盖差异大。WebGPU Compute Shader 是手写 WGSL 内核:可控性最强,可针对注意力、KV Cache 分块手工调优(如 tiling、shared memory),但算子融合与内存布局要靠开发者手工完成,开发成本高、易出 bug,不同浏览器对 WGSL 编译器与驱动(如 Metal/Vulkan/D3D12 桥接)的优化差异同样影响延迟与吞吐。KV Cache 管理上,显存容量决定可缓存的上下文长度:WebGPU 显存不够时需要把 KV 换出到系统内存(降低 tokens/s),WebNN 依赖后端的自动内存规划。生产实践是用基准测出当前设备/浏览器组合下的 TTFT 与 tokens/s,作为选后端与降级依据。

对比"声明式图编译优化"与"手工 shader 可控性"两条路线的性能来源,落到显存/KV Cache 与浏览器驱动差异上,最后以实测基线收尾,体现端侧推理的工程思维。

#

28. WebLLM 与 Gemini Nano 的生产选型矩阵应包含哪些维度

WebLLM 与 Gemini Nano 的生产选型矩阵应包含哪些维度?

  • 可用性(浏览器/设备覆盖与安装门槛)
  • 性能与模型能力(参数量、TTFT、tokens/s)
  • 成本、隐私与可维护性(下载体积、更新、供应商锁定)

选型矩阵至少包含五个维度:一是可用性,Gemini Nano 由 Chrome 内置、按设备灰度开放(需 LanguageModel.availability() 探测与下载流程),WebLLM 需用户先下载数百 MB 的模型到 WebGPU 设备,两者都要考虑目标用户的浏览器与硬件门槛;二是性能与能力,比较模型参数量/质量、首 Token 延迟、tokens/s、峰值内存与可处理的上下文长度,用统一基准在目标设备实测;三是下载与更新,模型体积、分片下载、版本更新策略与磁盘配额管理(WebLLM 走 CacheStorage,Gemini Nano 由浏览器管理);四是成本与隐私,端侧推理免 API 费用、数据不出设备,适合隐私敏感场景,但维护(模型升级、降级策略)成本要计入;五是锁定与生态,Gemini Nano 绑定 Chrome/Google,WebLLM 基于开源 WebLLM 生态可换模型但依赖 WebGPU 支持。生产上按"目标用户设备画像 × 任务质量要求 × 隐私合规"生成决策矩阵,并保留云端回退路径。

用"可用性、性能、下载更新、成本隐私、生态锁定"五个维度搭矩阵,强调实测基准与云端回退,展示生产选型的完整考量。

#

29. 如何为端侧生成建立覆盖高低端设备的性能基线,同时测量模型冷启动、预热后 TTFT、tokens/s、峰值内存、耗电与页面 FPS,并据此决定禁用或降级阈值

如何为端侧生成建立覆盖高低端设备的性能基线,测量模型冷启动、预热后 TTFT、tokens/s、峰值内存、耗电与页面 FPS,并据此决定禁用或降级阈值?

  • 分层设备矩阵与统一基准脚本
  • 关键指标测量方法(冷启动、TTFT、tokens/s、内存、耗电、FPS)
  • 阈值制定与禁用/降级策略

建立性能基线分三步:第一步定义分层设备矩阵,把目标设备按 CPU/GPU 算力、内存分为高端/中端/低端档,每档选取代表机型;第二步用统一的基准脚本测量指标:冷启动(从调用到可首响应的总时长,含模型加载)、预热后 TTFT(连续第二次调用)、tokens/s(流式生成速率)、峰值内存(performance.memory 或 WebGPU 显存查询)、耗电(用 Battery API 或真机功耗仪采样)、页面 FPS(长文本流式生成时用 rAF 计数丢帧率);测量多次取 P50/P95,排除浏览器后台与首屏干扰。第三步定阈值:把"体验合格线"(如 TTFT < 1.5s、tokens/s > 30、FPS 丢帧 < 5%)映射为设备能力分数,不达标的设备禁用端侧生成并回退云端或降级(如缩短上下文、降低模型档位、关闭多模态)。阈值要可配置并灰度验证,同时监控线上真实分布持续校准。

按"设备矩阵 → 指标测量 → 阈值决策"三步作答,指标覆盖性能、资源与体验三面,并强调统一脚本、P50/P95 统计与线上校准,体现数据驱动的端侧工程。