1.文档的收集与切割

        基于Spring boot 3.2.5 及spring AI Alibaba 1.0.0 M6

初始文档优化的建议

       1.1创建基于Pgvctor的向量数据库

        手动构建引入Maven坐标

<!--手动整合PGvector 向量存储-->
<!-- PostgreSQL JDBC 驱动 -->
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>
<!--JDBC-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--Spring ai pgvector-->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pgvector-store</artifactId>
    <version>1.0.0-M6</version>
</dependency>

application.yml

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/postgres
    username: postgres
    password: root
    driver-class-name: org.postgresql.Driver
  ai:
    vectorstore:   # 向量数据库选择
      pgvector:   # pgvector
        index-type: hnsw # 向量索引类型
        dimensions: 1536  # 向量维度
        dimension-type: COSINE_DISTANCE  # 使用哪种方式进行相似度检索 # 可选值:COSINE_DISTANCE、EUCLIDEAN_DISTANCE
        max-document-batch-size: 10000    #单次检索的文档数量

创建Pgvector配置类

package com.xiaog.aiapp.RAG;

import jakarta.annotation.Resource;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import static org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgDistanceType.COSINE_DISTANCE;
import static org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType.HNSW;

@Configuration
public class PgVectorVectorStoreConfig {
    //自动创建向量 库
    @Bean
    public VectorStore pgVectorVectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel dashScopeEmbeddingModel) {

        PgVectorStore vectoStore = PgVectorStore.builder(jdbcTemplate, dashScopeEmbeddingModel)
                .dimensions(1536)                    // Optional: defaults to model dimensions or 1536
                .distanceType(COSINE_DISTANCE)       // Optional: defaults to COSINE_DISTANCE // 使用哪一种方式进行相似度检索
                .indexType(HNSW)                     // Optional: defaults to HNSW  // 向量索引类型
                .initializeSchema(true)              // Optional: defaults to false // 是否初始化数据库
                .schemaName("public")                // Optional: defaults to "public" // 模式名
                .vectorTableName("vector_store")     // Optional: defaults to "vector_store" //表 名
                .maxDocumentBatchSize(10000)         // Optional: defaults to 10000
                .build();

//        vectoStore.add(loveAppDocumentLoader.loadMarkdowns());

        return vectoStore;
    }


}

1.2编写读取Markdown文档的类和方法

倒入Maven坐标

<!--spring AI Markdown 文件读取-->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-markdown-document-reader</artifactId>
    <version>1.0.0-M6</version>
</dependency>

编写读取markdown文档的类

package com.xiaog.aiapp.RAG;

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.markdown.MarkdownDocumentReader;
import org.springframework.ai.reader.markdown.config.MarkdownDocumentReaderConfig;
import org.springframework.ai.transformer.KeywordMetadataEnricher;
import org.springframework.ai.transformer.SummaryMetadataEnricher;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * markdown文档加载器
 * 会将markdown进行分段拆分,并生成Document 例如当前加载了3篇md文档,拆分成15个document
 *
 */

@Component
@Slf4j
public class LoveAppDocumentLoader {


    ChatModel dashscopeChatModel;

    private final ResourcePatternResolver resourcePatternResolver;

    LoveAppDocumentLoader(ResourcePatternResolver resourcePatternResolver,ChatModel dashscopeChatModel) {
        this.dashscopeChatModel=dashscopeChatModel;
        this.resourcePatternResolver = resourcePatternResolver;
    }

