开发者

浅析如何利用Spring AI构建一个简单的问答系统

开发者 https://www.devze.com 2025-05-20 10:32 出处:网络 作者: 风象南
目录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. 引
目录
  • 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密钥

      浅析如何利用Spring AI构建一个简单的问答系统

      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,并展示回答结果。

      浅析如何利用Spring 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)!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号