在本地知识库的构建中,其中重要的一环是对文本的向量计算,然后存入数据库备查。在这种知识库的项目中除了知识文本的重要性之外,向量计算几乎占据了绝大多数的比重,可以说:成败在此计算。
现在比较流行的有三个向量计算库:OpenAIEmbeddings、shibing624/text2vec-base-chinese和GanymedeNil/text2vec-large-chinese。接下来就实际测试下看看。
环境准备
python 3.10, 其它包:
pip install langchain chromadb openai tiktoken sentence-transformers python-dotenv
OpenAIEmbeddings
示例代码:
from langchain.text_splitter import CharacterTextSplitter
from langchain.document_loaders import TextLoader
from langchain.vectorstores import Chroma
from langchain.embeddings.openai import OpenAIEmbeddings
from dotenv import dotenv_values
env_vars = dotenv_values('.env')
# 加载和实例化数据库
persist_directory = './chroma'
collection = 'testcc'
embedding = OpenAIEmbeddings(
model="text-embedding-ada-002",
openai_api_key=env_vars['OPENAI_API_KEY']
)
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding, collection_name=collection)
# 文本分割
text_splitter = CharacterTextSplitter(chunk_size=400, chunk_overlap=0)
# chunk_size=400表示每次读取或写入数据时,数据的大小为400个字节, 约300~400个汉字
def saveToVectorDB(file):
try:
loader = TextLoader(file, encoding='gbk') #中文必须带 encoding='gbk'
documents = loader.load()
docs = text_splitter.split_documents(documents)
ids = vectordb.add_documents(documents=docs)
print(126, "saveDb ok", ids)
return "ok", 200
except Exception as e:
print(444, "saveDb error", e)
return "error", 500
# 查询相似度的文本
def queryVectorDB(ask):
s = vectordb.similarity_search_with_score(query=ask, k=3)
if len(s) == 0:
return ""
else:
if s[0][1] < 0.385:
return s[0][0].page_content
else:
return ""
往数据库中存入初始数据,就可以开始测试了。注意,这里用到了similarity_search_with_score这个函数。得到的数据如下:
[(Document(page_content='要选择优质菌种,配方更加科学......', metadata={'source': './uploads/yishejun.txt'}), 0.2091393032277543), (Document(page_content='益生菌是一类......', metadata={'source': './uploads/yishejun.txt'}), 0.29793976485387913), (Document(page_content='我们肠道所需要的有.....', metadata={'source': './uploads/yishejun.txt'}), 0.2995214947747933)]
每条数据都有一个得分,0.2091393032277543这就是问题和知识库文本相关的得分。越低表示越相关。这里就可以得到一组数据:
相关:
0.209
0.153
0.152
0.297
0.253
0.228
不相关:
0.453
0.476
0.475
0.479
可以看到,相关和不相关这两者之间有明显的界限。我们可以划出一个得分以区别相关性,我取得的0.385,效果还是可以。
shibing624/text2vec-base-chinese
还是上面同样的代码,只有向量函数换成:embedding = HuggingFaceEmbeddings(model_name='shibing624/text2vec-base-chinese') 即可。如果是第一次使用,程序会自动从HuggingFace上下载相关的模型,在本地完成计算。
用同样的文本去做计算测试,得到以下的分值:
相关:
288.64
190.68
221.10
153.35
201.33
308.08
不相关:
448.54
411.06
392.82
虽然在分界上表现还可以,但是在短文本上的查询很差,很多查不到! 这几乎可以说是它的致命缺点了。
GanymedeNil/text2vec-large-chinese
GanymedeNil/text2vec-large-chinese是在shibing624/text2vec-base-chinese基础上重新训练的模型,表现要更好些。跑分看看:
相关:
753.65
296.06
825.58
900.24
941.84
468.30
473.47
234.78
426.68
941.84
671.29
612.81
646.69
753.60
不相关:
820.72
915.02
910.17
381.96
774.05
864.51
915.02
948.56
784.89
753.06
虽然效果还可以,但是得分真的很迷惑啊,根本分不清是不是相关文本! 做了大量的实测后,也只能放弃,实在无法判断相关性。
做了这么多测试,也只有OpenAIEmbeddings是可行的。看来人家收钱是有道理的。现阶段,开源的向量计算模型还没有发展到可以实用的程度,只能静待下一步。