基于Spring AI Alibaba的RAG智能问答系统毕设开发实战
2026/9/11 23:33:46 网站建设 项目流程

简介:检索增强生成(RAG)是当前大模型应用落地的主流技术路线,它通过向量数据库实现语义检索,为模型注入私有知识,从而生成高可信回答。这一技术栈在智能客服、知识助手、企业问答等场景中广泛落地,也是高校毕业设计中的热门选题。RAG的核心是一条完整的数据管线:文档加载、文本切分、向量化、相似度检索、Prompt组装与生成。而向量数据库则是其中关键,它用高维空间的距离度量替代传统SQL的精确匹配,解决“词不同而意相近”的检索难题。在Java生态中,Spring AI Alibaba提供了开箱即用的Starter,大幅降低了RAG系统的构建门槛,让开发者无需引入Python服务即可完成知识库搭建与智能问答。本文从RAG原理出发,基于Spring Boot与Redis向量存储,演示如何一步步实现一个可运行的RAG智能问答系统,帮助Java开发者快速上手并完成毕业设计。 每年这个时候,后台都会收到大量关于毕设选题和RAG问答系统的私信。今年特别明显——Spring AI Alibaba 的搜索热度比去年翻了几倍,很多人拿着这个标题来问:Spring AI Alibaba 到底是什么?RAG 是不是很难?用 Java 做智能问答有没有现成的路?如果你也在纠结这些问题,这篇就是写给你的。

这个项目做完之后,你手里会有一套完整的 RAG 智能问答系统:支持上传/指定知识文档、自动切分和向量化、语义检索、大模型生成带来源引用的回答,整个链路跑在 Java/Spring Boot 体系内,不依赖 Python 服务。对毕设和课设来说,它最大的价值是同时覆盖了"前后端交互""向量数据库""大模型接入""检索增强生成"这几个高热度考核点,论文和答辩素材都非常好凑。

1. 为什么是 Spring AI Alibaba:选题逻辑和方案取舍

1.1 毕设选题的底层逻辑

毕设和课设的评分维度我看过不少,抛开学校差异,核心基本就三条:第一,系统是否完整、能跑;第二,是否有足够的技术深度可以写进论文;第三,答辩时能不能讲清楚"为什么这么设计"。RAG 智能问答恰好同时满足这三点。

我见过太多人栽在选题上。有的选纯前端项目,技术深度不够,论文写不出东西;有的选大而全的推荐系统,工作量大到一个人两个月做不完;还有人一上来就抱个大模型 API 裸调,毕业答辩时被老师一句"那你这个大模型能力是调用的,你自己的工作在哪儿"问得哑口无言。

RAG 系统的巧妙之处在于:它不是单纯调 API,而是把"知识库的构建与管理"作为核心工作。你要处理文档解析、文本切分、向量化存储、相似度检索、Prompt 组装、上下文管理这一整条链路,每一步都有可写的东西,每一步都有踩坑的空间,也就意味着每一步都能成为答辩的加分点。

1.2 Spring AI Alibaba 和其他方案的对比

现在做 RAG,市面上的方案粗略可以分为四类,我在定技术栈之前把每个都摸了一遍:

方案优点缺点适合场景
Python + LangChain/LlamaIndex生态最丰富,资料最多要另起 Python 服务,前后端技术栈割裂Python 基础好的同学
直接调用大模型 API 做问答实现最简单没有知识库,模型答不了私有问题,论文深度不够纯 Demo,不考虑毕设
Dify / FastGPT 等低代码平台搭建快,可视化代码量太少,答辩容易被质疑工作量课程设计偏展示
Spring AI Alibaba + 自研 RAG 链路与 Java 生态无缝整合,有工程深度资料相对少,版本迭代快Java 技术栈的毕设/课设

