LLM应用专辑(3) — ChatGPT遇上文档搜索:ChatPDF、ChatWeb、DocumentQA等开源项目算法思想与源码解析

原文:LLM应用专辑(3) — ChatGPT遇上文档搜索:ChatPDF、ChatWeb、DocumentQA等开源项目算法思想与源码解析 - 知乎

公众号在上一篇文章中,我们介绍了chatgpt与nlp结合过程中的一些具体prompt生成方法,掌握这些可以有效地提升生产效率。
而说到生产效率,我们不得不提chatgpt与文档相结合的场景。
实际上,最近已经陆续出现了chatpdf,chatweb,chatexcel,chatpaper等文档工具,其底层先对文档进行预处理,然后利用openai生成embedding,最后再进行答案搜索,能够解决一些摘要、问答的问题。
如何理解这些项目底层的原理,包括实现过程就显得十分有趣。本文主要介绍ChatPDF、ChatWeb以及基于向量数据库与GPT3.5的通用本地知识库方案这些开源项目,供大家一起参考。


老刘说NLP老刘,刘焕勇,NLP开源爱好者与践行者。主页:https://liuhuanyong.github.io。就职于360人工智能研究院、曾就职于中国科学院软件研究所。老刘说NLP,将定期发布语言资源、工程实践、技术总结等内容,欢迎关注。
241篇原创内容

公众号一、ChatPDF、ChatWeb、Document_QA项目方案
1、chatpdf-minimal-demo项目
该项目是chatpdf 的最小实现,目标是和文章对话。
地址:https://github.com/postor/chatpdf-minimal-demo


其实现原理很简单:

1)文章切片到段落;
2)通过 OpenAI 的 embedding 接口将每个段落转换为 embedding;
3)将提问的问题转换为 embedding
4)把问题的 embedding 比较所有段落 embedding 得到近似程度并排序
5)把和提问(语义)最接近的一个或几个段落作为上下文,通过 OpenAI 的对话接口得到最终的答案
2、ChatWeb项目
ChatWeb可以爬取任意网页并提取正文,生成概要,然后根据正文内容回答你的问题。
目前是个原理展示的Demo,还没有细分逻辑,基于gpt3.5的chatAPI和embeddingAPI,配合向量数据库。其基本原理在于:
1)爬取网页;
2)提取正文;
3)对于每一段落,使用gpt3.5的embeddingAPI生成向量 ;
4)每一段落的向量和全文向量做计算,生成概要;
5)将向量和文本对应关系存入向量数据库;
6)对于用户输入,生成向量 ;
7)使用向量数据库进行最近邻搜索,返回最相似的文本列表;
8)使用gpt3.5的chatAPI,设计prompt,使其基于最相似的文本列表进行回答 ;

9)就是先把大量文本中提取相关内容,再进行回答,最终可以达到类似突破token限制的效果 ;
3、Document_QA项目
同样的,Document_QA也采用了类似的思想进行处理:
1)读取文件,并进行分割;
2)对于每段文本,使用text-embedding-ada-002生成特征向量;
3)将向量和文本对应关系存入本地pkl文件;
4)对于用户输入,生成向量;
5)使用向量数据库进行最近邻搜索,返回最相似的文本列表;
6)使用gpt3.5的chatAPI,设计prompt,使其基于最相似的文本列表进行回答;

不过,就是先把大量文本中提取相关内容,再进行回答,最终可以达到类似突破token限制的效果,后续可以考虑将openai的文本向量改成自定义的向量生成工具

项目地址:https://github.com/fierceX/Document_QA
1、请求openai获取embedding
def create_embeddings(input):
"""Create embeddings for the provided input."""
result = []
# limit about 1000 tokens per request
lens = [len(text) for text in input]
query_len = 0
start_index = 0
tokens = 0

def get_embedding(input_slice):
embedding = openai.Embedding.create(model="text-embedding-ada-002", input=input_slice)
return [(text, data.embedding) for text, data in zip(input_slice, embedding.data)], embedding.usage.total_tokens

for index, l in tqdm(enumerate(lens)):
query_len += l
if query_len > 4096:
ebd, tk = get_embedding(input[start_index:index + 1])
query_len = 0
start_index = index + 1
tokens += tk
result.extend(ebd)

