LLM应用实战:当KBQA集成LLM(二)

1. 背景

又两周过去了,本qiang~依然奋斗在上周提到的项目KBQA集成LLM,感兴趣的可通过传送门查阅先前的文章《LLM应用实战:当KBQA集成LLM》。

本次又有什么更新呢?主要是针对上次提到的缺点进行优化改进。主要包含如下方面:

1. 数据落库

上次文章提到,KBQA服务会将图谱的概念、属性、实体、属性值全部加载到内存,所有的查询均在内存中进行,随之而来的问题就是如果图谱的体量很大呢,那内存不爆了么…

2. 支持基于属性值查实体

上篇文章不支持属性值查找实体,比如”最会照顾宝宝的是什么龙”,”什么龙是大龙和大龙生活,小龙和小龙生活”。本次已经此问题优化。

此篇文章是对这两周工作的一个整体总结,其中包含部分工程层面的优化。

2. 整体框架

整体框架和上篇大致相同,不同之处在于:

1. 对齐模块:先前是基于SIM筛选候选实体,本次基于ES进行候选实体召回

2. 解析模块:先前是基于hugegraph和内存中的实体信息进行解析,本次优化为基于hugegraphelasticsearch

3. 核心功能

3.1 数据库选型

由于需要支撑语义相似度检索,因此数据库选型为Milvus与Elasticsearch。

二者之间的比对如下:

Milvus

Elastic

扩展性层面

存储和计算分离

查询和插入分类

组件级别支持

服务器层面支持

多副本

动态分段 vs 静态分片

动态分段

静态分片

云原生

十亿级规模向量支持

功能性层面

权限控制

磁盘索引支撑

混合搜索

分区/命名空间/逻辑组

索引类型

11个(FLAT, IVF_FLAT, HNSW)等

1个(HNSW)

多内存索引支持

专门构建层面

为向量而设计

可调一致性

流批向量数据支持

二进制向量支持

多语言SDK

python, java, go, c++, node.js, ruby

python, java, go, c++, node.js, ruby, Rust, C#, PHP, Perl

数据库回滚

但由于Milvus针对国产化环境如华为Atlas适配不佳,而Es支持国产化环境,因此考虑到环境通用性,选择Es,且其文本搜索能力较强。

3.2 表结构设计

由于知识图谱的概念、属性一般量级较少,而实体数随着原始数据的丰富程度客场可短。因此将实体及其属性值在Es中进行存储。

针对KBQA集成LLM的场景,有两块内容会涉及语义搜索召回。

1. 对齐prompt中的候选实体

2. 解析模块中存在需要基于属性值查询实体的情况。

3. 涉及到数值类型的查询,如大于xx,最大,最小之类。

综合考虑,将Es的index结构设计如下:

属性

含义

类型

备注

name

实体名

keyword

concepts

所属概念

keyword

一个实体可能存在多个概念

property

属性

keyword

属性名称

value

属性值

text

ik分词器进行分词

numbers

数值属性值

double_range

会存在一个区间范围

embeddings

向量

elastiknn_dense_float_vector

1. 非数值属性对应value的向量

2. 使用elastiknn插件

3.3 安装部署

项目使用的Es版本是8.12.2,原因是elastiknn插件和Ik插件针对该版本均支持,且8.12.2版本是当前阶段的次新版本。

3.3.1 基于docker的ES部署

# 拉取镜像(最好先设置国内镜像加入)

docker pull elasticsearch:8.12.2

# es容器启动,存在SSL鉴权

docker run -d --name es01 --net host  -p 9200:9200 -it -e "ES_JAVA_OPTS=-Xms1024m -Xmx1024m" elasticsearch:8.13.2

# 容器中拉取需要鉴权的信息到本地

docker cp es01:/usr/share/elasticsearch/config/certs/http_ca.crt .

chmode 777 http_ca.crt

# 密码第一次启动的日志中有,需要保存下来

export ELASTIC_PASSWORD=xxxxxx

# 验证es是否启动成功

curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD https://localhost:9200

3.3.2 elastiknn插件集成

elastiknn插件是为了优化ES自身的向量检索性能,安装此插件后,ES的向量检索性能会提升数倍,如果再增加SSD固态硬盘,性能会进一步提升数倍

#下载插件包

wget https://github.com/alexklibisz/elastiknn/releases/download/8.12.2.1/elastiknn-8.12.2.1.zip

# 导入容器中指定目录

docker cp  elastiknn-8.12.2.1.zip es01:/usr/share/elasticsearch/

# 进入容器,默认目录即为/usr/share/elasticsearch/

docker exec -it es01 bash

# 安装插件

