第二章:6、对话记忆与引用标注

一、对话记忆(多轮对话)

1. 目标

让智能助手在自然对话的基础上,结合知识库进行问答,全面提升用户体验。

2. 提示词优化

  • 明确角色定位:知识库助手
  • 约束答案范围:仅基于参考资料作答
  • 处理无答案情况:无法回答时,明确告知用户

3. RAG客户端配置

(1)记忆持久化方式

支持三种记忆持久化方式:

  1. InMemory:默认,数据存于内存,重启后丢失
  2. Redis:数据存入Redis,支持分布式部署
  3. JDBC:数据持久化到数据库,最为可靠

配置:

具体配置可参考第三章:4、对话记忆与会话管理

(2)InMemoryChatMemory 职责分离重构

Spring AI 2.0 对 ChatMemory 进行了职责分离重构:

  • ChatMemoryRepository:存储和检索消息(支持InMemory/Redis/JDBC)
  • MessageWindowChatMemory:管理记忆窗口(保留最近N条消息)
  • MessageChatMemoryAdvisor:将记忆注入Prompt

(3)闲聊感知

  • 判断用户输入是闲聊还是知识性问题
  • 闲聊内容直接对话,不走RAG流程

详细实现请参见第三章:5、RAG进阶优化中的"闲聊感知查询改写"章节

(4)查询增强

  • ContextualQueryAugmenter:负责将检索到的文档与用户查询拼装为完整Prompt

详细配置请参见第三章:5、RAG进阶优化中的"查询增强与空上下文处理"章节

4. RAG + 记忆完整配置

java 复制代码
@Configuration
public class RagWithMemoryConfig {

    @Bean("ragMemoryChatClient")
    public ChatClient ragMemoryChatClient(
            ChatClient.Builder chatClientBuilder,
            VectorStore vectorStore,
            ChatMemoryRepository chatMemoryRepository) {

        // 设置记忆窗口:保留最近20条消息
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
            .chatMemoryRepository(chatMemoryRepository)
            .maxMessages(20)
            .build();

        RetrievalAugmentationAdvisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
            .documentRetriever(VectorStoreDocumentRetriever.builder()
                .vectorStore(vectorStore)
                .topK(5)
                .build())
            .build();

        return chatClientBuilder
            .defaultAdvisors(ragAdvisor, MessageChatMemoryAdvisor.builder()
                .chatMemory(chatMemory)
                .build())
            .build();
    }
}

二、多轮对话接口

java 复制代码
@RestController
@RequestMapping("/ai")
public class ChatController {

    @Resource(name = "ragMemoryChatClient")
    private ChatClient chatClient;

    @GetMapping("/chat")
    public Flux<String> chat(
            @RequestParam String message,
            @RequestParam(defaultValue = "default") String conversationId) {
        return chatClient.prompt()
            .user(message)
            .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
            .stream().content();
    }
}

三、引用标注

引用标注的核心思路:在返回答案的同时,附带答案来源的文档信息(citations)。

java 复制代码
@GetMapping("/ask-citation")
public Map<String, Object> askWithCitation(
        @RequestParam String message,
        @RequestParam(defaultValue = "default") String conversationId) {

    ChatResponse response = chatClient.prompt()
        .user(message)
        .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
        .call().chatResponse();

    Map<String, Object> result = new HashMap<>();
    result.put("answer", response.getResult().getOutput().getText());
    result.put("citations", extractCitations(response));
    return result;
}

四、总结

  • 对话记忆:赋予助手多轮对话能力
  • 引用标注:让答案来源可追溯
  • 结合RAG检索增强:打造专业、可信赖的知识库问答系统
相关推荐
拖孩15 小时前
AI 帮我写的小程序上线 44 天:36 个人进了收银台,8 个人付钱
前端·后端·微信小程序
VIP_CQCRE15 小时前
Claude Code 如何接入 Ace Data Cloud?终端与 VS Code 配置指南
api·ai编程·vs code·claude code·ace data cloud
濮水大叔15 小时前
AI Vibe Coding 实战(续):SMS 套件产品决策与开发方案
ai编程·全栈·vibecoding
Rain的Java大神之路15 小时前
我,13年Java老兵,建了个免费网站,公开叫板“Java已死”:没有广告,没有付费墙,151个页面全是踩坑干货
java·后端·程序员
萧瑟余晖15 小时前
Spring Integration企业集成概览详解
java·后端·spring
重生之我在番茄自学网安拯救世界15 小时前
AI开发者日报 第2期 | Anthropic零 Rust 团队靠Claude重写核心 API,CPU 降 40–50%
人工智能·网络安全·大模型·ai编程·claude
小小张说故事15 小时前
Python 的赋值为什么不会复制对象?拆开引用、浅拷贝与深拷贝
后端·python
SimonKing16 小时前
告别纸质合同,使用DocuSeal搭建私有电子签平台
java·后端·程序员
vipxieliang16 小时前
微服务架构设计:从拆分到治理的完整指南
openai·ai编程
日日大王学编程16 小时前
开源Agent项目记忆设计决策对比
python·ai·langchain·开源·ai编程