springboot 整合spring ai实现 基于知识库的客服问答
rag 需求产生的背景介绍:
在使用大模型时,常遇到的问题之一是模型可能产生幻觉,即生成的内容缺乏准确性。此外,由于大模型不直接访问企业的专有数据,其响应可能会显得泛泛而谈,不够精准或具体,无法充分利用企业内部的特定信息进行个性化回答。这些问题限制了大模型在某些需要高精度和定制化场景中的应用效果。
整体说明
我们使用了Spring AI来做检索增强,选择Spring AI是因为它解决了过去用Java编写AI应用时缺乏标准化封装的问题。Spring AI提供了一套兼容市面上主要生成任务的接口,极大简化了开发流程。通过Spring AI,开发者可以轻松实现对多种模型的支持,仅需更改配置即可切换不同的AI服务提供者,从而极大地提高了开发效率和灵活性。此外,Spring AI与Spring生态系统的无缝集成,进一步确保了应用程序的可移植性和模块化设计。
Spring AI alibaba介绍
Spring AI Alibaba是专为Java开发者设计的一个框架,它集成了阿里云的AI能力,特别是通义大模型服务,使得开发者能够快速实现诸如文本生成、绘画等基于AI的功能。其核心优势在于标准化了不同AI提供者(如OpenAI、Azure、阿里云)的接口,这意味着开发者只需编写一次代码,通过简单的配置调整即可切换不同的AI服务。对于绘画或图像生成而言,Spring AI Alibaba简化了与阿里云万象模型交互的过程,允许用户轻松调用API生成高质量图像。此外,框架还提供了包括OutputParser、Prompt Template在内的实用功能,进一步降低了开发复杂度,让开发者可以专注于业务逻辑而非底层技术细节。总之,Spring AI Alibaba极大提升了使用Java进行AI应用开发的效率和灵活性。
检索增强的后端代码编写
根据提供的我了解的信息,为了实现通过检索增强(RAG)方式读取阿里巴巴的财务报表PDF,并对外提供服务,需要按照如下步骤进行配置和编码。这将允许你先调用/buildIndex
构建索引,之后能够通过访问http://localhost:8080/ai/rag?message=...
来获取基于该文档内容生成的回答。
前置条件
确保你的开发环境满足以下要求:
- JDK版本为17或更高。
- Spring Boot版本为3.3.x或以上。
- 从阿里云获取通义千问API key并设置环境变量
AI_DASHSCOPE_API_KEY
或者直接在application.properties
中配置spring.ai.dashscope.api-key
。
添加Spring AI Alibaba依赖
在项目中添加必要的仓库以及spring-ai-alibaba-starter
依赖项:
<repositories><repository><id>sonatype-snapshots</id><url>https://oss.sonatype.org/content/repositories/snapshots</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId><version>1.0.0-M2</version></dependency><!-- 其他必要依赖 -->
</dependencies>
同时,请确保您的pom.xml
文件中定义了正确的Spring Boot父项目版本。
RAG服务类实现
创建一个名为RagService
的服务类,用于处理向量存储、文档检索等逻辑:
public class RagService {private final ChatClient chatClient;private final VectorStore vectorStore;private final DashScopeApi dashscopeApi = new DashScopeApi("YOUR_API_KEY_HERE");private DocumentRetriever retriever;public RagService(ChatClient chatClient, EmbeddingModel embeddingModel) {this.chatClient = chatClient;vectorStore = new DashScopeCloudStore(dashscopeApi, new DashScopeStoreOptions("financial-reports"));retriever = new DashScopeDocumentRetriever(dashscopeApi,DashScopeDocumentRetrieverOptions.builder().withIndexName("financial-reports").build());}public String buildIndex() {String filePath = "/path/to/your/AlibabaFinancialReport.pdf";DocumentReader reader = new DashScopeDocumentCloudReader(filePath, dashscopeApi, null);List<Document> documents = reader.get();vectorStore.add(documents);return "SUCCESS";}public StreamResponseSpec queryWithDocumentRetrieval(String message) {return chatClient.prompt().user(message).advisors(new DocumentRetrievalAdvisor(retriever, """上下文信息如下。---------------------{documents}---------------------根据上下文回答问题。如果答案不在上下文中,请告知用户无法回答。""")).stream();}
}
控制器类实现
最后,实现一个REST控制器以暴露/buildIndex
与/rag
端点:
@RestController
@RequestMapping("/ai")
public class RagController {private final RagService ragService;@Autowiredpublic RagController(RagService ragService) {this.ragService = ragService;}@GetMapping("/buildIndex")public String buildIndex() {return ragService.buildIndex();}@GetMapping("/ragChat")public Flux<String> generate(@RequestParam(value = "input") String message, HttpServletResponse response) {response.setCharacterEncoding("UTF-8");return ragService.queryWithDocumentRetrieval(message).content();}
}
通过上述步骤,您已经成功设置了使用RAG技术处理PDF文档并提供问答服务的基础架构。记得首先运行/buildIndex
来初始化数据索引,随后可以通过/rag?message=...
发起查询请求获取结果。
检索增强的前端代码编写
构建项目并填写代码
首先,创建一个新的 React 应用并安装所需的依赖:
npx create-react-app ragChatFrontend
cd ragChatFrontend
npm install
public/index.html
编辑public/index.html
文件以确保基础HTML结构正确设置。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>RAG Chat App</title></head><body><div id="root"></div></body></html>
src/index.js
配置React应用入口点。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,document.getElementById('root')
);
src/App.js
定义主应用组件,并引入聊天组件。
import React from 'react';
import RAGChatComponent from './components/RAGChatComponent';function App() {return (<div className="App"><RAGChatComponent /></div>);
}export default App;
src/components/RAGChatComponent.js
这是核心的聊天组件,实现了与后端流式接口的交互。这里我们假设后端支持GET
方法来接收查询参数input
并返回flux<String>
格式的数据流。
import React, { useState } from 'react';function RAGChatComponent() {const [input, setInput] = useState('');const [messages, setMessages] = useState('');const handleInputChange = (event) => {setInput(event.target.value);};const handleSendMessage = async () => {try {// 注意这里的URL和请求方式要与你的后端服务相匹配const response = await fetch(`http://localhost:8080/ai/ragChat?input=${input}`);if (!response.ok) throw new Error('Network response was not ok');const reader = response.body.getReader();const decoder = new TextDecoder('utf-8');let done = false;while (!done) {const { value, done: readerDone } = await reader.read();done = readerDone;const chunk = decoder.decode(value, { stream: true });setMessages((prevMessages) => prevMessages + chunk); // 拼接消息}// 在每次完整的消息接收完毕后添加分隔符setMessages((prevMessages) => prevMessages + '\n\n------------------------\n\n');} catch (error) {console.error('Failed to fetch data:', error);}};const handleClearMessages = () => {setMessages('');};return (<div><inputtype="text"value={input}onChange={handleInputChange}placeholder="输入您的问题..."/><button onClick={handleSendMessage}>发送</button><button onClick={handleClearMessages}>清空</button><h3>聊天记录:</h3><pre>{messages}</pre></div>);
}export default RAGChatComponent;
运行项目
完成以上步骤后,您可以通过以下命令启动前端应用进行测试:
cd ragChatFrontend
npm start
这将打开一个本地服务器,默认访问地址为 http://localhost:3000,您可以在这里查看到构建好的应用程序界面。
上述实现基于React框架,并通过fetch API
调用后端提供的流式数据接口。每当用户点击“发送”按钮时,会触发对指定后端服务的HTTP GET请求,随后从前端逐段读取返回的流数据并显示给用户。请注意调整实际部署时可能涉及的跨域策略(CORS)以保证前后端之间通信顺畅。
相关文章:

springboot 整合spring ai实现 基于知识库的客服问答
rag 需求产生的背景介绍: 在使用大模型时,常遇到的问题之一是模型可能产生幻觉,即生成的内容缺乏准确性。此外,由于大模型不直接访问企业的专有数据,其响应可能会显得泛泛而谈,不够精准或具体,…...

云原生(四十九) | WordPress源码部署
文章目录 WordPress源码部署 一、WordPress部署步骤 二、创建项目目录 三、上传源码到WordPress 四、配置安全组 五、配置WordPress 六、访问WordPress WordPress源码部署 一、WordPress部署步骤 第一步:创建项目目录 第二步:上传源码到项目目…...

Spring Boot 集成 LiteFlow 实现业务流程编排
LiteFlow 是一款轻量级的流程编排框架,它允许开发者通过简单的配置方式,将复杂的业务流程分解为多个独立的节点,然后通过定义规则来编排节点,达到解耦业务逻辑、提高代码可维护性的目的 1. LiteFlow 的基本概念 在 LiteFlow 中,主要有以下几个概念: 节点 (Node):代表一…...

在 Android Studio 中引入android.os.SystemProperties
在 Android Studio 中引入android.os.SystemProperties 前言 网上有很多种方法,其中直接导入包的办法是行不通的,昨天自己发现问题后也踩了很多坑,现在把问题解决了也全面汇总了几种方法,确保可以百分百引入 1. layoutlib.jar包…...

代码随想录算法训练营总结
这几天一直有事情需要忙,所以现在来准备总结以下训练营的成果。 先说以下总体感受,非常值得!!! 从两个月前开始跟着每天看发布的任务,然后每天坚持打卡,收获还是很大的,从数组开始…...

【uniapp】使用uniapp实现一个输入英文单词翻译组件
目录 1、组件代码 2、组件代码 3、调用页面 4、展示 前言:使用uniapp调用一个在线单词翻译功能 1、组件代码 2、组件代码 YouDaoWordTranslator <template><view class"translator"><input class"ipttext" type"te…...

6. 继承、重写、super、final
文章目录 一、重新定义需求二、继承1. 继续分析2. 概念3. 代码① 父类② 子类③ 测试结果 4. 饿狼传说之多层继承① 概念② 代码 5. 多继承 三、方法的重写1. 情境2. 代码① 吃什么② 怎么叫(Override重写) 3. 小结 四、super1. 啃老2. 啃老啃到底 五、final1. 用途及特征2. 举…...

Redis 其他类型 渐进式遍历
我们之前已经学过了Redis最常用的五个类型了,然而Redis还有一些在特定场景下比较好用的类型 Redis最关键的五个数据类型: 上面的类型是非常常用,很重要的类型。 除此之外的其他类型不常用,只是在特定的场景能够发挥用处&#…...

科研绘图系列:R语言绘制SCI文章图2
文章目录 介绍加载R包导入数据图a图b图d系统信息介绍 文章提供了绘制图a,图b和图d的数据和代码 加载R包 library(ggplot2) library(dplyr) library(readxl) library(ggpmisc)导入数据 数据可从以下链接下载(画图所需要的所有数据): 百度网盘下载链接: https://pan.baid…...

ARM知识点三和串口代码的编写流程
ARM的一些常见问题 ARM 体系结构的主要特点是什么? 精简指令集 (RISC):ARM 采用 RISC 结构,指令集较小且简单,执行效率高。相比于复杂指令集 (CISC),RISC 更强调每条指令的执行速度。低功耗设计:ARM 处理…...

【unity踩坑】打开vs2022没有文字联想/杂项文件
unity打开vs2022没有文字联想 修改外置编辑器安装unity开发插件vs编辑器显示杂项文件 修改外置编辑器安装unity开发插件 参考 在unity项目里选择Edit-> Preferences->External Tools然后更换编辑器 在vs工具界面添加unity游戏开发选项。 重新打开还是有问题ÿ…...

WebGoat JAVA反序列化漏洞源码分析
目录 InsecureDeserializationTask.java 代码分析 反序列化漏洞知识补充 VulnerableTaskHolder类分析 poc 编写 WebGoat 靶场地址:GitHub - WebGoat/WebGoat: WebGoat is a deliberately insecure application 这里就不介绍怎么搭建了,可以参考其他…...

大数据-161 Apache Kylin 构建Cube 按照日期、区域、产品、渠道 与 Cube 优化
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

uni-app使用v-show编译成微信小程序的问题
问题 在uni-app使用v-show语法编译成微信小程序会有一个问题 当我们设置成v-show"false" 在Hbuilder X里面确实没有显示 然后运行到 微信开发程序里面 发现显示了出来,说明设置的 v-show"false"没有起作用 解决办法 首先去uniapp官网查看v…...

充电宝租赁管理系统网站毕业设计SpringBootSSM框架开发
目录 1. 概述 2. 技术选择与介绍 3. 系统设计 4. 功能实现 5. 需求分析 1. 概述 充电宝租赁管理系统网站是一个既实用又具有挑战性的项目。 随着移动设备的普及和人们日常生活对电力的持续依赖,充电宝租赁服务已成为现代都市生活中的一项重要便利设施。它不仅为…...

喜讯!迈威通信TSN产品通过“时间敏感网络(TSN)产业链名录计划”评测,各项指标名列前茅
TSN技术,作为推动企业网络化与智能化转型的关键力量,已成为工业网络迈向下一代演进的共识方向,正加速重构工业网络的技术架构与产业生态。为响应这一趋势,工业互联网产业联盟携手中国信息通信研究院及50余家产学研用单位ÿ…...

国产工具链GCKontrol-GCAir助力控制律开发快速验证
前言 随着航空领域技术的不断发展,飞机的飞行品质评估和优化成为了航空领域的一个重要任务,为了确保飞行器在各种复杂条件下的稳定性,控制律设计过程中的模型和数据验证需要大量仿真和测试。 本文将探讨基于世冠科技的国产软件工具链GCKont…...

嵌入式开发:STM32 硬件 CRC 使用
测试平台:STM32G474系列 STM32硬件的CRC不占用MCU的资源,计算速度快。由于硬件CRC需要配置一些选项,配置不对就会导致计算结果错误,导致使用上没有软件计算CRC方便。但硬件CRC更快的速度在一些有时间资源要求的场合还是非…...

基于STM32的智能家居语音控制系统:集成LD3320、ESP8266设计流程
一、项目概述 项目目标和用途 近年来,智能家居产品逐渐成为家庭生活中不可或缺的一部分。为了提升家庭生活的便捷性和舒适度,本项目旨在设计一款基于STM32F407VGT6(Cortex-M4内核)微控制器的多功能智能家居语音控制系统。该系统…...

【docker】要将容器中的 livox_to_pointcloud2 文件夹复制到宿主机上
复制文件夹 使用 docker cp 命令从容器复制文件夹到宿主机: docker cp <container_id_or_name>:/ws_livox/src/livox_to_pointcloud2 /path/to/host/folder sudo docker cp dandong_orin_docker:/ws_livox/src/livox_to_pointcloud2 /home...

网络编程(17)——asio多线程模型IOThreadPool
十七、day17 之前我们介绍了IOServicePool的方式,一个IOServicePool开启n个线程和n个iocontext,每个线程内独立运行iocontext, 各个iocontext监听各自绑定的socket是否就绪,如果就绪就在各自线程里触发回调函数。为避免线程安全问题…...

【rust/egui/android】在android中使用egui库
文章目录 说在前面AndroidStudio安装编译安装运行问题 说在前面 操作系统:windows11java版本:23android sdk版本:35android ndk版本:22rust版本: AndroidStudio安装 安装AndroidStudio是为了安装sdk、ndk,…...

Git---Git打标签
打标签 像其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。 在本节中,你将会学习如…...
深入理解Transformer的笔记记录(精简版本)---- Transformer
自注意力机制开启大规模预训练时代 1 从机器翻译模型举例 1.1把编码器和解码器联合起来看待的话,则整个流程就是(如下图从左至右所示): 1.首先,从编码器输入的句子会先经过一个自注意力层(即self-attention),它会帮助编码器在对每个单词编码时关注输入句子中的的其他单…...

Ubuntu 更换内核版本
更换内核脚本 这里以更换 5.15.0-88-generic 版本内核为例 cat kernel.sh#!/bin/bashapt install linux-image-5.15.0-88-generic # Ubuntu内核切换脚本# 检查是否具有root权限 if [[ $(id -u) -ne 0 ]]; thenecho "请以root身份运行此脚本。"exit 1 fi# 检查系统是…...

博士找高校教职避坑指南:史上最全的避坑秘籍
在学术的海洋中遨游多年,博士们终于要踏上寻找高校教职的征程。这不仅是职业生涯的新起点,更是一场充满未知与挑战的冒险。今天,就让我们来聊聊那些在寻找高校教职时需要避开的坑,希望能为你的求职之路保驾护航。 1. 薪资结构&am…...

Study-Oracle-11-ORALCE19C-ADG集群搭建
一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 一、ORACLE--ADG VS ORACLE--DG的区别 1、DG是Oracle数据库的一种灾难恢复和数据保护解决方案,它通过在主数据库和一个或多个备用数据库之间实时复制数据,提供了数据的冗余备份和故障切换功能。…...

【C++】map详解(键值对的概念,与multimap的不同)
目录 00.引言 set 和 map 的区别 键值对的概念 01.map容器 主要特性 常用操作 主要用途 02.multimap容器 特性 常用操作 用途 00.引言 set 和 map 的区别 set 和 map 都是C标准模板库(STL)中的容器,它们的区别如下:…...

私域电商新纪元:消费增值模式引领百万业绩飞跃
各位朋友,我是吴军,专注于带领大家深入探索私域电商领域的非凡魅力与潜在机会。 今天,我想与大家分享一个鼓舞人心的真实故事。在短短的一个月内,我们的合作伙伴实现了业绩的飞跃,突破百万大关,并且用户活跃…...

AAA Mysql与redis的主从复制原理
一 :Mysql主从复制 重要的两个日志文件:bin log 和 relay log bin log:二进制日志(binnary log)以事件形式记录了对MySQL数据库执行更改的所有操作。 relay log:用来保存从节点I/O线程接受的bin log日志…...