前言

最近在开发一个建筑行业的AI智能体应用,使用到了流式输出,总结一下。
随着AI大模型的普及,越来越多的应用需要将模型的生成内容“边生成边输出”,即流式输出。这样可以显著提升用户体验,尤其是在聊天、文案生成等场景。本文将介绍如何在Java项目中实现大模型流式输出,包括原理、主流API对接方式、代码实战和常见问题。


在这里插入图片描述
图片上的感兴趣的底部联系我

一、流式输出原理

流式输出(Streaming Output)指的是大模型生成内容时,服务端将已生成的部分内容立即推送给客户端,客户端实时显示,无需等待全部生成完毕。常用的技术实现方式有:

  • HTTP SSE(Server-Sent Events)
  • WebSocket
  • HTTP 长连接分段响应

大多数主流大模型API(如OpenAI、阿里Qwen、百度文心一言等)都支持流式接口,一般通过HTTP SSE或WebSocket实现。


二、主流大模型流式API示例

以OpenAI GPT-4接口为例,流式输出参数为stream=true,响应为SSE格式。

POST https://api.openai.com/v1/chat/completions
Headers:
  Authorization: Bearer YOUR_API_KEY
Body:
  {
    "model": "gpt-4",
    "messages": [...],
    "stream": true
  }

响应内容类似:

data: {"choices":[{"delta":{"content":"你好"},"index":0,"finish_reason":null}]}
data: {"choices":[{"delta":{"content":","},"index":0,"finish_reason":null}]}
data: {"choices":[{"delta":{"content":"世界!"},"index":0,"finish_reason":"stop"}]}

三、Java流式输出实现方案

1. 使用HttpClient处理SSE流

Java 11+自带的HttpClient不直接支持SSE,需要手动读取流。推荐用okhttpspring-webfluxSseEmitter等。

方案一:OkHttp处理流式响应
import okhttp3.*;

public class OpenAIStreamDemo {
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("https://api.openai.com/v1/chat/completions")
                .addHeader("Authorization", "Bearer YOUR_API_KEY")
                .post(RequestBody.create(
                    MediaType.parse("application/json"),
                    "{ \"model\": \"gpt-4\", \"messages\": [...], \"stream\": true }"
                ))
                .build();

        Call call = client.newCall(request);
        Response response = call.execute();
        BufferedReader reader = new BufferedReader(new InputStreamReader(response.body().byteStream()));

        String line;
        while ((line = reader.readLine()) != null) {
            if (line.startsWith("data: ")) {
                String json = line.substring(6);
                System.out.println("收到片段: " + json);
                // 可解析json,拼接输出
            }
        }
        reader.close();
    }
}
方案二:Spring Boot + SseEmitter

适合在后端接口转发流式内容给前端。

@GetMapping("/stream-chat")
public SseEmitter streamChat(@RequestParam String prompt) {
    SseEmitter emitter = new SseEmitter();
    new Thread(() -> {
        // 调用大模型API,逐步读取流内容
        try (BufferedReader reader = ...) {
            String line;
            while ((line = reader.readLine()) != null) {
                emitter.send(line);
            }
            emitter.complete();
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
    }).start();
    return emitter;
}

前端用 EventSource 或 fetch/ReadableStream 实时显示。


四、前端流式显示(配合Java后端)

前端可用如下方式接收SSE流:

const source = new EventSource('/stream-chat?prompt=你好');
source.onmessage = function(event) {
    console.log('收到片段:', event.data);
    // 追加显示到页面
};

五、常见问题与优化建议

  1. 流断开/重连处理:后端需捕获异常,前端可自动重连。
  2. 内容拼接:后端/前端需按API协议拼接完整内容。
  3. 超时与心跳:流式连接较长,注意设置合理超时和心跳包。
  4. 并发与资源释放:合理管理线程、连接,防止资源泄漏。

六、其他主流模型流式接入参考

  • Qwen/Qianwen(阿里/字节):接口参数和OpenAI类似,流式响应格式一致。
  • 文心一言(百度):支持流式,Java代码实现同上。
  • 自部署模型(如llama.cpp服务):支持WebSocket或HTTP分段,Java可用javax.websocketokhttp实现。

Logo

更多推荐