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

Spring-AI讲解

Spring-AI

langchain(python) langchain4j

官网:

https://spring.io/projects/spring-ai#learn

整合chatgpt

前置准备
  1. open-ai-key:
    https://api.xty.app/register?aff=PuZD
    https://xiaoai.plus/
    https://eylink.cn/
    或者淘宝搜: open ai key
  2. 魔法软件, 由于国家相关法律规定,建议大家自行准备。(中转可暂不准备)
  3. jdk17
    4 springboot3
    示例代码:https://gitee.com/xscodeit/ai-openai-examples.git

实现
在这里插入图片描述

创建完后会发现加入了依赖:

<dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.0.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>

设置代理, 如果你请求的大模型的api接口不是国内的。需要将程序设置代理:

public static void main(String[] args) {// 设置代理String proxy = "127.0.0.1";  // 如果代理在你本机就127.0.0.1 ,  如果代理是其他服务器相应设置int port = 7890;   //设置科学上网代理的端口,System.setProperty("proxyType", "4");System.setProperty("proxyPort", Integer.toString(port));System.setProperty("proxyHost", proxy);System.setProperty("proxySet", "true");SpringApplication.run(Application.class, args);}

设置key:

xushu:# 官方(自行配置)openai:key: ${OPENAI_KEY}url: ${OPENAI_URL}# 中转(自行配置)aicore:key: ${OPEN_AI_KEY}url: ${OPEN_AI_URL}spring:ai:openai:api-key: ${xushu.aicore.key}base-url: ${xushu.aicore.url}

示例代码:

private final ChatClient chatClient;
private final OpenAiChatModel chatClient2;
private final OpenAiImageModel imageClient;
private final OpenAiAudioTranscriptionModel audioClient;
private final  OpenAiAudioApi openAiAudioApi;@Value("${OPEN_AI_KEY}")
private String openAiKey;@GetMapping("/ai/simple")
public Map<String, String> completion(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message) {System.out.println(openAiKey);var value=chatClient.prompt().user(message).call().content();return Map.of("generation",value );
}@GetMapping(value="/ai/stream",produces="text/sse;charset=UTF-8")
public Flux<String> stream(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message ) {System.out.println(openAiKey);return chatClient.prompt().user(message).stream().content();
}@GetMapping(value="/ai/img",produces="text/html")
public String image(@RequestParam(value = "message", defaultValue = "猫") String message ) {ImageResponse response = imageClient.call(new ImagePrompt(message,OpenAiImageOptions.builder().withQuality("hd").withN(1).withModel(OpenAiImageApi.ImageModel.DALL_E_2.getValue())// dall-e-2 256.withHeight(256).withWidth(256).build()));String url = response.getResult().getOutput().getUrl();System.out.println(url);return "<img src='"+url+"'/>";}@GetMapping(value="/ai/audit2text")
public String audit2text() {var transcriptionOptions = OpenAiAudioTranscriptionOptions.builder().withResponseFormat(OpenAiAudioApi.TranscriptResponseFormat.TEXT).withTemperature(0f).build();// flac、mp3、mp4、mpeg、mpga、m4a、ogg、wav 或 webm。var audioFile = new ClassPathResource("/hello.mp3");AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioFile, transcriptionOptions);AudioTranscriptionResponse response = audioClient.call(transcriptionRequest);//openAiAudioApi.createTranscription()return response.getResult().getOutput();
}@GetMapping(value="/ai/text2audit")
public String text2audit() {ResponseEntity<byte[]> speech = openAiAudioApi.createSpeech(OpenAiAudioApi.SpeechRequest.builder().withVoice(OpenAiAudioApi.SpeechRequest.Voice.ONYX).withInput("你好,我是徐庶").build());byte[] body = speech.getBody();// 将byte[]存为 mp3文件try {writeByteArrayToMp3(body, System.getProperty("user.dir"));} catch (IOException e) {throw new RuntimeException(e);}return "ok";
}public static void writeByteArrayToMp3(byte[] audioBytes, String outputFilePath) throws IOException {// 创建FileOutputStream实例FileOutputStream fos = new FileOutputStream(outputFilePath+"/xushu.mp3");// 将字节数组写入文件fos.write(audioBytes);// 关闭文件输出流fos.close();
}@GetMapping(value="/ai/mutil")
public String mutilModel(String message,String imgUrl) throws IOException {byte[] imageData = new ClassPathResource("/test.png").getContentAsByteArray();var userMessage = new UserMessage("这个图片你看出什么?", // contentList.of(new Media(MimeTypeUtils.IMAGE_PNG, imageData))); // mediaChatResponse response = chatClient.call(new Prompt(userMessage,OpenAiChatOptions.builder().withModel(OpenAiApi.ChatModel.GPT_4_TURBO_PREVIEW.getValue()).build()));return  response.getResult().getOutput().getContent();
}
function-call

AI本身是不具备实时消息能力的, 比如问“现在北京的天气是什么”, AI是不知道的, 这个时候我们需要通过接口来帮助AI完成,大致流程:
在这里插入图片描述

function-call实现的代码:
  1. 在发送文本时, 同时设置Funcation ; 关键代码:.withFunction(“getWaitTime”)
ChatResponse response = chatClient.call(new Prompt(List.of(userMessage),OpenAiChatOptions.builder().withFunction("getWaitTime").build()));
  1. 当代码执行完call时(AI响应之后), 会再调用getWaitTime对应的bean的apply方法。
@Bean
public Function<WaitTimeService.Request, WaitTimeService.Response> getWaitTime() {return new WaitTimeService();
}
  1. 并且会把 getWaitTime该bean的Request作为funcation-call的返回参数, 即可在apply方法中获取Request对应的参数
@Override
public Response apply(Request request) {String name =  request.name();String location =  request.location();// todo...return new Response(location+"有10个!");
}
// jdk17新特性 密封类
public record Request(String name,String location) {}
public record Response(String weather) {}

随后Response会再次丢给AI组织语言, 进行响应,最终

源码:

看源码之前, 了解下该接口需要哪些参数:https://platform.openai.com/docs/api-reference/chat/create
请求: userMessage=“长沙有多少叫徐庶的”
调用call方法, 执行openai的远程api请求

@Override
public ChatResponse call(Prompt prompt) {ChatCompletionRequest request = createRequest(prompt, false);return this.retryTemplate.execute(ctx -> {ResponseEntity<ChatCompletion> completionEntity = this.callWithFunctionSupport(request);var chatCompletion = completionEntity.getBody();if (chatCompletion == null) {logger.warn("No chat completion returned for prompt: {}", prompt);return new ChatResponse(List.of());}RateLimit rateLimits = OpenAiResponseHeaderExtractor.extractAiResponseHeaders(completionEntity);List<Generation> generations = chatCompletion.choices().stream().map(choice -> {return new Generation(choice.message().content(), toMap(chatCompletion.id(), choice)).withGenerationMetadata(ChatGenerationMetadata.from(choice.finishReason().name(), null));}).toList();return new ChatResponse(generations,OpenAiChatResponseMetadata.from(completionEntity.getBody()).withRateLimit(rateLimits));});
  1. 通过createRequest将withFunction参数解析到request.tools
ChatCompletionRequest request = createRequest(prompt, false);

tools属性:包含了
在这里插入图片描述

关于open-ai对tools参数的说明:https://platform.openai.com/docs/api-reference/chat/create#chat-create-tools
在这里插入图片描述

  1. 来到callWithFunctionSupport 真正调用远程api接口
    protected Resp callWithFunctionSupport(Req request) { Resp response = this.doChatCompletion(request); return this.handleFunctionCallOrReturn(request, response); }
    这里2句关键代码:

  2. this.doChatCompletion(request); 方法会正常请求chat completion 接口并且会带上funcation-call参数并携带tools属性 , 并且返回对话中的funcation-call所需参数(即WaitTimeService.Request的参数)
    在这里插入图片描述

  3. handleFunctionCallOrReturn 执行Function-callback方法, 此时会调用WaitTimeService.apply方法
    a. 拿到之前解析的functionCallback即
    b. 将arguments从Json转换为对象调用WaitTimeService.apply
    c. 将返回的数据再次请求大模型

发展

SpringAI社区非常活跃
在后续的版本都会更新国内常用的大模型
https://github.com/spring-projects/spring-ai/issues?q=Moonshot
在这里插入图片描述

阿里也率先为自己得通义大模型封装了基于SpringAI的spring-cloud-starter-alibaba-ai
https://sca.aliyun.com/?spm=0.29160081.0.0.77ff60c5NGK3QD

相关文章:

Spring-AI讲解

Spring-AI langchain(python) langchain4j 官网&#xff1a; https://spring.io/projects/spring-ai#learn 整合chatgpt 前置准备 open-ai-key: https://api.xty.app/register?affPuZD https://xiaoai.plus/ https://eylink.cn/ 或者淘宝搜&#xff1a; open ai key魔法…...

【brew安装失败】DNS 查询 raw.githubusercontent.com 返回的是 0.0.0.0

从你提供的 nslookup 输出看&#xff0c;DNS 查询 raw.githubusercontent.com 返回的是 0.0.0.0&#xff0c;这通常意味着无法解析该域名或该域名被某些 DNS 屏蔽了。这种情况通常有几个可能的原因&#xff1a; 可能的原因和解决方法 本地 DNS 问题&#xff1a; 有可能是你的本…...

HTML——29. 音频引入二

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>音频引入</title></head><body><!--audio:在网页中引入音频IE8以及之前版本不支持属性名和属性值一样&#xff0c;可以只写属性名src属性:指定音频文件…...

代码随想录训练营第三十四天| 62.不同路径 63. 不同路径 II

62.不同路径 题目链接&#xff1a;62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 讲解链接&#xff1a;代码随想录 动态规划五步走 1 定义dp数组是到dp[i][j]时有dp[i][j]条路径 dp[i][j] &#xff1a;表示从&#xff08;0 &#xff0c;0&#xff09;出发&#xf…...

V90伺服PN版组态配置<一>

1、添加PLC之后&#xff0c;继续博图中网络视图中添加新设备&#xff0c;添加伺服驱动器组态设备 2、SINAMICS V90 PN V1.0 3、修改驱动器的IP地址。 【注意】 在项目中提前做好项目规划&#xff0c;如PLC设备从192.168.0.1开始&#xff0c;顺序递增------个位数都是CPU设备…...

又一年。。。。。。

2024&#xff0c;浑浑噩噩的一年。 除了100以内的加减法&#xff08;数据&#xff0c;数据&#xff0c;还是数据。。。。。。&#xff09;&#xff0c;似乎没做些什么。 脸盲症越来越重的&#xff0c;怕是哪天连自己都不认得自己的了。 看到什么&#xff0c;听到什…...

xterm + vue3 + websocket 终端界面

xterm.js 下载插件 // xterm npm install --save xterm// xterm-addon-fit 使终端适应包含元素 npm install --save xterm-addon-fit// xterm-addon-attach 通过websocket附加到运行中的服务器进程 npm install --save xterm-addon-attach <template><div :…...

医疗数仓业务数据采集与同步

业务数据采集与同步 业务采集组件配置业务数据同步概述数据同步策略选择数据同步工具概述1.1.4 全量表数据同步DataX配置文件生成全量表数据同步脚本增量表数据同步 MySQL - Maxwell - Kafka - Flume - HDFSMaxwell配置增量表首日全量同步 业务采集组件配置 Maxwell将业务采集到…...

数字孪生智慧水利与水务所包含的应用场景有哪些?二者有何区别

水利和水务是两个密切相关但有所区别的概念&#xff0c;它们在水资源管理和保护方面各自承担着不同的职责和功能。 定义 智慧水务&#xff1a;智慧水务是指通过物联网、大数据、云计算、人工智能等新一代信息技术&#xff0c;对城市供水、排水、污水处理、水质监测等水务系统…...

Qt Creator项目构建配置说明

QT安装好之后&#xff0c;在安装目录的Tools\QtCreator\bin下找到qtcreator.exe文件并双击打开 点击文件-新建文件或项目 选择Qt Widgets Application 设置项目名称以及路径 make工具选择qmake&#xff08;cmake还未尝试过&#xff09; 设置主界面对应类的名称、父类&#…...

进程间通信的“五大武器”

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…...

全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之循环结构(for循环语句)(六)

实战训练1—输出九九乘法表 问题描述: 在学校里学过九九乘法表&#xff0c;编程实现打印九九乘法表。 输入格式&#xff1a; 无输入 输出格式&#xff1a; 1*11 2*12 2*24 3*13 3*26 3*39 4*14 4*28 4*312 4*416 5*15 5*210 5*315 5*420 5*525 6*16 6*212 6*318 6*424 6*5…...

封装echarts成vue component

封装echarts成vue component EChartsLineComponent 文章目录 封装echarts成vue component EChartsLineComponent封装说明重写重点EChartsLineComponent的源码 使用说明调用EChartsLineComponent示例源码 封装说明 为了减少一些公共代码和方便使用echarts的line图形&#xff0c…...

uniapp Stripe 支付

引入 Stripe npm install stripe/stripe-js import { loadStripe } from stripe/stripe-js; Stripe 提供两种不同类型组件 Payment Element 和 Card Element&#xff1a;如果你使用的是 Payment Element&#xff0c;它是一个更高级别的组件&#xff0c;能够自动处理多种支…...

Windows onnxruntime编译openvino

理论上来说&#xff0c;可以直接访问 ONNXRuntime Releases 下载 dll 文件&#xff0c;然后从官方文档中下载缺少的头文件以直接调用&#xff0c;但我没有尝试过。 1. 下载 OpenVINO 包 从官网下载 OpenVINO 的安装包并放置在 C:\Program Files (x86) 路径下&#xff0c;例如…...

vue3+TS+vite中Echarts的安装与使用

概述 技术栈&#xff1a;Vue3TsViteEcharts 简述&#xff1a;图文详解&#xff0c;教你如何在Vue项目中引入Echarts&#xff0c;封装Echarts组件&#xff0c;并实现常用Echats图列 文章目录 一&#xff0c;效果图 二&#xff0c;引入Echarts 2.1安装Echarts 2.2main.ts中引…...

期末算法分析程序填空题

目录 5-1 最小生成树&#xff08;普里姆算法&#xff09; 5-2 快速排序&#xff08;分治法&#xff09; 输入样例&#xff1a; 输出样例&#xff1a; 5-3 归并排序(递归法) 输入样例&#xff1a; 输出样例&#xff1a; 5-4 求解编辑距离问题&#xff08;动态规划法&#xff09;…...

搭建android开发环境 android studio

1、环境介绍 在进行安卓开发时&#xff0c;需要掌握java&#xff0c;需要安卓SDK&#xff0c;需要一款编辑器&#xff0c;还需要软件的测试环境&#xff08;真机或虚拟机&#xff09;。 早起开发安卓app&#xff0c;使用的是eclipse加安卓SDK&#xff0c;需要自行搭建。 目前开…...

R语言6种将字符转成数字的方法,写在新年来临之际

咱们临床研究中&#xff0c;拿到数据后首先要对数据进行清洗&#xff0c;把数据变成咱们想要的格式&#xff0c;才能进行下一步分析&#xff0c;其中数据中的字符转成数字是个重要的内容&#xff0c;因为字符中常含有特殊符号&#xff0c;不利于分析&#xff0c;转成数字后才能…...

RocketMQ学习笔记(持续更新中......)

目录 1. 单机搭建 2. 测试RocketMQ 3. 集群搭建 4. 集群启动 5. RocketMQ-DashBoard搭建 6. 不同类型消息发送 1.同步消息 2. 异步消息发送 3. 单向发送消息 7. 消费消息 1. 单机搭建 1. 先从rocketmq官网下载二进制包&#xff0c;ftp上传至linux服务器&#xff0c…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...