首页 > 编程语言 >深入解析Spring AI框架:在Java应用中实现智能化交互的关键

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

时间:2024-10-12 09:14:39浏览次数:6  
标签:实体类 Java AI Spring call 我们

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

Spring AI的基本用法:https://www.cnblogs.com/guoxiaoyu/p/18284842

Spring.3版本自动装配机制的演变与实践:https://www.cnblogs.com/guoxiaoyu/p/18384642

SpringBoot.3中的aot.factories到底有什么用:https://www.cnblogs.com/guoxiaoyu/p/18434660

Spring AI的阻塞式请求与响应机制的核心逻辑:https://www.cnblogs.com/guoxiaoyu/p/18440488

Spring AI的流式回答源码分析:https://www.cnblogs.com/guoxiaoyu/p/18440684

今天我们的主题将聚焦于最后一步:如何将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 实体类所对应的提示词格式。

image

具体如下:

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

image

从表面上看,我们可以清晰地看出该过程涉及到 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,我们可以观察到思考轮数的运用,这其中涉及了多个工具的调用。这种方式为我们的智能体提供了更丰富的功能和灵活性。

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

image

在这里,我们使用了一个固定的 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 生成的。在这个基础上,我们会进行进一步的判断,以决定是否需要调用函数工具。

image

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

image

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

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为例:

image

调用函数接口

由于我们的函数实现了 @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的一系列源码分析到此结束,以后如果还有感兴趣的出发点,我也会继续为大家带来分析!

image


我是努力的小雨,一名 Java 服务端码农,潜心研究着 AI 技术的奥秘。我热爱技术交流与分享,对开源社区充满热情。同时也是一位腾讯云创作之星、阿里云专家博主、华为云云享专家、掘金优秀作者。

标签:实体类,Java,AI,Spring,call,我们
From: https://www.cnblogs.com/guoxiaoyu/p/18441709

相关文章

  • 在Java程序中监听mysql的binlog
    目录1、背景2、mysql-binlog-connector-java简介3、准备工作1、验证数据库是否开启binlog2、开启数据库的binlog3、创建具有REPLICATIONSLAVE权限的用户4、事件类型eventType解释1、TABLE_MAP的注意事项2、获取操作的列名5、监听binlog的position1、从最新的binlog位置开始监......
  • Java中class对象的学习
    Class对象目录Class对象获取class对象的三种方法获取类的各种信息获取类名获取类修饰符获取包的信息获取父类的class对象获取接口信息构造函数Constructor两种创建对象的方式使用Class.forName()加载类并创建对象使用Class.forName()加载类,并调用特定的构造器获取class对象的三......
  • 题解 QOJ5048【[ECFinal19K] All Pair Maximum Flow】
    题目描述给你一个\(n\)个点\(m\)条边的图,它是平面上的正\(n\)边形和一些对角线,节点按逆时针方向编号为\(1\)到\(n\)。对角线只可能在节点处相交。每条边有一个容量,求每个点对之间的最大流的和。\(n\leq200000,m\leq400000\)。solution做法每次找出边权最小的边\(......
  • 微软发布Windows 11 2024更新,新型Copilot+ AI PC功能亮相
    前言微软在Windows11的2024更新中加强了对人工智能的应用,推出了新功能Copilot+。此次更新的版本号为26100.1742,Copilot+将首先在WindowsInsider中推出,计划于11月向特定设备和市场推广,用户需开启“尽快获取最新更新”选项以接收此更新。系统获取https://pan.xunlei.com......
  • 基于nodejs+vue基于JAVA的城镇社区服务管理平台[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,城镇化进程的加快,社区服务管理面临着前所未有的挑战与机遇。传统的社区服务管理模式存在信息不透明、服务效率低、居民参与度不高等......
  • 基于nodejs+vue基于Java的超市进销存系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和商业竞争的日益激烈,超市作为零售业的重要组成部分,其管理效率和服务质量直接关系到企业的生存与发展。传统的超市进销存管理往往依......
  • 基于nodejs+vue基于Java的比亚迪汽车大数据评分系统[开题+源码+程序+论文]计算机毕业
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,大数据技术在各行各业中的应用日益广泛。汽车行业作为国民经济的重要支柱,其数据规模庞大且复杂。比亚迪作为中国新能源汽车的领军企......
  • 理解Java中的面向对象
    文章目录前言1封装性1.1C语言中的封装1.2Java中的封装1.2.1基本概念1.2.2类的使用方法1.2.2.1构造方法1.2.2.2对象的创建与使用1.2.3访问权限2继承性3多态性3.1方法重写3.2方法重载总结前言面向对象与面向过程是当今编程世界的两种编程思想,面向过程......
  • 【02】手把手教你0基础部署SpringCloud微服务商城教学-Mybatis篇(下)
    上期回顾:【01】手把手教你0基础部署SpringCloud微服务商城教学-Mybatis篇(上)Part1.续接上文Mybatis-plus的批处理功能接下来我们学习一下IService的批量查询,我们用以往的for循环做一个对比这是for循环部分的代码privateUserbuilderUser(inti){Useruser=new......
  • Spring源码理解 类接口说明
    FactoryBean、BeanFactoryBeanFactoryBeanFactory是管理和生产Bean的,它是用于访问SpringBean容器的根接口。,定义了管理Bean的方法,获取Bean、包含Bean、是否单例Bean、获取Bean类型等。Spring根据他提供了很多实现,如DefaultListableBeanFactory、XmlBeanFactory、Applica......