请设计一个支持"断线重连+消息去重"的SSE客户端,并处理AI长文本生成中的网络抖动问题
场景 :在"印客学院"的AI答疑系统中,学生提问后AI需要长时间生成答案,期间网络可能不稳定,需要确保连接中断后能自动重连,并且不丢失、不重复已接收数据。
核心答案 :
设计一个SSE客户端,封装原生 EventSource ,添加以下功能:
- 断线重连 :监听
onerror事件,连接断开后按指数退避策略重连 - 消息去重 :服务器为每个消息分配唯一ID,客户端记录已接收的最后一个ID,重连时通过
Last-Event-ID头告知服务器 - 网络抖动处理 :设置合理
retry时间,客户端检测长时间无消息时发送心跳包
实现要点 :
- 使用
EventSource的retry字段和lastEventId机制 - 客户端记录最后接收的消息ID,重连时传入
- 设置心跳检测,长时间无数据主动重连
- 使用指数退避算法控制重连间隔
代码示例 :
class InkeSSEClient {
private eventSource: EventSource | null = null;
private lastEventId: string = '';
private retryCount = 0;
private maxRetries = 5;
private retryDelay = 1000;
connect(url: string) {
const eventSourceInitDict: EventSourceInit = {};
if (this.lastEventId) {
eventSourceInitDict.lastEventId = this.lastEventId;
}
this.eventSource = new EventSource(url, eventSourceInitDict);
this.eventSource.onmessage = (event) => {
this.retryCount = 0;
this.retryDelay = 1000;
if (event.lastEventId) {
this.lastEventId = event.lastEventId;
}
// 处理消息
};
this.eventSource.onerror = () => {
this.eventSource?.close();
if (this.retryCount < this.maxRetries) {
setTimeout(() => {
this.retryCount++;
this.retryDelay *= 2;
this.connect(url);
}, this.retryDelay);
}
};
}
}
如何在前端实现一个"流式Markdown解析器",在AI逐字输出过程中实时渲染标题、列表、代码块,并避免标签截断?
场景 :"印客学院"的AI在回答技术问题时流式输出Markdown格式文本,需实时渲染并保证结构完整性。
核心答案 :使用增量解析策略,维护解析状态,只解析新增部分。避免在标签中间截断导致HTML解析错误。
实现要点 :
- 使用
marked库的lexer进行词法分析 - 维护token队列,每次只对新内容进行词法分析
- 检测未闭合结构(如代码块),暂不渲染
- 使用
requestAnimationFrame控制渲染频率
处理流程 :
- 新文本到达 → 词法分析得到新tokens
- 合并到现有token队列
- 检查当前是否有未闭合结构
- 渲染所有完整tokens
- 未闭合结构用占位符显示
当AI流式返回的数据包含多个独立片段时,如何设计Chunk合并算法以保证片段完整性?
场景 :"印客学院"的AI在回答复杂问题时,交替生成文本、代码、表格等多种内容,每个类型可能分多次返回。
核心答案 :设计基于"边界检测"的合并算法。为每种内容类型定义开始和结束标记,使用状态机分析新Chunk,决定创建新片段、追加到现有片段还是结束片段。
算法步骤 :
定义片段类型和边界标记(代码块用```,表格用|)
维护当前活跃片段
对于每个新Chunk:
- 检测是否包含开始标记 → 开始新片段
- 检测是否包含结束标记 → 结束当前片段
- 否则 → 追加到当前片段
片段完成后加入已完成列表
状态转换 :
初始状态
↓
检测到开始标记 → 创建新片段(活跃状态)
↓
接收数据 → 追加到活跃片段
↓
检测到结束标记 → 完成片段 → 加入完成列表
请实现一个支持"优先级调度"的流式请求队列,允许用户中断低优先级生成以优先处理高优先级任务
场景 :"印客学院"学习平台中,学生可能同时发起多个AI请求,如翻译句子(低优先级)和生成代码(高优先级)。
核心答案 :设计请求队列,每个请求带有优先级属性。队列管理器根据优先级调度请求,同一时间只执行一个请求。高优先级请求可中断低优先级请求。
实现要点 :
- 请求封装为任务,包含优先级、可取消的异步函数
- 队列按优先级排序,高优先级先执行
- 当前执行任务可被中断(通过AbortController)
- 中断后任务状态保存,可重新加入队列
队列管理逻辑 :
- 添加任务 → 按优先级插入队列
- 执行任务 → 从队列取最高优先级任务
- 高优先级任务到达 → 中断当前低优先级任务
- 任务完成/中断 → 处理下一个任务
在React 18+中,如何用useTransition与useDeferredValue优化AI流式输出的渲染性能,避免主线程阻塞?
场景 :"印客学院"的React前端中,AI流式输出导致组件频繁重渲染,可能阻塞主线程,影响用户交互。
核心答案 : useTransition 标记状态更新为"非紧急",React在空闲时处理; useDeferredValue 延迟更新某个值,提供"滞后"版本,让界面先显示旧内容。
优化策略 :
- 将AI流式输出的状态更新包裹在
startTransition中 - 使用
useDeferredValue延迟显示快速变化的流式文本 - 利用
isPending显示加载状态 - 配合
Suspense处理加载状态
代码结构 :
function AIStreamComponent() {
const [text, setText] = useState('');
const [isPending, startTransition] = useTransition();
const deferredText = useDeferredValue(text);
const handleStream = (chunk) => {
startTransition(() => {
setText(prev => prev + chunk);
});
};
return (
<>
{isPending && <LoadingIndicator />}
<div>{deferredText}</div>
</>
);
}
设计一个"流式数据缓存"策略,将AI已生成的内容分段存储于IndexedDB,支持离线续写与历史回放
场景 :"印客学院"的AI写作助手生成长篇文章时,用户可能中途离开,希望下次能继续之前内容。
核心答案 :将AI生成的流式数据按时间或逻辑分段存储到IndexedDB,每个片段包含元数据。提供API支持离线续写和历史回放。
存储结构 :
interface StreamChunk {
id?: number;
sessionId: string; // 会话ID
chunkIndex: number; // 片段序号
content: string; // 内容
timestamp: number; // 时间戳
isFinal: boolean; // 是否结束
}
核心功能 :
- 保存片段:按顺序存储到IndexedDB
- 获取会话片段:按sessionId查询,按chunkIndex排序
- 获取最后片段:用于续写
- 回放功能:按时间间隔"播放"历史片段
- 清理策略:按时间或数量清理旧数据
如何用Web Worker并行处理多个AI流式响应,并实现跨线程状态同步?
场景 :"印客学院"的智能批改系统需要同时处理多个学生作业,每个作业的AI评语都是流式生成。
核心答案 :将每个AI流式请求分配给独立Web Worker处理,Worker负责接收流数据、解析、处理,通过postMessage将结果发送回主线程。
架构设计 :
- 创建Worker池管理多个Worker实例
- 每个Worker处理一个独立AI流
- 主线程通过MessageChannel与Worker通信
- 使用Transferable Objects高效传输数据
主线程管理 :
- Worker池:管理可用Worker
- 任务队列:待处理任务
- 任务分发:空闲Worker执行任务
- 状态同步:通过消息传递更新UI
Worker职责 :
- 建立SSE连接
- 解析流式数据
- 处理数据(如格式化)
- 发送结果回主线程
当AI服务端返回的流式数据包含自定义事件时,前端如何解析并触发相应回调?
场景 :"印客学院"的AI服务除了返回文本内容,还会发送自定义事件,如生成开始/结束、工具调用请求、错误信息等。
核心答案 :设计事件驱动的解析器,为每种事件类型注册处理器。解析SSE流时,提取 event 字段,根据事件类型分发到对应回调函数。
事件格式 :
event: <事件类型>
data: <JSON数据>
id: <事件ID>
retry: <重试时间>
解析器设计 :
- 解析SSE格式,提取event、data、id、retry字段
- 建立事件类型到处理函数的映射表
- 根据event字段调用对应处理器
- 提供默认处理器处理未知事件
处理器注册 :
parser.on('message', (data) => { /* 处理消息 */ });
parser.on('tool_call', (data) => { /* 处理工具调用 */ });
parser.on('error', (data) => { /* 处理错误 */ });
请设计一个"流式进度估算"组件,根据已接收的Token数与模型速率,动态预测AI生成剩余时间
场景 :"印客学院"的AI写作助手中,用户希望看到文章生成的预计剩余时间。
核心答案 :基于已接收Token数量、接收时间间隔和模型理论生成速度,使用加权移动平均算法估算剩余时间。考虑网络波动、服务器负载等因素,提供置信区间。
估算算法 :
- 记录每个Token的到达时间戳
- 计算最近N个Token的平均生成速度(加权平均,最近权重高)
- 根据总Token数估算和已生成Token数计算剩余Token
- 使用当前速度估算剩余时间
- 计算速度方差,提供乐观/悲观估计范围
关键指标 :
- 当前速度:最近N个Token的平均生成速度
- 剩余Token:总估计Token数 - 已生成Token数
- 剩余时间:剩余Token / 当前速度
- 置信区间:基于速度方差计算
如何实现AI流式输出的"语音同步朗读",确保语音与文字逐句对应,并支持暂停、跳过?
场景 :"印客学院"的听力练习中,AI生成的英文句子需要同步朗读,用户可能暂停、跳过某句,或调整朗读速度。
核心答案 :使用Web Speech API的SpeechSynthesis实现TTS,结合句子边界检测算法将流式文本分割为句子,为每个句子创建独立语音任务队列。
实现步骤 :
- 句子边界检测:基于标点、换行分割文本
- 语音队列管理:按句子顺序播放,支持控制操作
- 文字高亮同步:朗读时高亮当前句子
- 控制功能:播放、暂停、停止、跳过、语速调整
队列管理 :
- 添加句子到队列
- 按顺序播放队列中的句子
- 当前句子播放完成后播放下一个
- 支持中断当前句子,跳转到指定句子
在微前端场景下,多个子应用同时订阅同一个AI流式连接,如何设计共享连接管理器以避免重复请求?
场景 :"印客学院"的微前端架构中,多个子应用(聊天、笔记、作业)都需要接收同一个AI助手的流式输出。
核心答案 :设计共享的AI流式连接管理器作为单例运行在主应用或独立共享层中。子应用通过消息总线订阅流式数据,由管理器统一维护连接状态、重连逻辑,并将数据广播给所有订阅者。
管理器设计 :
- 单例模式:确保全局只有一个连接管理器
- 订阅/发布模式:子应用订阅感兴趣的数据
- 连接池管理:根据需要建立/关闭连接
- 引用计数:当最后一个订阅者取消订阅时关闭连接
- 数据广播:将接收到的数据发送给所有订阅者
订阅机制 :
class SharedConnectionManager {
private subscribers = new Set<Subscriber>();
subscribe(callback) {
this.subscribers.add(callback);
if (this.subscribers.size === 1) {
this.connect(); // 第一个订阅者建立连接
}
return () => this.unsubscribe(callback);
}
private broadcast(data) {
this.subscribers.forEach(callback => callback(data));
}
}
如何用Service Worker拦截AI流式请求,实现离线缓存、请求重试与带宽节省?
场景 :"印客学院"的PWA应用中,希望即使网络不稳定也能提供AI流式回答的部分功能,并能缓存常见问题的回答。
核心答案 :使用Service Worker作为网络代理,拦截对AI流式接口的请求。离线时返回缓存的响应;在线时添加重试逻辑,对响应进行压缩/解压以节省带宽。
Service Worker策略 :
- 预缓存:安装时缓存常见问题的回答模板
- 缓存优先:检查缓存,有则返回,无则请求
- 网络优先:先尝试网络请求,失败则回退到缓存
- 重试机制:网络请求失败时自动重试
- 压缩传输:对响应进行gzip压缩(需服务器支持)
缓存策略 :
- 静态回答:预缓存到Cache Storage
- 动态回答:运行时缓存,设置合适过期时间
- 存储管理:LRU策略清理旧缓存
- 版本管理:缓存版本号,避免旧缓存
设计一个"流式数据可视化"方案,实时展示AI生成过程中的Token分布、注意力权重或置信度变化
场景 :"印客学院"的AI模型解释性工具中,希望将AI生成文本时的内部状态实时可视化,帮助理解AI的"思考过程"。
核心答案 :从AI服务端获取额外的元数据(如每个Token的logits、注意力矩阵),前端使用Canvas或WebGL实时绘制热力图、概率分布图等。采用增量更新和采样策略处理大数据量。
可视化类型 :
- Token概率热力图:x轴为生成步骤,y轴为top_k Token,颜色表示概率
- 注意力权重矩阵:显示当前Token与之前Token的关联强度
- 置信度曲线:显示生成置信度随时间变化
- Token分布饼图:显示当前步骤的概率分布
性能优化 :
- 增量渲染:只更新新增数据部分
- 采样显示:数据点过多时进行采样
- 双缓冲Canvas:减少渲染闪烁
- WebGL加速:大数据量时使用WebGL渲染
当AI流式输出包含结构化数据时,如何在前端逐步解析并验证其完整性?
场景 :"印客学院"的AI数据助手场景中,AI可能流式输出JSON或XML格式的结构化数据(如表格数据、配置对象)。
核心答案 :使用状态机解析器逐步构建结构化数据。对于JSON,逐字符分析,跟踪大括号、中括号的配对情况,当检测到完整对象时进行解析和验证。对于XML,等待接收完整标签后再解析,或使用SAX风格解析器。
JSON流式解析 :
- 状态跟踪:括号深度、是否在字符串中、转义状态
- 缓冲区管理:累积字符直到形成完整JSON
- 完整性检测:括号深度为0时尝试解析
- 错误恢复:解析失败时等待更多数据
XML流式解析 :
- 标签跟踪:记录打开标签栈
- 部分解析:对不完整XML进行容错处理
- 完整性验证:检查标签是否闭合
- 错误处理:标签不匹配时的恢复策略
如何用EventSource的last-event-id机制实现AI生成中断后的续接,确保数据不丢失?
场景 :"印客学院"的在线编辑器中,AI正在生成长篇文章,突然网络中断。重连后,希望从断点继续生成。
核心答案 :利用SSE的 last-event-id 机制,客户端在重连时将上次收到的最后一个事件ID通过 Last-Event-ID 头发送给服务器,服务器从该ID之后继续发送事件。
实现步骤 :
- 服务器为每个事件分配唯一递增ID
- 客户端监听事件,存储最后一个事件ID到本地存储
- 连接中断后,重新创建EventSource,设置
lastEventId - 服务器收到
Last-Event-ID头,从该ID之后的事件开始发送
客户端实现 :
class ResumeableEventSource {
constructor(url) {
this.lastEventId = localStorage.getItem('lastEventId') || '';
this.eventSource = new EventSource(url, {
lastEventId: this.lastEventId
});
this.eventSource.onmessage = (event) => {
if (event.lastEventId) {
this.lastEventId = event.lastEventId;
localStorage.setItem('lastEventId', event.lastEventId);
}
};
}
}
在低代码平台中,如何设计一个"流式UI生成器",根据AI返回的JSON描述实时渲染表单、图表等组件?
场景 :"印客学院"的低代码平台中,用户用自然语言描述界面,AI流式返回UI的JSON描述(组件树、属性)。
核心答案 :定义UI描述语言(JSON Schema),描述组件类型、属性、子组件等。前端维护组件映射表,将组件类型映射到React/Vue组件。当接收到流式JSON时,逐步构建组件树,使用虚拟DOM差异更新实现渐进式渲染。
UI描述协议 :
{
"type": "Container",
"props": { "className": "app" },
"children": [
{ "type": "Input", "props": { "placeholder": "请输入" } },
{ "type": "Button", "props": { "label": "提交" } }
]
}
渲染引擎 :
- 组件注册表:组件类型到实际组件的映射
- JSON解析:流式解析UI描述JSON
- 组件实例化:根据描述创建组件实例
- 差异更新:比较新旧组件树,最小化更新
- 渐进渲染:逐步显示生成的UI
请实现一个"流式差异对比"功能,实时高亮AI编辑前后文本的差异(如语法修正、风格改写)
场景 :"印客学院"的写作助手中,AI对用户输入的文本进行流式改进(语法修正、风格优化)。希望实时显示修改前后的差异。
核心答案 :使用差异算法(如Myers diff算法)比较原始文本和AI流式输出的文本,生成差异列表(插入、删除、替换)。然后在前端将差异实时高亮显示,用颜色区分新增、删除和修改内容。
差异算法流程 :
- 输入:原始文本、当前AI输出文本
- 计算差异:生成操作序列(相等、插入、删除)
- 转换为HTML:
<ins>标签表示新增,<del>标签表示删除 - 实时更新:每次AI输出新内容重新计算差异
- 性能优化:增量计算差异,避免全量比较
显示效果 :
- 新增内容:绿色背景
- 删除内容:红色背景+删除线
- 修改内容:删除旧内容+新增新内容
- 实时更新:随着AI输出逐渐显示更多差异
如何用WebRTC DataChannel替代SSE/WebSocket,实现P2P架构下的AI流式数据传输?
场景 :"印客学院"的分布式AI系统中,希望实现端到端的AI流式传输,减少服务器压力,支持点对点的实时AI协作。
核心答案 :WebRTC DataChannel提供了浏览器之间的直接数据传输通道。建立过程需要信令服务器协助交换连接信息(SDP),之后数据直接在客户端之间传输。
建立流程 :
- 信令交换:通过WebSocket交换SDP和ICE候选
- 建立连接:创建RTCPeerConnection
- 创建通道:建立DataChannel
- 数据传输:通过DataChannel发送/接收流式数据
- 连接维护:处理断开、重连
优缺点 :
- 优点:低延迟、P2P传输、减少服务器负载
- 缺点:需要信令服务器、NAT穿透可能失败、连接建立复杂
适用场景 :
- 客户端之间的AI协作
- 局域网内的AI服务发现
- 边缘计算场景下的AI推理
设计一个"流式内容审核"管道,在AI生成过程中实时调用敏感词过滤、图片鉴黄等异步服务
场景 :"印客学院"的社区AI生成内容中,需要在生成过程中实时审核,一旦发现违规内容立即停止生成。
核心答案 :构建可插拔的审核管道,每个审核器(如敏感词、图片、违禁品)独立工作,并行或串行审核流式数据。审核结果通过事件通知,可中断流式生成。
管道设计 :
interface Moderator {
name: string;
moderate(content: string): Promise<{ passed: boolean; reason?: string }>;
}
class ModerationPipeline {
private moderators: Moderator[] = [];
async process(content: string) {
const results = await Promise.all(
this.moderators.map(m => m.moderate(content))
);
return results.every(r => r.passed);
}
}
审核器类型 :
- 文本审核:敏感词、违禁词、政治敏感
- 图片审核:鉴黄、鉴暴、OCR文字审核
- 音频审核:语音转文字后审核
- 视频审核:抽帧后图片审核+音频审核
处理策略 :
- 并行审核:多个审核器同时工作
- 快速失败:任一审核器失败立即停止
- 分级审核:先快速检查,后深度分析
- 异步回调:审核结果通过事件或回调通知
如何在前端实现"流式翻译记忆库",将AI翻译的句子片段实时存储并用于后续相似句子的加速?
场景 :"印客学院"的多语言学习平台中,AI实时翻译用户输入的句子。希望将翻译结果存储为记忆库,当用户输入相似句子时,优先从记忆库中检索。
核心答案 :使用向量相似度搜索(如sentence-transformers生成句子向量)或基于前缀树的模糊匹配。将翻译对(原文、译文)存储到IndexedDB,建立向量索引。新句子到来时,先搜索记忆库,找到高相似度的直接返回译文,否则调用AI翻译。
技术栈 :
- 向量化:将句子转换为向量(TensorFlow.js + Universal Sentence Encoder)
- 存储:IndexedDB存储向量和翻译对
- 检索:近似最近邻搜索(ANN)
- 相似度计算:余弦相似度、欧氏距离
- 缓存策略:LRU缓存常用翻译
工作流程 :
输入句子 → 向量化 → 搜索记忆库 → 相似度 > 阈值?
↓是 ↓否
返回缓存译文 调用AI翻译
↓ ↓
更新使用频率 存储到记忆库
当AI流式输出被用户中途修改时,如何设计撤销/重做栈以保留每一步的流式状态?
场景 :"印客学院"的AI写作工具中,用户可能在中途修改AI生成的内容,需要支持撤销/重做功能,回退到任意历史状态。
核心答案 :设计命令模式实现撤销/重做栈。每个用户操作(输入、删除、格式化)和AI生成的每个有意义片段都作为命令对象保存。栈中保存完整状态或差异,支持选择性保存流式状态。
命令设计 :
interface Command {
execute(): void;
undo(): void;
redo(): void;
}
class TextInsertCommand implements Command {
constructor(private editor: Editor, private text: string, private pos: number) {}
execute() { this.editor.insert(this.text, this.pos); }
undo() { this.editor.delete(this.pos, this.text.length); }
redo() { this.execute(); }
}
流式状态保存策略 :
- 完整快照:每个操作保存完整文档状态(内存消耗大)
- 差异保存:只保存变化部分(需计算差异)
- 检查点:定期保存完整状态,之间保存差异
- 选择性保存:只保存用户操作,AI生成作为原子操作
栈管理 :
- 最大深度限制防止内存溢出
- 分支支持(实验性功能)
- 状态序列化/反序列化
- 与AI流式生成的集成
请设计一个"流式数据分片上传"方案,将用户输入的大文件(如视频)切片后流式发送给AI处理
场景 :"印客学院"的视频分析功能中,用户上传大视频文件给AI分析,需要支持断点续传、进度显示和并行上传。
核心答案 :将大文件分割为固定大小的块(如5MB),使用可恢复上传协议(如Tus协议)或自定义分片上传。前端管理分片上传队列,支持暂停、恢复、重试和并行上传。
上传流程 :
- 文件分片:按固定大小切割文件
- 创建上传任务:生成唯一上传ID
- 上传分片:并行上传多个分片
- 服务端合并:所有分片上传完成后合并
- 通知AI处理:调用AI处理接口
关键特性 :
- 断点续传:记录已上传分片,中断后可继续
- 并行上传:多个分片同时上传
- 进度计算:基于已上传分片计算进度
- 错误重试:失败分片自动重试
- 暂停/恢复:手动暂停和恢复上传
代码结构 :
class ChunkedUploader {
async upload(file: File, onProgress: (progress: number) => void) {
const chunkSize = 5 * 1024 * 1024; // 5MB
const totalChunks = Math.ceil(file.size / chunkSize);
const uploadId = await this.createUploadSession(file);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
await this.uploadChunk(uploadId, chunk, i);
onProgress((i + 1) / totalChunks * 100);
}
await this.completeUpload(uploadId);
}
}
如何用TransformStream在浏览器侧对AI流式输出进行实时转码(如Base64解码、gzip解压)?
场景 :"印客学院"的AI服务返回gzip压缩的流式数据,需要在浏览器端实时解压;或返回Base64编码的二进制数据,需要实时解码。
核心答案 :使用Streams API的TransformStream创建转换流,在fetch的Response.body上添加转换管道,实时处理流式数据。可用于解码、解压、格式转换等操作。
TransformStream示例 :
// Base64解码TransformStream
class Base64Decoder extends TransformStream {
constructor() {
super({
transform(chunk, controller) {
const text = new TextDecoder().decode(chunk);
const decoded = atob(text); // Base64解码
controller.enqueue(new TextEncoder().encode(decoded));
}
});
}
}
// 使用
fetch('/ai-stream')
.then(response => {
const decodedStream = response.body
.pipeThrough(new Base64Decoder())
.pipeThrough(new TextDecoderStream());
return new Response(decodedStream);
});
常见转换 :
- Base64解码/编码
- gzip解压/压缩(使用CompressionStreams API)
- 字符编码转换(UTF-8 ↔ UTF-16)
- JSON流解析
- 数据格式转换(CSV → JSON)
性能考虑 :
- 流式处理避免内存峰值
- 适当缓冲区大小平衡延迟和吞吐
- Worker中处理CPU密集型转换
- 错误处理和恢复机制
在AI代码生成场景中,如何实现流式输出的"实时语法检查"与错误高亮?
场景 :"印客学院"的AI代码助手中,AI流式生成代码时,需要实时检查语法错误并高亮显示,帮助用户及时发现错误。
核心答案 :集成代码语法检查器(如ESLint、TypeScript编译器、pyflakes等)到前端,在流式输出过程中定期检查代码语法。使用Web Worker避免阻塞主线程,实时高亮错误位置。
实现方案 :
- 语法检查器选择:根据语言选择合适检查器
- 增量检查:每次新增代码时只检查受影响部分
- 延迟检查:防抖处理避免频繁检查
- 错误高亮:在代码编辑器中标记错误位置
- 错误解释:提供错误原因和修复建议
工作流程 :
AI流式输出代码 → 累积到缓冲区 → 防抖延迟 → 发送到Worker检查
↓ ↓
实时显示 语法分析
↓ ↓
用户查看 返回错误位置和描述
↓ ↓
更新错误高亮
Web Worker集成 :
// 主线程
const worker = new Worker('code-checker.js');
worker.onmessage = (event) => {
const errors = event.data;
// 更新错误高亮
};
function checkCode(code) {
worker.postMessage({ code, language: 'javascript' });
}
// Worker线程
importScripts('eslint.js', 'babel-parser.js');
self.onmessage = (event) => {
const { code, language } = event.data;
const errors = eslint.verify(code, { parser: 'babel' });
self.postMessage(errors);
};
设计一个"多模型流式对比"界面,同时展示GPT、Claude等不同模型的生成过程,并支持并行暂停/继续
场景 :"印客学院"的模型对比工具中,用户输入一个问题,同时发送给多个AI模型(GPT-4、Claude、Gemini),实时对比它们的生成过程和结果。
核心答案 :创建多个并行的流式连接,每个连接对应一个AI模型。使用统一的控制器管理所有连接的启动、暂停、继续和停止。设计对比界面并排显示各模型的生成过程,支持同步滚动和进度对比。
架构设计 :
- 模型管理器:管理多个模型连接实例
- 统一控制器:控制所有模型的播放状态
- 数据同步:确保各模型时间轴对齐
- 视图对比:并排或分栏显示对比结果
控制器功能 :
class MultiModelController {
private models: Map<string, ModelStream> = new Map();
private state: 'playing' | 'paused' = 'playing';
async startAll(prompt: string) {
for (const [name, model] of this.models) {
model.start(prompt);
}
}
pauseAll() {
this.state = 'paused';
for (const model of this.models.values()) {
model.pause();
}
}
resumeAll() {
this.state = 'playing';
for (const model of this.models.values()) {
model.resume();
}
}
}
对比界面设计 :
- 并排视图:多个编辑器水平排列
- 同步滚动:一个编辑器滚动时其他跟随
- 进度对比:显示各模型的生成速度和进度
- 差异高亮:高亮不同模型的输出差异
- 模型标签:清晰标识每个模型的输出
性能优化 :
- 虚拟滚动:大量输出时使用虚拟滚动
- 增量渲染:只渲染可视区域内容
- 节流更新:控制UI更新频率
- 内存管理:清理历史数据防止内存泄漏
