Spring Boot项目 实现百度文心一言流式输出及 Java 流式输出常用方法

Spring Boot项目 实现百度文心一言流式输出及 Java 流式输出常用方法

引言

在当今的软件开发领域,流式输出技术扮演着重要的角色。它能够让数据逐个元素或按块输出,而非一次性输出全部数据,这不仅降低了内存占用,还能使数据在生成时就开始传输,显著提升了效率。一方面,百度文心一言作为强大的大语言模型,其流式输出功能可在 Java 的 Spring Boot 项目中实现,为用户带来更好的交互体验;另一方面,Java 本身也提供了多种实现流式输出的常用方法,适用于不同的应用场景。本文将详细介绍如何在 Spring Boot 项目中实现百度文心一言流式输出,同时深入探讨 Java 中实现流式输出的常用方法。

利用 Java 和 Spring Boot 实现百度文心一言流式输出

环境准备

在开始之前,你需要确保已经安装了以下环境:

  1. Java 开发环境:建议使用 Java 8 及以上版本。
  2. Maven:用于管理项目依赖。
  3. Spring Boot:创建 Spring Boot 项目,你可以使用 Spring Initializr(https://start.spring.io/)来快速搭建项目结构。

引入依赖

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 密钥

你需要在百度云平台上创建一个文心一言应用,获取 API KeySecret Key,这两个密钥将用于后续的身份验证。

实现流式输出逻辑

1. 创建配置类

创建一个配置类,用于存储 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
2. 创建获取访问令牌的工具类
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;
    }
}
3. 创建流式输出服务类
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);
    }
}
4. 创建控制器类
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 中实现流式输出的常用方法

1. 使用 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();
        }
    }
}

解释

  • 借助 PrintWriterFileWriter 把数据写入文件。
  • 利用 println 方法逐行输出数据,每输出一行就调用 flush 方法将缓冲区的数据刷新到文件中。

2. 使用 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 将缓冲区的数据写入文件。

3. 使用 Java 8 的 Stream API

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 方法逐个输出元素。

4. 使用 Servlet 实现流式输出到客户端

在 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();
    }
}

解释

  • 在 Servlet 里,通过 HttpServletResponse 获取 PrintWriter
  • 逐行输出数据,每次输出后调用 flush 方法将数据发送给客户端。

总结

通过以上内容,我们详细介绍了如何在 Java 的 Spring Boot 项目中实现百度文心一言的流式输出,以及 Java 中实现流式输出的常用方法。流式输出技术在不同场景下都能发挥重要作用,无论是与大语言模型交互还是进行文件操作、Web 数据传输等。希望本文能帮助你更好地理解和运用流式输出技术,让你的 Java 程序更加高效和灵活。如果你在实践过程中遇到任何问题,欢迎留言讨论。

你可能感兴趣的:(java,spring,boot,百度)