1. RAG技术概述:从原理到实战
大型语言模型(LLM)虽然强大,但存在一个致命缺陷——它们只能基于训练时已知的信息生成内容。这就好比一个记忆力超群但足不出户的学者,虽然学识渊博,却对墙外的新事物一无所知。当用户询问训练数据之外的问题时,LLM往往会"一本正经地胡说八道",这种现象在业内被称为"幻觉"(Hallucination)。
RAG(Retrieval Augmented Generation,检索增强生成)技术正是为了解决这一问题而生。它的核心思想很简单:在LLM回答问题前,先从一个外部知识库中检索出与问题最相关的信息,然后将这些信息与原始问题一起输入LLM。这就相当于给那位足不出户的学者配备了一个强大的图书馆检索系统,让他能够随时查阅最新的资料。
1.1 RAG与MCP的异同
在深入探讨RAG之前,有必要将其与另一种增强LLM能力的技术——MCP(Memory-Centric Processing)进行对比:
| 特性 | RAG | MCP |
|---|---|---|
| 核心功能 | 知识检索增强 | 工具调用能力增强 |
| 数据来源 | 向量数据库中的文档片段 | 各种API、工具和外部系统 |
| 适用场景 | 需要专业知识支持的问答 | 需要执行具体操作的自动化任务 |
| 实现复杂度 | 中等(需要构建知识库) | 高(需要集成各种工具) |
| 响应延迟 | 较高(需要检索+生成) | 取决于工具响应速度 |
MCP让LLM具备了调用外部程序的能力,可以完成诸如文件操作、数据查询等自动化工作。而RAG则专注于知识检索,通过从数据库中找出与问题最相关的知识片段来增强LLM的上下文信息。
1.2 RAG工作流程全景图
一个完整的RAG系统包含两个主要部分:离线处理和在线处理。
离线处理(知识准备阶段):
- 文档分块(Chunking):将原始文档分割成适当大小的片段
- 向量嵌入(Embedding):使用Embedding模型将文本转换为高维向量
- 向量存储:将向量及其元数据存入向量数据库,并建立高效索引
在线处理(实时问答阶段):
- 问题向量化:将用户问题转换为向量
- 相似性搜索:在向量库中找出最相关的知识片段
- 重排序(可选):对初步结果进行精细排序
- 提示词构建:将检索结果与问题组合成完整提示
- 答案生成:LLM基于增强的上下文生成最终回答

需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. RAG核心技术深度解析
2.1 文档分块(Chunking)策略
文档分块是RAG流程中的第一步,也是影响最终效果的关键因素。分块质量直接决定了后续检索的准确性和LLM回答的效果。想象一下,如果你把整本百科全书作为一个块存入数据库,那么检索系统每次都会返回整本书,LLM将难以找到真正相关的部分。
2.1.1 常见分块策略对比
| 策略类型 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 固定大小拆分 | 按指定字数或token数切分 | 实现简单、速度快 | 可能割裂语句,破坏语义完整性 |
| 结构拆分 | 基于HTML/Markdown等格式拆分 | 保留文档结构,语义完整度高 | 依赖规范的结构化文档 |
| 语义拆分 | 使用NLP方法按语义边界(段落、主题)拆分 | 最符合人类理解,保持语义一致性 | 实现复杂,计算开销大 |
| 递归拆分 | 先按大分隔符拆分,再逐级细分 | 平衡语义完整性和长度控制 | 需要精心设计分层和停止条件 |
| 滑动窗口 | 设置重叠区域避免信息割裂 | 减少边界信息丢失 | 增加存储和计算负担 |
在实际项目中,我们通常会组合使用多种策略。例如,对于技术文档,可以先按章节(结构拆分),再对每章内容使用滑动窗口(固定大小+重叠)进行细分。
2.1.2 TokenTextSplitter实战
Spring AI提供了TokenTextSplitter来实现基于token的分块策略。以下是其核心参数解析:
java复制new TokenTextSplitter(
200, // chunkSize: 每个块的目标token数
200, // minChunkSizeChars: 每个块最少字符数
5, // minChunkLengthToEmbed: 最小嵌入长度
10000, // maxNumChunks: 最大分块数
true // keepSeparator: 是否保留分隔符
)
经验分享:
- 技术文档通常设置chunkSize在500-800token之间
- 设置10-15%的重叠区域能显著减少边界效应
- 对于中文文档,minChunkSizeChars建议不小于100字
2.2 向量嵌入(Embedding)技术
2.2.1 Embedding模型原理
Embedding模型能够将文本转换为固定长度的浮点数组(向量)。以OpenAI的text-embedding-3-small模型为例,它会将任何长度的文本转换为1536维的向量。神奇的是,语义相似的文本,其向量在空间中的位置也会很接近。

