跳到主要内容

RAG 检索增强

RAG (Retrieval-Augmented Generation) 是一种结合信息检索和文本生成的技术,可以显著提高 AI 模型回答问题的准确性和相关性。

什么是 RAG?

RAG 技术通过以下步骤工作:

  1. 检索:从外部知识库中检索与用户问题相关的信息
  2. 生成:基于检索到的信息生成准确的回答

Spring AI 中的 RAG 实现

1. 向量存储配置

@Configuration
public class VectorStoreConfiguration {

@Bean
public VectorStore vectorStore() {
// 使用 PostgreSQL 向量存储
return new PgVectorStore(dataSource(), embeddingClient());
}

@Bean
public EmbeddingClient embeddingClient() {
return new OpenAiEmbeddingClient(openAiApi());
}

@Bean
public OpenAiApi openAiApi() {
return new OpenAiApi(apiKey);
}
}

2. 文档加载和嵌入

@Service
public class DocumentService {

private final VectorStore vectorStore;
private final EmbeddingClient embeddingClient;

public DocumentService(VectorStore vectorStore, EmbeddingClient embeddingClient) {
this.vectorStore = vectorStore;
this.embeddingClient = embeddingClient;
}

public void loadDocuments(List<String> documents) {
List<Document> embeddedDocuments = documents.stream()
.map(content -> {
// 生成嵌入向量
Embedding embedding = embeddingClient.embed(content);
return new Document(content, embedding);
})
.collect(Collectors.toList());

// 存储到向量数据库
vectorStore.add(embeddedDocuments);
}
}

3. RAG 查询实现

@Service
public class RagService {

private final VectorStore vectorStore;
private final ChatClient chatClient;

public RagService(VectorStore vectorStore, ChatClient chatClient) {
this.vectorStore = vectorStore;
this.chatClient = chatClient;
}

public String answerQuestion(String question) {
// 1. 将问题转换为向量
Embedding questionEmbedding = embeddingClient.embed(question);

// 2. 检索相关文档
List<Document> relevantDocuments = vectorStore.similaritySearch(questionEmbedding, 3);

// 3. 构造带有上下文的提示
String context = relevantDocuments.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n\n"));

Prompt prompt = new PromptTemplate("""
基于以下上下文回答问题,如果上下文不包含相关信息,请说明无法基于提供的资料回答:

上下文:
{context}

问题:
{question}

回答:
""")
.create(Map.of("context", context, "question", question));

// 4. 生成回答
return chatClient.call(prompt).getResult().getOutput().getContent();
}
}

高级 RAG 技术

查询重写

@Service
public class QueryRewriteService {

private final ChatClient chatClient;

public String rewriteQuery(String originalQuery) {
Prompt prompt = new PromptTemplate("""
请将以下查询重写为更精确的搜索查询:

原始查询:{originalQuery}

重写后的查询:
""")
.create(Map.of("originalQuery", originalQuery));

return chatClient.call(prompt).getResult().getOutput().getContent();
}
}

答案验证

@Service
public class AnswerValidationService {

private final ChatClient chatClient;

public boolean validateAnswer(String question, String answer, String context) {
Prompt prompt = new PromptTemplate("""
请判断以下回答是否基于提供的上下文准确回答了问题:

问题:{question}
回答:{answer}
上下文:{context}

请仅回答"是"或"否":
""")
.create(Map.of(
"question", question,
"answer", answer,
"context", context
));

String response = chatClient.call(prompt).getResult().getOutput().getContent();
return response.trim().equalsIgnoreCase("是");
}
}

实际应用示例

企业知识库问答

@RestController
@RequestMapping("/knowledge-base")
public class KnowledgeBaseController {

private final RagService ragService;
private final DocumentService documentService;

public KnowledgeBaseController(RagService ragService, DocumentService documentService) {
this.ragService = ragService;
this.documentService = documentService;
}

@PostMapping("/upload")
public ResponseEntity<String> uploadDocument(@RequestBody String content) {
documentService.loadDocuments(List.of(content));
return ResponseEntity.ok("文档上传成功");
}

@PostMapping("/ask")
public ResponseEntity<String> askQuestion(@RequestBody String question) {
String answer = ragService.answerQuestion(question);
return ResponseEntity.ok(answer);
}
}

最佳实践

1. 文档预处理

  • 清洗和标准化文档内容
  • 合理分割长文档
  • 提取关键信息和元数据

2. 检索优化

  • 调整相似度阈值
  • 使用混合检索策略
  • 实现查询扩展

3. 生成优化

  • 设计有效的提示模板
  • 处理无相关信息的情况
  • 提供答案置信度评估

通过合理使用 RAG 技术,可以显著提升 AI 应用的准确性和实用性,特别适用于需要基于特定知识库回答问题的场景。