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

GLM-4.1V-9B-Base算法应用:融合LSTM时序预测的智能视频内容分析平台

GLM-4.1V-9B-Base算法应用&#xff1a;融合LSTM时序预测的智能视频内容分析平台 1. 引言&#xff1a;当视频分析遇上多模态AI 想象一下这样的场景&#xff1a;一个商场监控室里&#xff0c;安保人员需要同时盯着几十个监控画面&#xff1b;或者一个短视频平台的内容审核团队&…...

傅里叶级数7大核心性质详解:从时移特性到微分性快速掌握

傅里叶级数7大核心性质详解&#xff1a;从时移特性到微分性快速掌握 信号与系统课程中&#xff0c;傅里叶级数就像一把瑞士军刀&#xff0c;能将复杂的周期信号拆解成简单的正弦波组合。对于备考学生而言&#xff0c;掌握其核心性质不仅能快速解题&#xff0c;更能深入理解信号…...

从零构建编译器:编译原理实战与考试重点解析

1. 编译器是什么&#xff1f;为什么需要学习编译原理&#xff1f; 当你用Python写下print("Hello World")时&#xff0c;计算机其实看不懂这行代码。编译器就像一位翻译官&#xff0c;把人类能理解的高级语言转换成机器能执行的二进制指令。我在第一次实现编译器时&a…...

YOLOv10实战:用官方镜像5分钟搭建智能监控原型系统

YOLOv10实战&#xff1a;用官方镜像5分钟搭建智能监控原型系统 想快速验证一个智能监控的想法&#xff0c;却卡在繁琐的环境配置和模型部署上&#xff1f;从安装CUDA、配置Python环境&#xff0c;到调试各种依赖库&#xff0c;可能半天时间就过去了&#xff0c;真正的业务逻辑…...

Qwen3-ASR性能优化:基于CNN的语音特征提取技术

Qwen3-ASR性能优化&#xff1a;基于CNN的语音特征提取技术 语音识别技术发展到今天&#xff0c;已经不再是实验室里的新奇玩具&#xff0c;而是我们日常生活中随处可见的实用工具。从手机语音助手到会议记录软件&#xff0c;从智能家居控制到车载语音交互&#xff0c;语音识别…...

2026年服装收银软件选型指南:五大功能决定门店提效与增长

很多服装门店都遇到过这样的困境&#xff1a;网络波动导致无法收款&#xff0c;眼睁睁看着顾客放下衣服离开&#xff1b;促销规则设置不到位&#xff0c;收银时算错优惠引发客诉&#xff1b;活动结束了&#xff0c;线上线下数据对不上&#xff0c;投入的钱看不到效果。这些问题…...

RTX 50系显卡用户看过来:在Windows上为CUDA 12.8和PyTorch Nightly版安装Triton的实战记录

RTX 50系显卡用户看过来&#xff1a;在Windows上为CUDA 12.8和PyTorch Nightly版安装Triton的实战记录 当GeForce RTX 50系列显卡遇上PyTorch Nightly和CUDA 12.8&#xff0c;这可能是目前最前沿的AI开发环境组合。但官方文档和主流教程往往跟不上硬件迭代的速度&#xff0c;让…...

创建基础数据表后数据无法保存怎么排查_权限设置与回滚处理

...

飞书机器人集成实战:OpenClaw+Phi-3-vision-128k-instruct打造智能问答助手

飞书机器人集成实战&#xff1a;OpenClawPhi-3-vision-128k-instruct打造智能问答助手 1. 为什么选择这个技术组合&#xff1f; 上周我接到一个产品经理的需求——希望能通过飞书直接发送产品截图&#xff0c;自动获得功能分析报告。传统方案需要开发整套服务端逻辑&#xff…...

从噪声数据中提取系统矩阵(对应论文式3)

控制顶刊IEEE TAC热点论文复现&#xff0c;前V章案例复现&#xff0c;内容包括数据驱动状态反馈控制和LQR控制&#xff0c;可应用于具有噪声的数据和非线性系统&#xff0c;附参考论文及详细代码注释对应到文中公式&#xff0c;易于掌握理解&#xff0c;需要代码最近在复现TAC上…...