    public List<Document> loadMarkdowns() {
        List<Document> allDocuments = new ArrayList<>();
        try {
            // 这里可以修改为你要加载的多个 Markdown 文件的路径模式 //当前指向 资源目录下的document文件下的所有markdown文件
            Resource[] resources = resourcePatternResolver.getResources("classpath:document/*.md");



                //加载多篇Markdown文件
            for (Resource resource : resources) {
                String fileName = resource.getFilename(); // 获取文件名
                //读取的配置设置
                MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder()
                        .withHorizontalRuleCreateDocument(true)//添加水平线
                        .withIncludeCodeBlock(false)//添加代码块
                        .withIncludeBlockquote(false)//添加引用
                        .withAdditionalMetadata("filename", fileName) //添加(元信息)而外信息 //比如文件名 其他标签等
                        .build();

                MarkdownDocumentReader reader = new MarkdownDocumentReader(resource, config);

                //拿到所有文档
                List<Document> documentList = reader.get();


                //切分文档 文档按照Token进行切分 可以配置token数量 上下文token交集 (使用该 文档切分效果并不是很好)
//                TokenTextSplitter tokenTextSplitter = new TokenTextSplitter();
//                List<Document> documentsSplitter = tokenTextSplitter.apply(documentList);

                // 添加元数据 提取关键词生成器 metadat 生成
                KeywordMetadataEnricher keywordMetadataEnricher = new KeywordMetadataEnricher(dashscopeChatModel, 3);
                List<Document> documentsMetaDataEnricher = keywordMetadataEnricher.apply(documentList);


//                //    //摘要生成器 生产 摘要
//                SummaryMetadataEnricher summaryMetadataEnricher = new SummaryMetadataEnricher(dashscopeChatModel,
//                        List.of(SummaryMetadataEnricher.SummaryType.PREVIOUS, //结合之前的文档
//                                SummaryMetadataEnricher.SummaryType.CURRENT,    //当前的文档
//                                SummaryMetadataEnricher.SummaryType.NEXT));        //下一个文档
//
//                List<Document> documents = summaryMetadataEnricher.apply(documentsMetaDataEnricher);

                //添加到集合
                allDocuments.addAll(documentsMetaDataEnricher);
            }
        } catch (IOException e) {
            log.error("Markdown 文档加载失败", e);
        }
        return allDocuments;
    }
}

1.3编写测试类,加载文档到向量数据库

       文件切分 

TokenTextSplitter

样例:

        更具文档token数量切割,可以构造函数配置切分规则

//    //切分文档 文档按照Token进行切分 可以配置token数量 上下文token交集
    TokenTextSplitter tokenTextSplitter = new TokenTextSplitter();
    List<Document> documentsSplitter = tokenTextSplitter.apply(documents);
       关键元信息添加 

 KeywordMetadataEnricher

示例
        需要调用大模型进行 关键元数据生成 对检索的帮助很大

    // 添加元数据 提取关键词生成器 metadat 生成
    KeywordMetadataEnricher keywordMetadataEnricher = new KeywordMetadataEnricher(dashscopeChatModel,3);
    List<Document> documentsMetaDataEnricher = keywordMetadataEnricher.apply(documents);
       文档摘要   

SummaryMetadataEnricher

示例:

给文档添加摘要信息,当单个文档太小时不要使用,不然摘要比文档还多

//    //摘要生成器 生产 摘要
    SummaryMetadataEnricher summaryMetadataEnricher = new SummaryMetadataEnricher(dashscopeChatModel,
            List.of(SummaryMetadataEnricher.SummaryType.PREVIOUS, //结合之前的文档
                    SummaryMetadataEnricher.SummaryType.CURRENT,    //当前的文档
                    SummaryMetadataEnricher.SummaryType.NEXT));        //下一个文档

    List<Document> documentList = summaryMetadataEnricher.apply(documentsMetaDataEnricher);

接下来就是测试添加文档到向量数据库 ,并且查看是否正常切割

package com.xiaog.aiapp;

import com.xiaog.aiapp.RAG.LoveAppDocumentLoader;
import com.xiaog.aiapp.app.LoveApp;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.document.Document;
import org.springframework.ai.transformer.KeywordMetadataEnricher;
import org.springframework.ai.transformer.SummaryMetadataEnricher;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SpringBootTest
public class PgVectorStoreTest {


    @Resource
    VectorStore pgVectorVectorStore;

    @Resource
    LoveAppDocumentLoader loveAppDocumentLoader;

    @Resource
    ChatModel dashscopeChatModel;


