目录
- 1. 引言
- 2. 环境准备
- 2.1 项目依赖
- 2.2 配置API密钥
- 3. 核心代码实现
- 3.1 主应用类
- 3.2 请求模型
- 3.3 问答服务
- 3.4 REST控制器
- 3.5 简单html前端
- 4. 运行与测试
- 5. 功能扩展
- 5.1 添加对话历史
- 5.2 添加知识库集成
- 6. 总结
1. 引言
随着大语言模型(LLM)技术的不断发展,将AI能力集成到企业应用中变得越来越重要。Spring AI是Spring生态系统的最新成员,旨在简化AI服务与Spring应用的集成过程。
本文将详细介绍如何利用Spring AI构建一个简单的问答系统,帮助开发者快速入门AI应用开发。
2. 环境准备
2.1 项目依赖
首先,创建一个Spring Boot项目,并添加必要的依赖
<?XML version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>spring-ai-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <repositories> <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> <repository> <name>Central Portal Snapshots</name> <id>central-portal-snapshots</id> <url>https://central.sonatype.com/repository/maven-snapshots/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-core</artifactId> <version>1.0.0-M6</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.25</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>21</source> <target>21</target> <encoding>utf-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>3.2.0</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
2.2 配置API密钥
在application.yml
中配置API密钥
server: port: 5555 spring: ai: openai: api-key: sk-xxxxx # 需要替换为上图所示的硅基流动API密钥 base-url: https://api.siliconflow.cn/ embedding: options: model: BAAI/bge-m3 chat: options: model: deepseek-ai/DeepSeek-V3
注意:为了安全起见,建议通过环境变量注入API密钥,而不是直接硬编码在配置文件中。
3. 核心代码实现
3.1 主应用类
创建Spring Boot应用的入口类:
import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.vectorstore.SimpleVectorStore; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import Java.util.List; @SpringBootApplication public class QaApplication { public static void main(String[] args) { SpringApplication.run(QaApplication.class, args); } @Bean public ChatClient chatClient(OpenAiChatModel model){ return ChatClient .builder(model) .build(); } @Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { VectorStore vectorStore = SimpleVectorStore.builder(embeddingModel).build(); php // 构建测试数据 List<Document> documents = List.of(new Document("Hello Spring AI"), new Document("Hello Spring Boot")); // 添加到向量数据库 vectorStore.add(documents); return vectorStore; } }
3.2 请求模型
创建一个简单的模型类来封装问题请求:
import lombok.Data; @Data public class QuestionRequest { private String question; private String sessionId; }
3.3 问答服务
实现问答核心服务:
import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service public class QaService { private final ChatClient chatClient; private final PromptTemplate promptTemplate; @Autowired public QaService(ChatClient chatClient) { this.chatClient = chatClient; // 创建一个提示模板,指导AI如何回答问题 this.promptTemplate = new PromptTemplate(""" 你是一个智能问答助手,请简洁、准确地回答用户的问题。 如果你不知道答案,请直接说不知道,不要编造信息。 用户问题: {question} 回答: """); } public String getAnswer(String question) { // 准备模板参数 Majavascriptp<String, Object> parameters = new HashMap<>(); parameters.put("question", question); // 创建提示 Prompt prompt = promptTemplate.create(parameters); // 调用AI获取回答 return chatClient.prompt(prompt).call().content(); } }
3.4 REST控制器
创建REST API接口,处理问题请求:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/qa") public class QaController { private final QaService qaService; private final ConversationService conversationService; private final KnowledgeBaseQaService knowledgeBaseQaService; @Autowired public QaController(QaService qaService, ConversationService conversationService, KnowledgeBaseQaService knowledgeBaseQaService ) { this.qaService = qaService; this.conversationService = conversationService; this.knowledgeBaseQaService = knowledgeBaseQaService; } @PostMapping("/ask") public Map<String, String> askQuestion(@RequestBody QuestionRequest request) { String answer = qaService.getAnswer(request.getQuestion()); Map<String, String> response = new HashMap<>(); response.put("question", request.getQuestion()); response.put("answer", answer); return response; } @PostMapping("/ask-session") public Map<String, String> askSession(@RequestBody QuestionRequest request) { String answer = conversationService.chat(request.getSessionId(),request.getQuestion()); Map<String, String> response = new HashMap<>(); response.put("question", request.getQuestion()); response.put("answer", answer); return response; } @PostMapping("/ask-knowledge") public Map<String, String> askKnowledge(@RequestBody QuestionRequest request) { String answer = knowledgeBaseQaService.getAnswerWithKnowledgeBase(request.getQuestion()); Map<String, String> response = new HashMap<>(); response.put("question", request.getQuestion()); response.put("answer", answer); return response; } }
3.5 简单HTML前端
在src/main/resources/static
目录下创建一个简单的HTML页面(qa.html):
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AI问答系统</title> <style> body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; } .container { border: 1px solid #ddd; border-radius: 5px; padding: 20px; margin-top: 20px; } .question-form { margin-bottom: 20px; } #question { width: 100%; padding: 10px; margin-bottom: 10px; border: 1px solid #ddd; border-radius: 4px; } button { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; } button:hover { background-color: #45a049; } .answer { margin-top: 20px; padding: 15px; background-color: #f9f9f9; border-radius: 4px; white-space: pre-wrap; } .loading { color: #888; font-style: italic; display: none; } </style> </head> <body> <h1>AI问答系统</h1> <div class="container"> <div class="question-form"> <h2>请输入您的问题</h2> <textarea id="question" rows="4" placeholder="例如:什么是Spring AI?"></textarea> <button id="ask-button">提问</button> <p class="loading" id="loading">AI正在思考中,请稍候...</p> </div> <div class="answer" id="answer-container"> <h2>回答</h2> <div id="answer-text"></div> </div> </div> <script> document.getElementById('ask-button').addEventListener('click', async function() { const question = document.getElementById('question').value.trim(); if (!question) { alert('请输入问题'); return; } // 显示加载状态 document.getElementById('ljavascriptoading').style.display = 'block'; document.getElementById('answer-container').style.display = 'none'; try { // 普通模式 /api/qa/ask // 会话模式 /api/qa/ask-session // 知识库模式 /api/qa/ask-knowledge const response = await fetch('/api/qa/ask', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question: question, sessionId: '12345' }) }); if (!response.ok) { throw new Error('服务器错误'); } const data = await response.json(); // 显示回答 document.getElementById('answer-text').textContent = data.answer; document.getElementById('answer-container').style.display = 'block'; } catch (error) { console.error('Error:', error); document.getElementById('answer-text').textContent = '发生错误: ' + error.message; document.getElementById('answer-container').style.display = 'block'; } finally { // 隐藏加载状态 document.getElementById('loading').style.display = 'none'; } }); </script> </body> </html>
4. 运行与测试
完成上述代码后,运行Spring Boot应用:
mvn spring-boot:run
或者使用IDE直接运行QaApplication
类。
启动后,访问http://localhost:5555/qa.html
,即可使用问答系统。在文本框中输入问题,点击"提问"按钮后,系统会将问题发送给AI,并展示回答结果。
5. 功能扩展
这个基础的问答系统可以通过以下方式进行扩展
5.1 添加对话历史
改进服务,支持多轮对话
import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @Service public class ConversationService { private final ChatClient chatClient; // TODO 此处仅为简单模拟,实际应为数据库或其他存储方式 private final Map<String, List<Message>> conversations = new ConcurrentHashMap<>(); @Autowired public ConversationService(ChatClient chatClient) { this.chatClient = chatClient; } public String chat(String sessionId, String userMessage) { // 获取或创建会话历史 List<Message> messages = conversations.computeIfAbsent(sessionId, k -> new ArrayList<>()); // 添加用户消息 messages.add(new UserMessage(userMessage)); // 创建带有历史上下文的提示 Prompt prompt = new Prompt(messages); // 调用AI String response = chatClient.prompt(prompt).call().content(); // 保存AI回复 messages.add(new AssistantMessage(response)); // 管理会话长度,避免超出Token限制 if (messages.size() > 10) { messages = messages.subList(messages.size() - 10, messages.size()); conversations.put(sessionId, messages); } return response; } public void clearConversation(String sessionId) { conversations.remove(sessionId); } }
5.2 添加知识库集成
使用向量存储和检索增强生成(RAG)
import org.springframework.ai.chat.client.ChatClient; import org.springfttMomramework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.Embedding; import org.springframework.ai.vectorstore.SearchRequest; import pythonorg.springframework.ai.vectorstore.VectorStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; @Service public class KnowledgeBaseQaService { private final ChatClient chatClient; private final VectorStore vectorStore; @Autowired public KnowledgeBaseQaService( ChatClient chatClient, VectorStore vectorStore) { this.chatClient = chatClient; this.vectorStore = vectorStore; } public String getAnswerWithKnowledgeBase(String question) { // 在知识库中搜索相关文档 List<Document> relevantDocs = vectorStore.similaritySearch(question); // 构建上下文 StringBuilder context = new StringBuilder(); for (Document doc : relevantDocs) { context.append(doc.getText()).append("\n\n"); } // 创建提示模板 PromptTemplate promptTemplate = new PromptTemplate(""" 你是一个智能问答助手。请根据以下提供的信息回答用户问题。 如果无法从提供的信息中找到答案,请基于你的知识谨慎回答,并明确指出这是你的一般性了解。 参考信息: {context} 用户问题: {question} 回答: """); // 准备参数 Map<String, Object> parameters = new HashMap<>(); parameters.put("context", context.toString()); parameters.put("question", question); // 创建提示并调用AI Prompt prompt = promptTemplate.create(parameters); return chatClient.prompt(prompt).call().content(); } }
6. 总结
本文详细介绍了如何使用Spring AI创建一个简单的问答系统。通过Spring AI提供的抽象层,我们能够轻松地集成大语言模型,无需深入了解底层API细节。这种方式可以让开发者专注于业务逻辑,同时保持了Spring生态系统的一致性。。
到此这篇关于浅析如何利用Spring AI构建一个简单的问答系统的文章就介绍到这了,更多相关Spring AI构建问答系统内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论