在实际应用中,我们通过计算向量间的距离来判断文本相似度。常用的距离度量方式包括:
- 余弦相似度:测量向量方向的相似性,范围[-1,1],值越大越相似
- 欧氏距离:测量向量间的直线距离,值越小越相似
- 点积:综合考虑长度和方向,适合加权场景
2.2.2 Spring AI集成Embedding
在Spring AI中集成OpenAI的Embedding模型非常简单:
- 添加依赖:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
- 配置参数:
yaml复制spring:
ai:
openai:
base-url: [你的API地址]
api-key: [你的密钥]
embedding:
options:
model: text-embedding-ada-002
- 使用示例:
java复制@Autowired
private EmbeddingModel embeddingModel;
public void embedText(String text) {
float[] vector = embeddingModel.embed(text);
System.out.println("向量维度: " + vector.length);
}
性能提示:
- 批量处理文本能显著提高效率
- 对不变的内容缓存Embedding结果
- 中文文本建议使用专门优化的模型
2.3 向量数据库选型与实践
2.3.1 为什么需要向量数据库?
传统关系型数据库擅长精确匹配查询,但RAG需要进行的是相似性搜索——找到"意思相近"而不是"完全匹配"的内容。向量数据库就是为这种场景设计的,它能高效存储和检索高维向量数据。
主流向量数据库对比:
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| Pinecone | 全托管服务,简单易用 | 生产环境快速部署 |
| Chroma | 轻量级,支持内存模式 | 开发测试环境 |
| PGVector | PostgreSQL扩展,兼容SQL | 已有PG基础设施的项目 |
| Milvus | 高性能,支持分布式 | 超大规模向量搜索 |
| Weaviate | 内置多模态支持 | 需要处理多种数据类型 |
2.3.2 PGVector实战配置
Spring AI对PGVector提供了开箱即用的支持:
- 添加依赖:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
- 配置参数:
yaml复制spring:
ai:
vectorstore:
pgvector:
initialize-schema: true
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 1536
datasource:
url: jdbc:postgresql://localhost/postgres
username: [用户名]
password: [密码]
- 自动生成的Schema:
sql复制CREATE TABLE IF NOT EXISTS vector_store (
id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
content text,
metadata json,
embedding vector(1536)
);
CREATE INDEX ON vector_store USING HNSW (embedding vector_cosine_ops);
性能优化建议:
- 生产环境建议单独的表空间存放向量数据
- 定期执行VACUUM ANALYZE维护数据库性能
- 合理设置HNSW的构建参数(ef_construction, m)
2.4 近似最近邻搜索(ANN)算法
在百万级甚至更大规模的向量集合中,精确计算每个向量的距离是不现实的。近似最近邻(ANN)算法在可接受的精度损失下,将搜索速度提高了数个数量级。
2.4.1 主流ANN算法对比
| 算法 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| LSH | 局部敏感哈希 | 实现简单,查询速度快 | 精度较低 |
| Annoy | 随机投影树 | 内存效率高 | 构建时间较长 |
| HNSW | 分层导航小世界图 | 查询速度极快,精度高 | 内存占用较大 |
| IVF | 倒排文件索引+聚类 | 适合超大规模数据 | 需要定期重新训练 |
| ScaNN | 各向异性量化 | Google出品,优化好 | 配置复杂 |
2.4.2 HNSW算法深度解析
HNSW(Hierarchical Navigable Small World)是当前最流行的ANN算法之一,PGVector默认采用的就是这种索引类型。