    @Autowired
    LoveApp app;

@Test
    public void testPgVectorStore() throws Exception {

    List<Document> documents=new ArrayList<>();
    // 手动 添加文档信息
    documents.add( new Document("Spring AI 的官方文档就算一坨大便", Map.of("meata1","meata1")));

    documents.addAll(loveAppDocumentLoader.loadMarkdowns());
//
//    //切分文档 文档按照Token进行切分 可以配置token数量 上下文token交集
//    TokenTextSplitter tokenTextSplitter = new TokenTextSplitter();
//    List<Document> documentsSplitter = tokenTextSplitter.apply(documents);
//
    // 添加元数据 提取关键词生成器 metadat 生成
    KeywordMetadataEnricher keywordMetadataEnricher = new KeywordMetadataEnricher(dashscopeChatModel,3);
    List<Document> documentsMetaDataEnricher = keywordMetadataEnricher.apply(documents);

//    //摘要生成器 生产 摘要
//    SummaryMetadataEnricher summaryMetadataEnricher = new SummaryMetadataEnricher(dashscopeChatModel,
//            List.of(SummaryMetadataEnricher.SummaryType.PREVIOUS, //结合之前的文档
//                    SummaryMetadataEnricher.SummaryType.CURRENT,    //当前的文档
//                    SummaryMetadataEnricher.SummaryType.NEXT));        //下一个文档
//
//    List<Document> documentList = summaryMetadataEnricher.apply(documentsMetaDataEnricher);


    pgVectorVectorStore.add(documentsMetaDataEnricher);

    testPgVectorStoreDoChat();
//    List<Document> result=pgVectorVectorStore.similaritySearch(SearchRequest.builder().query("Spring").build());
//
//    System.out.println(result);

}


        @Test
    public void testPgVectorStoreDoChat(){
            String systemMessage = app.dochatRag("你是谁?我还是单身,应该怎么提高脱单的概率", "123");

            System.out.println(systemMessage);
        }




}

启动

testPgVectorStore

测试方法

查看数据库

文档正常切割添加到数据库

2.用户消息的增强

2.1用户消息重写

“用户消息重写”指的是在将用户的原始问题(Query)发送给向量数据库进行检索之前,先通过一个大语言模型(LLM)对这个原始问题进行改写、扩展、澄清或优化的过程

用户的原始问题可能:

  1. 过于简短或模糊: 如 “它怎么样?” (缺少上下文)。
  2. 包含指代: 如 “这个功能的优缺点是什么?” (“这个” 指什么?)。
  3. 不够具体: 如 “告诉我关于 AI 的事” (范围太广)。
  4. 需要扩展: 加入同义词或相关概念能提高检索召回率。
  5. 需要澄清: 将口语化表达转为更正式、明确的查询。

在spring AI中提供了

QueryTransformer接口 

现在我们编写一个用户消息重写的类

package com.xiaog.aiapp.RAG;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.preretrieval.query.transformation.QueryTransformer;
import org.springframework.ai.rag.preretrieval.query.transformation.RewriteQueryTransformer;
import org.springframework.stereotype.Component;

/**
 * 用户消息重写器,尝试修改用户输入,使其更清晰和准确
 */


@Component
public class QueryRewriter {

    private final QueryTransformer queryTransformer;

    public QueryRewriter(ChatModel dashscopeChatModel) {
        ChatClient.Builder builder = ChatClient.builder(dashscopeChatModel);
        // 创建查询重写转换器
        queryTransformer = RewriteQueryTransformer.builder()
                .chatClientBuilder(builder)
                .build();
    }

    public String doQueryRewrite(String prompt) {
        Query query = new Query(prompt);
        // 执行查询重写
        Query transformedQuery = queryTransformer.transform(query);
        // 输出重写后的查询
        return transformedQuery.text();
    }
}

  app对话方法(在对话方法用调用 重写用户消息方法)

package com.xiaog.aiapp.app;

import com.xiaog.aiapp.RAG.QueryRewriter;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Component;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Component
public class LoveApp {

    ChatClient chatClient;