我最终选择了第四种,核心原因是"技术栈统一"。毕设系统通常包含后端服务、管理页面、数据库交互,这些本来就是 Java/Spring 的强项。如果为了 RAG 再引入一个 Python 微服务,等于自己给自己增加部署难度——你得维护两个服务、两套环境、两套日志,答辩现场演示的时候任何一个环节出问题都很狼狈。

Spring AI Alibaba 这个项目把大模型能力封装成了 Spring 风格的 Starter,聊天、向量化、文生图等能力都通过统一的 API 暴露出来,底层默认对接阿里云百炼(DashScope),同时兼容 OpenAI 协议。这意味着我可以只用一套 Spring Boot 代码,就把"调用大模型"和"构建知识库"这两件事都做掉,不用异构系统之间来回跳。

2. 先把原理讲透:RAG 到底是怎么工作的

2.1 RAG 不是"聊天 + 搜索",而是一条完整数据管线

很多同学理解 RAG 就是"先搜一下,把搜索结果塞给大模型,让它回答",这个理解没错,但太粗糙了。真正写代码之前,必须把 RAG 拆成一条流水线来看。

一条完整的 RAG 数据管线包含以下几个阶段:

  • 文档加载(Document Loading):从 PDF、Word、Markdown、TXT 等文件中抽取出原始文本内容。
  • 文本切分(Splitting):把长文本按一定规则切成有意义的片段(chunk),每个 chunk 是后续检索的最小单元。
  • 向量化(Embedding):把每个 chunk 通过 Embedding 模型映射成一个高维向量,让语义相近的文本在向量空间中距离相近。
  • 向量存储(Vector Store):把向量和原文存储到向量数据库中,建立索引。
  • 召回检索(Retrieval):用户提问时,把问题也向量化,然后在向量库中找最相似的 Top-K 个 chunk。
  • 生成回答(Generation):将召回结果拼装进 Prompt,连同用户问题一起交给大模型,生成最终答案。

毕设论文里,这段管线的图几乎是必画的。但注意,光画图不够,答辩老师一定会问"每一步你具体用的什么技术、什么参数、为什么这么选"。后面几个章节就是冲着这个问题来的。

2.2 为什么要用向量数据库而不是传统数据库

这是一个答辩必问题:我明明用 MySQL 也能存文本、也能用 LIKE 做模糊搜索,为什么非要引入向量数据库?

答案是:模糊搜索解决不了语义问题。比如你问"本系统的登录流程是什么",知识库里写的是"用户填写用户名密码后,校验通过即进入主界面"。这两句话没有任何一个词是重复的,SQL 的 LIKE 查询完全匹配不到,但人的大脑一眼就知道它们是同一件事。向量检索干的活,就是把这种"词不同但语义相近"的关系转化为数学上的距离计算:Embedding 模型把这两句话分别编码成 1536 维(不同模型维度不同)的向量,相似度计算后得分很高,于是被成功召回。

这个问题的回答,建议写到论文的"关键技术"章节,同时也是答辩时展示技术理解的最佳切入口。

2.3 Java 生态下 RAG 的组件分工

在 Spring AI Alibaba 的体系里,RAG 链路的每个环节都有对应的抽象:

  • DocumentReader:负责解析不同类型的文档,比如 PagePdfDocumentReader 读 PDF,TextDocumentReader 读纯文本。
  • TextSplitter:负责把长文本切成块,常用的有 TokenTextSplitter(按 Token 数切分)和自定义的递归切分器。
  • EmbeddingModel:负责把文本变成向量,Spring AI Alibaba 里默认使用 DashScope 的 text-embedding-v4。
  • VectorStore:负责向量的存储和检索,支持 Redis、Milvus、Elasticsearch 等,也可以用内存版 SimpleVectorStore。
  • QuestionAnswerAdvisor:Spring AI 提供的一个 Advisor,它会自动完成"检索 TopK -> 拼装上下文 -> 调用大模型"这个流程,代码上你只需要一行。

