RAG 与向量数据库集成:Spring Boot 中的检索增强生成架构实战
RAG 与向量数据库集成:Spring Boot 中的检索增强生成架构实战
一、大模型的知识边界:为什么"参数化记忆"不够用
大模型的知识来源于训练数据,存在三个根本性限制:其一,训练数据有截止日期,模型无法回答训练之后发生的事件;其二,模型对专业领域知识(如企业内部文档、行业法规)的掌握深度不足;其三,模型可能产生"幻觉"——自信地编造不存在的事实。
检索增强生成(Retrieval-Augmented Generation, RAG)通过在推理时动态检索外部知识库,将相关文档注入 Prompt 上下文,弥补模型的知识盲区。但 RAG 的工程实现远不止"查向量数据库 + 拼接到 Prompt"这么简单——文档切分策略、Embedding 模型选型、检索精度优化、上下文窗口管理,每个环节都直接影响最终效果。
二、RAG 架构:从文档摄入到检索增强生成
完整的 RAG 系统包含两条链路:离线的文档摄入管线和在线的检索生成管线。
flowchart LR
subgraph 离线摄入
A[原始文档] --> B[文档解析<br/>PDF/Word/HTML]
B --> C[文本切分<br/>Chunk Strategy]
C --> D[Embedding 向量化]
D --> E[写入向量数据库]
end
subgraph 在线检索
F[用户查询] --> G[查询向量化]
G --> H[向量相似度检索]
H --> I[结果重排序<br/>Reranking]
I --> J[上下文组装]
J --> K[调用大模型生成]
K --> L[返回增强响应]
end
E -.-> H
关键设计决策在于 Chunk 策略和检索策略的配合。Chunk 过大导致检索精度下降(无关信息稀释关键内容),Chunk 过小导致语义不完整(关键信息被切断)。检索策略需要平衡召回率和精度——召回太少可能遗漏关键文档,召回太多会超出上下文窗口。
三、生产级代码实现:文档摄入、向量检索与上下文组装
3.1 文档摄入管线
@Service
public class DocumentIngestionService {
private final DocumentParser parser;
private final ChunkStrategy chunkStrategy;
private final EmbeddingModel embeddingModel;
private final VectorStore vectorStore;
@Async("ingestionExecutor")
public CompletableFuture<Void> ingest(Resource document,
Map<String, Object> metadata) {
// 1. 解析文档为纯文本
String text = parser.parse(document);
// 2. 按语义边界切分
List<TextChunk> chunks = chunkStrategy.split(text,
new ChunkConfig(500, 50)); // 500 Token, 50 Token 重叠
// 3. 向量化并存储
List<Document> documents = chunks.stream()
.map(chunk -> {
float[] embedding = embeddingModel.embed(chunk.getText());
Document doc = new Document(chunk.getText(), metadata);
doc.setEmbedding(embedding);
return doc;
})
.toList();
vectorStore.add(documents);
return CompletableFuture.completedFuture(null);
}
}
3.2 语义切分策略
@Component
public class SemanticChunkStrategy implements ChunkStrategy {
private final EmbeddingModel embeddingModel;
@Override
public List<TextChunk> split(String text, ChunkConfig config) {
// 先按段落切分
List<String> paragraphs = Arrays.asList(text.split("\n\n+"));
List<TextChunk> chunks = new ArrayList<>();
StringBuilder currentChunk = new StringBuilder();
int currentTokens = 0;
for (String para : paragraphs) {
int paraTokens = estimateTokens(para);
if (currentTokens + paraTokens > config.getMaxTokens()
&& currentTokens > 0) {
chunks.add(new TextChunk(currentChunk.toString().trim()));
// 保留重叠部分,避免语义断裂
String overlap = getOverlap(currentChunk.toString(),
config.getOverlapTokens());
currentChunk = new StringBuilder(overlap);
currentTokens = estimateTokens(overlap);
}
currentChunk.append(para).append("\n\n");
currentTokens += paraTokens;
}
if (currentTokens > 0) {
chunks.add(new TextChunk(currentChunk.toString().trim()));
}
return chunks;
}
}
3.3 检索与上下文组装
@Service
public class RAGService {
private final VectorStore vectorStore;
private final EmbeddingModel embeddingModel;
private final ChatClient chatClient;
private final PromptTemplateService promptTemplateService;
public String query(String userQuery, int topK) {
// 1. 向量检索相关文档
List<Document> relevantDocs = vectorStore.similaritySearch(
SearchRequest.query(userQuery)
.withTopK(topK)
.withSimilarityThreshold(0.75)
);
// 2. 组装上下文
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n---\n"));
// 3. 渲染 Prompt 模板
Map<String, Object> variables = Map.of(
"context", context,
"question", userQuery
);
String prompt = promptTemplateService.render(
"rag-qa-template", variables);
// 4. 调用大模型
return chatClient.call(prompt);
}
}
四、RAG 架构的精度瓶颈与工程权衡
检索精度的不确定性:向量相似度检索基于 Embedding 空间的距离度量,但语义相似不等于问题相关。用户问"如何配置 SSL 证书",检索可能返回"SSL 握手原理"的文档而非"SSL 证书配置步骤"。Reranking 模型(如 Cohere Rerank)可以提升精度,但增加了额外的推理延迟和成本。
上下文窗口的容量限制:检索到的文档加上用户查询和系统 Prompt,总长度可能超出模型上下文窗口。简单的截断策略可能丢失关键信息,需要根据文档与查询的相关性排序后,从高到低填充直到窗口上限。
Embedding 模型的领域适配:通用 Embedding 模型(如 text-embedding-3-small)在专业领域(如法律、医疗)的语义表达能力有限,可能导致检索精度下降。领域适配需要微调 Embedding 模型,但标注数据获取成本高,且微调后的模型可能丧失通用能力。
文档更新的实时性:向量数据库中的文档与源文档之间的同步存在延迟。当源文档更新后,需要重新摄入并替换旧的向量,这个过程的延迟取决于摄入管线的吞吐量。对于实时性要求高的场景(如新闻资讯),需要设计增量更新机制。
五、总结
RAG 的本质是将"参数化记忆"扩展为"参数化记忆 + 外部知识库"的混合架构,通过检索弥补模型的知识盲区。本文方案的核心链路为:文档解析 → 语义切分 → 向量化存储 → 检索重排序 → 上下文组装 → 模型生成。落地时需重点关注三个参数:Chunk 大小(建议 300-500 Token)、检索 topK 值(建议 3-5)、相似度阈值(建议 0.7-0.8)。建议从高质量的小规模知识库(如 FAQ 文档)开始验证,逐步扩展到大文档库,并在每个阶段评估检索准确率和生成质量。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)