elasticsearch-plugin install file:elastiknn-8.12.2.1.zip

# 退出,重启容器

docker restart es01

# 验证

# 创建mapping

curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -XPOST https://localhost:9200/test/_mapping -H 'Content-Type:application/json' -d '

{

         "properties": {

                  "embeddings": {

                          "type": "elastiknn_dense_float_vector",

                          "elastiknn": {

                                   "model": "lsh",

                                   "similarity": "cosine",

                                   "dims": 768,

                                   "L": 99,

                                   "k": 3

                          }

                  }

         }

}'

# 验证mapping是否生效

curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -XGET https://localhost:9200/test/_mapping?pretty

采坑总结:

1. elastiknn插件导入始终无法安装,且报错。

解决:

(1) 一定要注意,安装es插件需要指定路径,且增加”file:” 的前缀,不加此前缀,那就等着报错吧

(2) 拷贝到容器内部,一定要注意,不要将elastiknn-8.12.2.1.zip拷贝至/usr/share/elasticsearch/plugins目录,否则安装也报错。

3.3.3 ik分词器插件集成

#下载插件包

wget https://github.com/infinilabs/analysis-ik/releases/download/v8.12.2/elasticsearch-analysis-ik-8.12.2.zip

# 导入容器中指定目录

docker cp elasticsearch-analysis-ik-8.12.2.zip es01:/usr/share/elasticsearch/

# 进入容器,默认目录即为/usr/share/elasticsearch/

docker exec -it es01 bash

# 安装插件

elasticsearch-plugin install file:elasticsearch-analysis-ik-8.12.2.zip

# 退出,重启容器

docker restart es01

# 验证是否生效

curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -XPOST https://localhost:9200/_analyze?pretty -H 'Content-Type:application/json' -d '{"text":"三角龙或者霸王龙","analyzer": "ik_smart"}'

# 返回结果中不包含”或者”,因为”或者”在默认的停用词表中。

采坑总结:

1. ik分词器插件导入始终无法安装,且报错。

解决:一定要注意,安装es插件需要指定路径,且增加”file:” 的前缀,不加此前缀,那就等着报错吧

2. ik分词器添加自定义专有名词以及停用词不生效(浪费了1天的时间来排查)

解决:

(1) 一定要注意,8.12.2版本的ik分词器如果想要配置自定义专有名词或停用词,配置的完整目录是/usr/share/elasticsearch/config/analysis-ik,而不是/usr/share/elasticsearch/plugins/analysis-ik,这点需要注意下。

在config/analysis-ik中配置IKAnalyzer.cfg.xml,修改内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

<properties>

         <comment>IK Analyzer 扩展配置</comment>

         <!--用户可以在这里配置自己的扩展字典 -->

         <entry key="ext_dict">extra_main.dic</entry>

          <!--用户可以在这里配置自己的扩展停止词字典-->

         <entry key="ext_stopwords">extra_stopword.dic</entry>

         <!--用户可以在这里配置远程扩展字典 -->

         <!-- <entry key="remote_ext_dict">words_location</entry> -->

         <!--用户可以在这里配置远程扩展停止词字典-->

         <!-- <entry key="remote_ext_stopwords">words_location</entry> -->

</properties>

(2) 一定要注意,extra_main.dicextra_stopword.dic的编码格式是UTF-8,如果编码格式不对的话,分词也不生效。

4. Es操作相关源码

4.1 es_client连接

self.es_client = Elasticsearch(config['url'], basic_auth=(config['user'], config['password']), ca_certs=config['crt_path'],http_compress=True,request_timeout=int(config['request_timeout']) if 'request_timeout' in config else 60,max_retries=int(config['max_retries']) if 'max_retries' in config else 5,retry_on_timeout=True)

4.2 构建表结构

def index(self, kg_id, force=False):"""构建表"""if force:try:self.es_client.indices.delete(index=kg_id, ignore_unavailable=True)except EngineError as e:logger.exception(f"code:{ES_DELETE_INDEX_ERROR}, message:{str(e)}")raise eif not self.es_client.indices.exists(index=kg_id):body = {'settings': {'index': {'number_of_shards': 2}},'mappings': {'dynamic': False,'properties': {'name': {'type': 'keyword'},'concepts': {'type': 'keyword'},'property': {'type': 'keyword'},'value': {'type': 'text', 'analyzer': 'ik_max_word', 'search_analyzer': 'ik_smart'},'numbers': {'type': 'double_range'},'embeddings': {'type': 'elastiknn_dense_float_vector', 'elastiknn': {'dims': 768, 'model': 'lsh', 'similarity': 'cosine', 'L': 99, 'k': 3}}}}}try:self.es_client.indices.create(index=kg_id, body=body)except EngineError as e:logger.exception(f"code:1008, message:{str(e)}")raise etry:   self.es_client.indices.refresh(index=kg_id, ignore_unavailable=True)except EngineError as e:logger.exception(f"code:1008, message:{str(e)}")raise e

