深入解析Spring AI框架如何在Java应用中实现智能化交互的关键

 更新时间:2024年11月14日 11:54:02   作者:努力的小雨  
本文详细介绍了SpringAI框架在Java应用中的应用,包括实体类映射、函数回调等核心功能的实现,通过源码分析,帮助开发者更好地理解和使用这些高级特性,提升业务效率,感兴趣的朋友跟随小编一起看看吧

今天我们的Spring AI源码分析主题即将结束。我已经对自己感兴趣的基本内容进行了全面的审视,并将这些分析分享给大家。如果你对这个主题感兴趣,可以阅读以下几篇文章。每篇文章都层层递进,深入探讨相关内容。考虑到长文可能让大家感到疲惫,我采用了逐步推进的方式,确保每一篇都简明易懂,便于理解。希望能为你们提供有价值的参考!

Spring AI的基本用法:https://www.jb51.net/program/330616f4f.htm

Spring.3版本自动装配机制的演变与实践:https://www.jb51.net/program/325161cdp.htm

Spring AI的阻塞式请求与响应机制的核心逻辑:https://www.jb51.net/program/3306809ji.htm

Spring AI的流式回答源码分析:https://www.jb51.net/program/3306816zk.htm

今天我们的主题将聚焦于最后一步:如何将AI技术有效应用于Java程序中。众所周知,Java是一种面向对象的编程语言,因此不论我们调用什么AI接口,从业务的角度来看,它本质上只是一个接口,而AI则充当了一个第三方对接平台。然而,值得注意的是,AI的聊天回复往往不适用于对象,因为这些回复无法直接返回格式化的JSON数据。这一问题导致Spring无法将其转化为实体类,从而无法真正融入业务流程。

今天,我们将探讨Spring AI框架是如何有效解决这一挑战的。通过深入分析框架的设计和实现,我们希望为大家展示如何将AI能力顺利整合到Java应用中,推动业务的进一步发展。

除此之外,function call 函数回调也是AI技术的一个重要特性。那么,Spring AI是如何应对这一挑战的呢?今天,我们将深入探讨这个问题,解析Spring AI框架如何有效处理函数回调,从而增强AI与Java程序之间的交互能力。

实体化类

实体类在Java程序中扮演着不可或缺的角色,无论是进行内部操作,还是将数据返回给前端的RESTful接口,实体类都是业务中信息传递的核心。在Spring AI框架中,我们可以有效地控制AI的回答,以确保其能够正确映射到实体类。接下来,我们将探讨Spring AI是如何实现这一功能的,基本用法如下:

@GetMapping("/ai-Entity")
ActorFilms generationByEntity() {
    ActorFilms actorFilms = chatClient.prompt()
            .user("Generate the filmography for a random actor.")
            .call()
            .entity(ActorFilms.class);
    return actorFilms;
}

源码分析

在这里,我们不再直接调用 content 方法,而是选择使用 entity 方法作为返回类型。这一变化意味着我们需要重点关注 entity 的实现及其在整个流程中的作用。接下来,让我们通过代码示例来深入分析这一关键部分:

public <T> T entity(Class<T> type) {
      Assert.notNull(type, "the class must be non-null");
      var boc = new BeanOutputConverter<T>(type);
      return doSingleWithBeanOutputConverter(boc);
}

这里使用了一个名为 BeanOutputConverter 的转换器。接下来,我们来详细查看一下 doSingleWithBeanOutputConverter 方法的具体实现。

        private <T> T doSingleWithBeanOutputConverter(StructuredOutputConverter<T> boc) {
            var chatResponse = doGetObservableChatResponse(this.request, boc.getFormat());
            var stringResponse = chatResponse.getResult().getOutput().getContent();
            return boc.convert(stringResponse);
        }

在这里,我们要讨论的 doGetObservableChatResponse 方法主要负责与第三方 API 的交互过程。由于我们在之前的讲解中已经对聊天调用API方法的实现进行了详细分析,因此这次我们就不再深入探讨其具体内容,而是集中于方法的核心功能和应用场景。

实体类提示词限制

在这里,我们来查看一下 boc.getFormat() 方法。这个方法返回一段提示词,而这些提示词会根据不同的类型而有所区别。为了更好地理解,我们可以具体分析一下单个 Bean 实体类所对应的提示词格式。