    private static final String SYSTEM_PROMPT = "扮演深耕恋爱心理领域的专家。开场向用户表明身份,告知用户可倾诉恋爱难题。" +
            "围绕单身、恋爱、已婚三种状态提问:单身状态询问社交圈拓展及追求心仪对象的困扰;" +
            "恋爱状态询问沟通、习惯差异引发的矛盾;已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述事情经过、对方反应及自身想法,以便给出专属解决方案。";


    public LoveApp(ChatModel dashscopeChatModel)
    {
        // 初始化基于内存的对话记忆
        ChatMemory chatMemory = new InMemoryChatMemory();

//        String basePath = System.getProperty("user.home")+ "/.tmp/chat-memory";
//        System.out.println("basePath:"+basePath);
//        //初始化基于文件的对话记忆
//        ChatMemory chatMemory = new FileBasedChatMemory(basePath);

        chatClient = ChatClient.builder(dashscopeChatModel) // 创建基于(某个chatModel)大模型的ChatClient
                .defaultSystem(SYSTEM_PROMPT) // 设置默认系统提示词
                .defaultAdvisors(  // 设置默认的Advisor
                        new MessageChatMemoryAdvisor(chatMemory) // 设置基于内存的对话记忆的Advisor
//                        ,new MyLogAdvisor() // 设置日志Advisor
//                        ,new ReReadingAdvisor()
                )
                .build();//构建返回client
    }



    @Resource
    QueryRewriter queryRewriter;

    @Resource
    VectorStore pgVectorVectorStore;


    /**
     * 基于RAG问答功能
     */
    public String dochatRag(String message,String id){

        //用户提问重写
        String newMessage = queryRewriter.doQueryRewrite(message);


        ChatResponse chatResponse = chatClient
                .prompt()
                .user(newMessage)
                .advisors(advisorSpec -> advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, id) //根据会话id获取对话历史
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))//获取历史消息的条数
//                .advisors(new MyLogAdvisor())

                //应用RAG(知识库问答)(自定义知识库) QuestionAnswerAdvisor 是问答(Q&A)助手,专门用于 RAG(检索增强生成)
//                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))

                //基于云知识库
                //应用RAG知识库(检索增强服务) 基于阿里百练知识库 且使用RetrievalAugmentedGenerationAssistant 功能更强大
//                .advisors(loveAppRagCloudAdvisor)

                //基于PGVector知识库
                .advisors(   // 第一个 Advisor: RetrievalAugmentationAdvisor
//                           RetrievalAugmentationAdvisor.builder()
//                                   .documentRetriever(documentRetriever(pgVectorVectorStore)) // 使用已配置好检索参数的 documentRetriever
//                                   .build(),

                        // 第二个 Advisor: QuestionAnswerAdvisor (已修改参数)
                        QuestionAnswerAdvisor.builder(pgVectorVectorStore)
                                .searchRequest(SearchRequest.builder()
                                        .similarityThreshold(0.4d) // 检索关联度达到 0.4
                                        .topK(5)                  // 文档5篇
                                        .build()).build()
                ) //设置搜索参数 关联度达到0.4的 取6条数据


                .call()
                .chatResponse();

        return chatResponse.getResult().getOutput().getText();
    }






}

调用测试

这个是我们输入给ai的消息,debug启动查看ai给我们改成了什么样

被ai修改后的消息:

3.文档的检索优化

srping ai中有检索器,可以优化我们所需要检索的文档信息,这是影响检索质量的关键,主要包括三个方面,例如相似度阈值,返回文档数,和过滤规则等

3.1第一种 RetrievalAugmentationAdvisor +自定义检索器

编写自定义检索器        

package com.xiaog.aiapp.RAG;

import org.springframework.ai.document.Document;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.retrieval.search.DocumentRetriever;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;

import java.util.List;

/**
 * 自定义文档检索器
 */

public class MyDocumentRetriever implements DocumentRetriever{

    VectorStoreDocumentRetriever vectorStoreDocumentRetriever;

