当前位置: 首页 > 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…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...