Skip to main content

6 posts tagged with "Stream"

View All Tags

SSE 和 STDIO 区别?

· 5 min read

SSE 和 STDIO 是 MCP 的两种传输方式,区别不在通信模式,在进程边界——STDIO 面向本地进程,SSE 面向远程服务。

  • STDIO:客户端 fork 子进程,通过 stdin/stdout 收发 JSON-RPC,零网络开销
  • SSE:客户端连远程 HTTP 端点,服务端推送事件,需处理鉴权和网络延迟
  • 选择逻辑:本地工具用 STDIO,远程共享服务用 SSE,场景决定选型
  • 核心差异:STDIO 进程由客户端管理生命周期,SSE 服务端独立部署
  • MCP 演进:原始 HTTP+SSE 已被 Streamable HTTP 替代,不再需要双通道拆分
  • 关键提醒本地工具用 SSE 是自找麻烦,多了端口、CORS、鉴权,收益为零

在处理AI模型的流式输出时,通常使用 SSE 或者WebSocket, 各自优缺点?

· 4 min read

AI 模型的流式输出本质是单向长文本推送,SSE 比 WebSocket 更合适,多数场景不需要双向通道。

  • SSE:基于 HTTP,服务端到客户端单向推送,内置自动重连,零额外握手成本
  • WebSocket:全双工双向通信,需要协议升级,实现复杂、资源开销大
  • 选择逻辑:AI 问答是客户端发一条请求、服务端流式返回文本,单向通道完全够用
  • 双向需求:语音对话、实时协作编辑才需要 WebSocket,纯文本问答不需要
  • 坑 ①:HTTP/1.1 下同一域名最多 6 个 SSE 并发连接,多标签页可能占满
  • 坑 ②:组件卸载时忘记手动关闭 EventSource,连接不会自动释放,导致内存泄漏

JS 的异步迭代器 AsyncIterable 是什么?

· 5 min read

for await...of 不是 async 版 for...of,而是一套"随时间产生的值流"消费模型。

  1. 普通 for...of 遍历同步数组,迭代立刻拿到值;for await...of 每次迭代要等下一个值,生产者产出与消费者消费完全解耦
  2. 这就是流式响应的底层逻辑:Node Stream、AsyncGenerator、LLM streaming 本质上是同一件事
  3. 实现 Symbol.asyncIterator 协议就能让任意对象变成可异步遍历的流
  4. Async Generator 是最简洁的生产端实现:yield 产出,for await...of 消费
  5. 适用场景:分页 API、Stream、实时事件——凡是数据"不是一次性到齐"的地方

ClaudeCode 客户端消息流是如何确保按序输出的?

· 6 min read

ClaudeCode 客户端消息流的有序性,本质上是 单写者 + 显式序号 + 受控并发 换来的工程纪律,不是靠运行时去猜消息该怎么排。

要点拆解:

  1. 所有 stream 事件先汇入统一写入通道,由 序号 决定渲染顺序,不按到达时间。
  2. 工具并发被框死在 读可并行、写必串行 的边界内。
  3. UI 层只信任已经定序的快照,从不直接消费裸 SSE,否则就是乱序事故的源头。
  4. 回合作为原子单位,失败整体丢弃,不修补半截回合。

理解这套规则,比追着 SDK 文档更有用。

OpenCode 客户端消息流是如何确保按序输出的?

· 6 min read

OpenCode 客户端保证消息有序,靠的不是排序算法,而是 "按 partID 分桶 + 桶内就地更新" 的状态合并模型。

核心设计 点:

  1. 每个 part 由服务端分配全局唯一 id创建顺序 = 渲染顺序
  2. 后续 part.updated 事件按 id 就地覆盖,不动 partOrder
  3. 断线重连先拉快照、再续 SSE,幂等更新天然无缝衔接

反面教材:早期每次更新都 setMessages([...messages]) 全量复制,消息一长 CPU 直接飙满。Streaming UI 的性能瓶颈从来不在网络,而在前端的更新粒度。