Skip to content

Standard RAG 模式

Standard RAG 采用固定的 检索 → 生成 流程,适合常规问答场景。

完整流程


查询构建

首轮对话

直接使用用户原问题:

java
String retrievalQuery = context.getQuery();
// 用户: "什么是分布式锁?"
// 检索查询: "什么是分布式锁?"

多轮对话

拼接历史问题 + 当前问题:

java
// 伪代码 - 多轮对话查询构建
private String buildRetrievalQuery(RagContext context) {
    List<KlChatMessageEntity> history = context.getHistoryMessages();
    String currentQuery = context.getQuery();
    
    // 首轮: 直接用原问题
    if (history == null || history.isEmpty()) {
        return currentQuery;
    }
    
    // 后续轮次: 组合历史问题 + 当前问题
    StringBuilder sb = new StringBuilder();
    int maxMessages = context.getHistoryTurns() * 2;  // 用户+助手消息
    int startIndex = Math.max(0, history.size() - maxMessages);
    
    for (int i = startIndex; i < history.size(); i++) {
        KlChatMessageEntity msg = history.get(i);
        if ("user".equals(msg.getRole())) {
            sb.append(msg.getContent()).append(" ");
        }
    }
    
    sb.append(currentQuery);
    return sb.toString().trim();
}

示例

对话历史:
用户: 什么是分布式锁?
助手: 分布式锁是一种在分布式系统中...
用户: 它有哪些特性?
助手: 分布式锁的核心特性包括...

当前问题: 如何实现?

检索查询: "什么是分布式锁? 它有哪些特性? 如何实现?"

设计思路: 通过拼接历史问题,弥补当前问题可能的指代不清。


Prompt 构建

系统提示词

java
private static final String RAG_SYSTEM_PROMPT = """
    你是一个专业的知识库问答助手。
    请根据提供的参考资料回答用户问题。
    
    ## 回答要求:
    1. 优先使用参考资料中的信息
    2. 如果参考资料中没有相关信息,请明确告知用户
    3. 回答要准确、简洁、有条理
    4. 可以适当引用资料来源,如"根据[文档名]..."
    5. 如果问题涉及多个方面,请分点说明
    """;

用户提示词

java
// 伪代码 - 构建用户 Prompt
private String buildUserPrompt(RagContext context, List<RetrievedDocument> docs, String historyContext) {
    StringBuilder sb = new StringBuilder();
    
    // 历史对话 (可选)
    if (historyContext != null && !historyContext.isEmpty()) {
        sb.append("【历史对话】\n").append(historyContext).append("\n\n");
    }
    
    // 参考资料
    if (docs != null && !docs.isEmpty()) {
        sb.append("【参考资料】\n\n");
        for (int i = 0; i < docs.size(); i++) {
            RetrievedDocument doc = docs.get(i);
            sb.append("资料").append(i + 1).append(": ");
            if (doc.getTitle() != null) {
                sb.append("[").append(doc.getTitle()).append("] ");
            }
            sb.append("\n").append(doc.getContent()).append("\n\n");
        }
    } else {
        sb.append("【参考资料】无相关文档\n\n");
    }
    
    // 用户问题
    sb.append("【用户问题】\n").append(context.getQuery());
    
    return sb.toString();
}

完整 Prompt 示例

你是一个专业的知识库问答助手...

【历史对话】
用户: 什么是分布式锁?
助手: 分布式锁是一种...

【参考资料】

资料1: [分布式锁指南]
分布式锁是分布式系统中用于协调多个节点访问共享资源的机制...

资料2: [Redis 实战]
MolanDev 提供了基于 Redis 的分布式锁实现...

【用户问题】
如何使用 MolanDev 的分布式锁?

LLM 调用

流式生成

java
// 伪代码 - 流式调用 LLM
private Flux<RagChatResponse> generateAnswer(RagContext context, String fullPrompt) {
    return chatClient.prompt(fullPrompt)
            .options(OpenAiChatOptions.builder()
                    .model("gpt-4o")
                    .temperature(0.7)
                    .extraBody(Map.of("enable_thinking", context.isThink()))  // 深度思考
                    .build())
            .stream()
            .chatResponse()
            .map(response -> {
                // 处理 thinking 内容
                String thinking = response.getResult()
                        .getOutput()
                        .getMetadata()
                        .get("reasoningContent");
                
                if (thinking != null && !thinking.isEmpty()) {
                    context.appendThinking(thinking);
                    return RagChatResponse.thinking(thinking);
                }
                
                // 处理回答内容
                String content = response.getResult().getOutput().getText();
                if (content != null && !content.isEmpty()) {
                    context.appendResponse(content);
                    return RagChatResponse.content(content);
                }
                
                return null;
            });
}

深度思考

启用深度思考模式:

java
RagContext context = RagContext.builder()
        .query("分布式锁如何保证高可用?")
        .libraryIds(List.of("lib-001"))
        .think(true)  // 启用深度思考
        .build();

效果展示:

【思考过程】
用户问的是分布式锁的高可用,我需要从以下几个方面分析:
1. 单点故障问题
2. 主从切换时的锁丢失
3. Redlock 算法的解决方案...

【回答内容】
分布式锁保证高可用需要考虑以下关键点...

消息持久化

对话消息自动持久化到数据库:

java
// 保存用户消息
KlChatMessageEntity userMsg = new KlChatMessageEntity();
userMsg.setConversationId(context.getConversationId());
userMsg.setRole("user");
userMsg.setContent(context.getQuery());
userMsg.setMessageType("rag");
messageService.save(userMsg);

// 保存 AI 消息
KlChatMessageEntity aiMsg = new KlChatMessageEntity();
aiMsg.setConversationId(context.getConversationId());
aiMsg.setRole("assistant");
aiMsg.setContent(context.getResponseContent());
aiMsg.setThinkingContent(context.getThinkingContent());
aiMsg.setTokenUsage(context.getTokenUsage());
aiMsg.setMessageType("rag");
messageService.save(aiMsg);

// 保存引用文档关联
if (docs != null && !docs.isEmpty()) {
    messageDocService.saveDocs(context.getAssistantMessageId(), docs);
}

使用方式

基础问答

在问答界面输入问题,选择知识库后即可获取回答:

  • 输入你的问题
  • 选择要检索的知识库
  • 系统自动检索相关内容并生成回答

多轮对话

系统自动记住对话历史,支持上下文理解:

  • 首轮: "什么是分布式锁?"
  • 后续: "它有哪些实现方式?" — 系统理解"它"指代"分布式锁"

高级选项

对于需要更高精度的场景,可开启以下功能:

  • 混合检索 — 结合关键词和语义检索
  • 深度思考 — 展示模型的推理过程

💡 可通过系统界面直接体验 Standard RAG 问答功能。


适用场景

场景是否适用说明
概念查询单次检索已足够
FAQ 问答问题明确,不需要多次检索
文档摘要检索相关文档后生成摘要
复杂对比⚠️可考虑 Agent 模式
多步分析⚠️可考虑 Agent 模式

下一步