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

相关推荐
_.Switch14 分钟前
Python 自动化运维持续优化与性能调优
运维·开发语言·python·缓存·自动化·运维开发
徐*红15 分钟前
java 线程池
java·开发语言
尚学教辅学习资料15 分钟前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
2401_8576363915 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
1 9 J17 分钟前
Java 上机实践4(类与对象)
java·开发语言·算法
Code apprenticeship18 分钟前
Java面试题(2)
java·开发语言
J不A秃V头A20 分钟前
Python爬虫:获取国家货币编码、货币名称
开发语言·爬虫·python
憨子周1 小时前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨3 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404193 小时前
javaSE面试题
java·开发语言·面试