Spring AI与RAG技术实战:构建企业级智能文档问答系统
引言
在人工智能快速发展的今天,如何将AI能力有效集成到企业应用中成为了技术团队面临的重要挑战。Spring AI作为Spring生态系统中的AI集成框架,结合RAG(检索增强生成)技术,为企业构建智能文档问答系统提供了强大的技术支撑。本文将深入探讨如何使用Spring AI和RAG技术构建高效、准确的企业级智能问答系统。
技术架构概述
核心组件
我们的智能文档问答系统主要包含以下核心组件:
- 文档处理层:负责文档的加载、解析和预处理
- 向量化层:使用Embedding模型将文本转换为向量表示
- 向量数据库:存储和管理文档向量,支持高效的相似性搜索
- 检索增强生成层:结合检索结果和生成模型提供准确回答
- API服务层:提供RESTful接口供前端调用
技术选型
- 框架:Spring Boot 3.x + Spring AI
- 向量数据库:Redis Vector Search
- Embedding模型:OpenAI text-embedding-ada-002
- 生成模型:OpenAI GPT-4
- 文档处理:Apache Tika + LangChain4j
环境准备与配置
Maven依赖配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>0.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis-spring-boot-starter</artifactId>
<version>0.8.1</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-4
embedding:
options:
model: text-embedding-ada-002
data:
redis:
host: localhost
port: 6379
username: default
password: ${REDIS_PASSWORD}
核心实现
文档处理服务
@Service
@Slf4j
public class DocumentProcessingService {
@Autowired
private EmbeddingClient embeddingClient;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void processDocument(MultipartFile file) {
try {
// 解析文档内容
String content = parseDocumentContent(file);
// 分块处理
List<String> chunks = splitContentIntoChunks(content);
// 向量化并存储
for (int i = 0; i < chunks.size(); i++) {
String chunk = chunks.get(i);
float[] embedding = embeddingClient.embed(chunk);
DocumentChunk documentChunk = new DocumentChunk(
file.getOriginalFilename(),
chunk,
embedding,
i
);
storeInVectorDB(documentChunk);
}
log.info("文档处理完成: {}", file.getOriginalFilename());
} catch (Exception e) {
log.error("文档处理失败", e);
throw new RuntimeException("文档处理失败", e);
}
}
private List<String> splitContentIntoChunks(String content) {
// 实现文档分块逻辑
return TextSplitter.split(content, 1000, 200);
}
private void storeInVectorDB(DocumentChunk chunk) {
// 存储到Redis向量数据库
String key = "doc:" + chunk.getFileName() + ":" + chunk.getChunkIndex();
redisTemplate.opsForValue().set(key, chunk);
}
}
向量检索服务
@Service
public class VectorSearchService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private EmbeddingClient embeddingClient;
public List<DocumentChunk> searchSimilarDocuments(String query, int topK) {
// 将查询文本向量化
float[] queryEmbedding = embeddingClient.embed(query);
// 在Redis中进行向量相似性搜索
List<DocumentChunk> results = new ArrayList<>();
// 这里简化实现,实际应使用Redis的向量搜索功能
Set<String> keys = redisTemplate.keys("doc:*");
for (String key : keys) {
DocumentChunk chunk = (DocumentChunk) redisTemplate.opsForValue().get(key);
float similarity = calculateCosineSimilarity(queryEmbedding, chunk.getEmbedding());
if (similarity > 0.7) { // 相似度阈值
results.add(chunk);
if (results.size() >= topK) {
break;
}
}
}
// 按相似度排序
results.sort((a, b) -> Float.compare(
calculateCosineSimilarity(queryEmbedding, b.getEmbedding()),
calculateCosineSimilarity(queryEmbedding, a.getEmbedding())
));
return results;
}
private float calculateCosineSimilarity(float[] vec1, float[] vec2) {
// 计算余弦相似度
float dotProduct = 0;
float norm1 = 0;
float norm2 = 0;
for (int i = 0; i < vec1.length; i++) {
dotProduct += vec1[i] * vec2[i];
norm1 += vec1[i] * vec1[i];
norm2 += vec2[i] * vec2[i];
}
return (float) (dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)));
}
}
RAG问答服务
@Service
public class RAGQuestionAnsweringService {
@Autowired
private ChatClient chatClient;
@Autowired
private VectorSearchService vectorSearchService;
public String answerQuestion(String question) {
// 检索相关文档片段
List<DocumentChunk> relevantChunks = vectorSearchService.searchSimilarDocuments(question, 3);
if (relevantChunks.isEmpty()) {
return "抱歉,没有找到相关的信息来回答您的问题。";
}
// 构建提示词
String context = buildContextFromChunks(relevantChunks);
String prompt = buildRAGPrompt(question, context);
// 调用AI模型生成回答
ChatResponse response = chatClient.call(new UserMessage(prompt));
return response.getResult().getOutput().getContent();
}
private String buildContextFromChunks(List<DocumentChunk> chunks) {
StringBuilder contextBuilder = new StringBuilder();
for (DocumentChunk chunk : chunks) {
contextBuilder.append("文档片段: ").append(chunk.getContent()).append("\n\n");
}
return contextBuilder.toString();
}
private String buildRAGPrompt(String question, String context) {
return String.format("""
基于以下文档内容,请回答用户的问题。
文档内容:
%s
用户问题:%s
请根据文档内容提供准确、简洁的回答。如果文档中没有相关信息,请如实告知。
""", context, question);
}
}
RESTful API设计
@RestController
@RequestMapping("/api/rag")
public class RAGController {
@Autowired
private RAGQuestionAnsweringService ragService;
@Autowired
private DocumentProcessingService documentService;
@PostMapping("/upload")
public ResponseEntity<String> uploadDocument(@RequestParam("file") MultipartFile file) {
try {
documentService.processDocument(file);
return ResponseEntity.ok("文档上传和处理成功");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文档处理失败: " + e.getMessage());
}
}
@PostMapping("/ask")
public ResponseEntity<String> askQuestion(@RequestBody QuestionRequest request) {
try {
String answer = ragService.answerQuestion(request.getQuestion());
return ResponseEntity.ok(answer);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("回答问题失败: " + e.getMessage());
}
}
@GetMapping("/health")
public ResponseEntity<String> healthCheck() {
return ResponseEntity.ok("RAG服务运行正常");
}
}
@Data
class QuestionRequest {
private String question;
}
性能优化策略
1. 向量索引优化
@Configuration
public class VectorIndexConfig {
@Bean
public RedisIndexOperations redisIndexOperations(RedisConnectionFactory connectionFactory) {
RedisIndexOperations indexOps = new RedisIndexOperations(connectionFactory);
// 创建向量索引
indexOps.createIndex("document_chunks", VectorFieldType.FLOAT32, 1536,
Map.of("algorithm", "HNSW", "ef_construction", "200", "m", "16"));
return indexOps;
}
}
2. 缓存策略
@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 CachedRAGService {
@Autowired
private RAGQuestionAnsweringService ragService;
@Cacheable(value = "answers", key = "#question")
public String getCachedAnswer(String question) {
return ragService.answerQuestion(question);
}
}
3. 异步处理
@Async
public CompletableFuture<String> processDocumentAsync(MultipartFile file) {
return CompletableFuture.supplyAsync(() -> {
documentService.processDocument(file);
return "处理完成";
});
}
测试策略
单元测试
@SpringBootTest
@ExtendWith(MockitoExtension.class)
class RAGQuestionAnsweringServiceTest {
@Mock
private ChatClient chatClient;
@Mock
private VectorSearchService vectorSearchService;
@InjectMocks
private RAGQuestionAnsweringService ragService;
@Test
void testAnswerQuestionWithRelevantContext() {
// 模拟向量搜索返回相关文档
DocumentChunk chunk = new DocumentChunk("test.txt", "Spring AI是Spring生态的AI集成框架",
new float[1536], 0);
when(vectorSearchService.searchSimilarDocuments(anyString(), anyInt()))
.thenReturn(List.of(chunk));
// 模拟AI回答
when(chatClient.call(any())).thenReturn(
new ChatResponse(new Generation("Spring AI提供了AI能力集成解决方案"))
);
String answer = ragService.answerQuestion("什么是Spring AI?");
assertNotNull(answer);
assertTrue(answer.contains("Spring AI"));
}
}
集成测试
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
class RAGIntegrationTest {
@Container
static RedisContainer redis = new RedisContainer("redis:7-alpine");
@Test
void testFullRAGWorkflow() {
// 测试完整的RAG工作流
// 包括文档上传、向量化、检索和问答
}
}
部署与监控
Docker部署
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/rag-system-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Prometheus监控
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
tags:
application: rag-system
总结与展望
本文详细介绍了如何使用Spring AI和RAG技术构建企业级智能文档问答系统。通过结合向量数据库、Embedding模型和大语言模型,我们实现了准确、高效的文档问答能力。
关键优势:
- 准确性提升:RAG技术有效减少了AI幻觉问题
- 可扩展性:基于Spring生态,易于集成和扩展
- 性能优化:通过向量索引和缓存策略确保系统性能
- 企业级特性:支持完整的文档处理流程和监控
未来改进方向:
- 支持多模态文档处理(图片、表格等)
- 实现实时文档更新和增量索引
- 加入用户反馈机制,持续优化回答质量
- 支持多租户和权限管理
Spring AI与RAG技术的结合为企业智能化转型提供了强有力的技术支撑,相信随着技术的不断发展,这类系统将在企业知识管理领域发挥越来越重要的作用。

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



