【实操】基于ChatGPT构建知识库

前言

最近有些实践,因为后面要去研究fine-tune了,想着记录一下chatgpt+向量数据库构建知识库的一些实操经验,不记我很快就忘了,哈哈。

首先,提一下为啥会出现向量数据库这个技术方案?

大家经过实践发现,如果通过简单的prompt与ChatGPT聊一下专业领域或实时性比较强的内容时,效果是很差的,比如公司有广告投放的业务,我们就需要一批同学去研究不同平台的广告投放文档,这些API文档实时性比较强,你让ChatGPT直接去生成代码,效果就很差。

为了让效果好一点,我们可以将页面的所有内容都复制出来,放到prompt中,类似于:

context:{document content}please base the context generate xxxx code use python.

我们将最新的内容放到prompt中,ChatGPT就会基于最新的内容去生成代码了,类似的方式,我们可以将公司内部的文档放到prompt中,让ChatGPT基于文档内容回答。

但,ChatGPT有Tokens数量限制,我常用的GPT-3.5-16k,就是有16k的tokens限制,即单次request+response的tokens数不能超过16k,超过则会报错,所以如果文档内容稍微多一点,就无法全丢到prompt中。

目前的折中的解决方案就是使用向量数据库,其原理就是对文本进行embed后,再进行相似度运算。

关于embeddings原理,网上内容很多,我就不费篇章了,推荐一篇比较系统讲embed的文章:https://www.featureform.com/post/the-definitive-guide-to-embeddings

向量数据库基本使用

比较火的例子就是让ChatGPT基于你的PDF文件来聊天,这里的PDF文件可以有多个,比如100个PDF,那变通一下,就可以基于这套来构建公司的知识库。

我找了一张图,来自视频:https://www.youtube.com/watch?v=TLf90ipMzfE

4b0b45bd14591bceaa214f8b1a4c305a.png

我简单描述一下:

首先要做预处理:

  • 1.你需要将所有的PDF中的内容都抽成纯文档,如果PDF中是不可编辑的图片,你就需要使用OCR来获得内容。

  • 2.获得纯文本后,你需要对文本进行切块,太多内容放在一起生成一个embed vector(嵌入向量)效果是不好的。

  • 3.存入向量数据库

当用户提问时,定义问题为A,首先会将问题A通过同样的embed model转成embed vector,然后再计算问题A的embed vector与之前所有PDF生成的一系列embed vector的相似度(你可以用余弦来算,也可以用其他计算向量距离的算法来算)。

计算后,会获得当前PDF中与问题A最相近的内容(向量在空间上距离最近的),然后将这部分PDF内容和问题A一同输入给ChatGPT,其实就是为ChatGPT提供了上下文,让ChatGPT基于上下文回答。

一些细节:

  • Q:为何太多内容一起生成一个embed vector效果不好?

  • A:理论上是,内容多时,一般意思就多(信息多),此时对embed vector做相似计算时,获得一堆意思很多的内容给ChatGPT,生成的效果也是比较差的,我们做向量相似度计算的目的就是将与用户提问最相关的内容找出来,如果你每次都找出一大段的内容,效果就不好,所以这里可以引入很明显的优化点:做好数据的合理切块。

  • Q:具体要怎么计算相似度?内容那么多,代码上有没有轮子可以用?

  • A:一般不自己计算,而是交给向量数据库,通过SQL或相应的方法直接查询结果,向量数据库底层会帮你做向量相似度的计算。

上面整个流程其实在langchain文档中都给了具体的代码,30行左右的代码:https://colab.research.google.com/drive/181BSOH6KF_1o2lFG8DQ6eJd2MZyiSBNt?usp=sharing

当然熟练了上面的代码后,你会发现langchain给我们提供了RetrieverQA这个类,它做的就是将上面的过程再简化,5行左右的代码搞定基于文档的简单问答系统,详情:https://python.langchain.com/docs/use_cases/question_answering/vector_db_qa

一些问题

我实操了一些项目,通过这20行代码已经可以实现基本的知识库了,但深入使用后,还是会感到有点不足:

  • 1.准确度有时比较低

  • 2.会发散回答一些无关的内容

2个问题都无法100%解决,因为这不是工程问题,而是因为GPT模型本身的基底是概率性质的,但实践后,确实有一些改进方法。

过发散问题

首先说一些GPT发散回答的问题,最基本的改进方法就是在prompt中强调不要发散回答,要严格基于提供的上下文回答,如果上下文没有相关的内容,则回答不知道,例如:

# Context
{content from vector database}# Requirements:
- 1. Before responding, please assess whether you have sufficient Context knowledge to answer the question. If you cannot answer, please reply directly with: "I'm sorry, I cannot answer your question."
- 2. Respond to questions using the provided Context knowledge.。# Question:
{question}

进一步,就需要自己再做一层工程过滤,比如收集相关的问题,训练一个二分类模型,参考分类垃圾邮件相关的算法就好了。

准确度问题

关于准确度的问题,简单思索会发现有2个方面会影响最终生成内容的准确度:

  • 1.数据预处理

  • 2.embed算法和相似度算法

数据预处理

经过实践,发现数据做好预处理,准确度确实有所改进。

我有个项目,是做代码文档知识库的,这是为我个人打造的,场景是:我需要使用新的技术解决方案时,比如我要学openai怎么用,我就希望自己简单知道概念后,直接让ChatGPT帮我写代码,我做一套简单的解决方案:

  • 1.爬虫递归爬取相关的文档

  • 2.利用类似上文提到的PDF方案,20~30行代码,解决了核心功能(基于文档的问答系统)

  • 3.用streamlit弄了一个UI

但深入用时,会发现生成的代码,有时问题比较多。

因为常见的文本切分都是按固定字数切分的,这种方法可能会将语义连贯的部分切分开,导致计算相似向量时,获得的内容不全,然后因为是技术文档,通常会有example code,按字数切分容易将code切开,就很尴尬。

langchain本身提供了一个方法来降低这种影响,就是文档切开后,可以留一部分重复的内容,比如切块后的最后50字,与第二块的前50字是一样的,从而维持关联性,方法代码如下:

text_splitter = CharacterTextSplitter(        separator = "\n",chunk_size = 1000,# 维持关联性chunk_overlap  = 200,length_function = len,
)

但效果没有太大改善,所以我做了一些数据预处理:

1.按title来分,通常一个title中的内容是强关联的,不再按字数分,如果一个title下的内容很多,就拆分一下,但title依旧会带上,例如:

原文:title 1
content(1800 char)预处理后(按1000char切分):title 1
content(0~1000 char)title 1(不同块都带上原本的title)
content(1000~1800 char)

2.特殊内容直接业务处理,比如我处理的是代码文档,其中的example code挺重要的,我会将其单独存起来,不做embed vector,而是直接存原内容,然后通过id与相关的embed vector关联上,例如:

原文:title 1
content(300 char)
code(100 char)
content(200 char)title 2:
content(1200 char)
code(100 char)
content(200 char)预处理后(按1000char切分)title 1 + all content(300+500) = embed vector , code(100 char)存表获得code id => 表里会记录 embed vector 与 code_id的关联关系title 2 + 1000 char + code_id
title 2 + 400 char(200 + 200) + code_id

这样相似度搜索后,我会将相关的code_id的内容也直接从数据库搜出来,将code直接输入给chatgpt,从而提高生成代码的合理性(当然很多文档本身就是屎一样,example code的代码就是有问题的,这种就是硬伤,但还是可以省点时间)

3.在prmopt中加上一些背景知识,还是以代码文档为例,比如我希望生成Python代码,有些文档的example只给了curl的请求方式,此时就可以在system prompt中加上,如:遇到curl转成python requests的代码之类的。

替换模型和算法

我目前主要使用openai的text-embedding-ada-002,但其实还有很多embedding model,上huggingface翻阅一下,然后看看对比,比如m3e的对比数据就比openai的ada-002要好一点:

7fe2e9ac63d7701766e4b2d213f54082.png

然后就是相似度算法,可以尝试替换,这里,我目前主要使用supabase来做,抛开supabase提供的其他功能,可以单纯将supabase当成Postgres database,然后开始白嫖,supabase中怎么做向量相似度计算的方案如下:

你如果不太了解,可以阅读supabase的这篇文章:https://supabase.com/blog/openai-embeddings-postgres-vector

基于supabase + vercel + nextjs,你会发现,做一个知识库项目早期只需要花域名钱和OpenAI的API钱,向量数据库、服务器这些,都可以白嫖。

其他方案

Bybrid Search

我们可以参考其他系统,比如推荐系统,如果遇到推荐不准确时,一个常用的方案就是多路召回,直白说,就是除了从向量数据库通过向量相似度计算获得数据外,再通过其他方式获得相关数据,做多一路。

看langchain的人twitter分享,将关键词搜索加入其中,准确率提高了20%,他将这种方式称为:Bybrid Search。

5f7dc052fdea7794d0e06b8a84cf666d.jpeg

Bybrid Search的代码目前只存在langchain JS版本中,Python版本是没有的,用起来很简单:https://js.langchain.com/docs/modules/data_connection/retrievers/integrations/supabase-hybrid,替换一下参数就好了。

langchain这个库多数时候都这样,功能帮你封装好,你要用,很简单的,你要定制化的用,抱歉,你需要自己解决,所以很多人吐槽langchain的过度封装,我自己到感觉还好,我的很多需求,确实需要定制化,但也很简单,继承langchain的类,将需要重写的方法重写掉,通常只需要加一点点自己的业务代码就好了。

改写用户提问

这是一个有风险的操作,毕竟你的改写可能会改变用户的语义,你可以用一些工具尝试改写一下,或将是否改写的选择权交给用户,比如UI上弄一个按钮:【优化提问】,之类的。

你可以尝试一下直接套多一层ChatGPT,让ChatGPT帮你将用户的问题在不改变语义的情况下,将问题写的更详细,这是有效果的。

或者,你可以直接使用PromptPerfect这类工具(我还没用过)

c5228f2463db67d1de2fe9b8ccf3d49f.png

multi-Document Agents

multi-Document Agents的核心思路就是构建Agent和不同的文档索引方案,让Agent帮你选择,具体如下图:

3e685e07bc6575cbcadab49c55e2e2aa.jpeg

我第一次了解这个方式是在LlamaIndex框架创始人的twitter上看见的,他在twitter上说受到了递归文档代理(Recursive Document Agents)的启发,弄了Multi-Dcouemtn Agents,相关推文:https://twitter.com/jerryjliu0/status/1693421308674289822。

在我看来,langchain定义是更通用的框架,它的功能非常多,而LlamaIndex主要目的是构建一个索引、搜索的LLM框架,因为langchain也有这部分功能,所以挺多人会对比一下,社区间主流的观点是LlamaIndex会快一点,如果大量的数据处理,推荐用LlamaIndex,而Langchain功能更多更灵活一些,在文档检索+LLM这个领域(狭义点就是知识库领域),两者都强调自己的Retrieval-Augending Generation(RAG,检索增强生成)的功能可以帮助你更好的利用文档内容😄。

回到Multi-Dcouemtn Agents,代码基本的细节可以看LlamaIndex文档:https://gpt-index.readthedocs.io/en/latest/examples/query_engine/recursive_retriever_agents.html。

获得实时性强的回答

有时,我们希望ChatGPT除了可以基于知识库回答一些专业性比较强的问题外,还希望可以回答外部实时性比较强的问题,比如行业咨询等。

这里的核心依旧是,通过某种方式可以获得外部数据,然后将其放到Prompt中,这样ChatGPT就知道了。嗯,具体怎么做呢?

假设,你希望通过Google获得实时性的信息,你就需要写一个Google爬虫,Google爬虫要比较稳定的运行,需要购买住宅IP,不然很容易被Google风控限了,当然,我建议你直接用相关的SaaS,比如:https://serpapi.com/,直接付费,然后就可以通过api获取Google数据了。

然后你会发现Langchain提供了serpaper相关的工具:SerpAPIWrapper,直接使用,便可以将Google获取的信息直接加到你现有的知识库项目中了。

如果还是不够清晰,可以直接看完整的代码解决方案:https://colab.research.google.com/drive/1Q-lm-apSJRYwoPvUZGiwYMezeky0yQXD?usp=sharing#scrollTo=XbOXzzQh-ASf

作者利用Langchain的RetrievalQA + SerpAPIWrapper构建了一个可以查询实时信息的知识库。

结尾

以上就是我实操过或简单尝试过的一些方案,简单而言,要构建一个好用的知识库,数据的预处理比较重要,有些企业会让员工人为的整理好原始的QA数据集,然后再基于这个QA做知识库,优质的预处理数据可以比较明显的提升知识库的效果,此外,直接基于原始QA数据集去做问答知识库的方案也被人拓展了一下,假设原数据是单纯的文档数据,那么就让ChatGPT帮你将文档数据转成QA数据集嘛,写个Prompt,让他基于内容问题之类的,但这个我没实操过,所以我也不清楚效果。

有了比较好的预处理数据,再结合本文上面的各种技巧,就可以获得一个准确度比较高的知识库解决方案了。

文章有点长,你居然看到了最后?不打赏一下增加我们的革命友谊吗?

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

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

相关文章

【传输层协议】UDP/TCP结构特点与原理(详解)

文章目录 1. UDP1.1 UDP结构1.2 UDP特点1. 无连接2. 不可靠3. 面向数据报4. 缓冲区5. 大小受限6. 无序性 2. TCP2.1 TCP结构2.2 TCP特点1. 有连接2. 可靠性3. 面向字节流4. 拥塞控制5. 头部开销 2.3 TCP原理1. 确认应答(安全机制)2. 超时重传&#xff08…

数据结构与算法--其他算法

数据结构与算法--其他算法 1 汉诺塔问题 2 字符串的全部子序列 3 字符串的全排列 4 纸牌问题 5 逆序栈问题 6 数字和字符串转换问题 7 背包问题 8 N皇后问题 暴力递归就是尝试 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续…

使用Elasticsearch来进行简单的DDL搜索数据

说明:Elasticsearch提供了多种多样的搜索方式来满足不同使用场景的需求,我们可以使用Elasticsearch来进行各种复制的查询,进行数据的检索。 1.1 精准查询 用来查询索引中某个类型为keyword的文本字段,类似于SQL的“”查询。 创…

【ElasticSearch】使用 Java 客户端 RestClient 实现对文档的查询操作,以及对搜索结果的排序、分页、高亮处理

文章目录 前言:RestClient 查询文档的 RestAPI一、全文检索查询1.1 match_all 查询1.2 match 查询1.3 multi_match 查询 二、精确查询2.1 term 查询2.2 range 查询 三、复合查询:Boolean 查询与 function score 查询的综合案例四、对查询结果的处理4.1 将…

050:mapboxGL加载geojson数据,同时包含点、多边形的处理示例

第050个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中加载geojson数据,既显示点又显示多边形。这个示例是显示了一种处理方式,通过过滤的方式将数据分离化,点和多边形通过两个不同的图层来加载表示。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实…

2018-2019 ACM-ICPC, Asia Nanjing Regional Contest G. Pyramid(组合数学 计数)

题目 t(t<1e6)组样例&#xff0c;每次给定一个n(n<1e9)&#xff0c;统计边长为n的上述三角形的等边三角形个数 其中等边三角形的三个顶点&#xff0c;可以在所有黑色三角形&白色三角形的顶点中任取&#xff0c; 答案对1e97取模 思路来源 申老师 & oeis A0003…

本地生活将成快手新的营收增长点

监制 | 何玺 排版 | 叶媛 快手本地生活开始强化B端市场。 据了解&#xff0c;快手 “本地商家”APP已经正式上线。这是快手为本地生活商家推出的独立工作平台&#xff0c;有助于商家提升经营效率。 新APP的上线&#xff0c;标志着快手本地生活业务布局&#xff0c;正从过去侧…

深入理解Kafka分区副本机制

1. Kafka集群 Kafka 使用 Zookeeper 来维护集群成员 (brokers) 的信息。每个 broker 都有一个唯一标识 broker.id&#xff0c;用于标识自己在集群中的身份&#xff0c;可以在配置文件 server.properties 中进行配置&#xff0c;或者由程序自动生成。下面是 Kafka brokers 集群自…

TLS/SSL 详解

目录 基础理论入门HTTPS对称加密非对称加密证书TLS握手过程握手总结 TLS 定义(记录层/握手层)HTTPS HTTP over TLS加密记录层分片 (Fragmentation)记录压缩和解压缩 (Record compression and decompression)空或标准流加密 (Null or standard stream cipher)CBC 块加密 (分组加…

VS2022新建项目时没有ASP.NET Web应用程序 (.NET Framework)

问题&#xff1a;如图&#xff0c;VS2022新建项目时没有“ASP.NET Web应用程序 &#xff08;.NET Framework&#xff09;”的选项解决方法&#xff1a;点击跳转至修改安装选项界面选择安装该项即可&#xff1a;

k8s-13 存储之secret

Secret 对象类型用来保存敏感信息&#xff0c;例如密码、OAuth 令牌和 ssh key。 敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活 。 Pod 可以用两种方式使用 secret:作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里 当 kubelet 为 pod 拉…

python:从Excel或者CSV中读取因变量与多个自变量,用于训练机器学习回归模型,并输出预测结果

作者:CSDN @ _养乐多_ 本文详细记录了从Excel读取用于训练机器学习模型的数据,包括独立变量和因变量数据,以供用于机器学习模型的训练。这些机器学习模型包括但不限于随机森林回归模型(RF)和支持向量机回归模型(SVM)。随后,我们将测试数据集应用于这些模型,进行预测和…

[开源]基于Vue+ElementUI+G2Plot+Echarts的仪表盘设计器

一、开源项目简介 基于SpringBoot、MyBatisPlus、ElementUI、G2Plot、Echarts等技术栈的仪表盘设计器&#xff0c;具备仪表盘目录管理、仪表盘设计、仪表盘预览能力&#xff0c;支持MySQL、Oracle、PostgreSQL、MSSQL、JSON等数据集接入&#xff0c;对于复杂数据处理还可以使用…

彩虹易支付 9.27 最新版加订单查询 sy 更新版

彩虹易支付 9.27 最新版加订单查询 sy 更新版 修复客服 2023/09/25&#xff1a; 1. 新增支付宝红包支付插件 2. 新增支付宝 APP 支付转 H5 支付 3. 更新了几个支付插件 安装教程&#xff1a; 环境&#xff1a;php7.2 上传后访问域名进行安装即可 源码下载&#xff1a;ht…

KdMapper扩展实现之SOKNO S.R.L(speedfan.sys)

1.背景 KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动&#xff0c;本文是利用其它漏洞&#xff08;参考《【转载】利用签名驱动漏洞加载未签名驱动》&#xff09;做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称spee…

POI报表的高级应用

POI报表的高级应用 掌握基于模板打印的POI报表导出理解自定义工具类的执行流程 熟练使用SXSSFWorkbook完成百万数据报表打印理解基于事件驱动的POI报表导入 模板打印 概述 自定义生成Excel报表文件还是有很多不尽如意的地方&#xff0c;特别是针对复杂报表头&#xff0c;单…

macbook电脑删除app怎么才能彻底清理?

macBook是苹果公司推出的一款笔记本电脑&#xff0c;它的操作系统是macOS。在macBook上安装的app可能会占用大量的存储空间&#xff0c;因此&#xff0c;当我们不再需要某个app时&#xff0c;需要将其彻底删除。macbook删除app&#xff0c;怎么才能彻底呢&#xff1f;本文将给大…

c#设计模式-行为型模式 之 备忘录模式

&#x1f680;简介 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;它保存一个对象的某个状态&#xff0c;以便在适当的时候恢复对象。所谓备忘录模式就是在不破坏封装的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象…

测试中Android与IOS分别关注的点

目录 1、自身不同点 2、测试注重点 3、其他测试点 主要从本身系统的不同点、系统造成的不同点、和注意的测试点做总结 1、自身不同点 研发商&#xff1a;Adroid是google公司做的手机系统&#xff0c;IOS是苹果公司做的手机系统   开源程度&#xff1a;Android是开源的&a…

06-React的路由

06-React的路由 1.相关理解 1).SPA的理解 单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。…