问题布景
常常说要带着问题阅览,当咱们阅览文章或许书本的时分,期望能够从中找到自己的答案,GPT出现后,是否能够经过GPT的问答来直接处理咱们的问题,而不需求咱们自己从文章或书本中寻找答案呢?
因为咱们期望向GPT询问关于文章的问题,所以需求咱们将文章作为Context 一同传给GPT,这样GPT才会有上下文。但一般文章或书本都是比较长的,比方以下面这篇arxiv.org/pdf/2302.04… 论文为例,全文有几万字,咱们把这几万字输入GPT后,会得到1个Token Limit的报错。
Token Limit的原因
这儿简述下,为什么GPT跟着输入内容的添加,费用也越来越高, 而且会有Token Limit的问题。
GPT是transformer decoder架构, 而transformer架构十分中心的是self-attention机制,由于需求考虑context,所以self-attention 在核算每个输出时都需求考虑一切输入,以下是示意图:
图片来历: speech.ee.ntu.edu.tw/~hylee/ml/m…
能够看到每一层self-attention跟着输入内容的添加,核算量将大幅添加,而且transformer中会有很多层self-attention结构。
已然悉数输入不是很靠谱,那有没有其他办法呢?
处理计划
已然悉数输入不可行,那假如咱们能够找到,和问题相关的几段内容,是不是就能够处理了呢?比方:
当咱们询问
依据下面的内容回答问题:
1. ...
2. ...
3. ...
4. ...
(1~4是从文章中选取的内容)
Toolformer 做了什么以及怎么作业的?
得到了以下不错的答案
那么怎么找到问题相关的内容呢?假如阅览者去找,那这个问答系统其实就没有用了,需求让机器帮咱们自动找到问题的相关内容。这儿用到了word embedding的技术。先简略介绍下word embedding。
word embedding
word embedding是一项让机器能够了解自然语言的技术,它将每个单词转换成向量形式,让核算机能够处理自然语言中的联系和语义。想象一下,假如咱们把单词比作五颜六色积木,而word embedding则是将这些积木依照它们的形状、大小、色彩等特征分门别类地组合起来,让机器能够更好地了解它们。在word embedding的国际里,每个单词都变成了一个向量,向量中的每个维度代表了该单词的一个特征,比方说某一个维度能够表示单词的情感色彩,另一个维度则能够表示单词的运动状况。
当然,在实践中,咱们也会遇到一些挑战。比方说,传统的Word embedding办法无法处理多义词和稀有词。这时出现了一些根据预练习模型的word embedding办法,比方BERT、GPT等,它们能够经过大规模的预练习学习来获取单词的上下文信息和语义信息,然后生成高质量的词向量和文本向量。这些词向量和文本向量能够用于下流自然语言处理使命的输入和特征提取,进步使命的准确性和功率。
有了word embedding后,咱们能够将问题和文章都转化为向量,然后经过余弦类似度等方法来从文章中寻找类似的内容。以下是流程:
在上面的流程图中,咱们将问题和文章转化为向量,但往往对一篇问题进行问答时会问多个问题,此刻每次询问的文章是相同的,没必要每次都做向量化,而且文章大多比较长,做向量化也会形成较大的资源糟蹋和时刻耗费。所以咱们期望将向量化后的文章存储下来。
接下来咱们就简略介绍向量的存储计划,向量数据库。
向量数据库
向量数据库是一种新式的数据库类型,它的首要特点是能够高效地存储和查询向量数据。
向量数据库的中心是向量的存储方法。在向量数据库中,每个向量都被存储为一行数据,每个维度都是一个列,每个值都是一个单元格。这种存储方法使得向量之间的距离核算变得十分高效。同时,为了能够高效地查询向量数据,向量数据库使用了向量索引。常见的向量索引包括KD-Tree、LSH和HNSW等。这些索引算法能够将向量数据划分红多个子空间,并在每个子空间中建立索引,然后使得向量的查找功率大大进步。
向量数据库的应用场景十分广泛。例如,在图像查找中,向量数据库能够对每张图片的特征向量建立索引,然后能够快速地找到与某张图片类似的其他图片;在语音识别中,向量数据库能够对每段语音的特征向量建立索引,然后能够快速地找到与某段语音类似的其他语音。此外,在自然语言处理中,向量数据库也能够用来存储词向量或许句向量等数据。
向量数据库首要包含了存储向量和查询类似向量的功用。所以咱们的流程变为:
代码完成
最终,咱们来看下代码完成,这儿咱们仍旧使用LangChain来做示例,处理这个问题:
import os
os.environ['OPENAI_API_KEY'] = "openai key"
from langchain.indexes.vectorstore import VectorstoreIndexCreator
from langchain.vectorstores import Chroma
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter, TextSplitter
from langchain.document_loaders import PyMuPDFLoader,PDFMinerLoader
from langchain.chains import VectorDBQAWithSourcesChain
from langchain.llms import OpenAIChat
from flask import Flask,request
from flask_cors import CORS
import json
app = Flask(__name__)
CORS(app)
def getPersistPath(name:str):
return "./chroma_store/" + name;
@app.route('/test', methods=["GET"])
def test():
return "read pdf with ai!"
@app.route('/load_pdf', methods=["POST"])
def loadPDF():
data = json.loads(request.data);
name = data['file_url'];
persistPath = getPersistPath(name)
if not os.path.exists(persistPath):
loader = PDFMinerLoader(name)
data = loader.load()
embeddings = OpenAIEmbeddings()
textsplitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docsearch = Chroma.from_documents(documents=textsplitter.split_documents(data), embedding=embeddings, persist_directory=persistPath)
docsearch.persist()
return json.dumps({'success': "load finish!"})
return json.dumps({'success': "has loaded!"})
@app.route('/read_with_ai', methods=["POST"])
def query():
data = json.loads(request.data);
queryMessage = data['query_message'];
preMessage = data['pre_message'];
name = data['file_url'];
if len(queryMessage):
embeddings = OpenAIEmbeddings()
persistPath = getPersistPath(name)
docsearch = Chroma(embedding_function=embeddings, persist_directory=persistPath)
llm = OpenAIChat()
if len(preMessage):
llm.prefix_messages = preMessage
chain = VectorDBQAWithSourcesChain.from_chain_type(llm, chain_type="stuff", vectorstore=docsearch)
similarityDoc = docsearch.similarity_search(queryMessage, k=5);
chatRes = chain({"input_documents": similarityDoc, "question": queryMessage}, return_only_outputs=True)
answer = chatRes.get('answer')
translationRes = llm.generate(["请将下面句子翻译为中文:" + answer]).generations[0][0].text
res = {'role': 'assistant', 'content': translationRes};
return json.dumps(res);
return "search error"
if __name__ == '__main__':
app.run(port=6666)
代码解说:
/load_pdf接口是用来加载pdf文件的,首要是将pdf文件转化为文本,并将文本进行切割,然后将切割后的文本进行向量化,最终将向量化后的结果进行耐久化。/read_with_ai接口是用来和用户交互,首要是将用户的问题进行向量化,然后在pdf文件中进行类似度查找,找到类似的文本,最终将类似的文本以及问题输入到OpenAI的语言模型中,得到答案并回来给用户。
这儿的embedding 计划咱们使用openai供给的embedding转换。
咱们使用Chroma作为向量数据库,在调用完load_pdf接口后,能够看到现已将pdf向量化并存储在向量数据数据库文件中:
作用展现:
能够看到,经过自动化寻找类似问题作为context,咱们现已能够让GPT回答关于方针文章的相关内容。
结尾
AI时代会有很多生活方法被改动,阅览也许便是其中之一,之前咱们带着问题在书中寻找答案,现在咱们向读过书的AI发问得到答案,未来已来。






