学习内容
- 用LangChain构建基于“易速鲜花”本地知识库的问答系统
补充知识
在讲解“易速鲜花”内部员工知识库问答系统这个项目时,这一节中提出了许多新的概念。我对于这些概念不是很了解,通过询问AI助手和阅读相关资料,在下面整理了一些补充知识。
词嵌入的实现
词嵌入(Word Embedding)是一种将文本中的词或短语映射为向量的技术,目的是将语言特征转化为能够被机器理解和处理的数字表示。词嵌入通过将具有类似含义的词映射到相似的向量空间位置,从而捕捉语义和上下文关系。实现词嵌入的方法包括:
-
计数模型 (Count-based Models) :利用共现矩阵和统计方法来表示词之间的关系。典型的方法包括潜在语义分析 (LSA) 和共现矩阵的降维处理。
-
预测模型 (Prediction-based Models) :
-
Word2Vec:由Google提出的词嵌入方法,通过训练神经网络来学习词的向量表示。包括以下两种模型:
- Skip-gram:给定一个词预测其上下文词。
- CBOW (Continuous Bag of Words) :给定上下文词预测中心词。
-
GloVe (Global Vectors for Word Representation) :结合计数统计和预测的优势,利用词与词之间的共现概率关系来学习嵌入表示。
-
-
基于上下文的嵌入 (Contextual Embeddings) :如ELMo、BERT等预训练语言模型,能够为同一词在不同上下文中生成不同的向量表示,捕捉更复杂的语义信息。
具体实现步骤通常包括:
- 数据预处理:对文本进行分词、去除停用词、标点等处理。
- 构建模型:选择一种嵌入方法(如Word2Vec、GloVe或更现代的Transformer模型)。
- 模型训练:通过输入大规模文本语料,训练模型来优化词的向量表示。
- 使用嵌入:生成的词向量可用于自然语言处理任务,如文本分类、情感分析、机器翻译等。
词嵌入模型通常在深度学习框架中如TensorFlow和PyTorch中实现,并结合NLP任务进行微调。
定义DoubaoEmbeddings类
class DoubaoEmbeddings(BaseModel, Embeddings):
client: Ark = None
api_key: str = ""
model: str
def __init__(self, **data: Any):
super().__init__(**data)
if self.api_key == "":
self.api_key = os.environ["OPENAI_API_KEY"]
self.client = Ark(
base_url=os.environ["OPENAI_BASE_URL"],
api_key=self.api_key
)
def embed_query(self, text: str) -> List[float]:
"""
生成输入文本的 embedding.
Args:
texts (str): 要生成 embedding 的文本.
Return:
embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.
"""
embeddings = self.client.embeddings.create(model=self.model, input=text)
return embeddings.data[0].embedding
def embed_documents(self, texts: List[str]) -> List[List[float]]:
return [self.embed_query(text) for text in texts]
下面是对代码的详细解释:
- 类定义和 继承
class DoubaoEmbeddings(BaseModel, Embeddings):
这里定义了一个新的类 DoubaoEmbeddings,它继承自 BaseModel 和 Embeddings。BaseModel 是 pydantic 库中的一个类,用于定义数据模型,而 Embeddings 是 langchain 库中的一个类,用于定义文本嵌入模型。
- 属性定义
client: Ark = None
api_key: str = ""
model: str
这些是类的属性,其中 client 是一个 Ark 类型的对象,用于与 API 进行交互;api_key 是 API 密钥,默认为空字符串;model 是嵌入模型的名称。
Ark 类被用来创建一个客户端对象,该对象可以调用火山引擎的API来生成文本的嵌入向量。
- 构造函数
def __init__(self, **data: Any):
super().__init__(**data)
if self.api_key == "":
self.api_key = os.environ["OPENAI_API_KEY"]
self.client = Ark(
base_url=os.environ["OPENAI_BASE_URL"],
api_key=self.api_key
)
这是类的构造函数,它首先调用父类的构造函数,然后检查 api_key 是否为空,如果为空,则从环境变量中获取 OPENAI_API_KEY。接着,它初始化 client 对象,用于与 API 进行交互。
**data 是一个参数传递的语法,它用于接收一个字典类型的参数。
在函数定义中使用 **data 作为参数,意味着函数可以接收任意数量的关键字参数,并且这些参数会被自动组织成一个字典。在函数内部,可以通过字典的键来访问这些参数的值。
- 嵌入查询方法
def embed_query(self, text: str) -> List[float]:
"""
生成输入文本的 embedding.
Args:
texts (str): 要生成 embedding 的文本.
Return:
embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.
"""
embeddings = self.client.embeddings.create(model=self.model, input=text)
return embeddings.data[0].embedding
这个方法用于生成单个文本的嵌入向量。它调用 client 的 embeddings.create 方法,传入模型名称和文本,然后返回第一个嵌入向量。
- 嵌入文档方法
def embed_documents(self, texts: List[str]) -> List[List[float]]:
return [self.embed_query(text) for text in texts]
这个方法用于生成多个文本的嵌入向量。它使用列表推导式调用 embed_query 方法,对每个文本生成嵌入向量,然后返回一个列表,其中包含每个文本的嵌入向量。