Http流式响应接口封装

1. 背景

需要对接某个大模型的流式http对话接口,因为该项目中还需要对接另外的大模型服务但是另一个请求方式为websocket,为了实现模型服务切换以及对客户端做统一的流式响应,需要对大模型服务的调用做统一的流式响应封装。

环境:JDK11

2. 代码

2.1 回调函数

java 复制代码
@FunctionalInterface
public interface LLMChatCallback {

    void callback(String message);

}

2.2 统一对话接口

java 复制代码
public interface LLMService {

    /**
     * 模型对话
     *
     * @param payload 用于请求大模型的参数
     * @param callback 响应回调 调用者通过实现callback函数接收消息
     **/
    void dialogue(String payload, LLMChatCallback callback);

}

2.3 StringSubscriber

java 复制代码
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Flow;

/**
 * http响应式流订阅
 **/
@Slf4j
public class StringSubscriber implements Flow.Subscriber<String> {

    Flow.Subscription subscription;

    /**
     * 消息回调接口
     */
    private final LLMChatCallback callback;

    public StringSubscriber(LLMChatCallback callback) {
        this.callback = callback;
    }

    @Override
    public void onSubscribe(Flow.Subscription subscription) {
        this.subscription = subscription;
        subscription.request(1);
    }

    @Override
    public void onNext(String item) {
        log.debug("onNext: {}", item);
        if (callback != null) {
            // 可做业务处理
            callback.callback(item);
        }
        subscription.request(1);
    }

    @Override
    public void onError(Throwable throwable) {
        log.error("StringSubscriber error", throwable);
    }

    @Override
    public void onComplete() {
        log.debug("StringSubscriber complete");
    }

}

2.4 大模型Service实现

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

/**
 * B大模型服务
 **/
@Slf4j
@Service
public class BLMService implements LLMService {

    @Override
    public void dialogue(String payload, LLMChatCallback callback) {
        HttpRequest httpRequest = HttpRequest.newBuilder(URI.create("this is url")).POST(HttpRequest.BodyPublishers.ofString("this is payload")).build();
        HttpClient httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofMinutes(5)).version(HttpClient.Version.HTTP_2).build();
        HttpResponse.BodySubscriber<Void> bodySubscriber = HttpResponse.BodySubscribers.fromLineSubscriber(new StringSubscriber(callback));
        httpClient.sendAsync(httpRequest, responseInfo -> bodySubscriber).join();
    }

}

2.5 使用

java 复制代码
@Resource
private BLMService bLMService;

public void void dialogue() {
    // 构建请求负载
    String payload = "this is payload";
    // 可以扩展使用工厂及策略模式获取对应的模型对话service
    bLMService.dialogue(payload, message -> {
        // 处理业务接收返回的信息 比如通过grpc的流式响应 onNext(message) 同步返回
        System.out.println(message);
    });
}
相关推荐
yaoxin5211233 小时前
384. Java IO API - Java 文件复制工具:Copy 示例完整解析
java·开发语言·python
编程牛马姐3 小时前
独立站SEO流量增长:提高Google排名的优化方法
前端·javascript·网络
NotFound4863 小时前
实战指南如何实现Java Web 拦截机制:Filter 与 Interceptor 深度分享
java·开发语言·前端
2401_873479403 小时前
如何从零搭建私有化IP查询平台?数据采集、清洗、建库到API发布全流程
服务器·网络·tcp/ip
学代码的真由酱3 小时前
HTTPS
网络协议·http·https
一 乐4 小时前
医院挂号|基于springboot + vue医院挂号管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·医院挂号管理系统
鱼鳞_5 小时前
Java学习笔记_Day29(异常)
java·笔记·学习
FS_Marking5 小时前
CWDM vs DWDM:区别是什么?
网络
烟锁池塘柳05 小时前
一文讲透 C++ / Java 中方法重载(Overload)与方法重写(Override)在调用时机等方面的区别
java·c++·面向对象
一叶飘零_sweeeet5 小时前
深入拆解 Fork/Join 框架:核心原理、分治模型与参数调优实战
java·并发编程