说明:

1. value字段需要经过IK分词,分词方式ik_max_word,查询方式是ik_smart

2. embeddings的类型为elastiknn_dense_float_vector,其中向量维度为768,相似度计算使用cosine

4.3 候选实体查询

def get_candidate_entities(self, kg_id, query, limit=15):"""基于查询串查找候选实体名称"""body = {'_source': {'excludes': ["embeddings"]},'query': {'function_score': {'query': {'bool': {'must': [{'match': {'value': query}},{'bool': {'filter': {'bool': {'should': [{'term': {"property": "名称"}},{'term': {"property": "别名"}},]}}}}]}},'functions': [{'elastiknn_nearest_neighbors': {'field': 'embeddings','vec': self.get_callback_ans({'query': [query]})['result'][0]['embeddings'],'model': 'lsh','similarity': 'cosine','candidates': 100} }]}},'size': limit}return self.es_client.search(index=kg_id, body=body)['hits']['hits']

说明:

1. '_source': {'excludes': ["embeddings"]}表示输出结果中过滤embeddings字段

2. 查询以function_score方式,其中的query表示别名或名称与问题的匹配程度,functions表示打分方式,目前的打分是基于向量相似度进行打分,其中, self.get_callback_ans表示语义相似度模型将文本转换为向量。注意:最终的得分由两部分组成,一部分是文本匹配,一部分是语义相似度匹配,不过可以增加参数boost_mode进行设置。

4.4 基于属性及属性值进行查询

def search_by_property_value(self, kg_id, property, value, limit=100):body = {'_source': {'excludes': ["embeddings"]},'query': {'function_score': {'query': {'bool': {'must': [{'match': {'value': value}},{'term': {"property": property}}]}},'functions': [{'elastiknn_nearest_neighbors': {'field': 'embeddings','vec': self.get_callback_ans({'query': [value]})['result'][0]['embeddings'],'model': 'lsh','similarity': 'cosine','candidates': 100} }],'boost_mode': 'replace'}},'size': limit}try:return self.es_client.search(index=kg_id, body=body)['hits']['hits']except EngineError as e:logger.exception(f"code:{ES_SEARCH_ERROR}, message:{str(e)}")raise e

4.5 数值属性范围查询

主要解决的场景有:体重大于9吨的恐龙有哪些?身长小于10米的角龙类有哪些?

其中,如果提供了实体名称,则查询范围是基于这些实体进行查询比较。

def search_by_number_property(self, kg_id, property, operate, entities, limit=100):musts = [{'term': {'property': property}}, {'range': {'numbers': operate}}]if entities:musts.append({'terms': {'name': entities}})body = {'_source': {'excludes': ['embeddings']},'query': {'bool': {'must': musts}},'size': limit}try:return self.es_client.search(index=kg_id, body=body)['hits']['hits']except EngineError as e:logger.exception(f"code:{ES_SEARCH_ERROR}, message:{str(e)}")raise e

4.6 数值属性最大最小查询

实现最大最小的逻辑,采用了sort机制,按照numbers进行排序,最大则顺排,最小则倒排。

def search_by_number_property_maxmin(self, kg_id, property, entities, sort_flag):musts = [{'term': {'property': property}}]if entities:musts.append({'terms': {'name': entities}})body = {'_source': {'excludes': ["embeddings"]},'query': {'bool': {'must': musts}},'sort': {'numbers': sort_flag},'size': 1}try:return self.es_client.search(index=kg_id, body=body)['hits']['hits']except EngineError as e:logger.exception(f"code:{ES_SEARCH_ERROR}, message:{str(e)}")raise e

5. 效果

上一版未解决的问题,在本版本优化的结果,主要是基于属性值查找实体。

1. 问:头像鸭头的龙有哪些?

答:头像鸭头的有慈母龙、原角龙、鹦鹉嘴龙、姜氏巴克龙、奇异辽宁龙、多背棘沱江龙、陆家屯鹦鹉嘴龙、盖斯顿龙、小盾龙、肿头龙、弯龙

2. 问:老师说的有一个特别会照顾宝宝的恐龙是什么龙?

答:慈母龙会照顾宝宝。

3. 问:有哪些恐龙会游泳啊?

答:滑齿龙、慢龙和色雷斯龙是会游泳的恐龙。

