浅谈人工智能之大模型的流式调用:Java 后端实践
引言
在现代AI应用中,大模型(如阿里云的Qwen、百度的ERNIE等)因其强大的语义理解和生成能力而备受关注。然而,这些模型往往伴随着庞大的计算资源消耗,尤其是对于长时间的对话或大规模文本生成任务。为了解决这一问题,流式调用技术应运而生,它允许开发者以流的方式与模型交互,从而实现实时响应和高效资源管理。本文将详细介绍如何在Java后端中实现大模型的流式调用。
流式调用的概念
流式调用是一种数据传输模式,其中数据不是一次性传输,而是分块或按需传输。在大模型的上下文中,这意味着模型的输出可以被逐步接收和处理,而不是等待整个响应完成后再进行处理。这种模式特别适用于实时应用,如聊天机器人、语音转文字、自动翻译等,同时也减少了对服务器内存的占用。
Java后端的流式调用实现
在Java中,流式调用主要依赖于InputStream和OutputStream类,它们允许数据以流的形式读取和写入。结合Hutool这样的工具库,我们可以更加优雅地处理HTTP请求和响应流。
引入依赖
首先,确保你的项目中引入了Hutool库。在Maven项目中,你可以在pom.xml文件中添加以下依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.3</version>
</dependency>
其次,我们需要处理json格式,所以我们再引入如下依赖包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
发起流式请求
使用Hutool的HttpRequest类发起POST请求,同时指定接收响应的流式处理方式并且进行输出:
import cn.hutool.core.io.IoUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class QwenSteam {
private final Logger log = LoggerFactory.getLogger(this.getClass());
public void OpenAI (String prompt){
String baseUrl = "http://XX.XX.XX.XX:8889/v1/chat/completions";
String model = "QWen";
String requestBody = "{\n" +
" \"model\": \"" + model + "\",\n" +
" \"messages\": [\n" +
" {\"role\": \"system\", \"content\": \"你是一个老中医,对咳嗽治疗尤其厉害。\"},\n" +
" {\"role\": \"user\", \"content\": \"" + prompt + "\"}\n" +
" ],\n" +
" \"stream\": \"" + true + "\",\n" +
" \"temperature\": 0.7,\n" +
" \"top_p\": 0.8,\n" +
" \"repetition_penalty\": 1.05,\n" +
" \"max_tokens\": 512\n" +
"}";
System.out.println(requestBody);
InputStream execute = HttpRequest.post(baseUrl)
.header("Content-Type", "application/json")
.body(requestBody).execute().bodyStream();
try(BufferedReader reader = new BufferedReader(new InputStreamReader(execute))){
String line;
String finalContent="";
while ((line = reader.readLine()) != null) {
if (!line.trim().isEmpty() && !"data: [DONE]".equals(line)) {
line = line.replace("data: ", "");
try {
JSONObject reqJson = JSONObject.parseObject(line);
JSONArray choicesArray = reqJson.getJSONArray("choices");
JSONObject firstChoice = choicesArray.getJSONObject(0);
JSONObject delta = firstChoice.getJSONObject("delta");
if (delta.size()!=0){
if(delta.containsKey("content")){
String content = delta.getString("content");
if(!content.equals(null)){
finalContent = finalContent + content;
// processPartialResponse(content);
System.out.println(finalContent);
}
}
}
} catch (Exception e) {
System.err.println("Failed to parse JSON: " + line);
e.printStackTrace();
}
}
}
}catch (Exception e){
e.printStackTrace();
}
// 关闭输入流
IoUtil.close(execute);
}
public static void main(String[] args) {
QwenSteam qwen = new QwenSteam();
qwen.OpenAI("我有点咳嗽");
}
}
注意事项
● 编码问题:确保在整个数据处理流程中使用一致的字符编码,通常推荐使用UTF-8。
● 流的关闭:在读取完流之后,记得关闭InputStream,以释放系统资源。
● 错误处理:在网络通信中,错误处理至关重要。确保你的代码能够妥善处理各种异常情况,如网络中断、服务器错误等。
● 性能优化:流式调用虽然可以减少内存占用,但对于高并发场景,你可能需要考虑线程池和异步处理机制,以进一步提升性能。
结论
流式调用是现代AI应用中处理大模型输出的一种高效方式。通过在Java后端中采用流式处理技术,我们可以实现实时响应和资源的有效管理,这对于提升用户体验和系统性能具有重要意义。希望本文能帮助你更好地理解和实现大模型的流式调用。