深入解析 Spring AI 系列:解析OpenAI接口对接

今天我们将主要探讨OpenAI是如何进行接口对接的,虽然我们不打算深入细节,但会对整体流程进行一个大概的了解。后续会逐步分析其中的具体细节,大家可以耐心等待,逐步展开。好的,现在让我们开始,下面是我简单绘制的一张图示,旨在帮助大家更好地理解接下来的分析流程。

OpenAiApi

我们第一步将直接查看 OpenAIApi 类,这是与接口最为密切相关的核心类。首先,我们会关注它的构造器部分,因为在构造器中,基本包含了与接口交互所需的最主要依赖和配置信息。通过这段代码,我们可以了解该类如何初始化并准备好与 OpenAI 接口进行通信。接下来,大家可以看到下面这段代码:

java 复制代码
public OpenAiApi(String baseUrl, String apiKey, MultiValueMap<String, String> headers, String completionsPath,
    String embeddingsPath, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder,
    ResponseErrorHandler responseErrorHandler) {

this.completionsPath = completionsPath;
this.embeddingsPath = embeddingsPath; 
Consumer<HttpHeaders> finalHeaders = h -> {
    h.setBearerAuth(apiKey);
    h.setContentType(MediaType.APPLICATION_JSON);
    h.addAll(headers);
};
this.restClient = restClientBuilder.baseUrl(baseUrl)
    .defaultHeaders(finalHeaders)
    .defaultStatusHandler(responseErrorHandler)
    .build();

this.webClient = webClientBuilder
    .baseUrl(baseUrl)
    .defaultHeaders(finalHeaders)
.build(); 
}

这段构造函数代码相对简单,主要负责创建一个包含认证信息和内容类型的HTTP头配置,并通过这些配置初始化RestClient和WebClient,从而为后续的网络请求提供基础支持。

RestClient

RestClient主要用于处理非流式的请求和响应,代码如下:

java 复制代码
public ResponseEntity<ChatCompletion> chatCompletionEntity(ChatCompletionRequest chatRequest,
        MultiValueMap<String, String> additionalHttpHeader) {

    return this.restClient.post()
        .uri(this.completionsPath)
        .headers(headers -> headers.addAll(additionalHttpHeader))
        .body(chatRequest)
        .retrieve()
        .toEntity(ChatCompletion.class);
}

WebClient

WebClient主要就是处理流式的请求和响应,代码看下:

java 复制代码
    public Flux<ChatCompletionChunk> chatCompletionStream(ChatCompletionRequest chatRequest,
            MultiValueMap<String, String> additionalHttpHeader) {

        AtomicBoolean isInsideTool = new AtomicBoolean(false);

        return this.webClient.post()
            .uri(this.completionsPath)
            //此处省略部分代码

这部分代码参数很多,我们就看下核心逻辑即可。

类属性

这样,在理解了主要流程之后,你就能更清晰地理解每个参数在具体实现中的角色,以及它们如何影响整体功能的执行。接下来,我们来一起看一下这段关键代码:

java 复制代码
public static final OpenAiApi.ChatModel DEFAULT_CHAT_MODEL = ChatModel.GPT_4_O;
public static final String DEFAULT_EMBEDDING_MODEL = EmbeddingModel.TEXT_EMBEDDING_ADA_002.getValue();
private static final Predicate<String> SSE_DONE_PREDICATE = "[DONE]"::equals;
private final String completionsPath;
private final String embeddingsPath;
private final RestClient restClient;
private final WebClient webClient;
private OpenAiStreamFunctionCallingHelper chunkMerger = new OpenAiStreamFunctionCallingHelper();

在去掉了向量的相关属性之后,剩下的部分就是chunkMerger,不过这个部分涉及的是处理流式响应的逻辑,暂时我们可以先不关注它。为了简化分析,当前我们主要关注的是最基本的、正常的阻塞式请求处理流程,因为这种模式更加直观易懂,便于我们理解和调试。

ChatCompletionRequest

接下来,我们将继续深入分析之前提到的阻塞请求 chatCompletionEntity。该请求的参数包括一个 ChatCompletionRequest 对象和一个包含额外头信息的 Map 结构。由于我们关注的重点是请求的核心内容,因此我们将主要分析 ChatCompletionRequest 的实现。

这部分内容相信大家一定很熟悉,它实际上就是接口请求的参数部分。具体来说,它是一个记录类,用于封装接口请求所需的各项信息。通过查看原有接口平台上展示的参数列表,我们可以很清楚地看到这个记录类是如何映射到实际接口请求中的各个字段的。如图所示:

ChatCompletion

他的返回参数是ResponseEntity ,他会将返回信息包装成一个ChatCompletion实体,猜一下也是接口返回相关的参数封装。如图所示:

usage

在之前我们说过usage这个类,他其实就是计算token用的。如果不看统计类的信息,也没啥大用。

这里就不拿官方接口做对比了,结果是一样的。

总结

通过今天的分析,我们初步了解了OpenAI接口对接的整体流程。虽然我们没有深入细节,但通过对OpenAiApi类、RestClient、WebClient及相关请求参数的分析,大家应该对接口的工作原理有了一个大致的认识。后续,我们将继续细化具体实现,逐步揭示每个部分的功能与逻辑。希望大家耐心等待,跟随我们一起深入探索更多的技术细节。这一过程将帮助我们更好地理解如何与OpenAI的接口进行高效对接与交互。


我是努力的小雨,一个正经的 Java 东北服务端开发,整天琢磨着 AI 技术这块儿的奥秘。特爱跟人交流技术,喜欢把自己的心得和大家分享。还当上了腾讯云创作之星,阿里云专家博主,华为云云享专家,掘金优秀作者。各种征文、开源比赛的牌子也拿了。

💡 想把我在技术路上走过的弯路和经验全都分享出来,给你们的学习和成长带来点启发,帮一把。

🌟 欢迎关注努力的小雨,咱一块儿进步!🌟

相关推荐
努力的小雨4 天前
深入解析 Spring AI 系列:以OpenAI与Moonshot案例为例寻找共同点
经验分享·ai智能
努力的小雨6 天前
深入解析 Spring AI 系列:剖析OpenAI接口接入组件
经验分享·源码分析·ai智能
努力的小雨1 个月前
教你自创工作流,赋予AI助理个性化推荐超能力
ai智能
努力的小雨1 个月前
借助AI助手快速解析LlamaIndex的Workflow设计与Java迁移
经验分享·ai智能
努力的小雨2 个月前
玩转AI工作流:一步步搭建灵活的自动化流程
ai智能
努力的小雨3 个月前
新概念英语学习助手之全拆解教程
ai智能
努力的小雨3 个月前
AI实战篇:Spring AI + 混元 手把手带你实现企业级稳定可部署的AI业务智能体
经验分享·ai智能