    public  MyDocumentRetriever(VectorStore pgVectorVectorStore,Double similarityThreshold, int topK) {
        vectorStoreDocumentRetriever = VectorStoreDocumentRetriever.builder()
                .vectorStore(pgVectorVectorStore)
                .similarityThreshold(similarityThreshold) // 相似度阈值
                .topK(topK) // 返回的文档数量
//                .filterExpression(
//                        new FilterExpressionBuilder()
//                                .eq("type", "web")   //寻回检索 元数据中 type 为 web 的文档
//                                .build()
//                )
                .build();
    }

    @Override
    public List<Document> retrieve(Query query) {
        return vectorStoreDocumentRetriever.retrieve(query);
    }

    @Override
    public List<Document> apply(Query query) {
       return vectorStoreDocumentRetriever.apply(query);
    }
}

ChatClient的使用 方法

dochatRag方法中的 

建议关联度达到0.4最好

package com.xiaog.aiapp.app;

import com.xiaog.aiapp.RAG.MyDocumentRetriever;
import com.xiaog.aiapp.RAG.QueryRewriter;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.stereotype.Component;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Component
public class LoveApp {

    ChatClient chatClient;

    private static final String SYSTEM_PROMPT = "扮演深耕恋爱心理领域的专家。开场向用户表明身份,告知用户可倾诉恋爱难题。" +
            "围绕单身、恋爱、已婚三种状态提问:单身状态询问社交圈拓展及追求心仪对象的困扰;" +
            "恋爱状态询问沟通、习惯差异引发的矛盾;已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述事情经过、对方反应及自身想法,以便给出专属解决方案。";


    public LoveApp(ChatModel dashscopeChatModel)
    {
        // 初始化基于内存的对话记忆
        ChatMemory chatMemory = new InMemoryChatMemory();

//        String basePath = System.getProperty("user.home")+ "/.tmp/chat-memory";
//        System.out.println("basePath:"+basePath);
//        //初始化基于文件的对话记忆
//        ChatMemory chatMemory = new FileBasedChatMemory(basePath);

        chatClient = ChatClient.builder(dashscopeChatModel) // 创建基于(某个chatModel)大模型的ChatClient
                .defaultSystem(SYSTEM_PROMPT) // 设置默认系统提示词
                .defaultAdvisors(  // 设置默认的Advisor
                        new MessageChatMemoryAdvisor(chatMemory) // 设置基于内存的对话记忆的Advisor
//                        ,new MyLogAdvisor() // 设置日志Advisor
//                        ,new ReReadingAdvisor()
                )
                .build();//构建返回client
    }



    @Resource
    QueryRewriter queryRewriter;

    @Resource
    VectorStore pgVectorVectorStore;


    /**
     * 基于RAG问答功能
     */
    public String dochatRag(String message,String id){

        //用户提问重写
        String newMessage = queryRewriter.doQueryRewrite(message);


        ChatResponse chatResponse = chatClient
                .prompt()
                .user(newMessage)
                .advisors(advisorSpec -> advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, id) //根据会话id获取对话历史
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))//获取历史消息的条数
//                .advisors(new MyLogAdvisor())

                //应用RAG(知识库问答)(自定义知识库) QuestionAnswerAdvisor 是问答(Q&A)助手,专门用于 RAG(检索增强生成)
//                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))

                //基于云知识库
                //应用RAG知识库(检索增强服务) 基于阿里百练知识库 且使用RetrievalAugmentedGenerationAssistant 功能更强大
//                .advisors(loveAppRagCloudAdvisor)

                //基于PGVector知识库
                .advisors(
                        // 第一个 Advisor: RetrievalAugmentationAdvisor
//
                           RetrievalAugmentationAdvisor.builder()
                                   .documentRetriever(new MyDocumentRetriever(pgVectorVectorStore, 0.7, 5)) // 使用已配置好检索参数的 documentRetriever
                                   .build()
////                        ,

                        // 第二个 Advisor: QuestionAnswerAdvisor (已修改参数)

//                        QuestionAnswerAdvisor.builder(pgVectorVectorStore)
//                                .searchRequest(SearchRequest.builder()
//                                        .similarityThreshold(0.4d) // 检索关联度达到 0.4
//                                        .topK(5)// 文档5篇
////                                        .filterExpression(
////                                                new FilterExpressionBuilder()
////                                                        .eq("type", "text").build()) //查询元数据中 type 为 text 的文档
//                                        .build()).build()

                ) 


                .call()
                .chatResponse();

        return chatResponse.getResult().getOutput().getText();
    }






}

