用于新闻推荐的大型语言模型和向量数据库

2023年12月20日 由 alex 发表 280 0

在本文中,我介绍了两个旨在解决这些问题的开源解决方案:


  • Sentence Transformers:一种基于文本信息的嵌入生成技术;
  • Qdrant:一个向量数据库,能够存储嵌入并提供一个简单的界面来查询它们。


这些工具应用于 NPR,这是一个新闻门户推荐数据集,旨在支持学术界开发推荐算法。


使用 Sentence Transformer 生成嵌入


首先,我们需要找到一种方法将输入数据转换成向量,我们将这些向量称为嵌入。


那么,让我们看看能够使用NPR数据集处理哪种类型的数据:


import pandas as pd
df = pd.read_parquet("articles.parquet")
df.tail()


2


我们可以看到,NPR拥有一些有趣的文本数据,比如文章的标题和正文内容。我们可以在下图所示的嵌入生成过程中使用它们:


3


一旦我们从输入数据中定义了文本特征,我们就需要建立一个嵌入模型来生成我们的数值表示。幸运的是,像HuggingFace这样的网站上有许多预训练模型,适用于特定语言或任务。在我们的示例中,我们可以使用neuralmind/bert-base-portuguese-cased模型,它是针对巴西葡萄牙语训练的,用于以下任务:


  • 命名实体识别
  • 句子文本相似性
  • 识别文本蕴含


从代码角度来看,这就是我们如何翻译嵌入生成过程:


from sentence_transformers import SentenceTransformer
model_name = "neuralmind/bert-base-portuguese-cased"
encoder = SentenceTransformer(model_name_or_path=model_name)
title = """
  Paraguaios vão às urnas neste domingo (30) para escolher novo presidente
"""
sentence = title
sentence_embedding = encoder.encode(sentence)
print (sentence_embedding)
# output: np.array([-0.2875876, 0.0356041, 0.31462672, 0.06252239, ...])


所以,给定一个示例输入数据,我们可以将标题和标签内容串联成一个单独的文本,并将其传递给编码器以生成文本嵌入。


我们可以对NPR数据集中的所有其他文章应用相同的过程:


def generate_item_sentence(item: pd.Series, text_columns=["title"]) -> str:
    return ' '.join([item[column] for column in text_columns])
df["sentence"] = df.apply(generate_item_sentence, axis=1)
df["sentence_embedding"] = df["sentence"].apply(encoder.encode)


储存嵌入向量


由于生成嵌入向量可能是一个耗费资源的过程,我们可以使用向量数据库来存储这些嵌入向量,并基于多种策略执行查询。


有几种向量数据库软件可以完成这项任务,但在本文中我将使用Qdrant,这是一个开源解决方案,它为流行的编程语言如Python、Go和Typescript提供了API。


设置Qdrant


为了处理所有Qdrant操作,我们需要创建一个指向向量数据库的客户端对象。Qdrant允许你创建一个免费的服务层以测试远程连接数据库,但为了简单起见,我将在本地创建并持久化数据库:


from qdrant_client import QdrantClient
client = QdrantClient(path="./qdrant_data")


连接建立后,我们就可以在数据库中创建一个集合来存储新闻文章的嵌入表示。


from qdrant_client import models
from qdrant_client.http.models import Distance, VectorParams
client.create_collection(
    collection_name = "news-articles",
    vectors_config = models.VectorParams(
        size = encoder.get_sentence_embedding_dimension(),
        distance = models.Distance.COSINE,
    ),
)
print (client.get_collections())
# output: CollectionsResponse(collections=[CollectionDescription(name='news-articles')])


请注意,矢量配置参数被用来创建集合。这些参数告诉Qdrant一些关于向量的属性,比如它们的大小以及当比较向量时使用的距离度量。


生成向量点


在最终填充数据库之前,我们需要创建适当的对象以便上传。在Qdrant中,向量可以使用PointStruct类存储,你可以用它来定义以下属性:


  • id:向量的ID(在NPR案例中,是newsId)
  • vector:表示向量的一维数组(由嵌入模型生成)
  • payload:一个包含任何其他相关元数据的字典,这些元数据以后可以用来在一个集合中查询向量(在NPR案例中,文章的标题、正文和标签)


