第二章: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检索增强:打造专业、可信赖的知识库问答系统
相关推荐
拖孩1 小时前
全程 AI 写的小程序,刚接上会员虚拟支付,上线第二天就有人真金白银买单了|双签名、定价、iOS 的坑我全踩了一遍
前端·后端·微信小程序
我是人✓1 小时前
SpringMVC异常处理与拦截器实战揭秘
java·开发语言·后端
仟里码1 小时前
九:goroutine(1.什么是协程)
后端
不是万能的豆学长1 小时前
排查Go服务40天后的内存泄漏问题
开发语言·后端·golang·go
阿狗童鞋1 小时前
SpringSecurity权限认证实战指南
java·后端·spring
韩振方1 小时前
Kubernetes Service 让会更换的 Pod 有稳定访问入口
后端
用户125758524361 小时前
Golang后台管理框架推荐:XYGo Admin与devinggo怎么选?
后端·go·ai编程
仟里码1 小时前
十一:goroutine(3. select基本使用)
后端
花间相见1 小时前
【计算基础|网络13】UDP 与可靠传输
后端·面试