浅谈人工智能之大模型的流式调用:Java 后端实践

浅谈人工智能之大模型的流式调用:Java 后端实践

引言

在现代AI应用中,大模型(如阿里云的Qwen、百度的ERNIE等)因其强大的语义理解和生成能力而备受关注。然而,这些模型往往伴随着庞大的计算资源消耗,尤其是对于长时间的对话或大规模文本生成任务。为了解决这一问题,流式调用技术应运而生,它允许开发者以流的方式与模型交互,从而实现实时响应和高效资源管理。本文将详细介绍如何在Java后端中实现大模型的流式调用。

流式调用的概念

流式调用是一种数据传输模式,其中数据不是一次性传输,而是分块或按需传输。在大模型的上下文中,这意味着模型的输出可以被逐步接收和处理,而不是等待整个响应完成后再进行处理。这种模式特别适用于实时应用,如聊天机器人、语音转文字、自动翻译等,同时也减少了对服务器内存的占用。

Java后端的流式调用实现

在Java中,流式调用主要依赖于InputStream和OutputStream类,它们允许数据以流的形式读取和写入。结合Hutool这样的工具库,我们可以更加优雅地处理HTTP请求和响应流。

引入依赖

首先,确保你的项目中引入了Hutool库。在Maven项目中,你可以在pom.xml文件中添加以下依赖:

xml 复制代码
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.6.3</version>
</dependency>

其次,我们需要处理json格式,所以我们再引入如下依赖包

xml 复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>

发起流式请求

使用Hutool的HttpRequest类发起POST请求,同时指定接收响应的流式处理方式并且进行输出:

java 复制代码
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后端中采用流式处理技术,我们可以实现实时响应和资源的有效管理,这对于提升用户体验和系统性能具有重要意义。希望本文能帮助你更好地理解和实现大模型的流式调用。

相关推荐
GIS数据转换器3 分钟前
城市生命线安全保障:技术应用与策略创新
大数据·人工智能·安全·3d·智慧城市
百流18 分钟前
scala文件编译相关理解
开发语言·学习·scala
蘑菇丁20 分钟前
ansible批量生产kerberos票据,并批量分发到所有其他主机脚本
java·ide·eclipse
呼啦啦啦啦啦啦啦啦1 小时前
【Redis】持久化机制
java·redis·mybatis
一水鉴天1 小时前
为AI聊天工具添加一个知识系统 之65 详细设计 之6 变形机器人及伺服跟随
人工智能
Evand J1 小时前
matlab绘图——彩色螺旋图
开发语言·matlab·信息可视化
我想学LINUX2 小时前
【2024年华为OD机试】 (A卷,100分)- 微服务的集成测试(JavaScript&Java & Python&C/C++)
java·c语言·javascript·python·华为od·微服务·集成测试
深度混淆2 小时前
C#,入门教程(04)——Visual Studio 2022 数据编程实例:随机数与组合
开发语言·c#
雁于飞2 小时前
c语言贪吃蛇(极简版,基本能玩)
c语言·开发语言·笔记·学习·其他·课程设计·大作业