当前位置: 首页 > article >正文

深入解析 Spring AI 系列:解析返回参数处理

关于普通聊天对接,目前已经完成了大部分讲解,剩下的就是最后一步,今天我们将重点讨论在返回参数时需要注意的几个关键点。为了更好地说明这些注意事项,我们仍然以OpenAI接口为例,逐步讲解相关的代码实现,帮助大家更清楚地理解这一部分的细节。

接下来,我们就直接看一下这一部分代码,分析其中的注意事项。

image

其实,对于这部分代码来说,核心逻辑的重点在于将大模型返回的内容封装到 response 中,从而完成对接工作。然而,值得注意的是,为什么代码中还要额外获取并处理一些看似并未直接使用的值,例如 metadatarateLimitusage 等?实际上,这并非多余的操作。这些信息虽然在当前版本的代码中并没有立即被使用,但它们的存在是为了为后续可能的需求变化做准备。

如果我们仅仅是为了简单地将获取到的返回内容输出给用户,其实是可以省去这些额外步骤的,也不需要做如此复杂的处理。如图所示:

image

这是Minimax算法的处理方式,相较于OpenAI的处理方式,这里采用的方法显得更加简洁和直观。因此,这部分代码的实现较为简单,理解后可以快速跳过,不必深入细节。在实际应用中,只需要在有用的地方将相应的信息提取并填充到response对象中即可。

如果某些信息在当前上下文中并未使用到,那么就不需要进行封装或处理,避免不必要的复杂度。

ChatGenerationMetadata

buildGeneration的核心逻辑其实就是在寻找需要的工具调用和结束信息,核心代码如下所示,看一下:

private Generation buildGeneration(Choice choice, Map<String, Object> metadata, ChatCompletionRequest request) {
    List<AssistantMessage.ToolCall> toolCalls = choice.message().toolCalls() == null ? List.of()
            : choice.message()
                .toolCalls()
                .stream()
                .map(toolCall -> new AssistantMessage.ToolCall(toolCall.id(), "function",
                        toolCall.function().name(), toolCall.function().arguments()))
                .toList();

    String finishReason = (choice.finishReason() != null ? choice.finishReason().name() : "");
    var generationMetadataBuilder = ChatGenerationMetadata.builder().finishReason(finishReason);

    List<Media> media = new ArrayList<>();
    String textContent = choice.message().content();
    var audioOutput = choice.message().audioOutput();
    if (audioOutput != null) {
        String mimeType = String.format("audio/%s", request.audioParameters().format().name().toLowerCase());
        byte[] audioData = Base64.getDecoder().decode(audioOutput.data());
        Resource resource = new ByteArrayResource(audioData);
        Media.builder().mimeType(MimeTypeUtils.parseMimeType(mimeType)).data(resource).id(audioOutput.id()).build();
        media.add(Media.builder()
            .mimeType(MimeTypeUtils.parseMimeType(mimeType))
            .data(resource)
            .id(audioOutput.id())
            .build());
        if (!StringUtils.hasText(textContent)) {
            textContent = audioOutput.transcript();
        }
        generationMetadataBuilder.metadata("audioId", audioOutput.id());
        generationMetadataBuilder.metadata("audioExpiresAt", audioOutput.expiresAt());
    }

    var assistantMessage = new AssistantMessage(textContent, metadata, toolCalls, media);
    return new Generation(assistantMessage, generationMetadataBuilder.build());
}

无论在何种情况下省略逻辑,toolCallsfinishReason这两个要素是必须要被识别和处理的。除非某个大型模型不支持toolCalls功能,否则我们在实现时不应忽略它们。实际上,绝大多数主流的大型模型都具备这部分功能,因为如果一个模型缺失了toolCalls功能,这意味着它无法支持Agent的开发和运行,进而就失去了介入Spring AI生态系统的基本目的。总之,确保对这两个关键要素的识别,对于实现模型的有效性和功能完整性至关重要。

关于media是因为OpenAI接口是会返回此信息字段,看下接口文档:

image

除此之外ChatGenerationMetadata目前除了finishReason我找到了使用目的,其他的还未找到用处,ChatGenerationMetadata功能基本如下:

  1. 可以用来测试

  2. 可以用来观测

  3. 目前还没咋用上,先留个心

ChatResponseMetadata

作用也是一样的,仍然是为了观测使用,只不过他封装的信息和上面有一些区别而已。如图所示:

image

Usage

本质上,这只是一个用于统计token使用情况的信息,功能上并没有特别复杂的内容,理解起来并不难。如果你之前不太了解这部分的细节,可以查看它的核心代码,这将帮助你迅速掌握其工作原理。

需要注意的是,绝大多数大型模型接口都提供了类似的字段,因为在实际应用中,了解token的消耗情况非常重要,毕竟资源的投入(如费用)最终需要与使用效果相对应,这也是模型开发者和使用者关心的重点之一。如图所示:

image

总结

在这一部分的讲解中,我们详细探讨了返回参数处理的关键要点,特别是如何封装与使用相关的字段。尽管某些信息(如metadatarateLimit等)在当前实现中未直接用到,但它们的引入是为了更好地支持未来的扩展和需求变化。

通过对比不同处理方式,我们也看到不同模型接口在设计上的差异。在实际开发过程中,理解这些细节对于保证接口的扩展性和系统的稳定性至关重要。

文章转载自:努力的小雨

原文链接:深入解析 Spring AI 系列:解析返回参数处理 - 努力的小雨 - 博客园

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构


http://www.kler.cn/a/515357.html

相关文章:

  • 《鸿蒙Next原生应用的独特用户体验之旅》
  • Glary Utilities Pro 多语便携版系统优化工具 v6.21.0.25
  • 构建高效稳定的网络环境
  • pikachu靶场-敏感信息泄露概述
  • Docker 部署 mysql
  • LAYA3.0 组件装饰器说明
  • 机器学习-K近邻算法
  • C# 匿名函数
  • 计算机网络 (56)交互式音频/视频
  • C语言初阶牛客网刷题——HJ73 计算日期到天数转换【难度:简单】
  • 文献精汇|121 模型:用于高收益交易的 LSTM 驱动的协整策略
  • 读写和解析简单的 nc 文件
  • flutter入门系列教程<2>:Http请求库-dio的使用
  • 二叉树的递归遍历力扣--145,144,94
  • 【深度学习】嘿马深度学习笔记第11篇:卷积神经网络,学习目标【附代码文档】
  • WPF自定义布局--瀑布布局
  • Kafka后台启动命令
  • 详细介绍:Kubernetes(K8s)的技术架构(核心概念、调度和资源管理、安全性、持续集成与持续部署、网络和服务发现)
  • wx036基于springboot+vue+uniapp的校园快递平台小程序
  • django admin list_display显示外键字段处理办法
  • 频繁刷新网页会对服务器造成哪些影响?
  • 如何轻松实现域名指向服务器
  • 代码统计工具cloc
  • 第五篇 vue3 ref 与 reactive 对比
  • 如何在 Flask 中实现用户认证?
  • 如何使用 Flask-Caching 提高性能?