Srping AI RAG 知识库 最佳实践
·
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)对这个原始问题进行改写、扩展、澄清或优化的过程
用户的原始问题可能:
- 过于简短或模糊: 如 “它怎么样?” (缺少上下文)。
- 包含指代: 如 “这个功能的优缺点是什么?” (“这个” 指什么?)。
- 不够具体: 如 “告诉我关于 AI 的事” (范围太广)。
- 需要扩展: 加入同义词或相关概念能提高检索召回率。
- 需要澄清: 将口语化表达转为更正式、明确的查询。
在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();
}
}
更多推荐



所有评论(0)