Java转AI大模型一文彻底搞懂大模型RAG
6年Java程序员,因公司做AI,所以转行AI大模型开发,刚学完RAG的基本概念和基本用法,给大家分享一下,让大家少走弯路
SpringAI对话和知识库
第一章 RAG
在当今这样一个快速发展的技术时代,人工智能(AI)已经成为各行各业的一种标配。而作为一款主流的Java应用开发框架Spring,肯定会紧跟时代的潮流,所以,推出了Spring AI框架。
1.1 什么是RAG
RAG(Retrieval Augmented Generation,简称RAG),也叫检索增强生成。
RAG是一种将大规模语言模型(LLM)与外部知识源的检索相结合,以改进问答能力的技术。
注意,上面重复强调了几次 检索 这两个字,检索就是查询,说白了RAG就是一门让AI回答(查询)更加精准的技术,避免答非所问,或者瞎答(看似回答的相关性很高,实际上一点作用都没有)
另外RAG是一个概念,并不是一门具体的技术。具体的技术比如Kafka,可以启动、发送消息、消费消费。RAG就不行,首先,光是启动就没有
1.2 为什么要知识库
1、不管是deepseek还是OpenAI,都是通用大模型,看上去啥都会,但是很多地方回答地也不专业,因为缺乏专业知识训练。比如你问deepseek:歼20是怎么制造的、图纸长什么样子。这种国家机密你能在互联网找到吗?肯定找不到,没有专业知识训练,大模型肯定也无法知道答案
2、对企业来说,公司内部数据不能外泄。比如你公司的五险一金基数和比例是什么?有没有足额缴纳?上班是双休还是单休?965还是996。这些信息能外泄在互联网上公开吗?肯定不能啊,你一公开,所有人都能查到你们公司五险一金按照2300的5%去交,尽管这已经不公开的秘密,但是晚一天公开,或许就能多压榨一天,多赚一天牛马的钱
3、很多行业需要专业、严谨的回答,而不是大白话的那种,比如医疗、法律、财税等
1.3 RAG工作流程概述
第一,用户输入问题
用户在输入窗口输入自己的问题,这一数据被接收,并作为后续处理的查询入口
例如:用户提问
“国内996、工资又低的公司有哪些?”
第二,问题向量化
根据用户初始输入的问题,调用Embedding模型,将问题转换为高维向量,以便于后续的想来那个相似度检索。
文本:"国内996、工资又低的公司有哪些?"
→ 向量:[0.125, 0.502, ..., 0.001]
第三,向量数据库检索
系统会连接到一个向量数据库(如FAISS、Milvus、Pinecone、Weaviate)。然后用刚才生成的问题向量,检索知识库中与之最相似的文档片段。我们这个案例是使用SimpleVectorStore(内存向量数据库,不需要安装)
当检索的时候,常见的检索参数包括:
- Tok-K :检索最相关的K条记录
- 相似度阈值:控制检索到内容的相关性
最后输出的结果往往是K条知识片段
1. "有软通动力,著名的外包公司,加班是常时,工资低的可怕。"
2. "广州骏伯网络科技,五险一金按照2300的5%来交。(为什么我知道,因为我面过)"
3. "华为OD,加班超级严重"
第四,构建上下文
这一阶段需要组织提示词(Prompt),让LLM更好地理解背景信息。
这一部分包括:
- 系统提示词(System Prompt)
提前告诉LLM需要遵循的行为规范,比如
你是一个专业的查询公司信息、网评的人。请基于提供的背景资料,准确回答用户的问题。如果资料中没有明确答案,请如实告诉用户而不是编造。
系统提示词可以有效地设定模型角色、控制回答风格、防止幻觉
-
构造最终输入(Final Prompt)
一般会结合以上内容,按照如下格式进行组织
【背景资料】 1. 有软通动力,著名的外包公司,加班是常时,工资低的可怕。 2. 广州骏伯网络科技,五险一金按照2300的5%来交。 3. 华为OD,加班超级严重。 【用户问题】 国内996、工资又低的公司有哪些? 【回答要求】 请结合以上资料,用简洁明了的方式回答用户的问题。如果答案无法直接从资料中找到,请礼貌告知用户。
第五,调用LLM
将构造好的Prompt提交给LLM(比如Deepseek、Qwen、GPT-4o、Claude等)
- 模型读取检索到的内容和问题
- 组织自然、连贯、准确的回答
生成结果示例:
“您好! 根据我们的资料,国内出了阿里、腾讯等几个互联网大厂给的工资足够高外,其他绝大部分公司都是福利待遇特别低,加班还超级严重,比如广州骏伯网络科技,五险一金按照2300的5%来交”
第六,返回最终回答给用户
最终系统将生成的回答返回前端,展示给用户。
总结:
在RAG工作时,其运行流程大致为:
1. 用户输入问题
2. 问题向量化
3. 向量数据库检索
4. 构建上下文(含系统提示词)
5. 携带检索内容,调用大模型进行回答
6. 返回最终答案给用户
第二章 Spring AI实现RAG
2.1 父工程的pom
<!--集成SpringAI 正式版-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
注意我是使用SpringAI的正式版,网上很多教程都是针对Spring AI的1.0.0-M6或者1.0.0-M8版本,这些都是非正式版,今年5月才出的1.0.0正式版,版本号就是1.0.0,别写错了
2.2 子工程的pom
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<!--SpringAI 读取PDF文件需要引入这个依赖,读其他文件,可能需要引入其他依赖-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
2.4 yml配置
server:
port: 8007
spring:
application:
name: rent-ai
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/rent-house
username: root
password: admin123
ai:
openai:
# 填写阿里云百炼平台的url,而不是openai的url
base-url: https://dashscope.aliyuncs.com/compatible-mode
# 百炼平台上申请的key
api-key: sk-c9b1616dcebt94d487eb924682c9f3a0a477
chat:
options:
# 模型的名字
model: qwen-max-latest
# 模型温度,值越大,输出结果越随机
temperature: 0.8
#向量配置
embedding:
options:
# 向量/嵌入模型名称,这里的向量模型名称叫:通用文本向量-v3
model: text-embedding-v3
# 向量维度,1024表示1024维空间的向量
dimensions: 1024
这里还是用的阿里百炼大模型,需要去申请api-key,怎么申请,看我前面的文章
2.5 配置类
package com.huqing.icu.rentai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @Description 知识库配置类,这个配置是参照尚硅谷的
* @Author huqing
* @Date 2025/6/7 14:07
**/
@Configuration
public class RagConfig {
@Bean
ChatClient chatClient(ChatClient.Builder builder) {
return builder.defaultSystem("你是一个打工人,对用户的问题作出解答").build();
}
@Bean
VectorStore vectorStore(EmbeddingModel embeddingModel) {
SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(embeddingModel).build();
//生成一个文本
List<Document> documentList = List.of(
new Document("打工人的理想就是: 不再打死工,开一家自己的公司,实现小级别的财富自己")
);
//把文本存到向量知识库
simpleVectorStore.add(documentList);
return simpleVectorStore;
}
}
Document:文本对象,存储文字内容
simpleVectorStore:简单向量数据库,基于内存的,不需要安装部署,如果使用Redis、ES等作为向量数据库,那就得部署。并且Spring AI官方文档也说了,适合教育目的
向量知识库中存的是文本吗?错,存的是向量。可能大家都毕业大多年了,数学知识早就还给老师了。
向量可以理解为(x, y)的坐标轴,这是二维向量,A和B两个点,在坐标周中越近,说明相关性很强,越远说明没啥关系,那A和B两个点在坐标轴上存的是文字吗?肯定不是,存的肯定是数字,比如A(1,1) B(2, 2)。同理,一段文字存到向量数据库中,存的就是数字。这是拿二维举例,三维也是同理,三维就是(x, y, z)了,也就是长宽高,我们人类的生存空间就是三维的。那有四维吗?有,在我们大脑的想象中,有三维就有四维,甚至千维。那维数越大,向量化后的数字就越精细、越精准,查询时自然也越精准
2.6 Controller
package com.huqing.icu.rentai.controller;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
;
/**
* @Description 知识库接口,这个接口是参考参照尚硅谷的
* @Author huqing
* @Date 2025/6/7 14:11
**/
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/rag/chat")
@Tag(name = "AI对话接口")
public class RagController {
@Autowired
private ChatClient chatClient;
@Autowired
private VectorStore vectorStore;
@GetMapping(value = "/v1", produces = "text/html;charset=utf-8")
public Flux<String> chatV1() {
String prompt = "打工人的理想是是什么";
//.advisors(new QuestionAnswerAdvisor(vectorStore)),没有加这个代码,就不会去向量数据库检索,而是大模型自己回答
return chatClient.prompt().user(prompt).stream().content();
}
@GetMapping(value = "/v2", produces = "text/html;charset=utf-8")
public Flux<String> chatV2() {
String prompt = "打工人的理想是什么";
//.advisors(new QuestionAnswerAdvisor(vectorStore)),这个代码就是为了去向量数据库检索
return chatClient.prompt().user(prompt).advisors(new QuestionAnswerAdvisor(vectorStore)).stream().content();
}
}
在对话时,怎么才能去知识库中查呢?使用QuestionAnswerAdvisor。当用户问题发送至AI模型时,QuestionAnswerAdvisor会查询向量数据库获取与问题有关的文档。如果不用QuestionAnswerAdvisor,比如v1接口,那AI模型就自由发挥了
2.7 测试
先测试v1接口,不去知识库中查,由AI自由发挥
再测试v2接口,去知识库中查
可能有些人会说我问的问题跟写入知识库的文本几乎一模一样,那我现在换个问题
AI回答
更多推荐
所有评论(0)