if query_len > 0:
ebd, tk = get_embedding(input[start_index:])
tokens += tk
result.extend(ebd)
return result, tokens

2、基于openai completion进行补全问答
class QA():
def __init__(self,data_embe) -> None:
d = 1536
index = faiss.IndexFlatL2(d)
embe = np.array([emm[1] for emm in data_embe])
data = [emm[0] for emm in data_embe]
index.add(embe)
self.index = index
self.data = data
def __call__(self, query):
embedding = create_embedding(query)
context = self.get_texts(embedding[1], limit)
answer = self.completion(query,context)
return answer,context
def get_texts(self,embeding,limit):
_,text_index = self.index.search(np.array([embeding]),limit)
context = []
for i in list(text_index[0]):
context.extend(self.data[i:i+5])
# context = [self.data[i] for i in list(text_index[0])]
return context

def completion(self,query, context):
"""Create a completion."""
lens = [len(text) for text in context]

maximum = 3000
for index, l in enumerate(lens):
maximum -= l
if maximum < 0:
context = context[:index + 1]
print("超过最大长度,截断到前", index + 1, "个片段")
break

text = "\n".join(f"{index}. {text}" for index, text in enumerate(context))
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{'role': 'system',
'content': f'你是一个有帮助的AI文章助手,从下文中提取有用的内容进行回答,不能回答不在下文提到的内容,相关性从高到底排序:\n\n{text}'},
{'role': 'user', 'content': query},
],
)
print("使用的tokens:", response.usage.total_tokens)
return response.choices[0].message.content

二、基于向量数据库与GPT3.5的通用本地知识库方案
基于向量数据库与GPT3.5的通用本地知识库方案(A universal local knowledge base solution based on vector database and GPT3.5),其主要采用了qdrant作为向量化索引库。
项目地址:https://qdrant.tech/documentation/
项目地址:https://github.com/GanymedeNil/document.ai/tree/main/code

整个流程非常简单,
1、本地文档数据其中:
普通感冒#####您会出现喉咙发痒或喉咙痛,流鼻涕,流清澈的稀鼻涕(液体),有时轻度发热。
常年过敏#####症状包括鼻塞或流鼻涕,鼻、口或喉咙发痒,眼睛流泪、发红、发痒、肿胀,打喷嚏。

