在当今的软件开发领域,流式输出技术扮演着重要的角色。它能够让数据逐个元素或按块输出,而非一次性输出全部数据,这不仅降低了内存占用,还能使数据在生成时就开始传输,显著提升了效率。一方面,百度文心一言作为强大的大语言模型,其流式输出功能可在 Java 的 Spring Boot 项目中实现,为用户带来更好的交互体验;另一方面,Java 本身也提供了多种实现流式输出的常用方法,适用于不同的应用场景。本文将详细介绍如何在 Spring Boot 项目中实现百度文心一言流式输出,同时深入探讨 Java 中实现流式输出的常用方法。
在开始之前,你需要确保已经安装了以下环境:
在 pom.xml
文件中添加必要的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.squareup.okhttp3groupId>
<artifactId>okhttpartifactId>
<version>4.9.3version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
dependency>
dependencies>
你需要在百度云平台上创建一个文心一言应用,获取 API Key
和 Secret Key
,这两个密钥将用于后续的身份验证。
创建一个配置类,用于存储 API 相关的信息:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "wenxin")
public class WenxinConfig {
private String apiKey;
private String secretKey;
private String apiUrl;
// Getters and Setters
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getApiUrl() {
return apiUrl;
}
public void setApiUrl(String apiUrl) {
this.apiUrl = apiUrl;
}
}
在 application.properties
中配置 API 信息:
wenxin.apiKey=your_api_key
wenxin.secretKey=your_secret_key
wenxin.apiUrl=https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_stream
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class TokenUtil {
@Autowired
private WenxinConfig wenxinConfig;
public String getAccessToken() throws IOException {
String apiKey = wenxinConfig.getApiKey();
String secretKey = wenxinConfig.getSecretKey();
String url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=" + apiKey + "&client_secret=" + secretKey;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.get()
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful() && response.body() != null) {
String responseBody = response.body().string();
// 解析 JSON 数据获取 access_token
int startIndex = responseBody.indexOf("\"access_token\":\"") + 15;
int endIndex = responseBody.indexOf("\"", startIndex);
return responseBody.substring(startIndex, endIndex);
}
}
return null;
}
}
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class WenxinStreamService {
@Autowired
private WenxinConfig wenxinConfig;
@Autowired
private TokenUtil tokenUtil;
public void streamOutput(String prompt, Callback callback) throws IOException {
String accessToken = tokenUtil.getAccessToken();
String apiUrl = wenxinConfig.getApiUrl() + "?access_token=" + accessToken;
OkHttpClient client = new OkHttpClient();
MediaType JSON = MediaType.get("application/json; charset=utf-8");
String json = "{\"messages\": [{\"role\": \"user\", \"content\": \"" + prompt + "\"}]}";
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(apiUrl)
.post(body)
.build();
client.newCall(request).enqueue(callback);
}
}
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class WenxinController {
@Autowired
private WenxinStreamService wenxinStreamService;
@GetMapping("/stream")
public void stream(@RequestParam String prompt) throws IOException {
wenxinStreamService.streamOutput(prompt, 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() && response.body() != null) {
try (ResponseBody responseBody = response.body()) {
BufferedSource source = responseBody.source();
String line;
while ((line = source.readUtf8Line()) != null) {
if (!line.isEmpty()) {
// 处理每一行输出
System.out.println(line);
}
}
}
}
}
});
}
}
启动 Spring Boot 项目,访问 http://localhost:8080/stream?prompt=你好
,你将在控制台看到文心一言的流式输出结果。
java.io
包中的流java.io
包提供了基础的输入输出流,你可以用它实现流式输出。
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class StreamOutputExample {
public static void main(String[] args) {
try (PrintWriter writer = new PrintWriter(new FileWriter("output.txt"))) {
for (int i = 0; i < 10; i++) {
// 逐行输出数据
writer.println("Line " + i);
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
解释:
PrintWriter
和 FileWriter
把数据写入文件。println
方法逐行输出数据,每输出一行就调用 flush
方法将缓冲区的数据刷新到文件中。java.nio
包中的通道和缓冲区java.nio
包提供了更高效的 I/O 操作,你可以用通道和缓冲区实现流式输出。
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioStreamOutputExample {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("output_nio.txt");
FileChannel channel = fos.getChannel()) {
for (int i = 0; i < 10; i++) {
String line = "Line " + i + "\n";
ByteBuffer buffer = ByteBuffer.wrap(line.getBytes());
while (buffer.hasRemaining()) {
channel.write(buffer);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
解释:
FileOutputStream
获取 FileChannel
。ByteBuffer
,再通过 FileChannel
将缓冲区的数据写入文件。Java 8 引入了 Stream API,能够对集合进行流式处理,同时也可用于输出。
import java.util.Arrays;
import java.util.List;
public class StreamApiOutputExample {
public static void main(String[] args) {
List<String> lines = Arrays.asList("Line 1", "Line 2", "Line 3");
lines.stream()
.forEach(System.out::println);
}
}
解释:
forEach
方法逐个输出元素。在 Web 应用里,你可以用 Servlet 实现流式输出,将数据逐步发送给客户端。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/stream")
public class StreamServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
for (int i = 0; i < 10; i++) {
out.println("Line " + i);
out.flush();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
out.close();
}
}
解释:
HttpServletResponse
获取 PrintWriter
。flush
方法将数据发送给客户端。通过以上内容,我们详细介绍了如何在 Java 的 Spring Boot 项目中实现百度文心一言的流式输出,以及 Java 中实现流式输出的常用方法。流式输出技术在不同场景下都能发挥重要作用,无论是与大语言模型交互还是进行文件操作、Web 数据传输等。希望本文能帮助你更好地理解和运用流式输出技术,让你的 Java 程序更加高效和灵活。如果你在实践过程中遇到任何问题,欢迎留言讨论。