Java基于大模型实现客服系统

2024-08-31 15:12
文章标签 java 实现 系统 模型 客服

本文主要是介绍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个实现类:

  1. AstraDbEmbeddingStore
  2. AzureAiSearchEmbeddingStore
  3. CassandraEmbeddingStore
  4. ChromaEmbeddingStore
  5. ElasticsearchEmbeddingStore
  6. InMemoryEmbeddingStore
  7. InfinispanEmbeddingStore
  8. MemoryIdEmbeddingStore
  9. MilvusEmbeddingStore
  10. MinimalEmbeddingStore
  11. MongoDbEmbeddingStore
  12. Neo4jEmbeddingStore
  13. OpenSearchEmbeddingStore
  14. PgVectorEmbeddingStore
  15. PineconeEmbeddingStore
  16. QdrantEmbeddingStore
  17. RedisEmbeddingStore
  18. VearchEmbeddingStore
  19. VespaEmbeddingStore
  20. 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基于大模型实现客服系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1124257

相关文章

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

idea maven编译报错Java heap space的解决方法

《ideamaven编译报错Javaheapspace的解决方法》这篇文章主要为大家详细介绍了ideamaven编译报错Javaheapspace的相关解决方法,文中的示例代码讲解详细,感兴趣的... 目录1.增加 Maven 编译的堆内存2. 增加 IntelliJ IDEA 的堆内存3. 优化 Mave

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St

springboot filter实现请求响应全链路拦截

《springbootfilter实现请求响应全链路拦截》这篇文章主要为大家详细介绍了SpringBoot如何结合Filter同时拦截请求和响应,从而实现​​日志采集自动化,感兴趣的小伙伴可以跟随小... 目录一、为什么你需要这个过滤器?​​​二、核心实现:一个Filter搞定双向数据流​​​​三、完整代码

SpringBoot利用@Validated注解优雅实现参数校验

《SpringBoot利用@Validated注解优雅实现参数校验》在开发Web应用时,用户输入的合法性校验是保障系统稳定性的基础,​SpringBoot的@Validated注解提供了一种更优雅的解... 目录​一、为什么需要参数校验二、Validated 的核心用法​1. 基础校验2. php分组校验3