如何用Java/Kotlin结合OkHttp实现OpenAI chat/completions流式响应?
使用OkHttp实现OpenAI Chat Completions流式响应
OpenAI的chat/completions API支持通过stream=true参数返回流式响应,以下是基于OkHttp客户端的Java和Kotlin实现示例:
Java 实现
1. 添加OkHttp依赖
如果使用Maven,在pom.xml中加入:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.11.0</version> <!-- 使用最新稳定版本 --> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> <!-- 用于JSON解析 --> </dependency>
2. 完整代码示例
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; import java.io.IOException; public class OpenAIStreamExample { private static final String API_KEY = "YOUR_OPENAI_API_KEY"; private static final String API_URL = "https://api.openai.com/v1/chat/completions"; private static final ObjectMapper objectMapper = new ObjectMapper(); public static void main(String[] args) { OkHttpClient client = new OkHttpClient(); // 构建请求体 String requestBody = """ { "model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": "请介绍一下Java语言"}], "stream": true } """; Request request = new Request.Builder() .url(API_URL) .header("Authorization", "Bearer " + API_KEY) .header("Content-Type", "application/json") .post(RequestBody.create(requestBody, MediaType.parse("application/json"))) .build(); // 异步发送请求并处理流式响应 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { if (!response.isSuccessful()) { System.err.println("请求失败: " + response.code() + " " + response.message()); return; } // 逐行读取响应流 try (ResponseBody responseBody = response.body()) { if (responseBody == null) { return; } responseBody.source().readAllLines().forEach(line -> { // 过滤空行和结束标记 if (line.isEmpty() || line.equals("data: [DONE]")) { return; } // 提取data部分的JSON内容 String jsonStr = line.substring(6); // 去掉前缀"data: " try { JsonNode jsonNode = objectMapper.readTree(jsonStr); JsonNode choices = jsonNode.get("choices"); if (choices != null && choices.size() > 0) { JsonNode delta = choices.get(0).get("delta"); if (delta != null && delta.has("content")) { // 输出流式返回的内容(不换行,模拟ChatGPT的打字效果) System.out.print(delta.get("content").asText()); } } } catch (Exception e) { e.printStackTrace(); } }); // 最后换行 System.out.println(); } finally { response.close(); } } }); // 防止主线程提前退出(仅示例用,实际项目按需处理) try { Thread.sleep(60000); } catch (InterruptedException e) { e.printStackTrace(); } } }
Kotlin 实现
1. 添加OkHttp依赖
Gradle项目在build.gradle.kts中加入:
dependencies { implementation("com.squareup.okhttp3:okhttp:4.11.0") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2") }
2. 完整代码示例(协程版)
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext data class StreamResponse( val choices: List<Choice> ) data class Choice( val delta: Delta ) data class Delta( val content: String? = null ) fun main() { val apiKey = "YOUR_OPENAI_API_KEY" val apiUrl = "https://api.openai.com/v1/chat/completions" val objectMapper = jacksonObjectMapper() val client = OkHttpClient() val requestBody = """ { "model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": "请介绍一下Kotlin语言"}], "stream": true } """.trimIndent() val request = Request.Builder() .url(apiUrl) .header("Authorization", "Bearer $apiKey") .header("Content-Type", "application/json") .post(requestBody.toRequestBody("application/json".toMediaType())) .build() // 使用协程异步处理 GlobalScope.launch(Dispatchers.IO) { try { client.newCall(request).execute().use { response -> if (!response.isSuccessful) { println("请求失败: ${response.code} ${response.message}") return@launch } response.body?.source()?.use { source -> while (!source.exhausted()) { val line = source.readUtf8Line() ?: continue if (line.isEmpty() || line == "data: [DONE]") continue val jsonStr = line.substring(6) val streamResponse = objectMapper.readValue<StreamResponse>(jsonStr) streamResponse.choices.firstOrNull()?.delta?.content?.let { content -> // 流式输出内容 print(content) } } println() } } } catch (e: Exception) { e.printStackTrace() } } // 防止主线程退出 Thread.sleep(60000) }
关键注意事项
- 替换代码中的
YOUR_OPENAI_API_KEY为你的OpenAI API密钥 - 请求必须设置
stream=true参数,API才会返回流式响应 - 响应流中的每行以
data:开头,最后一行是data: [DONE]表示响应结束 - 处理响应时需要逐行读取,过滤空行和结束标记,再解析JSON提取
content字段
内容的提问来源于stack exchange,提问作者Ziad Halabi
相关产品推荐
相关产品推荐