from qdrant_client.http.models import PointStruct
metadata_columns = df.drop(["newsId", "sentence", "sentence_embedding"], axis=1).columns
def create_vector_point(item:pd.Series) -> PointStruct:
    """Turn vectors into PointStruct"""
    return PointStruct(
        id = item["newsId"],
        vector = item["sentence_embedding"].tolist(),
        payload = {
            field: item[field]
            for field in metadata_columns
            if (str(item[field]) not in ['None', 'nan'])
        }
    )
points = df.apply(create_vector_point, axis=1).tolist()


上传向量


最后,在所有项目被转换为点结构后,我们可以将它们分块上传到数据库:


CHUNK_SIZE = 500
n_chunks = np.ceil(len(points)/CHUNK_SIZE)
for i, points_chunk in enumerate(np.array_split(points, n_chunks)):
    client.upsert(
        collection_name="news-articles",
        wait=True,
        points=points_chunk.tolist()
    )


查询向量


现在集合终于被向量填满了,我们可以开始对数据库进行查询了。我们可以通过多种方式输入信息来查询数据库,但我认为有两个非常有用的输入方式:


  • 输入文本
  • 输入向量ID


使用输入向量查询向量


假设我们构建这个向量数据库是为了在搜索引擎中使用。在这种情况下,我们期望用户的输入是一段输入文本,我们必须返回最相关的项目。


由于向量数据库中的所有操作都是用……向量来进行的,我们首先需要将用户的输入文本转换成一个向量,这样我们才能找到基于那个输入的相似项目。回想一下,我们使用句子转换器(Sentence Transformers)来将文本数据编码成嵌入向量,所以我们可以使用完全相同的编码器来为用户的输入文本生成一个数值表示。


既然NPR包含新闻文章,假设用户输入了“Donald Trump”来了解美国选举:


query_text = "Donald Trump"
query_vector = encoder.encode(query_text).tolist()
print (query_vector)
# output: [-0.048, -0.120, 0.695, ...]


一旦计算出输入查询向量,我们就可以在集合中搜索最接近的向量,并定义我们希望从这些向量中获取哪种类型的输出,比如它们的新闻ID、标题和主题:


from qdrant_client.models import Filter
from qdrant_client.http import models
client.search(
    collection_name="news-articles",
    query_vector=query_vector,
    with_payload=["newsId", "title", "topics"],
    query_filter=None
)


在运行此操作后,这里是生成的输出标题:


  • 输入句子:唐纳德·特朗普
  • 输出 1:巴拉圭人将在本周日(30日)投票选举新总统
  • 输出 2:选民表示,拜登和特朗普不应该在2024年竞选,路透/Ipsos民意调查显示
  • 输出 3:作家指控特朗普在1990年代对她进行了性侵犯
  • 输出 4:唐纳德·特朗普前副总统迈克·彭斯在法庭上的证词可能会给前总统带来麻烦


似乎除了带来与特朗普本人相关的新闻外,嵌入模型也成功代表了与总统选举相关的话题。注意,在第一个输出中,并没有直接提及输入术语“Donald Trump”,除了总统选举的相关性。


使用输入向量 ID 查询向量


最后,我们可以请求向量数据库“推荐”一些离我们想要的向量 ID 近但远离不需要的向量 ID 的项。所需和不需要的 ID 分别被称为正面和负面示例,它们被视为推荐的种子。


例如,假设我们有如下正面 ID:


seed_id = '8bc22460-532c-449b-ad71-28dd86790ca2'
# title (translated): 'Learn why Joe Biden launched his bid for re-election this Tuesday'


我们可以然后请求与这个例子相似的物品:


client.recommend(
    collection_name="news-articles",
    positive=[seed_id],
    negative=None,
    with_payload=["newsId", "title", "topics"]
)


在运行此操作后,以下是翻译后的标题:


  • 输入项目:了解乔·拜登为什么在这个星期二启动他的连任竞选
  • 输出1:拜登宣布他将竞选连任
  • 输出2:美国:导致拜登竞选连任的4个原因
  • 输出3:路透/益普索民意调查显示,选民认为拜登和特朗普都不应在2024年竞选
  • 输出4:拜登顾问的失言引发了关于选后可能出现第二届政府的疑问


结论


本文展示了如何结合LLM和向量数据库来提供推荐。特别是,使用Sentence Transformers从NPR数据集中的文本新闻文章生成数值表示(嵌入)。一旦计算出这些嵌入,就可以填充向量数据库例如Qdrant,它便于基于多种策略查询向量。

文章来源:https://medium.com/towards-data-science/large-language-models-and-vector-databases-for-news-recommendations-6f9348fd4030
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消