3.4 KiB
自定义关键字
为什么需要自定义关键字
在基于向量数据库和LLM进行问答对话的场景中,首先需要针对用户的提问从向量数据库中提取相关的内容片段,然后把用户提问和检索到的内容喂给LLM来生成回复。 在把文档切片存入向量数据库和基于用户提问到向量数据库搜索相关内容时,都需要一个嵌入模型来对文本进行嵌入来得到一个固定长度的向量。例如使用m3e-base来对 文本进行嵌入。
m3e-base和其他很多的embedding mode都是基于HuggingFaceEmbeddings实现的。HuggingFaceEmbeddings是基于sentence_transformers来实现的。 这部分详情请参考本项目中的kb_cache/base.py中EmbeddingsPool类的load_embeddings()函数中的代码。
sentence_transformers是Sentence Bert模型的实现,使用了Bert的基于wordpiece的tokenizer. Bert tokenizer在对文本进行tokenize时的结果 举例如下:
输入的文本(这里只是一个没分隔的一串字符):iphone13pro
生成的token id序列:[101, 8210, 8679, 10538, 102]
token到token id的映射:
[CLS]->101
iphone->8210
##13->8679
##pro->10538
[SEP]->102
这里可以看到iphone13pro被tokenize成为3个token, 分别是iphone, ##13, ##pro。 [CLS]和[SEP]是自动加入的特殊token。
输入的文本:中石油
生成的token id序列:[101, 704, 4767, 3779, 102]
token到token id的映射:
[CLS]->101
中->704
石->4767
油->3779
[SEP]->102
这里可以看到中石油被tokenize成了中,石,油三个token.
在上面的两个例子中,我们期望iphone13pro和中石油都被当做一个专有名词被tokenize成一个token。这样可以提高文本嵌入和搜索的精度。 如果进一步对嵌入模型进行精调时,这些专有名词做为不可分的关键字,可以做为一个token来得到更好的嵌入表示。
如何使用
-
如果需要自定义关键字,首先准备一个关键字的文本文件,每一行是一个关键字。例如:
文件key_words.txt: iphone13pro 中石油
-
配置model_config.py
EMBEDDING_KEYWORD_FILE = "keywords.txt" EMBEDDING_MODEL_OUTPUT_PATH = "output" -
运行keyword_preprocess.py,keywords文件中的每一个keyword做为一个独立的token, 整个embedding model的embedding及 tokenizer会被更新,并被存储到配置的目录中。这个目录和原始的embedding model的目录结构是一致的。使用运行后的目录做为embedding model, tokenize的结果如下:
输入的文本(这里只是一个没分隔的一串字符):iphone13pro 生成的token id序列:[101, 21128, 102] token到token id的映射: [CLS]->101 iphone13pro->21128 [SEP]->102
输入的文本:中石油 生成的token id序列:[101, 21129, 102] token到token id的映射: [CLS]->101 中石油->21129 [SEP]->102
-
配置model_config.py。然后按照原来的流程运行:
- 使用第3步生成的目录做为embedding model的目录
MODEL_PATH = { "embed_model": { "m3e-base": "output", } }- 运行init_database.py来初始化数据库和向量数据库
- 运行startup.py来启动程序