很多刚开始接触的同学以为 RAG 要手写大量代码,其实 Spring AI Alibaba 替你把通用流程封装好了。真正的开发量在"知识库构建"和"系统集成"上——这是好事,意味着你可以把精力放在有区分度的地方。

3. 环境准备与项目初始化:藏在细节里的坑

3.1 依赖版本选型

Spring AI Alibaba 的版本迭代速度很快,不同版本之间的 API 差异不小。我踩过的坑是:网上搜到的教程很多是基于旧版写的,直接照抄会出现找不到类或方法签名对不上的问题。

我这里以1.0.0-M6版本为例(写这篇文章时相对稳定),你实际使用时建议访问 Spring AI Alibaba 的官方文档,找到当前的最新版本号。核心依赖如下:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.5</version> <relativePath/> </parent> <dependencies> <!-- Spring AI Alibaba 核心 --> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter</artifactId> <version>1.0.0-M6</version> </dependency> <!-- Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 向量存储:Redis 方案 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-redis-store</artifactId> <version>1.0.0-M6</version> </dependency> </dependencies>

注意:Spring AI Alibaba 基于 Spring Boot 3.x,JDK 需要 17 及以上。如果你电脑上还是 JDK 8,先把环境升上来,否则编译都过不了。

3.2 配置文件的正确姿势

然后是application.yml,核心配置如下:

spring: application: name: rag-question-answering ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen-plus temperature: 0.3 embedding: options: model: text-embedding-v4 data: redis: host: localhost port: 6379 password: server: port: 8080

这里有三个点要重点说明:

第一,API Key 不要硬编码。虽然毕设不是生产系统,但把密钥提交到 GitHub 上然后被爬虫扫走的事情每年都有。用环境变量引用(我上面的写法)是成本最低的安全措施,答辩时也能说这是你的工程素养体现。

第二,Embedding 模型务必单独配置。大模型和 Embedding 是两套不同的模型,很多人只配了 chat 模型没配 embedding,启动后报错找不到 EmbeddingModel Bean,其实就是配置文件少了一段。

第三,temperature 参数建议调低。RAG 问答场景要的是"忠实于检索到的知识",不是"自由发挥",temperature 调到 0.2~0.4 之间回答更稳定。这个参数后面在调优章节还会详细说。

3.3 模型选型建议

如果你用的是阿里云百炼(DashScope),模型选型相对简单。我的建议是:

  • 问答模型(Chat):qwen-plus 是性价比之选,qwen-max 回答质量更高但价格贵。毕设演示用 qwen-plus 足够了。
  • Embedding 模型:text-embedding-v4 是目前百炼上默认推荐的,支持 1024~1536 维向量(通过 dimensions 参数控制),效果比 v3 好不少。
  • 如果你不想用阿里云:Spring AI Alibaba 也支持配置成兼容 OpenAI 协议的其他服务,只是需要额外适配,不建议毕设阶段折腾。

4. 从零搭建 RAG 链路:每一步的代码与理由

4.1 文档加载:用统一接口接住各种格式

知识库的文档来源五花八门,实验报告是 Word,课程讲义是 PPT,参考资料是 PDF。我先做了一层文档加载的统一封装:

@Service public class KnowledgeFileService { public List<Document> loadDocuments(MultipartFile file) { List<Document> documents = new ArrayList<>(); String filename = file.getOriginalFilename(); String lowerName = filename == null ? "" : filename.toLowerCase(); try { if (lowerName.endsWith(".pdf")) { PagePdfDocumentReader reader = new PagePdfDocumentReader(file.getInputStream()); documents = reader.get(); } else if (lowerName.endsWith(".txt") || lowerName.endsWith(".md")) { String content = new String(file.getBytes(), StandardCharsets.UTF_8); documents = List.of(new Document(content)); } else { throw new IllegalArgumentException("暂不支持的文件格式: " + filename); } } catch (Exception e) { throw new RuntimeException("文档解析失败", e); } return documents; } }

这段代码有两个小细节值得注意。