具体如下:

 public String getFormat() {
        String template = """
                Your response should be in JSON format.
                Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
                Do not include markdown code blocks in your response.
                Remove the ```json markdown from the output.
                Here is the JSON Schema instance your output must adhere to:
                ```%s```
                """;
        return String.format(template, this.jsonSchema);
    }

这其实非常简单。通过使用提示词来明确限制 AI 返回的格式,可以最大程度地确保其输出符合我们的要求。这种方式使得 Spring 能够有效地进行解析,而 jsonSchema 则仅仅是我们传递的实体类的各种信息。

封装实体类

boc.convert 方法负责将数据封装成实体类的过程。具体来说,它会接收原始数据,并通过内部逻辑进行转换,以生成符合我们定义的实体类结构。

从表面上看,我们可以清晰地看出该过程涉及到 JSON 序列化,它将数据封装成我们所期望的对象格式。然而,需要注意的是,虽然 AI 的提示词旨在尽量限制其回复内容,以使其尽可能符合我们的要求,但由于各种因素的影响,我们无法保证其返回的格式会完全按照预设进行。

因此,为了确保程序的稳健性和可靠性,在此过程中引入了异常捕获机制。这一机制能够有效地处理潜在的格式不一致或错误,从而确保应用在面对不符合预期的数据时,能够平稳运行而不至于崩溃。

函数回调

AI目前能够发挥一定作用,主要得益于模型的函数调用功能。如果仅仅依靠训练模型进行聊天回答,其实际价值是相对有限的,因为这种方式的成本非常高,很多企业难以承受。然而,随着函数回调功能的引入,AI可以实时访问和利用各种数据,包括实时数据和业务数据,使其能够根据提供的信息进行更为精准和有效的回答,从而具备了实质性的业务能力。

接下来,我们来看看Spring AI是如何实现这一点的。

基本用法

了解了之前的 Spring AI 用法文章后,你大概已经掌握了如何创建一个 Function 函数。接下来,我们将直接深入探讨如何将这个函数添加到我们的项目中。

@PostMapping("/ai-function")
ChatDataPO functionGenerationByText(@RequestParam("userInput")  String userInput) {
    String content = this.myChatClientWithSystem.prompt()
            .user(userInput)
            .functions("CurrentWeather")
            .call()
            .content();
    log.info("content: {}", content);
    ChatDataPO chatDataPO = ChatDataPO.builder().code("text").data(ChildData.builder().text(content).build()).build();;
    return chatDataPO;
}

在我们的项目中,functions 函数允许添加多种功能,不仅仅局限于单一工具的调用。例如,在可视化智能体的应用中,如千帆 AppBuilder,我们可以观察到思考轮数的运用,这其中涉及了多个工具的调用。这种方式为我们的智能体提供了更丰富的功能和灵活性。

接下来,我们将进行一次函数的调用,以实际展示其效果。

在这里,我们使用了一个固定的 30 度作为示例值,但你可以在函数方法内部通过接口调用其他第三方服务来获取实时数据。因此,通过集成外部数据源,你可以实现更为智能和适应性强的功能。

源码分析

还记得我们之前讨论过的内容吗?在回答的最后,我们会进行一次判断,以确定当前的输出是否为函数调用。这一过程是确保系统能够准确识别和执行函数的重要环节。接下来,我们将展示相关的源码,以便更深入地理解这一机制的具体实现:

if (isToolCall(chatResponse,
        Set.of(ChatCompletionFinishReason.TOOL_CALLS.name(), ChatCompletionFinishReason.STOP.name()))) {
    var toolCallConversation = handleToolCalls(prompt, chatResponse);
    // Recursively call the call method with the tool call message
    // conversation that contains the call responses.
    return this.call(new Prompt(toolCallConversation, prompt.getOptions()));
}

我也在这里设置了一个断点,以便大家可以清楚地看到这一过程。这一断点帮助我们确认,返回的结果完全是由 AI 生成的。在这个基础上,我们会进行进一步的判断,以决定是否需要调用函数工具。

接下来,我们将进入函数调用的过程。这一步骤至关重要,因为函数的返回值将被再次提供给 AI,作为后续回答的参考。我们来看看具体是如何进行函数调用的。虽然我已经找到了相关的源码,但为了让大家更容易理解这个过程,我将提供一张可视化的图片。这张图片将清晰地展示函数调用的流程,以及返回值是如何被整合进 AI 的回答中的。

