Spring AI与RAG技术实战:构建企业级智能文档问答系统
引言
在人工智能技术飞速发展的今天,如何将AI能力有效集成到企业应用中成为了技术团队面临的重要挑战。Spring AI作为Spring生态系统中的AI集成框架,结合RAG(检索增强生成)技术,为企业构建智能文档问答系统提供了强大的技术支撑。本文将深入探讨如何使用Spring AI和RAG技术构建高效、准确的企业级智能问答系统。
技术架构概述
核心组件
- Spring AI框架:提供统一的AI模型接入和调用接口
- RAG架构:检索增强生成技术,结合向量数据库和语义搜索
- 向量数据库:使用Milvus或Chroma存储文档向量
- Embedding模型:OpenAI或Ollama提供的文本向量化能力
- Spring Boot:作为应用基础框架
系统架构设计
用户请求 → Spring Boot应用 → 语义检索模块 → 向量数据库
↓
上下文增强 → AI模型 → 响应生成
环境准备与依赖配置
Maven依赖配置
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>0.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.milvus</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.3.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
应用配置
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-3.5-turbo
temperature: 0.7
data:
redis:
host: localhost
port: 6379
milvus:
host: localhost
port: 19530
核心功能实现
1. 文档处理与向量化
@Service
public class DocumentProcessor {
@Autowired
private EmbeddingClient embeddingClient;
@Autowired
private MilvusService milvusService;
public void processDocument(String documentContent, String documentId) {
// 文档分块处理
List<String> chunks = splitDocument(documentContent);
// 生成向量嵌入
List<List<Double>> embeddings = generateEmbeddings(chunks);
// 存储到向量数据库
storeInVectorDB(chunks, embeddings, documentId);
}
private List<String> splitDocument(String content) {
// 实现文档分块逻辑,每块约500字
return TextSplitter.splitByLength(content, 500);
}
private List<List<Double>> generateEmbeddings(List<String> chunks) {
return embeddingClient.embed(chunks);
}
private void storeInVectorDB(List<String> chunks,
List<List<Double>> embeddings,
String documentId) {
milvusService.insertVectors(chunks, embeddings, documentId);
}
}
2. 语义检索模块
@Service
public class SemanticSearchService {
@Autowired
private EmbeddingClient embeddingClient;
@Autowired
private MilvusService milvusService;
public List<SearchResult> searchRelevantContent(String query, int topK) {
// 生成查询向量
List<Double> queryVector = embeddingClient.embed(query);
// 在向量数据库中搜索相似内容
return milvusService.searchSimilarVectors(queryVector, topK);
}
public class SearchResult {
private String content;
private double similarity;
private String documentId;
// getters and setters
}
}
3. RAG问答服务
@Service
public class RAGQuestionAnsweringService {
@Autowired
private ChatClient chatClient;
@Autowired
private SemanticSearchService searchService;
public String answerQuestion(String question) {
// 检索相关文档内容
List<SearchResult> relevantContents =
searchService.searchRelevantContent(question, 5);
// 构建增强的提示词
String enhancedPrompt = buildEnhancedPrompt(question, relevantContents);
// 调用AI模型生成回答
return chatClient.generate(enhancedPrompt);
}
private String buildEnhancedPrompt(String question,
List<SearchResult> relevantContents) {
StringBuilder prompt = new StringBuilder();
prompt.append("请基于以下上下文信息回答问题:\n\n");
for (SearchResult result : relevantContents) {
prompt.append("上下文:").append(result.getContent()).append("\n\n");
}
prompt.append("问题:").append(question).append("\n\n");
prompt.append("请提供准确、详细的回答:");
return prompt.toString();
}
}
4. REST API控制器
@RestController
@RequestMapping("/api/rag")
public class RAGController {
@Autowired
private RAGQuestionAnsweringService qaService;
@Autowired
private DocumentProcessor documentProcessor;
@PostMapping("/ask")
public ResponseEntity<String> askQuestion(@RequestBody QuestionRequest request) {
try {
String answer = qaService.answerQuestion(request.getQuestion());
return ResponseEntity.ok(answer);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("处理问题时发生错误:" + e.getMessage());
}
}
@PostMapping("/document")
public ResponseEntity<String> processDocument(@RequestBody DocumentRequest request) {
try {
documentProcessor.processDocument(
request.getContent(),
request.getDocumentId()
);
return ResponseEntity.ok("文档处理成功");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文档处理失败:" + e.getMessage());
}
}
public static class QuestionRequest {
private String question;
// getter and setter
}
public static class DocumentRequest {
private String content;
private String documentId;
// getters and setters
}
}
高级特性实现
1. 对话记忆管理
@Service
public class ConversationMemoryService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String CONVERSATION_PREFIX = "conv:";
public void saveConversationTurn(String sessionId,
String userMessage,
String aiResponse) {
ConversationTurn turn = new ConversationTurn(userMessage, aiResponse);
redisTemplate.opsForList().rightPush(
CONVERSATION_PREFIX + sessionId,
turn
);
// 保持最近10轮对话
redisTemplate.opsForList().trim(
CONVERSATION_PREFIX + sessionId,
-10,
-1
);
}
public List<ConversationTurn> getConversationHistory(String sessionId) {
return redisTemplate.opsForList().range(
CONVERSATION_PREFIX + sessionId,
0,
-1
);
}
public static class ConversationTurn {
private String userMessage;
private String aiResponse;
private LocalDateTime timestamp;
public ConversationTurn(String userMessage, String aiResponse) {
this.userMessage = userMessage;
this.aiResponse = aiResponse;
this.timestamp = LocalDateTime.now();
}
// getters
}
}
2. 智能代理(Agent)框架
@Component
public class IntelligentAgent {
@Autowired
private RAGQuestionAnsweringService qaService;
@Autowired
private ConversationMemoryService memoryService;
@Autowired
private List<AgentTool> tools;
public String processRequest(String sessionId, String userInput) {
// 获取对话历史
List<ConversationTurn> history =
memoryService.getConversationHistory(sessionId);
// 分析用户意图
AgentIntent intent = analyzeIntent(userInput, history);
// 根据意图选择处理方式
String response;
if (intent.requiresToolExecution()) {
response = executeTool(intent, userInput);
} else {
response = qaService.answerQuestion(userInput);
}
// 保存对话记录
memoryService.saveConversationTurn(sessionId, userInput, response);
return response;
}
private AgentIntent analyzeIntent(String userInput,
List<ConversationTurn> history) {
// 实现意图分析逻辑
return new AgentIntent();
}
private String executeTool(AgentIntent intent, String userInput) {
// 根据意图选择合适的工具执行
return "工具执行结果";
}
}
性能优化与监控
1. 缓存策略
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return cacheManager;
}
}
@Service
public class CachedEmbeddingService {
@Autowired
private EmbeddingClient embeddingClient;
@Cacheable(value = "embeddings", key = "#text")
public List<Double> getCachedEmbedding(String text) {
return embeddingClient.embed(text);
}
}
2. 监控指标
@Component
public class RAGMetrics {
private final MeterRegistry meterRegistry;
private final Counter successfulQueries;
private final Counter failedQueries;
private final Timer responseTimeTimer;
public RAGMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.successfulQueries = meterRegistry.counter("rag.queries.successful");
this.failedQueries = meterRegistry.counter("rag.queries.failed");
this.responseTimeTimer = meterRegistry.timer("rag.response.time");
}
public void recordSuccess() {
successfulQueries.increment();
}
public void recordFailure() {
failedQueries.increment();
}
public Timer.Sample startTimer() {
return Timer.start(meterRegistry);
}
public void stopTimer(Timer.Sample sample) {
sample.stop(responseTimeTimer);
}
}
部署与运维
Docker容器化部署
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/rag-system.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Kubernetes部署配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: rag-system
spec:
replicas: 3
selector:
matchLabels:
app: rag-system
template:
metadata:
labels:
app: rag-system
spec:
containers:
- name: rag-app
image: rag-system:latest
ports:
- containerPort: 8080
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: api-secrets
key: openai-api-key
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: rag-service
spec:
selector:
app: rag-system
ports:
- port: 80
targetPort: 8080
测试策略
单元测试
@SpringBootTest
@ActiveProfiles("test")
public class RAGServiceTest {
@Autowired
private RAGQuestionAnsweringService qaService;
@MockBean
private SemanticSearchService searchService;
@Test
public void testAnswerQuestionWithContext() {
// 模拟搜索返回结果
when(searchService.searchRelevantContent(anyString(), anyInt()))
.thenReturn(Arrays.asList(
new SearchResult("Spring AI提供了统一的AI模型接入接口", 0.85, "doc1")
));
String answer = qaService.answerQuestion("什么是Spring AI?");
assertNotNull(answer);
assertTrue(answer.contains("Spring AI"));
}
}
集成测试
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RAGControllerIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testAskEndpoint() {
QuestionRequest request = new QuestionRequest();
request.setQuestion("如何配置Spring AI?");
ResponseEntity<String> response = restTemplate.postForEntity(
"http://localhost:" + port + "/api/rag/ask",
request,
String.class
);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
}
总结与展望
本文详细介绍了如何使用Spring AI和RAG技术构建企业级智能文档问答系统。通过结合向量数据库、语义搜索和大型语言模型,我们能够创建出准确、高效的问答系统。关键优势包括:
- 准确性提升:RAG技术有效减少了AI幻觉问题
- 可扩展性:模块化设计便于功能扩展和维护
- 性能优化:缓存策略和监控机制保障系统稳定运行
- 企业级特性:支持多租户、权限控制等企业需求
未来可以进一步探索的方向包括多模态支持、实时学习更新、以及更复杂的Agent工作流设计。Spring AI生态的持续发展将为构建更强大的AI应用提供更多可能性。
构建企业级智能问答系统实战指南

被折叠的 条评论
为什么被折叠?