4. 问:科学家在意大利阿尔卑斯山脉Preone山谷的乌迪内附近发现了一个会飞的史前动物化石,它是谁的化石?

答:科学家在意大利阿尔卑斯山脉Preone山谷的乌迪内附近发现的会飞的史前动物化石是沛温翼龙的化石。

6. 总结

一句话足矣~

本文主要是针对KBQA方案基于LLM实现存在的问题进行优化,主要涉及到图谱存储至Es,且支持Es的向量检索,还有解决了一部分基于属性值倒查实体的场景,且效果相对提升。

其次,提供了部分Es的操作源码,以飧读者。

附件:

1. es vs milvus: Milvus vs Elastic | Zilliz

2. docker安装es:Install Elasticsearch with Docker | Elasticsearch Guide [8.12] | Elastic

3. elastiknn性能分析

ES 8.x 向量检索性能测试 & 把向量检索性能提升100倍!_elastiknn-CSDN博客

4. es的function_score: Function score query | Elasticsearch Guide [8.12] | Elastic

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/3452.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多客圈子交友系统 uniapp+thinkphp6适配小程序/H5/app/api全开源,多款插件自选,支持个性定制!

网上交友的优点包括&#xff1a; 1. 方便&#xff1a;网上交友可以随时随地进行&#xff0c;不受时间和空间的限制&#xff0c;方便且高效。 2. 匿名性&#xff1a;网上交友可以实现匿名性&#xff0c;用户可以匿名地搜索、聊天或交换信息&#xff0c;保护个人隐私和安全。 3.…

COOIS 生产订单显示系统增强

需求说明&#xff1a;订单系统显示页面新增批量打印功能 增强点&#xff1a;CL_COIS_DISP_LIST_NAVIGATION -->TOOLBAR方法中新增隐式增强添加自定义打印按钮 增强点&#xff1a;BADI-->WORKORDER_INFOSYSTEM新增增强实施 实现位置&#xff1a;IF_EX_WORKORDER_INFOSYS…

制造型企业 如何实现便捷的机台文件统一管理?

机台文件统一管理&#xff0c;这是生产制造型企业都需要去做的&#xff0c;机台文件需要统一管理的原因主要包括以下几点&#xff1a; 1、提高效率&#xff1a;统一管理可以简化文件的访问和使用过程&#xff0c;提高工作效率&#xff0c;尤其是在需要频繁访问或更新机台文件的…

MySQL中什么情况下会出现索引失效?如何排查索引失效?

目录 1-引言&#xff1a;什么是MySQL的索引失效&#xff1f;(What、Why)1-1 索引失效定义1-2 为什么排查索引失效 2- 索引失效的原因及排查&#xff08;How&#xff09;2-1 索引失效的情况① 索引列参与计算② 对索引列进行函数操作③ 查询中使用了 OR 两边有范围查询 > 或 …

USB设备的音频类UAC

一、UAC简介 UAC&#xff08;USB Audio Class&#xff09;是USB设备的音频类&#xff0c;它定义了USB音频设备与主机计算机通信的方式。UAC标准是USB规范的一部分&#xff0c;并受到各种操作系统&#xff08;包括Windows、macOS和Linux&#xff09;的支持。 UAC是基于libusb,实…

图像在神经网络中的预处理与后处理的原理和作用(最详细版本)

1. 问题引出及内容介绍 相信大家在学习与图像任务相关的神经网络时&#xff0c;经常会见到这样一个预处理方式。 self.to_tensor_norm transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) 具体原理及作用稍后解释&…

java8 Stream流常用方法(持续更新中...)