2、建立索引
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, VectorParams
from qdrant_client.http.models import PointStruct
import os
import tqdm
import openai
def to_embeddings(items):
sentence_embeddings = openai.Embedding.create(
model="text-embedding-ada-002",
input=items[1]
)
return [items[0], items[1], sentence_embeddings["data"][0]["embedding"]]
if __name__ == '__main__':
client = QdrantClient("127.0.0.1", port=6333)
collection_name = "data_collection"
openai.api_key = os.getenv("OPENAI_API_KEY")
# 创建collection
client.recreate_collection(
collection_name=collection_name,
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
count = 0
for root, dirs, files in os.walk("./source_data"):
for file in tqdm.tqdm(files):
file_path = os.path.join(root, file)
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
parts = text.split('#####')
item = to_embeddings(parts)
client.upsert(
collection_name=collection_name,
wait=True,
points=[
PointStruct(id=count, vector=item[2], payload={"title": item[0], "text": item[1]}),
],
)
count += 1

3、查询服务
生成对话的示例提示语句,格式如下:
demo_q:
使用以下段落来回答问题,如果段落内容不相关就返回未查到相关信息:"成人头疼,流鼻涕是感冒还是过敏?"
1. 普通感冒:您会出现喉咙发痒或喉咙痛,流鼻涕,流清澈的稀鼻涕(液体),有时轻度发热。
2. 常年过敏:症状包括鼻塞或流鼻涕,鼻、口或喉咙发痒,眼睛流泪、发红、发痒、肿胀,打喷嚏。
demo_a:
成人出现头痛和流鼻涕的症状,可能是由于普通感冒或常年过敏引起的。如果病人出现咽喉痛和咳嗽,感冒的可能性比较大;而如果出现口、喉咙发痒、眼睛肿胀等症状,常年过敏的可能性比较大。
system:
你是一个医院问诊机器人

具体实现代码:
def prompt(question, answers):
demo_q = '使用以下段落来回答问题:"成人头疼,流鼻涕是感冒还是过敏?"\n1. 普通感冒:您会出现喉咙发痒或喉咙痛,流鼻涕,流清澈的稀鼻涕(液体),有时轻度发热。\n2. 常年过敏:症状包括鼻塞或流鼻涕,鼻、口或喉咙发痒,眼睛流泪、发红、发痒、肿胀,打喷嚏。'
demo_a = '成人出现头痛和流鼻涕的症状,可能是由于普通感冒或常年过敏引起的。如果病人出现咽喉痛和咳嗽,感冒的可能性比较大;而如果出现口、喉咙发痒、眼睛肿胀等症状,常年过敏的可能性比较大。'
system = '你是一个医院问诊机器人'
q = '使用以下段落来回答问题,如果段落内容不相关就返回未查到相关信息:"'
q += question + '"'
# 带有索引的格式
for index, answer in enumerate(answers):
q += str(index + 1) + '. ' + str(answer['title']) + ': ' + str(answer['text']) + '\n'

"""
system:代表的是你要让GPT生成内容的方向,在这个案例中我要让GPT生成的内容是医院问诊机器人的回答,所以我把system设置为医院问诊机器人
前面的user和assistant是我自己定义的,代表的是用户和医院问诊机器人的示例对话,主要规范输入和输出格式
下面的user代表的是实际的提问
"""
res = [
{'role': 'system', 'content': system},
{'role': 'user', 'content': demo_q},
{'role': 'assistant', 'content': demo_a},
{'role': 'user', 'content': q},
]
return res

4、执行查询
执行逻辑很简单,具体如下:
首先使用openai的Embedding 其API将输入的文本转换为向量,然后使用Qdrant的search API进行搜索,搜索结果中包含了向量和payload;
payload中包含了title和text,title是疾病的标题,text是摘要,最后使用openai的ChatCompletion API进行对话生成。
def query(text):
"""

"""
client = QdrantClient("127.0.0.1", port=6333)
collection_name = "data_collection"
openai.api_key = os.getenv("OPENAI_API_KEY")
sentence_embeddings = openai.Embedding.create(
model="text-embedding-ada-002",
input=text
)
"""
因为提示词的长度有限,所以我只取了搜索结果的前三个,如果想要更多的搜索结果,可以把limit设置为更大的值
"""
search_result = client.search(
collection_name=collection_name,
query_vector=sentence_embeddings["data"][0]["embedding"],
limit=3,
search_params={"exact": False, "hnsw_ef": 128}
)
answers = []
tags = []

"""
因为提示词的长度有限,每个匹配的相关摘要我在这里只取了前300个字符,如果想要更多的相关摘要,可以把这里的300改为更大的值
"""
for result in search_result:
if len(result.payload["text"]) > 300:
summary = result.payload["text"][:300]
else:
summary = result.payload["text"]
answers.append({"title": result.payload["title"], "text": summary})

completion = openai.ChatCompletion.create(
temperature=0.7,
model="gpt-3.5-turbo",
messages=prompt(text, answers),
)

return {
"answer": completion.choices[0].message.content,
"tags": tags,
}


总结
本文主要介绍了ChatPDF、ChatWeb以及基于向量数据库与GPT3.5的通用本地知识库方案这些开源项目。
从代码的角度来看,其实现路径较为简单,主要难点在于如何针对文档进行切分,尤其是针对一些扫描版文档,文档格式较为复杂的场景时,则需要使用版式分析、OCR等技术。
参考文献
1、https://qdrant.tech/documentation/
2、https://github.com/GanymedeNil/document.ai/tree/main/code
3、https://github.com/postor/chatpdf-minimal-demo
4、https://github.com/fierceX/Document_QA
5、

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

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

相关文章

Android的img镜像文件打开

有时需要获取系统的一些资源&#xff0c;就需要打开img镜像文件&#xff1b;可以使用&#xff1a;ext2explore.exe.exe 此篇以打开Android API 22的system.img为例&#xff0c;system.img文件可以在sdk目录system-images文件下 eg: 相对路径&#xff1a;android-sdk-windows\s…

使用tp5写登录验证及修改密码

使用到的工具 1,thinkphp5.0自带的验证码: think-captcha 可查看&#xff1a; https://www.kancloud.cn/manual/thinkphp5/154295 2,前台页面框架: layui 3,引用到的文件: jquery.min.js layui.css 登录样式最终图形 登录的html <body style"background:#f2f2f2…

基于MATLAB的隐函数偏导与多重积分(附代码)

一. 隐函数的偏导数 给定隐函数&#xff1a; 隐函数的偏导可得&#xff1a; MATLAB格式&#xff1a; F-diff(f,xj)/diff(f,xi) 例题1 已知&#xff1a; 求&#xff1a; 解&#xff1a; MATLAB代码&#xff1a; clc;clear; syms x y; f(x^2-2*x)*exp(-x^2-y^2-x*y); prett…

Wolfram Alpha 算微积分指令集合

一、Wolfram Alpha介绍 Wolfram Alpha网址&#xff1a;https://www.wolframalpha.com/ WolframAlpha是开发计算数学应用软件的沃尔夫勒姆研究公司开发出的新一代的搜索引擎&#xff0c;能根据问题直接给出答案的网站&#xff0c;用户在搜索框键入需要查询的问题后&#xff0c…

利用MATLAB求符号微积分

文章目录 摘要1 符号函数的极限&#xff08;1&#xff09;极限&#xff08;2&#xff09;单边极限 2 符号函数的导数3 符号函数的积分&#xff08;1&#xff09;不定积分&#xff08;2&#xff09;定积分 结语 摘要 本文是《科学计算与MATLAB语言》专题七第2小节的学习笔记&am…

高等数值计算方法学习笔记第4章第一部分【数值积分(数值微分)】

高等数值计算方法学习笔记第4章第一部分【数值积分&#xff08;数值微分&#xff09;】 一、数值积分概论1.数值求积的基本思想(牛-莱公式找不到原函数&#xff0c;用矩形近似)2.代数精度的概念1.上述四个公式的代数精度&#xff08;梯形&#xff0c;左中右矩形公式&#xff09…

真的能从脑电信号识别出我的情绪吗?

关注“心仪脑”查看更多脑科学知识的分享。 提到情绪&#xff0c;我们脑海中可能会浮现出各种各样的场景&#xff0c;可能是“哭着&#xff0c;叫着&#xff0c;像个孩子在胡闹”的悲痛。 &#xff08;图片来源于网络&#xff09; 抑或是《Lie to me》中Cal Lightman深邃的一双…

读取大脑计算机软件,专访脑机接口专家Jose:读取大脑信息已成现实

腾讯科技 韩依民 11月7日报道 《生活大爆炸》中有一个经典的搞笑桥段&#xff1a;谢耳朵手摁太阳穴&#xff0c;幻想通过脑电波攻击室友。这一举动因荒诞不羁而产生喜剧效果&#xff0c;但是一种新的科学技术正在让谢耳朵的幻想部分变成现实。 利用捕捉器将人们脑子里进行的活动…

脑机接口猴子通过“意念”打游戏!马斯克:未来能让瘫痪者用意念玩手机

来源&#xff1a;新智元 它是Pager&#xff0c;一只9岁的恒河猴&#xff0c;来自Neuralink&#xff0c;最近它刚刚get了新技能——用意念玩乒乓球游戏。 6个星期前&#xff0c;Pager的脑袋里被植入了两个叫N1 Link的装置&#xff0c;工作人员用香蕉奶昔诱惑它玩游戏&#xff0c…

证明人脑细胞在体外也有感知,「盘中之脑」论文正式登Cell子刊

詹士 发自 凹非寺量子位 | 公众号 QbitAI 这有一个放在盘中的「大脑」&#xff0c;它以为自己是游戏角色&#xff0c;其活着的意义就是完成游戏任务。 有「黑客帝国」内味儿了&#xff1f;&#xff1f;&#xff1f; 现实中&#xff0c;这个盘中大脑有人做出来了&#xff0c;命名…

Hinton 最新访谈:不出五年,我们就会破解大脑的运作机制,但不是通过反向传播...

点击上方“视学算法”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达 整理丨李梅、黄楠 来源丨AI科技评论 编辑丨极市平台 导读 过去十年&#xff0c;AI 在计算机视觉、语音识别、机器翻译、机器人、医学、计算生物学、蛋白质折叠预测等等领…

ChatGPT时代,如何训练大脑,以后不会被人工智能取代

当有一天&#xff0c;你的小孩子问我将来会不会被AI代替的时候&#xff0c;为人父母的我们应该怎么回答小孩子的问题呢&#xff1f;不知各位是否刷到一位名为浅爸谈英语的博主爸爸分享与他女儿关于AI对话的视频。 这段对话很有启发性&#xff0c;父亲的回答也很中肯。可以通过…

脑机接口照进现实:5位脑科学家带来的最新启示

大脑复杂、神秘&#xff0c;研究大脑被认为是人类终极的探索之一。作为最为复杂的科学探索领域&#xff0c;大脑的研究既令人着迷&#xff0c;也同样令人望而生畏。 脑机接口技术会使人类退化吗&#xff1f;一旦脑机接口技术得到应用&#xff0c;人类的自由意志会被他人操纵吗&…

马斯克脑机接口、BrainOS 相继发布,未来已来?

作者 | 马超 责编 | Carol 封图 | CSDN 下载自视觉中国 在北京时间的8月29日凌晨&#xff0c;钢铁侠埃隆马斯克投资1亿多美元的脑机接口初创公司公司Neuralink进行现场发布会&#xff0c;展示新一代的脑机接口设备。 这场发布会的热度可以和苹果iPhone4发布会相媲美&#xff0c…

脑科学真的可以启发AI吗?

智源导读&#xff1a;人工智能发展到当前阶段&#xff0c;大家都开始认识到脑科学和人工智能有很密切的关系&#xff0c;脑科学会对人工智能的发展产生很大帮助。反过来思考这个问题&#xff0c;脑科学对人工智能研究真的有帮助吗&#xff1f;离开脑科学之后&#xff0c;人工智…

Google员工说出了我不敢说的心里话!

前言&#xff1a;本文来自Beyond的投稿&#xff0c;码农翻身做了修改。 今天在Medium上看到一篇文章《The maze is in the mouse》&#xff0c;是一个刚从Google离职的员工写的&#xff0c;揭开了Google内部的各种问题&#xff0c;引发了很多人的共鸣&#xff0c;到目前为止&am…

RepVGG论文详解(结合代码)

目录 1.简介 2.RepVGG详情 2.1 RepVGG Block 2.2 结构重参数化 2.2.1融合Conv2d和BN&#xff0c;将三个分支上的卷积算子和BN算子都转化为卷积算子&#xff08;包括卷积核和偏置&#xff09; 2.2.2 将每个分支都扩充为一个3x3卷积核加一个偏置&#xff0c;然后进行相加融合…

MySQL如何支撑每秒百万QPS?

【编者按】本文主要介绍 PlanetScale 是如何通过 MySQL 的水平分片支撑每秒一百万个查询&#xff08;QPS&#xff09;的。 原文链接&#xff1a;https://planetscale.com/media/one-million-queries-per-second-with-mysql 未经允许&#xff0c;禁止转载&#xff01; 作者 | Jo…

用银联借记卡通过paypal支付美金

起了一个非常拗口的标题&#xff0c;意思是我要用关联了国内银联借记卡的paypal账户给国外网站支付费用&#xff0c;我直接在线就可以实现支付&#xff0c;不需要充值(paypal实际上是有充值付费这个流程的&#xff0c;只是我们没有感觉到)等一系列操作&#xff0c;也是非常的方…

B2B电商平台--ChinaPay银联电子支付功能

一、概念简介 理解什么是UnionPay、ChinaPay 这两个概念如果搞不清楚&#xff0c;绝对够你瞎折腾一段时间的。讲真&#xff0c;拿到这个改换ChinaPay银联支付需求时&#xff0c;我还以为产品经理给错我们官网地址了。 1、UnionPay 中国银联&#xff0c;最大的机构&#xff…