3.2 第二种 QuestionAnswerAdvisor 

package com.xiaog.aiapp.app;

import com.xiaog.aiapp.RAG.MyDocumentRetriever;
import com.xiaog.aiapp.RAG.QueryRewriter;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.stereotype.Component;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Component
public class LoveApp {

    ChatClient chatClient;

    private static final String SYSTEM_PROMPT = "扮演深耕恋爱心理领域的专家。开场向用户表明身份,告知用户可倾诉恋爱难题。" +
            "围绕单身、恋爱、已婚三种状态提问:单身状态询问社交圈拓展及追求心仪对象的困扰;" +
            "恋爱状态询问沟通、习惯差异引发的矛盾;已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述事情经过、对方反应及自身想法,以便给出专属解决方案。";


    public LoveApp(ChatModel dashscopeChatModel)
    {
        // 初始化基于内存的对话记忆
        ChatMemory chatMemory = new InMemoryChatMemory();

//        String basePath = System.getProperty("user.home")+ "/.tmp/chat-memory";
//        System.out.println("basePath:"+basePath);
//        //初始化基于文件的对话记忆
//        ChatMemory chatMemory = new FileBasedChatMemory(basePath);

        chatClient = ChatClient.builder(dashscopeChatModel) // 创建基于(某个chatModel)大模型的ChatClient
                .defaultSystem(SYSTEM_PROMPT) // 设置默认系统提示词
                .defaultAdvisors(  // 设置默认的Advisor
                        new MessageChatMemoryAdvisor(chatMemory) // 设置基于内存的对话记忆的Advisor
//                        ,new MyLogAdvisor() // 设置日志Advisor
//                        ,new ReReadingAdvisor()
                )
                .build();//构建返回client
    }



    @Resource
    QueryRewriter queryRewriter;

    @Resource
    VectorStore pgVectorVectorStore;


    /**
     * 基于RAG问答功能
     */
    public String dochatRag(String message,String id){

        //用户提问重写
        String newMessage = queryRewriter.doQueryRewrite(message);


        ChatResponse chatResponse = chatClient
                .prompt()
                .user(newMessage)
                .advisors(advisorSpec -> advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, id) //根据会话id获取对话历史
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))//获取历史消息的条数
//                .advisors(new MyLogAdvisor())

                //应用RAG(知识库问答)(自定义知识库) QuestionAnswerAdvisor 是问答(Q&A)助手,专门用于 RAG(检索增强生成)
//                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))

                //基于云知识库
                //应用RAG知识库(检索增强服务) 基于阿里百练知识库 且使用RetrievalAugmentedGenerationAssistant 功能更强大
//                .advisors(loveAppRagCloudAdvisor)

                //基于PGVector知识库
                .advisors(
                        // 第一个 Advisor: RetrievalAugmentationAdvisor
//
//                           RetrievalAugmentationAdvisor.builder()
//                                   .documentRetriever(new MyDocumentRetriever(pgVectorVectorStore, 0.4, 3)) // 使用已配置好检索参数的 documentRetriever
//                                   .build()
////                        ,

                        // 第二个 Advisor: QuestionAnswerAdvisor (已修改参数)

                            QuestionAnswerAdvisor.builder(pgVectorVectorStore)
                                .searchRequest(SearchRequest.builder()
                                        .similarityThreshold(0.4d) // 检索关联度达到 0.4
                                        .topK(5)// 文档5篇
//                                        .filterExpression(
//                                                new FilterExpressionBuilder()
//                                                        .eq("type", "text").build()) //查询元数据中 type 为 text 的文档
                                        .build()).build()

                )


                .call()
                .chatResponse();

        return chatResponse.getResult().getOutput().getText();
    }






}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