资讯详情

资讯详情

Spring AI与RAG技术融合实战:构建智能客服系统

1. 项目概述Spring AI与RAG技术融合实战去年在给某金融客户做智能客服系统升级时我第一次将Spring AI与RAG技术栈结合使用。当时客户要求系统既要能查询内部产品文档又要能获取实时市场数据这套技术组合完美解决了需求。现在我就把从零搭建的完整经验分享给大家包含本地知识库构建和联网搜索两大核心功能。RAG检索增强生成技术本质上是通过向量数据库这个中间人让大语言模型具备了查阅资料的能力。当用户提问时系统会先到向量库中检索相关文档片段再把它们作为上下文喂给LLM生成回答。Spring AI作为Spring生态的AI统一接口用熟悉的Spring风格封装了各类AI服务调用让Java开发者也能轻松玩转AI应用。本次实现的技术栈选择Spring AI 1.0统一AI服务调用接口PGVector开源向量数据库也可替换为ElasticsearchTavily API联网搜索服务Ollama本地运行的LLM可选2. 环境准备与依赖配置2.1 基础环境搭建建议使用Java 17和Spring Boot 3.2.x版本。在pom.xml中添加关键依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version1.0.0/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pgvector-store/artifactId version1.0.0/version /dependency如果是Gradle项目对应配置为implementation org.springframework.ai:spring-ai-openai-spring-boot-starter:1.0.0 implementation org.springframework.ai:spring-ai-pgvector-store:1.0.02.2 数据库配置使用Docker快速启动PGVector实例docker run --name pgvector -e POSTGRES_PASSWORDpassword -p 5432:5432 -d ankane/pgvector在application.yml中配置spring: datasource: url: jdbc:postgresql://localhost:5432/postgres username: postgres password: password driver-class-name: org.postgresql.Driver注意生产环境务必配置连接池推荐使用HikariCP。我曾遇到过因连接泄漏导致系统崩溃的情况后来通过以下配置解决spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.leak-detection-threshold50003. 核心功能实现3.1 知识库构建流程文档处理是RAG系统的核心环节我总结的最佳实践流程如下文档加载支持PDF、Word、HTML等格式// PDF示例 Resource resource new ClassPathResource(产品手册.pdf); DocumentReader pdfReader new PagePdfDocumentReader(resource); ListDocument documents pdfReader.get();文本分块采用重叠分块策略TextSplitter splitter new TokenTextSplitter( 1000, // chunkSize 200 // overlapSize ); ListDocument chunks splitter.split(documents);向量化存储使用PGVector存储Bean VectorStore vectorStore(EmbeddingClient embeddingClient, DataSource dataSource) { return new PgVectorStore( new JdbcTemplate(dataSource), embeddingClient, PgVectorStore.PgVectorStoreConfig.builder() .withTableName(product_docs) .withEmbeddingDimensions(1536) // OpenAI维度 .build() ); }踩坑记录初期直接使用全文存储导致检索效果差后来发现分块大小对结果影响巨大。经过测试技术文档适合800-1200token的块大小重叠200token效果最佳。3.2 混合检索策略实现结合本地知识库和联网搜索的完整检索流程public String hybridSearch(String query) { // 1. 本地知识库检索 ListDocument localResults vectorStore.similaritySearch( SearchRequest.defaults() .withQuery(query) .withTopK(3) ); // 2. 联网搜索需配置Tavily API key WebSearchClient webClient new TavilyWebSearchClient(); ListDocument webResults webClient.search(query) .stream() .map(result - new Document(result.content())) .collect(Collectors.toList()); // 3. 结果融合与重排序 ListDocument allResults new ArrayList(); allResults.addAll(localResults); allResults.addAll(webResults); return chatClient.call( new Prompt( 基于以下信息回答问题\n allResults.stream() .map(Document::getContent) .collect(Collectors.joining(\n---\n)), Map.of(question, query) ) ).getResult().getOutput().getContent(); }3.3 性能优化技巧缓存策略Cacheable(value vectorSearch, key #query) public ListDocument cachedSearch(String query) { return vectorStore.similaritySearch(query); }异步处理Async public CompletableFutureListDocument asyncWebSearch(String query) { return CompletableFuture.completedFuture(webClient.search(query)); }混合搜索并行化CompletableFutureListDocument localFuture CompletableFuture.supplyAsync( () - vectorStore.similaritySearch(query)); CompletableFutureListDocument webFuture CompletableFuture.supplyAsync( () - webClient.search(query)); CompletableFuture.allOf(localFuture, webFuture).join();4. 高级功能扩展4.1 多租户支持在实际项目中我们经常需要为不同客户隔离数据。PGVector的多租户实现方案public class TenantAwareVectorStore implements VectorStore { private final ThreadLocalString tenantId new ThreadLocal(); public void setTenantId(String tenantId) { this.tenantId.set(tenantId); } Override public void add(ListDocument documents) { documents.forEach(doc - doc.getMetadata().put(tenant_id, tenantId.get())); delegate.add(documents); } Override public ListDocument similaritySearch(SearchRequest request) { request.getFilter().put(tenant_id, tenantId.get()); return delegate.similaritySearch(request); } }4.2 对话历史管理实现多轮对话的关键代码public class ConversationManager { private final MapString, ListChatMessage sessions new ConcurrentHashMap(); public String chat(String sessionId, String userMessage) { ListChatMessage history sessions.computeIfAbsent( sessionId, k - new ArrayList()); history.add(new ChatMessage(ChatMessageType.USER, userMessage)); Prompt prompt new Prompt(history); ChatResponse response chatClient.call(prompt); history.add(new ChatMessage( ChatMessageType.ASSISTANT, response.getResult().getOutput().getContent())); return response.getResult().getOutput().getContent(); } }5. 生产环境注意事项监控指标配置management.endpoints.web.exposure.includehealth,metrics,prometheus management.metrics.export.prometheus.enabledtrue关键监控项spring_ai_embedding_seconds向量化耗时spring_ai_vector_store_seconds向量检索耗时spring_ai_chat_secondsLLM响应耗时灾备方案Retryable(maxAttempts3, backoffBackoff(delay1000)) public ListDocument fallbackSearch(String query) { try { return vectorStore.similaritySearch(query); } catch (Exception e) { return cachedSearch(query); // 降级到缓存 } }6. 完整示例代码结构src/main/java ├── config │ ├── VectorStoreConfig.java # 向量库配置 │ └── WebClientConfig.java # 联网搜索配置 ├── controller │ └── RagController.java # REST接口 ├── service │ ├── DocumentService.java # 文档处理 │ ├── SearchService.java # 检索逻辑 │ └── ChatService.java # 对话管理 └── Application.java # 启动类启动应用后可以通过以下端点测试POST /api/ingest- 上传文档到知识库GET /api/search?q{query}- 执行混合搜索POST /api/chat- 开启对话会话这套方案在某保险公司知识管理系统中的实际表现问题回答准确率从42%提升至89%平均响应时间从3.2s降至1.4s人工客服咨询量减少65%最后分享一个实用技巧定期用ANALYZE命令优化PGVector索引性能-- 每周执行一次 ANALYZE product_docs;
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →