我正在使用来自OpenAI
的OpenAIEmbeddings()
类,它使用text-embedding-3-small
模型。根据文档,它会为任何输入文本生成一个1536维的向量。
然而,我对它的工作原理有些困惑:
- 1536维向量是否是针对整个输入文本生成的?
- 如果1536维向量代表整个输入文本,那么模型如何处理单个词与更长的文本如句子或段落?
我的预期是这样的:
如果我的输入文本中有100个词,我期望OpenAIEmbeddings()
会输出100个向量,每个向量的大小为1536。
但输出结果是针对整个输入文本的一个大小为1536的单一向量。
为什么我会有这样的预期?
因为在我的学习过程中,我了解到像Word2Vec或GloVe这样的嵌入技术为语料库中的每个词提供向量。OpenAIEmbeddings的做法与此有何不同?
我想了解是否有方法使用这个模型提取单个词的嵌入,或者输出是否总是代表整个输入的单一向量。
任何见解或示例都将不胜感激!
回答:
你描述的一切都是100%符合预期的。
问:1536维向量是否是针对整个输入文本生成的?
答:是的。
问:如果1536维向量代表整个输入文本,模型如何处理单个词与更长的文本如句子或段落?
答:首先,OpenAI嵌入模型对单个词和长文本的处理没有区别。对于模型来说,这都是输入。输入甚至可以是一个单字符(例如,“a”),但从中计算嵌入向量没有意义,因为“a”对我们人类来说没有语义意义。
其次,你可能想问的是当你使用这些嵌入进行相似性搜索时会发生什么。换句话说,当你使用它们时会发生什么?如果你使用词、句子、段落或整个文本的嵌入,会有什么不同吗?是的!
这被称为分块。如何分块你的文本取决于用例。最好的方法可能是简单地尝试并观察。如果在进行相似性搜索后得到有意义的结果,那么这意味着分块是合适的(即使这意味着分块整个文本)。如果在进行相似性搜索后没有得到有意义的结果,那么这意味着分块不合适(例如,不按段落分块,而是尝试按句子分块)。
关于这个话题,有一篇非常好的Stack Overflow 博客文章你应该阅读(注意加粗的文字,因为这是最好的解释):
在RAG中,你创建了你想要从中提取和检索的数据片段的文本嵌入。这允许你将源文本的一部分放置在LLM用来创建响应的语义空间中。
/…/
在RAG系统中,你需要特别注意单个数据片段的大小。你如何划分数据被称为分块,这比嵌入整个文档更复杂。
/…/
分块数据的大小将对搜索中出现的信息产生巨大影响。当你嵌入一个数据片段时,整个片段都被转换为一个向量。如果一个块中包含的内容过多,向量将失去对其讨论内容的具体性。如果包含的内容过少,你将失去数据的上下文。