java8 Stream流常用方法 1.过滤数据中年龄大于等于十八的学生2.获取对象中其中的一个字段并添加到集合(以学生姓名&#xff08;name&#xff09;为例)3.获取对象中其中的一个字段并转为其他数据类型最后添加到集合(以学生性别&#xff08;sex&#xff09;为例&#xff0c;将Str…

Apache Doris 2.x 版本【保姆级】安装+使用教程

Doris简介 Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以极速易用的特点被人们所熟知&#xff0c;仅需亚秒级响应时间即可返回海量数据下的查询结果&#xff0c;不仅可以支持高并发的点查询场景&#xff0c;也能支持高吞吐的复杂分析场景。基于…

【论文速读】|大语言模型(LLM)智能体可以自主利用1-day漏洞

本次分享论文&#xff1a; LLM Agents can Autonomously Exploit One-day Vulnerabilities 基本信息 原文作者&#xff1a;Richard Fang, Rohan Bindu, Akul Gupta, Daniel Kang 作者单位&#xff1a;无详细信息提供 关键词&#xff1a;大语言模型, 网络安全, 1-day漏洞, …

Redisson分布式锁 --- 源码分析

1.获取一把锁 RLock lock redissonClient.getLock("订单lock"); 2.业务代码加锁 lock.lock(); 2.1 lock.tryAcquire Long ttl tryAcquire(leaseTime, unit, threadId); 2.2 lua脚本: tryLockInnerAsync方法 如果获取锁失败&#xff0c;返回的结果是这个key的剩…

MMSeg搭建模型的坑

Input type(torch.suda.FloatTensor) and weight type (torch.FloatTensor) should be same 自己搭建模型的时候&#xff0c;经常会遇到二者不匹配&#xff0c;以这种情况为例&#xff0c;是因为部分模型没有加载到CUDA上面造成的。 注意搭建模型的时候&#xff0c;所有层都应…

【氮化镓】液态Ga在GaN(0001)和(0001̅)表面上的三维有序排列随温度的变化

文章标题是《Temperature dependence of liquid-gallium ordering on the surface of epitaxially grown GaN》&#xff0c;作者是Takuo Sasaki等人&#xff0c;发表在《Applied Physics Express》上。文章主要研究了在分子束外延(MBE)条件下&#xff0c;液态镓(Ga)在GaN(0001)…

WCH RISC CH32V303RCT6 单片机的SDI Printf 虚拟串口功能 类似RTT打印功能 简单分析

参考&#xff1a; 有关于 SDI printf 更多的信息和资料吗&#xff1f; 关于 CH32 系列 MCU SDI 虚拟串口功能的使用 【CH32X035 评估板测评】 教你使用 SDI 接口重定向 printf 0.前言 有段时间没有看CH32V单片机的开发了&#xff0c;今天帮新来的同事调试时候看到debug.c里面有…

java-spring 06 图灵 getBean方法和 doGetBean方法

01.一般的流程是&#xff0c;这里是从上一章的preInstantiateSingleton方法顺序过来的。 getBean() -> doGetBean() -> createBean() -> doCreateBean() -> createBeanInstance() -> populateBean() -> initializeBean() 02.getBean方法&#xff0c;一般就…

项目十:学会python爬虫数据保存(小白圆满级)

前言 上篇我们学会的文本文件、csv文件和excel文件的相关基础知识和操作&#xff0c;这一次我们再来了解一下四个文件操作方式 存储方法 HTML文件 将数据保存为HTML格式&#xff0c;可以直接在浏览器中查看。 使用字符串拼接将数据保存为HTML格式。 代码案例 # 创建数据…

Cookie、Session以及Token的区别

Cookei、Session以及Token总的来说都是为了实现客户端访问服务器数据而利用的一种手段&#xff0c;可以把服务器数据看成是密码箱&#xff0c;而它们是三种不同的钥匙。 一、定义 1.Cookie 客户端第一次访问服务器时&#xff0c;服务器返回cookie给客户端A&#xff0c;客户端…

ABTest如何计算最小样本量-工具篇

如果是比例类指标&#xff0c;有一个可以快速计算最小样本量的工具&#xff1a; https://www.evanmiller.org/ab-testing/sample-size.html 计算样本量有4个要输入的参数&#xff1a;①一类错误概率&#xff0c;②二类错误概率 &#xff08;一般是取固定取值&#xff09;&…

第 394 场 LeetCode 周赛题解

A 统计特殊字母的数量 I 哈希&#xff1a;遍历然后枚举 class Solution {public:int numberOfSpecialChars(string word) {unordered_map<char, int> m;for (auto ch : word)m[ch] 1;int res 0;for (char ch a; ch < z; ch)if (m.count(ch) && m.count(A …

【SpringCloud】OpenFeign高级特性

【SpringCloud】OpenFeign高级特性 文章目录 【SpringCloud】OpenFeign高级特性1. 超时控制1.1 全局配置1.2 指定配置 2. 重试机制3. 替换Http客户端3.1 引入依赖3.2 配置 4. 请求/响应压缩5. 日志打印6. 综合配置 1. 超时控制 默认OpenFeign客户端等待60秒钟&#xff0c;但是服…

8.4.1 实验1:创建 VLAN 和划分端口

1、实验目的 通过本实验可以掌握&#xff1a; VLAN的概念。创建VLAN的方法。把交换机端口划分到VLAN中的方法。 2、实验拓扑 创建 VLAN 和划分端口的实验拓扑如下图所示。 图8-5 创建 VLAN 和划分端口的实验拓扑 3、实验步骤 &#xff08;1&#xff09;实验准备 S1#eras…