🎉🎉《Spring Boot实战案例合集》目前已更新147个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
本篇文章将使用 Spring AI 实现网页问答。给定一个网页地址,在本案例中应用程序会将其内容加载到向量数据库中进行存储,当我们进行提问时,会先从向量数据库中进行相似性查询,将查询到的结果 + 用户的提问 一起发送给 LLM 形成最终的回答返回给用户。
2.1 准备环境
引入依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-advisors-vector-store</artifactId></dependency><!--使用ollama上的bge-m3模型将文本生成向量数据--><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-ollama</artifactId></dependency><!--将向量数据存入Miluvs向量数据库--><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-milvus</artifactId></dependency><!--阿里百炼平台--><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-autoconfigure-dashscope</artifactId><version>1.0.0.2</version></dependency><!--使用该库进行网页内容的读取--><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.18.3</version></dependency>
配置文件
spring:ai:dashscope:api-key: sk-xxxooobase-url: https://dashscope.aliyuncs.com/compatible-mode/v1chat:options:model: qwen-turboembedding:enabled: false---spring:ai:ollama:base-url: http://localhost:11111embedding:model: bge-m3:latest---spring:ai:vectorstore:milvus:client:host: localhostport: 19530username: xxxpassword: oooinitialize-schema: truedatabaseName: "mydb"collectionName: "mydocs"autoId: trueid-field-name: idembeddingDimension: 1024
由于我们同时引入了ollama及阿里的百炼,这时候的ChatClient及Embedding就会配置2个;所以,我们这里要将不用的排除自动配置:
@SpringBootApplication(exclude = {OllamaChatAutoConfiguration.class,DashScopeEmbeddingAutoConfiguration.class})public class SpringBootAiWebQaApplication {}
以上基础环境就配置完成了,接下来我们就可以实现具体的功能了。
2.2 文档读取器
首先,我们要根据提供的URL加载网页内容。通过 jsoup 库来完成。而这里我们需要实现 Spring AI 中 DocumentReader 接口,它负责将网页内容转换为 Document 对象。
public class WebDocumentReader implements DocumentReader {private static final Logger logger = LoggerFactory.getLogger(WebDocumentReader.class);private final String url;public WebDocumentReader(String url) {this.url = url;}public List<Document> get() {try {X509ExtendedTrustManager trustManager = createTrustManager();SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());org.jsoup.nodes.Document doc = Jsoup.connect(url).sslSocketFactory(sslContext.getSocketFactory()).get();Map<String, Object> metadata = Map.of("source", url,"date", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));return List.of(new Document(doc.body().text(), metadata));} catch (Exception e) {logger.error("加载【{}】发生错误: {}", this.url, e);return List.of() ;}}private X509ExtendedTrustManager createTrustManager() {return new X509ExtendedTrustManager() {public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}// 其它方法};}}
2.3 文档写入向量数据库
在上一步我们将网页内容转换为Document对象后,接下来,我们就需要对这些Document切割并保存到向量数据库。
public class WebDocumentService {private final VectorStore vectorStore ;public WebDocumentService(VectorStore vectorStore) {this.vectorStore = vectorStore;}public void save(String url) {WebDocumentReader reader = new WebDocumentReader(url) ;List<Document> docs = reader.get() ;TokenTextSplitter splitter = new TokenTextSplitter(1000, 400, 10, 5000, true);List<Document> result = splitter.apply(docs);this.vectorStore.add(result) ;}}
Spring AI还提供了如下几种切割文档的实现:
TokenTextSplitter
该类 是 TextSplitter 的一种实现,它使用 CL100K_BASE 编码,根据标记数将文本分割成块。
ContentFormatTransformer
内容格式转换器
KeywordMetadataEnricher
一个文档转换器,它使用生成式人工智能模型从文档内容中提取关键词,并将其添加为元数据。
SummaryMetadataEnricher
摘要元数据丰富器(SummaryMetadataEnricher)是一个文档转换器,它使用生成式人工智能模型为文档创建摘要并将其添加为元数据。它可以为当前文档以及相邻文档(上一个和下一个)生成摘要。
2.4 配置ChatClient
public class ChatConfig {ChatClient chatClient(ChatClient.Builder builder, VectorStore vectorStore) {// 默认是英文的,所以我们这里简单点就是翻译过来PromptTemplate promptTemplate = new PromptTemplate("""上下文信息如下。---------------------{context}---------------------根据上下文信息且无先验知识的情况下,回答查询。遵循以下规则:1.如果答案不在上下文中,直接说明"我不知道"。2.避免使用"根据上下文……"或"提供的信息……"等表述。查询: {query}回答:""") ;QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder().promptTemplate(promptTemplate ).build() ;Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder().queryAugmenter(queryAugmenter).documentRetriever(VectorStoreDocumentRetriever.builder().similarityThreshold(0.40).topK(1).vectorStore(vectorStore).build()).build();List<Advisor> advisors = List.of(new SimpleLoggerAdvisor(), retrievalAugmentationAdvisor);return builder.defaultAdvisors(advisors).build() ;}}
上面我们配置了 RetrievalAugmentationAdvisor 切面,Spring AI 包含一系列检索增强生成(RAG)模块库,你可利用这些模块构建自己的 RAG 流程。RetrievalAugmentationAdvisor 是一个顾问类(Advisor),它基于模块化架构,为最常见的 RAG 流程提供了开箱即用的实现方案。
简单说,该切面就是根据你的提示词(你的问题)到向量数据库中进行查询数据,最后将查询的结果一起发送给大模型。
2.5 Controller接口
定义两个接口,分别用来将网页内容存入向量数据库和聊天对话。
public class WebController {private final WebDocumentService webDocumentService ;public WebController(WebDocumentService webDocumentService) {this.webDocumentService = webDocumentService;}public ResponseEntity<?> load(String url) {this.webDocumentService.save(url) ;return ResponseEntity.ok("success") ;}}public class ChatController {private final ChatClient chatClient ;public ChatController(ChatClient chatClient) {this.chatClient = chatClient;}public ResponseEntity<?> chat(String prompt) {String body = this.chatClient.prompt(prompt).call().content() ;return ResponseEntity.ok(body) ;}}
2.6 测试
首先,我们将如下的url网页内容保存到向量数据库中
https://news.cctv.com/2025/07/12/ARTIQut4IA1QEu4yRQfAyTfj250712.shtml?spm=C73544894212.P9moqzeXHoOr.EogkW3VdRtw6.8
数据成功保存到Milvus中,并且对应的文本都转换为向量数据。
接下来进行查询
控制台输出如下:
推荐文章
Spring Boot 加载配置的6种骚操作,第6种知道的人很少
Spring Boot Rest API十大常见错误及避免方法
技术专家:零代码,Spring Boot存储加密解密,支持JDBC、MyBatis及JPA
基于 Spring Boot 玩转JPA各种锁的应用(乐观锁,悲观锁)
Tika 与 Spring Boot 的完美结合:支持任意文档解析的神器
Jackson才是王!SpringBoot优雅的控制JSON数据


