AI大模型流式输出,OkHttp Log拦截打印方案

发布于:2025-06-29 ⋅ 阅读:(17) ⋅ 点赞:(0)

 背景:

使用okhttp框架进行网络访问时,一般会使用 HttpLoggingInterceptor 打印请求和响应的log。在使用okhttp访问AI大模型时,如果选择流式输出,那么响应的body数据使用的SSE技术,服务异步发送大模型生成的增量token,使用HttpLoggingInterceptor拦截后,会在所有数据接收完成后一次打印完,业务逻辑处也是在log打印完后,才集中收到全部的内容,达不到流式返回的效果。

优化方案:

优化的思路是将body 流拦截打印,然后重新构建response,responsebody和inputstream。将真实的body数据重新写入到重新构建的responsebody流里面,这样业务端就会实时收到流式返回的内容。下面是拦截打印body部分的代码:

@Override
public Response intercept(@NotNull Chain chain) throws IOException {
    Response response = chain.proceed(chain.request());
    PipedOutputStream pipedOutputStream = new PipedOutputStream();
    PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
    BufferedSource cloneSource = Okio.buffer(Okio.source(pipedInputStream));
    ResponseBody cloneBody = ResponseBody.create(cloneSource, response.body().contentType() , response.body().contentLength());
    Response cloneResponse = response.newBuilder().body(cloneBody).build();
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(pipedOutputStream));

    InputStream inputStream = response.body().byteStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

    new Thread(() -> {
        String line;
        while (true) {
            try {
                if ((line = reader.readLine()) == null) break;
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
            System.out.println(">>>>>>>>>>>>> log intercept:" + line);
            try {
                writer.write(line);
                writer.write("\r\n");
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("log intercept end");
    }).start();
    return cloneResponse;
}