先这样答
设计 Agent 的流式输出,核心是把单一的文本流升级为混合流结构,并在传输协议上根据交互形态在 SSE 和 WebSocket 之间做取舍。
具体的流式设计需要满足两种前端展示需求。第一种是 Token 流,即模型生成文本时的逐字推送,用于实现最终回答的打字机效果。第二种是事件流,Agent 执行任务时会产生工具调用、知识库检索、任务规划等中间步骤,这些过程需要封装成结构化事件推送给前端。服务端需定义清晰的事件数据结构,包含事件类型、数据载荷及序号。前端接收后按类型分发,分别渲染进度指示器或拼接打字机内容。
在传输协议选择上,SSE 是大模型流式输出的事实标准。它基于 HTTP 协议,实现简单,支持断线自动重连,且单向推送特性对文本对话完全够用。相比之下,WebSocket 提供全双工双向传输。只有在特定交互场景下才需要 WebSocket,例如涉及语音流实时上行,或需要高频双向打断与通信。对多数图文 Agent 来说,SSE 是更合理的选择。
在工程落地时,流式输出还需完善中途取消机制。当用户在前端点击停止生成,中断信号需沿着网络请求透传到服务端的模型调用层,及时终止请求并释放计算资源。
面试官会怎么追问
-
「如果用 SSE,前端怎么区分当前推过来的是普通文本还是工具调用的中间状态?」 服务端会在 SSE 的事件流中定义不同的事件类型。将普通文本定义为文本事件,将工具调用定义为工具事件,并在数据字段中放入对应的结构化载荷。前端通过监听不同类型的事件来执行分支逻辑,分别更新对话框或中间步骤面板。
-
「用户点击停止生成,服务端的取消操作具体怎么实现?」 前端调用中止方法断开 HTTP 连接,服务端框架监听到连接断开事件。服务端接收到信号后,利用上下文对象将取消信号传递给底层的模型客户端。这样可以中断正在进行的网络请求,避免模型继续生成无用内容浪费计算资源。
-
「如果中间有个工具调用执行时间特别长,SSE 连接断了怎么办?」 SSE 协议本身内置了重连机制,浏览器会在连接断开后自动尝试重新发起请求。服务端可以在每次推送时附带事件序号,前端重连时通过请求头带上最后接收到的序号。服务端根据该序号从缓存恢复执行上下文,继续推送后续事件。
回答的坑
- 认为 WebSocket 性能更好所以应该无条件选择 WebSocket,忽略了其在连接保活和扩容上的运维成本,正确做法是默认选择 SSE。
- 把 Token 流和事件流混在同一个字符串里靠正则解析,这种做法在模型输出不稳定时容易出错,正确做法是在服务端做好结构化封装再推送。
同系列的题