需启用流式输出机制,其核心依赖server-sent events(sse)协议,通过持久化http连接实时推送文本块;前端可用eventsource或fetch+readablestream监听,后端spring boot用sseemitter、php用curl+writefunction、ollama需穿透双重缓冲实现逐字响应。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

如果您在集成通义千问时希望用户能实时看到模型逐字生成的响应,而非等待全部内容完成后再一次性呈现,则需启用流式输出机制。该机制依赖于服务端持续推送数据的能力,核心实现路径围绕 Server-Sent Events(SSE)协议展开。以下是具体实施步骤:
一、理解流式输出的技术基础
流式输出的本质是将模型推理过程中产生的文本块(chunk)即时封装为事件流,通过持久化 HTTP 连接推送给前端。与传统 REST API 的“请求-等待-响应”模式不同,SSE 允许服务器在单次连接中多次发送数据,且浏览器原生支持解析 event: message 格式的数据帧。这种单向、低开销、无需轮询的通信方式,特别适配大语言模型边生成边返回的自然过程。
1、确认所用通义千问 SDK 或 API 接口支持 stream 参数,并设置为 true;
2、确保后端服务返回的 Content-Type 为 text/event-stream;
3、验证客户端使用 EventSource 或 fetch + ReadableStream 方式监听数据流,而非普通 XMLHttpRequest;
二、基于 Fetch API 的前端流式接收实现
现代浏览器可通过原生 fetch 配合 response.body.getReader() 获取可读流,再利用 TextDecoder 逐块解码服务端推送的 UTF-8 数据。该方式绕过 EventSource 的自动重连机制,便于精细控制中断、错误处理与渲染节奏。
1、发起带 stream: true 参数的 POST 请求,Header 中包含 Authorization 和 Content-Type: application/json;
2、调用 response.body.getReader() 获取流读取器;
3、使用 while 循环配合 reader.read() 持续读取 chunk,每次读取后用 TextDecoder.decode(chunk.value, {stream: true}) 解析;
4、对每段解码后的文本进行清理(如去除 data: 前缀、过滤空行),并追加至 DOM 元素中;
5、当 done 为 true 时终止循环,关闭流连接;
三、Spring Boot 后端使用 SseEmitter 实现推送
Spring Boot 提供了 SseEmitter 类作为 SSE 协议的封装抽象,它内部维护一个异步连接,允许控制器在任意时刻调用 emitter.send() 推送事件。该方式适用于基于 Servlet 容器的传统 Web 应用,无需引入 WebFlux。
1、定义 @GetMapping 接口,produces 设置为 MediaType.TEXT_EVENT_STREAM_VALUE;
2、方法返回类型声明为 SseEmitter,并设置超时时间(如 30000 毫秒);
3、在新线程中调用通义千问 Java SDK 的流式接口(如 Generation.stream()),获取 Flowable
4、订阅 Flowable,对每个 GenerationResult 调用 emitter.send(SseEmitter.event().data(result.getOutput().getText()));
5、捕获异常后调用 emitter.completeWithError(e),正常结束时调用 emitter.complete();
四、PHP 环境下通过 cURL 实现流式响应透传
在无原生 SSE 支持的 PHP 环境中,可借助 cURL 的 WRITEFUNCTION 回调函数捕获服务端分块返回的数据,并立即输出至标准输出流。配合 ob_flush() 和 flush() 可强制刷新缓冲区,使前端浏览器按 chunk 解析。
1、初始化 cURL 句柄,设置 CURLOPT_URL 为通义千问兼容模式接口地址;
2、启用 CURLOPT_POST 并传入 JSON 请求体,其中 'stream' => true 必须显式设置;
3、配置 CURLOPT_HTTPHEADER 包含 Authorization Bearer Token 和 application/json;
4、设置 CURLOPT_WRITEFUNCTION 回调,在回调中对原始 $data 执行 processStreamedData() 解析逻辑;
5、每次解析出有效文本片段后,执行 echo 输出并紧跟 ob_flush() 和 flush();
五、Ollama + Ollama-WebUI 环境下的双重缓冲优化
当通过 Ollama-WebUI 调用本地部署的 Qwen3-14B 或 Qwen2.5 模型时,Ollama 服务端与 WebUI 前端各自存在独立缓冲区,导致 token 级延迟叠加。必须穿透两层缓冲,才能还原 SSE 的实时性。
1、修改 Ollama 启动参数,添加 --no-cache 和 --stream 强制启用底层流式通道;
2、在 Ollama-WebUI 的代理配置中禁用 response buffering,设置 Nginx 的 proxy_buffering off 与 proxy_cache off;
3、检查 Ollama-WebUI 前端是否对 EventSource 进行了额外包装,若存在中间解析层则需绕过或重写;
4、直接调用 Ollama 的 /api/chat 接口并手动构造 Accept: text/event-stream 请求头;
5、在前端使用自定义 fetch 流式读取,避免依赖 WebUI 内置的非流式封装函数;