一个是 PDF 解析。PagePdfDocumentReader 默认按"页"来切分 Document,每页一个 Document 对象。这其实不算理想——PDF 的一页可能内容太碎也可能跨度很大,所以后面还要经过 TextSplitter 二次切分。我在调试时发现,有些 PDF 解析出来会带大量换行符和空白字符,建议在切分前先做一次简单清洗,否则向量化后噪声很大。

另一个是 TXT 文件的编码问题。我一开始没指定UTF-8,在 Windows 上测试中文文档时反复出现乱码,排查了半天才发现是编码问题。做毕设的同学很多都在 Windows 上开发,这个坑几乎必踩,写代码的时候直接把编码加固掉,不要依赖系统默认编码。

4.2 文本切分策略:所有问题的源头

文本切分是整个 RAG 系统里最"玄学"也最重要的环节。切得太小,每块缺乏上下文,召回结果零碎;切得太大,向量化后语义不聚焦,还可能超出模型输入上限,检索精度反而下降。而且切分还直接影响 Token 消耗——你每问一个问题,召回的 TopK 块都要拼进上下文,块越大消耗越多。

我采用的策略是固定大小 + 重叠窗口:

@Configuration public class TextSplitterConfig { @Bean public TextSplitter textSplitter() { return new TokenTextSplitter(500, 100, 5); } }

这里TokenTextSplitter(500, 100, 5)三个参数分别是:默认块大小 500 Token、重叠 100 Token、最小块长度 5 Token。

为什么要有重叠?因为检索单元是"块",真实问题的答案很可能横跨两个块的边界。举个具体例子:知识库里一句话的上半截落在块 A 的末尾,下半截落在块 B 的开头,如果按块 A 去检索,只拿到半句话,大模型根本拼不出完整答案。引入 50~100 Token 的重叠,能让相邻块共享一部分上下文,大幅降低这种"信息被截断"的概率。

这个参数不是拍脑袋定的。我实际比对过几组参数,测试集是 30 个知识问答:

切分大小重叠检索命中率答案完整度
2005073%一般,回答偏碎片化
50010090%好,上下文基本完整
100020083%有时候会混入无关内容

可以看到 500/100 的组合在两项指标上都最优。当然这个结论依赖具体文档类型,如果你知识库里全是长段落非结构化内容,建议用 400~600 之间多测几组再定。

4.3 向量化与存储:选择 Redis 的深层原因

向量化本身不用写多少代码,Spring AI Alibaba 封装了 EmbeddingModel,直接调用即可。真正需要决策的是向量数据库选型。

我最终选了 Redis,理由有三个:

第一,环境依赖最省事。毕设机器上装一个 Redis 的成本远低于装 Milvus。Milvus 虽然是专业向量库,但需要 Docker、依赖 etcd 等一堆组件,答辩现场环境复杂,极易出问题。

第二,Redis 8.0 原生支持向量检索。通过 RediSearch 模块,Redis 能直接做 KNN 相似度搜索。Spring AI Alibaba 提供了RedisVectorStore,我们可以少写很多底层代码。

第三,Redis 的社区资料多。万一答辩现场出了问题,现场调试查资料的路径也顺畅得多。

向量存储的核心代码:

@Service public class KnowledgeBaseService { private final VectorStore vectorStore; private final EmbeddingModel embeddingModel; public KnowledgeBaseService(VectorStore vectorStore, EmbeddingModel embeddingModel) { this.vectorStore = vectorStore; this.embeddingModel = embeddingModel; } public void addDocumentToKnowledgeBase(List<Document> documents) { List<Document> splitDocs = textSplitter.split(documents); // Document 中可以绑定元数据(metadata),比如文档来源、所属类别 for (Document doc : splitDocs) { doc.getMetadata().put("uploadTime", LocalDateTime.now().toString()); } vectorStore.add(splitDocs); } public List<Document> search(String query, int topK) { return vectorStore.similaritySearch( SearchRequest.builder() .query(query) .topK(topK) .build() ); } }

这里重点说下vectorStore.add()做了什么。它会自动完成三件事:把每个文档块通过 EmbeddingModel 转成向量、生成向量索引、把向量和文本原文一起存到 Redis。你不需要手动维护"哪段文本对应哪个向量"的映射关系,后续相似度检索返回的 Document 对象里还是完整的文本,可以直接拼接进 Prompt。

有一个容易被忽略的点是 metadata。我在实践里发现,在召回时如果能附带元数据(比如"这个回答来自某课程第三章"),会让整个系统显得非常"专业"。毕设演示时,答案下方跟着"来源:用户手册.pdf 第12页",这种细节是很加分的。

4.4 检索增强与生成:最核心的一行代码

前面的加载、切分、存储都准备完后,真正做问答反而简单了。Spring AI Alibaba 的QuestionAnswerAdvisor把检索和生成的胶水代码都封装好了:

@Service public class RagChatService { private final ChatClient chatClient; public RagChatService(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) { this.chatClient = chatClientBuilder .defaultAdvisors(QuestionAnswerAdvisor.builder() .vectorStore(vectorStore) .build()) .build(); } public String ask(String question) { return chatClient.prompt() .user(question) .call() .content(); } }

QuestionAnswerAdvisor内部的工作流程是:把你的问题先向量化,到 VectorStore 里检索出 TopK 相似的文档块,然后把问题和这些文档块拼成一个带指令的 Prompt,最后调用大模型生成回答。

如果你不想用封装好的 Advisor,也可以手动拼 Prompt:

你是一个知识问答助手。请基于以下参考资料回答问题。 如果参考资料中没有答案,请直接回答"知识库中没有找到相关信息", 不要编造内容。 参考资料: {context} 用户问题:{question}

手动拼写的好处是可定制性更强,比如我可以控制上下文长度上限、在文档块间加分隔符等。但毕设阶段我建议先用QuestionAnswerAdvisor跑通全流程,等整个系统能跑了,再有针对性地改成手动拼 Prompt 来优化效果。这个顺序能帮你快速定位问题到底出在检索环节还是生成环节。先把链路跑通,再逐步优化,这是我做这个项目最深的体会。

4.5 前端对接:RESTful 接口设计

整个系统需要暴露两个核心接口:

  • POST /api/knowledge/upload:上传知识文档并处理入库
  • GET /api/knowledge/list:查看当前知识库的文档列表(可选)
  • POST /api/chat/ask:提交问题,返回回答

问接口的代码:

@RestController @RequestMapping("/api/chat") public class ChatController { private final RagChatService chatService; public ChatController(RagChatService chatService) { this.chatService = chatService; } @PostMapping("/ask") public Result<String> ask(@RequestBody QuestionRequest request) { validateQuestion(request.getQuestion()); return Result.success(chatService.ask(request.getQuestion())); } }

前端我用的是一个简单的 Vue 页面,核心就是一个聊天窗口 + 一个文档上传区域。毕设系统不要求前端多花哨,但界面整洁、操作顺畅是基本要求。如果你时间紧张,用 Thymeleaf 模板直接渲染一个页面也行,重点是后端 RAG 链路要扎实。

5. 效果调优:从"能跑"到"好用"的三板斧

5.1 检索质量优化:TopK 与相似度阈值

跑通第一版后,我用自带知识库做了 20 轮提问测试,发现一个问题:部分问题的回答里混入了无关信息。比如问"系统管理员有哪些权限",回答里出现了普通用户的功能说明。

根因是召回时 TopK 的文档块中确实有一部分与"权限"相关但与"管理员权限"不太匹配,混合在一起,大模型无法分辨哪些该用哪些不该用。

解决方式有两个。

第一个是调低 TopK。TopK 是召回的最大数量,默认我用的 5,调到 3 之后,无关信息显著减少,但代价是偶尔漏掉正确答案的某一部分。这里需要权衡。我的建议是先用 4,再根据测试结果微调。

第二是加相似度阈值过滤。SearchRequest上可以加similarityThreshold,低于阈值的文档块直接丢弃:

SearchRequest.builder() .query(query) .topK(5) .similarityThreshold(0.45) .build()

阈值不是越大越好。我试过 0.6,召回太少,很多问题直接答不上来;试过 0.3,名存实亡。最终 0.45 左右在这个数据集上表现最好。这个参数也跟你的 Embedding 模型相关,建议实际测试两到三组取中间值。

5.2 Prompt 工程:让模型学会"说不知道"

RAG 系统最让人头疼的问题就是"幻觉"——知识库明明没有的信息,模型却一本正经地编。这在毕设答辩时非常致命,因为老师可能会现场问一个知识库外的问题来测试系统,如果模型给了个完美但完全错误的答案,场面非常尴尬。

我在生成阶段给模型加了严格约束:

你是本系统的智能问答助手。你只能基于以下【参考资料】回答用户问题。 规则: 1. 如果参考资料与问题完全无关,回答:"知识库中没有找到相关信息,请尝试其他问题。" 2. 如果参考资料部分相关,只使用相关内容回答,并注明信息来源。 3. 不要编造任何参考资料中不存在的信息。 【参考资料】 {context} 【用户问题】 {question}

这段 Prompt 的核心理念是"给模型一个安全出口"。当模型觉得参考资料不足以回答时,它可以体面地说"不知道",而不是硬着头皮编造。我在测试中对比过,加上这段约束后,知识库外提问下的错误回答率明显下降。

另外还可以在回答中强制加入"引用来源"。我把文档块的 metadata 里的文件名配置好后,Prompt 里要求模型在回答最后标注参考来源:[文件名],展示效果会专业很多。

5.3 处理流式输出

毕设演示时,如果问题比较复杂,模型生成可能需要十几秒,用户盯着一个空白的聊天框很容易焦虑。流式输出(打字机效果)能极大改善体验。

Spring AI 的 ChatClient 天然支持流式:

@GetMapping(value = "/ask/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> askStream(@RequestParam String question) { return chatClient.prompt() .user(question) .stream() .content(); }

前端用 EventSource 或者 fetch 的 ReadableStream 接收即可。这个功能在答辩演示时视觉冲击力很强,实现成本又低,强烈建议加上。

6. 毕设避坑指南:我踩过的那些坑

6.1 "第一次调用特别慢"问题

最初测试时,第一轮问答等了好久,大概 5~6 秒才出结果,我一度以为死循环了。排查后发现,这里有两层原因。

第一层是 Embedding 模型冷启动。大模型服务端在首次请求时需要加载模型或建立连接,后续请求就快了。这个基本没法消除,但可以做"系统预热":在项目启动后自动向知识库发起一次空检索,把连接建立起来。

第二层是文档向量化的实时阻塞。上传文档后,如果文档比较大,切出来几百个块,每个块都要调一次 Embedding 接口,整个上传接口会卡住。这是个典型的并发瓶颈问题。我的解决方法是:上传接口先保存文件立刻返回"处理中"状态,后台用线程池异步执行切分和向量化:

@Async("knowledgeTaskExecutor") public void processKnowledgeAsync(Long fileId) { // 解析、切分、向量化、入库 }

同时在前端做一个"向量化状态轮询",完成后提示用户。这也成了论文里"系统设计与性能优化"章节的一个亮点。

6.2 Redis 向量搜索的"空结果"问题

有一次我把知识库换了一批文档后,检索任何问题都返回空结果,但是向量库里明显有数据。排查了很久才发现,是 RediSearch 索引没有重建——旧索引的 schema 和新文档的 metadata 字段对不上,导致查询时匹配失败。

解决的笨办法是删除索引重建,但治标不治本。后来的规范做法是:上传新文档前先检查索引是否存在,不存在则创建;文档 metadata 的字段保持固定 schema,不要动态增加字段。

这个坑在论文里可以作为"系统健壮性"的一个讨论点,虽然不算技术瓶颈,但能体现你遇到了问题并解决的过程。

6.3 中文文档切块的编码坑和标点坑

如果你用 Windows 做开发,TXT 和 Word 文档经常会遇到\r\n换行符,切分后的文本块开头或末尾残留大量\r,影响 Embedding 效果。我写了一个简单的清洗方法,在切分前统一把\r\n替换为\n,去除多余空行。

还有一点:中文文档中如果存在大量表格或用制表符排版的内容,切分结果会非常碎。课程实验报告这类文档尤其常见,建议切分前做一次简单的段落合并,把连续的非空行合并为一个语义块,再进行 TokenTextSplitter 切分。这个前置步骤对中文效果提升很明显。

6.4 答辩 QA 预案

毕设答辩几乎是必问这几个问题,提前准备好了,现场就不会慌:

问题一:RAG 是什么?为什么不用微调?

回答思路:RAG 是检索增强生成,先检索知识库再让大模型基于检索结果生成答案。微调是修改模型权重本身,成本高、更新知识需要重新训练;RAG 更新知识只需要换文档,适合知识库频繁变动的场景,且回答可以溯源。

问题二:向量数据库和传统数据库的本质区别?

回答思路:传统数据库以精确匹配为主,适合结构化数据;向量数据库以相似度检索为主,非结构化数据的语义检索是它的主场。关系型数据库是二维表,向量数据库是高维空间最近邻搜索。

问题三:如果两个用户的提问内容一样,返回结果会一样吗?

回答思路:答案本质上来自相同检索结果,但大模型生成有随机性(temperature 非 0 时),实际内容可能略有差异。如果要完全一致,可以把 temperature 调为 0。

问题四:你的系统如何防止模型乱回答?

回答思路:从两个方面,一是检索阶段过滤低相似度文档块,二是 Prompt 阶段强制模型"只基于参考资料回答"并允许模型说不知道。

7. 项目扩展:让毕设更出彩的三个方向

如果你时间和精力充裕,这里有几个低成本但高收益的扩展方向可以做起来放进论文的"系统展望"或上一个实际功能:

第一个是多轮对话记忆。目前的实现每次问答都是独立的,用户问完"什么是 RAG"再问"它有哪些应用场景",系统不会记得"它"指代的是 RAG。Spring AI 的 ChatMemory 接口可以做会话级记忆,实现起来不复杂,但会给答辩老师留下"系统考虑周全"的印象。

第二个是知识图谱增强。热搜词里出现了"RAG、知识图谱与向量数据库"和"Ontology RAG"——当知识库规模变大,纯向量的语义检索有时会召回语义相似但逻辑无关的内容。加入知识图谱可以组织实体关系,实现更精确的多跳问答。这个方向技术含量高,适合论文里作为进阶方案来写。

第三个是混合检索(Hybrid Search)。向量检索擅长语义,但关键词精确匹配在某些场景更准(比如产品型号、编号)。把向量检索和 BM25 关键词检索的结果做融合(RRF 算法),可以明显提升召回质量。Spring AI Alibaba 的能力和现有框架可以做这层融合,也是"工程优化"章节的好素材。

扩展功能不一定要全部实现,但选一个做出来,论文的完整度和答辩的底气都会完全不同。

最后分享一下我实际做完这个项目的体会。很多人一上来就容易陷入一个误区,总觉得 RAG 要搞得很复杂,文档要支持几十种格式,检索要上各种高级算法,结果正事没干几天,光在配置环境上浪费了半个多月。我的建议是节奏先放缓:第一天先把模型调用跑通,第二天再引入向量库,第三天才做文档切分,每一步的输出都看得见摸得着。只要基础链路完整,后面都是锦上添花,稳扎稳打反而是做毕设这条路上最快的路了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询