《基于航空智能客服+RAG》实战

  1. 配置向量数据库
  2. 写入数据(Embedding)
  3. 查询

本服务条款适用于您对 Funnair 的体验。预订航班,即表示您同意这些条款。

  1. 预订航班
  • 通过我们的网站或移动应用程序预订。
  • 预订时需要全额付款。
  • 确保个人信息(姓名、ID 等)的准确性,因为更正可能会产生 25 的费用。
  1. 更改预订
  • 允许在航班起飞前 24 小时更改。
  • 通过在线更改或联系我们的支持人员。
  • 改签费:经济舱 50,豪华经济舱 30,商务舱免费。
  1. 取消预订
  • 最晚在航班起飞前 48 小时取消。
  • 取消费用:经济舱 75 美元,豪华经济舱 50 美元,商务舱 25 美元。
  • 退款将在 7 个工作日内处理。

向量数据库

@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
	return new SimpleVectorStore(embeddingModel);
}

写入向量数据库
在这里插入图片描述

@Bean
CommandLineRunner ingestTermOfServiceToVectorStore(EmbeddingModel embeddingModel, VectorStore vectorStore,
                                                   @Value("classpath:rag/terms-of-service.txt") Resource termsOfServiceDocs) {

    return args -> { 
        vectorStore.write(                                  // 3.写入
            new TokenTextSplitter().transform(          // 2.转换
                new TextReader(termsOfServiceDocs).read())  // 1.读取
        );

    };
}

配置Advisor:

new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()), // RAG
QuestionAnswerAdvisor可以在用户发起的提问时,先向数据库查询相关的文档,再把相关的文档拼接到用户的提问中,再让模型生成答案。那就是RAG的实现了。

 this.chatClient = chatClientBuilder
                .defaultSystem("""
					   您是“图灵”航空公司的客户聊天支持代理。请以友好、乐于助人且愉快的方式来回复。
                       您正在通过在线聊天系统与客户互动。
                       
                        在提供有关预订或取消预订的信息之前,您必须始终
                        从用户处获取以下信息:预订号、客户姓名。
                        在询问用户之前,请检查消息历史记录以获取此信息。
                        在更改或退订之前,请先获取预订信息待用户回复确定之后才进行更改或退订的function-call。 
                       请讲中文。
                       今天的日期是 {current_date}.
					""")
                .defaultAdvisors(
                        new PromptChatMemoryAdvisor(chatMemory),
    						new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()), // RAG
                        new LoggingAdvisor())
				.defaultFunctions("getBookingDetails", "changeBooking", "cancelBooking") // FUNCTION CALLING
				.build();

文档嵌入

在上面的VectorStore配置中我们提供了EmbeddingModel,调用vectorStore.add(splitDocuments)底层会把文档给EmbeddingModel把文本变成向量然后再存入向量数据库。

private final VectorStore vectorStore;
   /**
     * 嵌入文件
     *
     * @param file 待嵌入的文件
     * @return 是否成功
     */
    @SneakyThrows
    @PostMapping("embedding")
    public Boolean embedding(@RequestParam MultipartFile file) {
        // 从IO流中读取文件
        TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(new InputStreamResource(file.getInputStream()));
        // 将文本内容划分成更小的块
        List<Document> splitDocuments = new TokenTextSplitter()
                .apply(tikaDocumentReader.read());
        // 存入向量数据库,这个过程会自动调用embeddingModel,将文本变成向量再存入。
        vectorStore.add(splitDocuments);
        return true;
    }

文档查询

调用vectorStore.similaritySearch(query)时同样会先把用户的提问给EmbeddingModel,将提问变成向量,然后与向量数据库中的文档向量进行相似度计算(cosine值)。
要注意:此时向量数据库不会回答用户的提问。要回答用户的提问需要指定advisor

	/**
     * 查询向量数据库
     *
     * @param query 用户的提问
     * @return 匹配到的文档
     */

    @GetMapping("query")
    public List<Document> query(@RequestParam String query) {
        return vectorStore.similaritySearch(query);
    }

指定advisor

return chatClient.prompt()
                .user(prompt)
                // 2. QuestionAnswerAdvisor会在运行时替换模板中的占位符`question_answer_context`,替换成向量数据库中查询到的文档。此时的query=用户的提问+替换完的提示词模板;
                .advisors(new QuestionAnswerAdvisor(vectorStore, prompt))
                .stream()
                // 3. query发送给大模型得到答案
                .content()
                .map(chatResponse -> ServerSentEvent.builder(chatResponse)
                        .event("message")
                        .build());
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