发送这些参数的原因在于,在发起请求时已经设置了相关限制。以下是我截取下来的请求参数:

tools=[FunctionTool[type=FUNCTION, function=Function[description=获取指定地点的天气情况, name=CurrentWeather, parameters={$schema=https://json-schema.org/draft/2020-12/schema, type=object, properties={location={type=string}, unit={type=string, enum=[C, F]}}}]]]

目前几乎所有第三方AI接口都提供了一个名为 tools 的参数,用于传递我们需要的参数。以OpenAI为例:

调用函数接口

由于我们的函数实现了 @FunctionalInterface 接口,因此 call 这一行实际上会调用我们定义的 apply 接口。鉴于我们的参数是一个实体记录,系统会对其进行 JSON 转化和封装,随后再进行调用。具体过程如下所示:

 public String call(String functionArguments) {
        // Convert the tool calls JSON arguments into a Java function request object.
        I request = fromJson(functionArguments, inputType);
        // extend conversation with function response.
        return this.andThen(this.responseConverter).apply(request);
    }

因此,即使所有操作都已结束,如果在下次 AI 判断中仍然需要调用工具,系统将继续进行循环,直到所有问题都得到完整的回答为止。这种设计确保了整个过程的连贯性和完整性。

总结

在这次探讨中,我们深入挖掘了Spring AI框架如何与Java程序完美结合,提升业务能力。随着AI技术的不断发展,其在Java应用中的整合成为了提升开发效率和用户体验的关键。我们不仅分析了实体类的映射与控制,还探讨了函数回调的强大功能,展示了如何通过Spring AI有效处理这些复杂交互。

希望这些分析能够激发你对AI应用的灵感,并促使你在自己的项目中大胆尝试,将AI技术融入到业务流程中。期待未来能看到大家的创意实现和应用!

完结撒花!关于Spring AI的一系列源码分析到此结束,以后如果还有感兴趣的出发点,我也会继续为大家带来分析!

到此这篇关于深入解析Spring AI框架如何在Java应用中实现智能化交互的关键的文章就介绍到这了,更多相关springAI智能化交互内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决阿里代码规范检测中方法缺少javadoc注释的问题

    解决阿里代码规范检测中方法缺少javadoc注释的问题

    这篇文章主要介绍了解决阿里代码规范检测中方法缺少javadoc注释的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • java中实现excel合并单元格详细代码实例

    java中实现excel合并单元格详细代码实例

    最近的工作中,遇到一个需求在生成的Excel表格后需要在尾部添加一个合并的单元格数据,这篇文章主要给大家介绍了关于java中实现excel合并单元格的相关资料,需要的朋友可以参考下
    2024-06-06
  • 浅谈java 执行jar包中的main方法

    浅谈java 执行jar包中的main方法

    下面小编就为大家带来一篇浅谈java 执行jar包中的main方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • Java实现浏览器端大文件分片上传

    Java实现浏览器端大文件分片上传

    本文主要介绍了Java实现浏览器端大文件分片上传,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • java Class文件内部结构解析过程详解

    java Class文件内部结构解析过程详解

    java class的文件结构,java class文件结构是基于字节流的,用unicode进行编码,下面说说java Class文件内部结构分析
    2013-11-11
  • 关于fastjson的@JSONField注解的一些问题(详解)

    关于fastjson的@JSONField注解的一些问题(详解)

    下面小编就为大家带来一篇关于fastjson的@JSONField注解的一些问题(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 详解IntelliJ IDEA 2020 的Debug功能

    详解IntelliJ IDEA 2020 的Debug功能

    这篇文章主要介绍了IntelliJ IDEA 2020 的Debug功能,本文通过实例截图相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Java cglib为实体类(javabean)动态添加属性方式

    Java cglib为实体类(javabean)动态添加属性方式

    这篇文章主要介绍了Java cglib为实体类(javabean)动态添加属性方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java中Session的详解

    Java中Session的详解

    这篇文章主要介绍了了解java中的session的相关问题,什么是session,session怎么用等,具有一定参考价值,需要的朋友可以了解下。
    2021-10-10
  • java代码实现双向链表

    java代码实现双向链表

    这篇文章主要为大家详细介绍了java代码实现双向链表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05

最新评论