HNSW的核心特点:
- 分层结构:上层用于快速定位,下层用于精细搜索
- 小世界网络:每个节点都有远距离和近距离连接
- 启发式搜索:采用贪婪算法在图中导航
参数调优指南:
- ef_construction:影响索引构建质量和速度(建议100-200)
- m:每个节点的最大连接数(建议16-64)
- ef_search:查询时考察的候选数(建议50-400)
3. Spring AI实现RAG全流程
3.1 环境准备与项目搭建
3.1.1 基础环境要求
| 组件 | 版本要求 | 备注 |
|---|---|---|
| JDK | 17+ | 推荐使用Azul Zulu |
| SpringBoot | 3.5.0+ | |
| Spring AI | 1.0.0+ | 注意BOM版本管理 |
| PostgreSQL | 15+ | 需要安装PGVector扩展 |
| Maven | 3.9+ | 或使用Gradle 8+ |
3.1.2 项目依赖配置
完整的pom.xml依赖配置:
xml复制<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot基础 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI核心 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<!-- RAG功能 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
<!-- 向量数据库 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
</dependencies>
3.1.3 配置文件详解
application.yml完整配置:
yaml复制spring:
ai:
openai:
base-url: ${OPENAI_BASE_URL}
api-key: ${OPENAI_API_KEY}
chat:
options:
model: Qwen/Qwen2.5-72B-Instruct
embedding:
options:
model: text-embedding-ada-002
vectorstore:
pgvector:
initialize-schema: true
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 1536
datasource:
url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME}
username: ${DB_USER}
password: ${DB_PASSWORD}
logging:
level:
org:
springframework:
ai:
chat:
client:
advisor: DEBUG
3.2 ETL流程实现
ETL(Extract, Transform, Load)是构建知识库的核心流程。Spring AI提供了完整的组件支持:
3.2.1 文档读取(Extract)
支持多种文档格式:
java复制// 文本文件
TextReader textReader = new TextReader(resource);
// PDF文件
PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(resource);
// Markdown文件
MarkdownDocumentReader mdReader = new MarkdownDocumentReader(resource);
// HTML文件
JsoupDocumentReader htmlReader = new JsoupDocumentReader(resource);
3.2.2 文档转换(Transform)
java复制TokenTextSplitter splitter = new TokenTextSplitter(
800, // 目标token数
350, // 最小字符数
5, // 最小嵌入长度
1000, // 最大分块数
true // 保留分隔符
);
List<Document> transformed = splitter.apply(extractedDocs);
3.2.3 向量存储(Load)
java复制vectorStore.add(transformedDocs);
完整ETL流程示例:
java复制@Value("classpath:/docs/technical_manual.pdf")
private Resource pdfResource;
public void processTechnicalManual() {
// Extract
PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(pdfResource);
List<Document> rawDocs = pdfReader.read();
// Transform
TokenTextSplitter splitter = new TokenTextSplitter(800, 350, 5, 1000, true);
List<Document> chunks = splitter.apply(rawDocs);
// Load
vectorStore.add(chunks);
logger.info("成功处理技术文档,生成{}个知识块", chunks.size());
}
3.3 RAG问答系统实现
3.3.1 核心组件配置
java复制@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
@Bean
public VectorStore vectorStore(PgVectorStore.Builder builder) {
return builder.build();
}
3.3.2 检索增强生成实现
java复制@GetMapping("/ask")
public String askQuestion(@RequestParam String question) {
// 构建检索增强advisor
Advisor advisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.similarityThreshold(0.6)
.vectorStore(vectorStore)
.build())
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(false)
.build())
.build();
// 执行问答
return chatClient.prompt()
.advisors(advisor)
.user(question)
.call()
.content();
}
3.3.3 自定义Prompt模板
默认模板可能不适合所有场景,我们可以自定义:
java复制String customTemplate = """
你是一个专业的技术支持助手。请基于以下上下文信息回答问题。
上下文:
{documents}
问题:
{question}
回答要求:
- 使用中文回答
- 如果信息不足,请明确说"根据现有信息无法确定"
- 保持专业但友好的语气
""";
PromptTemplate template = new PromptTemplate(customTemplate);
// 在advisor配置中使用自定义模板
RetrievalAugmentationAdvisor.builder()
.promptTemplate(template)
// ...其他配置
.build();
3.4 性能优化与生产建议
3.4.1 检索性能优化
-
索引调优:
sql复制CREATE INDEX ON vector_store USING HNSW (embedding vector_cosine_ops) WITH (m = 32, ef_construction = 200); -
查询参数优化:
java复制VectorStoreDocumentRetriever.builder() .similarityThreshold(0.5) // 相似度阈值 .topK(5) // 返回结果数 .build(); -
批量处理:
java复制// 批量插入提高效率 vectorStore.add(List.of(doc1, doc2, doc3));
3.4.2 缓存策略
-
问题向量缓存:
java复制@Cacheable(value = "questionEmbeddings", key = "#question") public float[] getQuestionEmbedding(String question) { return embeddingModel.embed(question); } -
检索结果缓存:
java复制@Cacheable(value = "similarDocuments", key = "#question") public List<Document> findSimilarDocuments(String question) { // 检索逻辑 }
3.4.3 监控与评估
-
关键指标监控:
- 检索耗时
- 检索结果相关性
- LLM生成耗时
- 最终回答质量
-
A/B测试框架:
java复制// 实现不同参数配置的对比测试 public EvaluationResult evaluateRAGVariants(String question) { // 测试不同配置 }
4. 高级特性与最佳实践
4.1 多模态RAG实现
现代RAG系统已经不再局限于文本,Spring AI也支持处理多种数据类型:
4.1.1 图像处理流程
- 使用CLIP等模型生成图像向量
- 将向量与文本数据一起存储
- 实现跨模态检索
java复制// 伪代码示例
ImageReader imageReader = new ImageReader();
TextEmbeddingClient textEmbedder = ...;
ImageEmbeddingClient imageEmbedder = ...;
// 处理图文混合内容
List<Document> multiModalDocs = new ArrayList<>();
for (Image image : images) {
float[] imageVector = imageEmbedder.embed(image);
Document doc = new Document(image.getDescription(),
Map.of("embedding", imageVector));
multiModalDocs.add(doc);
}
vectorStore.add(multiModalDocs);
4.2 动态数据更新策略
知识库需要定期更新以保持信息新鲜度:
4.2.1 增量更新机制
java复制@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
public void updateKnowledgeBase() {
// 1. 获取变更内容
List<Document> changes = getRecentChanges();
// 2. 删除过时内容
vectorStore.delete(changes.stream()
.map(Document::getId)
.collect(Collectors.toList()));
// 3. 添加新内容
vectorStore.add(changes);
}
4.2.2 版本控制方案
sql复制ALTER TABLE vector_store ADD COLUMN version INT DEFAULT 1;
-- 查询时指定版本
SELECT * FROM vector_store
WHERE version = (SELECT MAX(version) FROM vector_store);
4.3 安全与权限控制
4.3.1 数据访问控制
-
元数据过滤:
java复制MetadataFilter filter = MetadataFilter.builder() .with("department", "engineering") .build(); SearchRequest request = SearchRequest.builder() .withQuery(query) .withFilter(filter) .build(); -
行级安全(PostgreSQL):
sql复制CREATE POLICY rag_access_policy ON vector_store USING (metadata->>'department' = current_setting('app.current_dept'));
4.3.2 敏感信息处理
-
数据脱敏:
java复制public Document sanitize(Document doc) { String cleanText = removeSensitiveInfo(doc.getText()); return new Document(cleanText, doc.getMetadata()); } -
访问日志:
java复制@Aspect @Component public class RagAccessLogger { @Before("execution(* com.example..VectorStore.*(..))") public void logAccess(JoinPoint jp) { // 记录操作日志 } }
4.4 生产环境部署架构
4.4.1 高可用架构设计
code复制 [负载均衡器]
|
---------------------------------------------------
| | |
[应用实例1] [应用实例2] [应用实例3]
| | |
[PG主节点] <-------------> [PG副本1] <-----------> [PG副本2]
4.4.2 关键配置参数
-
连接池配置:
yaml复制spring: datasource: hikari: maximum-pool-size: 20 connection-timeout: 30000 -
超时设置:
java复制RetrievalAugmentationAdvisor.builder() .timeout(Duration.ofSeconds(10)) .build(); -
重试策略:
java复制@Retryable(value = {TimeoutException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000)) public String askQuestionWithRetry(String question) { return askQuestion(question); }
5. 常见问题排查与调试
5.1 检索质量问题
5.1.1 症状:检索结果不相关
可能原因:
- Embedding模型不适合当前领域
- 分块策略不合理,导致语义碎片化
- 相似度阈值设置不当
解决方案:
- 尝试领域特定的Embedding模型
- 调整分块大小和重叠区域
- 逐步调整相似度阈值(0.5-0.7是常见范围)
java复制// 调试检索过程
List<Document> results = vectorStore.similaritySearch(
SearchRequest.query(question)
.withTopK(5)
.withSimilarityThreshold(0.6)
);
logger.debug("检索结果:{}", results);
5.1.2 症状:重要信息被截断
可能原因:
- 分块大小设置过小
- 分块边界切分了关键内容
解决方案:
- 增加chunkSize(如从500调到800)
- 使用语义分块代替固定分块
- 增加重叠区域大小
java复制new TokenTextSplitter(
800, // 增大chunkSize
200,
50, // 增加minChunkLengthToEmbed
1000,
true
);
5.2 性能问题
5.2.1 症状:检索速度慢
可能原因:
- 向量索引未正确构建
- 数据库资源不足
- ANN参数配置不当
解决方案:
- 确认HNSW索引已建立
- 检查PG配置(shared_buffers, work_mem等)
- 调整HNSW参数:
sql复制-- 重建索引优化性能
CREATE INDEX CONCURRENTLY ON vector_store
USING hnsw (embedding vector_cosine_ops)
WITH (m = 32, ef_construction = 200);
5.2.2 症状:高并发时响应延迟
可能原因:
- 连接池不足
- 未实施缓存策略
- 硬件资源瓶颈
解决方案:
- 增加连接池大小
- 实现问题向量缓存
- 考虑读写分离架构
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 30 # 根据实际情况调整
5.3 LLM生成问题
5.3.1 症状:回答未使用检索内容
可能原因:
- Prompt模板设计不合理
- 检索结果质量差
- LLM温度参数过高
解决方案:
- 强化Prompt中的指令:
code复制你必须严格基于以下上下文回答问题:
{context}
如果信息不足,请回答"根据提供的信息无法确定"。
- 降低temperature参数:
yaml复制spring:
ai:
openai:
chat:
options:
temperature: 0.3 # 降低随机性
5.3.2 症状:回答包含幻觉信息
可能原因:
- 检索结果不足但LLM强行回答
- 未设置拒绝回答的机制
解决方案:
- 设置allowEmptyContext=false
- 在Prompt中明确限制:
code复制如果上下文不足以回答问题,你必须回答:"根据提供的信息无法确定"。
5.4 系统集成问题
5.4.1 症状:启动时报EmbeddingModel缺失
完整错误:
code复制BeanCreationException: Could not autowire. No beans of 'EmbeddingModel' type found.
解决方案:
- 确认已添加spring-ai-starter-model-openai依赖
- 检查application.yml中的openai配置
- 确保API密钥和URL正确
5.4.2 症状:PGVector连接失败
解决方案:
- 确认PostgreSQL已安装PGVector扩展:
sql复制CREATE EXTENSION IF NOT EXISTS vector;
- 检查数据库用户权限
- 验证网络连接和防火墙设置
5.5 调试技巧与工具
5.5.1 检索过程可视化
java复制// 打印检索到的文档及其相似度得分
vectorStore.similaritySearch(query).forEach(doc -> {
System.out.printf("相似度: %.2f | 内容: %.30s...\n",
doc.getScore(),
doc.getText());
});
5.5.2 Embedding质量检查
java复制// 比较两个文本的相似度
float[] emb1 = embeddingModel.embed("Java编程");
float[] emb2 = embeddingModel.embed("Python开发");
double similarity = cosineSimilarity(emb1, emb2);
System.out.println("语义相似度: " + similarity);
5.5.3 使用PGAdmin分析
-
检查向量表数据:
sql复制SELECT id, left(content, 50) as preview FROM vector_store LIMIT 10; -
分析索引使用情况:
sql复制EXPLAIN ANALYZE SELECT id FROM vector_store ORDER BY embedding <-> '[0.1,0.2,...]' LIMIT 5;
6. 项目扩展与进阶方向
6.1 多知识库路由
对于大型企业应用,可能需要根据问题类型选择不同的知识库:
java复制public VectorStore selectKnowledgeBase(String question) {
if (question.contains("技术问题")) {
return techVectorStore;
} else if (question.contains("产品问题")) {
return productVectorStore;
}
return defaultVectorStore;
}
// 在问答流程中使用
VectorStore store = selectKnowledgeBase(question);
advisorBuilder.documentRetriever(store);
6.2 混合检索策略
结合关键词检索和向量检索的优势:
java复制// 关键词检索结果
List<Document> keywordResults = keywordSearch(question);
// 向量检索结果
List<Document> vectorResults = vectorStore.similaritySearch(question);
// 混合并去重
List<Document> finalResults = mergeResults(keywordResults, vectorResults);
6.3 反馈学习机制
收集用户反馈持续改进系统:
java复制@PostMapping("/feedback")
public void handleFeedback(
@RequestParam String question,
@RequestParam String answer,
@RequestParam boolean wasHelpful) {
if (!wasHelpful) {
// 记录问题以便后续分析
feedbackService.recordPoorAnswer(question, answer);
// 可能的自动修正
if (shouldUpdateKnowledgeBase(question)) {
updateKnowledgeBase(question);
}
}
}
6.4 性能优化进阶
6.4.1 量化索引
sql复制-- 使用标量量化减小索引大小
CREATE INDEX ON vector_store
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100, quantizer = 'sq');
6.4.2 分级存储
java复制// 热数据存内存,冷数据存磁盘
ConfigurableVectorStore store = new ConfigurableVectorStore()
.withMemoryStore(hotDataStore)
.withDiskStore(coldDataStore);
6.5 领域特定优化
6.5.1 法律领域
- 使用法律专用Embedding模型
- 实现精确的法条引用功能
- 添加免责声明生成
6.5.2 医疗领域
- 集成医学术语标准化
- 实现多轮问诊流程
- 严格的内容审核机制
java复制MedicalTermNormalizer normalizer = new MedicalTermNormalizer();
String normalizedQuery = normalizer.normalize(question);
advisorBuilder.queryAugmenter(q -> normalizer.normalize(q));
7. 完整代码示例
7.1 项目结构
code复制src/main/java/
├── config/
│ └── AiConfig.java # AI相关Bean配置
├── controller/
│ └── RagController.java # REST接口
├── service/
│ ├── KnowledgeService.java # 知识库管理
│ └── RagService.java # 核心RAG逻辑
└── Application.java # 启动类
7.2 核心配置类
java复制@Configuration
public class AiConfig {
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
@Bean
public VectorStore vectorStore(
PgVectorStore.Builder builder,
EmbeddingModel embeddingModel) {
return builder
.withEmbeddingModel(embeddingModel)
.withInitializeSchema(true)
.build();
}
}
7.3 REST控制器
java复制@RestController
@RequestMapping("/api/rag")
public class RagController {
@Autowired
private RagService ragService;
@PostMapping("/ask")
public ResponseEntity<String> askQuestion(
@RequestBody QuestionRequest request) {
String answer = ragService.askQuestion(request.getQuestion());
return ResponseEntity.ok(answer);
}
@PostMapping("/upload")
public ResponseEntity<String> uploadDocument(
@RequestParam MultipartFile file) {
ragService.processDocument(file);
return ResponseEntity.ok("文档处理完成");
}
}
7.4 核心服务类
java复制@Service
public class RagService {
@Autowired
private ChatClient chatClient;
@Autowired
private VectorStore vectorStore;
@Autowired
private KnowledgeService knowledgeService;
@Value("${rag.similarity.threshold:0.6}")
private double similarityThreshold;
public String askQuestion(String question) {
Advisor advisor = buildAdvisor();
return chatClient.prompt()
.advisors(advisor)
.user(question)
.call()
.content();
}
public void processDocument(MultipartFile file) {
List<Document> documents = knowledgeService.extractContent(file);
List<Document> chunks = knowledgeService.splitDocuments(documents);
vectorStore.add(chunks);
}
private Advisor buildAdvisor() {
return RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(similarityThreshold)
.build())
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(false)
.build())
.build();
}
}
7.5 知识库服务
java复制@Service
public class KnowledgeService {
@Autowired
private ResourcePatternResolver resourceResolver;
public List<Document> extractContent(MultipartFile file) throws IOException {
Resource resource = new InputStreamResource(file.getInputStream());
if (file.getContentType().contains("pdf")) {
PagePdfDocumentReader reader = new PagePdfDocumentReader(resource);
return reader.read();
} else if (file.getContentType().contains("text")) {
TextReader reader = new TextReader(resource);
return reader.read();
}
throw new UnsupportedOperationException("不支持的文档类型");
}
public List<Document> splitDocuments(List<Document> documents) {
TokenTextSplitter splitter = new TokenTextSplitter(
800, 200, 5, 1000, true);
return splitter.apply(documents);
}
@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
public void refreshKnowledgeBase() {
// 实现知识库定期更新
}
}
8. 实际应用案例
8.1 企业知识管理系统
场景:某科技公司拥有大量技术文档、产品手册和客户案例,需要构建智能问答系统。
解决方案:
- 按部门建立多个知识库(研发、产品、销售等)
- 实现基于权限的知识访问控制
- 集成到企业IM工具中
效果:
- 客服响应速度提升70%
- 内部培训成本降低40%
- 知识利用率提高3倍
8.2 教育领域应用
场景:在线教育平台需要为课程资料提供智能问答功能。
特殊需求:
- 支持数学公式和代码的语义理解
- 适应不同年级的知识水平
- 防止直接给出答案,鼓励思考
**实现技巧
