本文主要是介绍Java基于大模型实现客服系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
如果你问大模型企业私有化的问题,大模型很可能就答非所问了,倘若让大模型结合企业内部数据回答, 用户满意度大幅提升 。以下基于RAG技术实现客服系统
1、引入相关包
<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><langchain4j.version>0.33.0</langchain4j.version></properties><dependencies><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId><version>${langchain4j.version}</version></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId><version>${langchain4j.version}</version></dependency><dependency><groupId>org.tinylog</groupId><artifactId>tinylog-impl</artifactId><version>2.6.2</version></dependency><dependency><groupId>org.tinylog</groupId><artifactId>slf4j-tinylog</artifactId><version>2.6.2</version></dependency></dependencies>
官网链接: OpenAI | LangChain4j
2、文本转向量
向量是数学中的一个基本概念,表示具有大小(gpt的向量长度是1536位)和方向的量。在深度学习中,向量通常用于表示数据点或特征。
向量数据库是一种专门用于存储和查询向量数据的数据库系统。它能够高效地处理高维向量数据,支持基于向量相似性的搜索。
OpenAiEmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();Response<Embedding> embeddingResponse = embeddingModel.embed("hello word");String string = embeddingResponse.content().toString();System.out.println(string);System.out.println('length:' + embeddingResponse.content().vector().length);
控制台输出:
Embedding { vector = [-0.014903838, 0.0013317588, -0.018488139, -0.031072723, -0.024273094, 0.0075046294, -0.023034403, -0.0010262037, -0.012795426, -0.022441411,
… … …
0.020333, 0.0042761234, -0.023324309, -0.034920577, 0.0142844925, 5.39457E-4, -0.0304402, -0.0035184128, -0.011095519] }
length:1536
3、保存向量
RAG(Retrieval-Augmented Generation,检索增强生成) 技术是一种结合信息检索(Retrieval)和生成(Generation)的混合模型方法,旨在通过检索相关信息来增强生成模型的性能。 RAG技术的核心思想是在生成回复时,不仅依赖模型自身的语言理解能力,还通过检索外部知识库(如产品手册等)来增强回复的准确性和丰富性。
基于客服系统需要涉及企业内部私有的信息,需要事先转为向量存储在向量数据库
向量数据库有很多,在LangChain4j中,EmbeddingStore表示向量数据库,它有20个实现类:
- AstraDbEmbeddingStore
- AzureAiSearchEmbeddingStore
- CassandraEmbeddingStore
- ChromaEmbeddingStore
- ElasticsearchEmbeddingStore
- InMemoryEmbeddingStore
- InfinispanEmbeddingStore
- MemoryIdEmbeddingStore
- MilvusEmbeddingStore
- MinimalEmbeddingStore
- MongoDbEmbeddingStore
- Neo4jEmbeddingStore
- OpenSearchEmbeddingStore
- PgVectorEmbeddingStore
- PineconeEmbeddingStore
- QdrantEmbeddingStore
- RedisEmbeddingStore
- VearchEmbeddingStore
- VespaEmbeddingStore
- WeaviateEmbeddingStore
比如redis,使用docker安装
docker run --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest
官网链接:https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/
删除索引和数据命令
redis-cli FT.DROPINDEX embedding-index DD
文档:https://redis.io/docs/latest/commands/ft.dropindex/#examples
maven中引入相关包
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-redis</artifactId><version>${langchain4j.version}</version>
</dependency>
以下以客服电话举例
OpenAiEmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();RedisEmbeddingStore embeddingStore = RedisEmbeddingStore.builder().host("47.xxx.xxx.16").port(6379).dimension(1536)// 不设置默认:embedding-index
// .indexName("test").build();TextSegment textSegment1 = TextSegment.textSegment("客服电话:95152");TextSegment textSegment2 = TextSegment.textSegment("客服时间:周一至周日 08:30-22:00");TextSegment textSegment3 = TextSegment.textSegment("违法和不良信息举报电话:400-140-2108");Response<Embedding> embed1 = embeddingModel.embed(textSegment1);Response<Embedding> embed2 = embeddingModel.embed(textSegment2);Response<Embedding> embed3 = embeddingModel.embed(textSegment3);// 把向量和对应的文本一并存入embeddingStore.add(embed1.content(), textSegment1);embeddingStore.add(embed2.content(), textSegment2);embeddingStore.add(embed3.content(), textSegment3);
查询,看下是否保存成功
redis-cli FT.SEARCH embedding-index "*" LIMIT 0 1
redis-cli FT.SEARCH embedding-index "*" LIMIT 0 1
1) (integer) 3
2) "embedding:c013b1ff-e20a-4124-895b-ebfc1abdca23"
3) 1) "$"2) "{\"vector\":[0.0077204346,-0.011896749,-0.0042433655,0.001396096,-0.017382152,0.018825343,-0.00072119647,0.011034666,-0.007969481............"
java查询
OpenAiEmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").build();RedisEmbeddingStore embeddingStore = RedisEmbeddingStore.builder().host("47.xxx.xxx.16").port(6379).dimension(1536).build();Response<Embedding> embed = embeddingModel.embed("客服电话多少");List<EmbeddingMatch<TextSegment>> result = embeddingStore.findRelevant(embed.content(), 3);for (EmbeddingMatch<TextSegment> embeddingMatch : result){System.out.println(embeddingMatch.embedded().text() + ",分数为:" + embeddingMatch.score());}
代码指定了查询3条,第一条匹配度最高
控制台输出如下:
客服电话:95152,分数为:0.9283385276795
客服时间:周一至周日 08:30-22:00,分数为:0.924619972706
违法和不良信息举报电话:400-140-2108,分数为:0.912132680416
以上介绍了如何把文字转为向量,并存入数据库中
4、客服系统实现
4.1 知识库数据处理
假设知识是如下格式(myDocument.txt),一个问题紧接着一个答案,每个问答之间有一个空行
Q:余额提现到账时间是多久?
1-7个工作日内可退回您的支付账户。由于银行处理可能有延迟,具体以账户的到账时间为准。Q:申请退款后,商家拒绝了怎么办?
申请退款后,如果商家拒绝,此时回到订单页面点击“退款申诉”,美团客服介入处理。Q:怎么取消退款呢?
请在订单页点击“不退款了”,商家还会正常送餐的。
4.1.1 解析文件为document对象
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.TextDocumentParser;
....
Document document;
// 读取文本
Path documentPath = Paths.get("src/main/resources/myDocument.txt");
DocumentParser documentParser = new TextDocumentParser();
document = FileSystemDocumentLoader.loadDocument(documentPath, documentParser);
4.1.2 使用正则\\s*\\R\\s*\\R\\s*
切分文件
先实现DocumentSplitter接口
class CustomerServiceDocumentSplitter implements DocumentSplitter {@Overridepublic List<TextSegment> split(Document document) {List<TextSegment> segments = new ArrayList<>();String[] parts = split(document.text());for (String part : parts){segments.add(TextSegment.from(part));}return segments;}public String[] split(String text) {return text.split("\\s*\\R\\s*\\R\\s*");}}
调用方法切分
import dev.langchain4j.data.segment.TextSegment;
....
CustomerServiceDocumentSplitter splitter = new CustomerServiceDocumentSplitter();
List<TextSegment> segments = splitter.split(document);
TextSegment对象有个属性text存储了我们的问答对
4.2 问答对向量存储
把知识库的文本向量化并存储至向量数据库中
// 文本向量化
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey("demo")
.baseUrl("http://langchain4j.dev/demo/openai/v1")
.build();
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
System.out.println("向量化完毕");// 存redis
EmbeddingStore<TextSegment> embeddingStore = RedisEmbeddingStore.builder()
.host("47.xxx.xxx.16")
.port(6379)
.dimension(1536)
.build();
embeddingStore.addAll(embeddings, segments);
System.out.println("向量存储完毕");
4.3 从向量库中检索内容
创建了一个ContentRetriever对象,用于从向量库中检索内容
// 内容查找ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()// 指定模型.embeddingModel(embeddingModel)// 指定向量库.embeddingStore(embeddingStore)// 最多返回5条数据.maxResults(5)// 最低匹配分数为0.8.minScore(0.8).build();Query query = Query.from("余额什么时候到账?");
List<Content> retrieve = contentRetriever.retrieve(query);
// 输出检索到的内容数量:5
System.out.println("size:" + retrieve.size());
// 打印第一条检索结果的文本内容
System.out.println(retrieve.get(0).textSegment().text());
4.4 借助大模型和向量数据库查询答案
根据以上知识,使用AiServices编写代码
AiServices基础参考
interface CustomerServiceAgent {String answer(String question);// 利用AiServices创建一个CustomerServiceAgent的代理对象static CustomerServiceAgent create() {// 构造ChatMemory,用来保存历史聊天记录ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().apiKey("demo").baseUrl("http://langchain4j.dev/demo/openai/v1").build();EmbeddingStore<TextSegment> embeddingStore = RedisEmbeddingStore.builder().host("47.xxx.xxx.16").port(6379).dimension(1536).build();ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder().embeddingModel(embeddingModel).embeddingStore(embeddingStore).maxResults(3).minScore(0.8).build();ChatLanguageModel model = OpenAiChatModel.builder().apiKey("demo").baseUrl("http://langchain4j.dev/demo/openai/v1").build();return AiServices.builder(CustomerServiceAgent.class).chatLanguageModel(model).chatMemory(chatMemory).contentRetriever(contentRetriever).build();}}
写个main函数测试
public static void main(String[] args) {String answer = CustomerServiceAgent.create().answer("余额什么时候到账?");System.out.println("-------answer:" +answer);}
控制台输出:
-------answer:余额提现到账时间是1-7个工作日内,具体以账户的到账时间为准。
这篇关于Java基于大模型实现客服系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!