基于大型语言模型和向量数据库开发新闻推荐系统

近年来,随着诸如ChatGPT、Bard等生成式人工智能工具的发布,大型语言模型(LLM)在机器学习社区引起了全球热议。这些解决方案背后的核心思想之一是计算非结构化数据(如文本和图像)的数字表示,并找出这些表示之间的相似之处。

然而,将所有这些概念应用到生产环境中存在其自身的一系列机器学习工程挑战:

  • 如何快速生成这些表示?
  • 如何将它们存储在适当的数据库中?
  • 如何快速计算生产环境的相似性?在这篇文章中,我将介绍两种开源解决方案,目的是解决下面这些问题:
  • 句子变换器(https://www.sbert.net/;参考引文1):一种基于文本信息的嵌入生成技术;
  • Qdrant(https://qdrant.tech/):一种能够存储嵌入并提供简单的查询接口的向量数据库。这两个工具都将应用于开发本文中的新闻门户推荐系统(参考引文2)。NPR(News Portal Recommendation),即新闻门户推荐数据集(在Kaggle网络公开免费使用:https://www.kaggle.com/datasets/joelpl/news-portal-recommendations-npr-by-globo),旨在支持学术界开发推荐算法。在本文的最后,您将学会:
  • 使用句子转换器生成新闻嵌入
  • 使用Qdrant数据库存储嵌入
  • 查询嵌入以推荐新闻文章需要说明的是,本文的所有代码您都可以在Github网站上获得。

1.使用句子转换器生成嵌入

首先,我们需要找到一种将输入数据转换为向量的方法,我们称之为嵌入(如果你想深入了解嵌入概念,我推荐您阅读一下Boykis的文章《什么是嵌入?》,参考引文3:https://vickiboykis.com/what_are_embeddings/about.html)。

因此,首先让我们来看看我们可以使用NPR数据集处理什么样的数据:

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

NPR数据集提供的样本数据(图片由作者本人生成)

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

嵌入生成过程(作者本人提供的图片)

这样一来,一旦我们从输入数据中定义了文本特征,我们就需要建立一个嵌入模型来生成我们的数字表示。幸运的是,存在像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)

请注意:上面这个过程可能需要耗费更长的时间,具体情况取决于您的机器的处理能力。

一旦我们有了所有新闻文章的嵌入;接下来,我们就可以定义一个存储它们的策略了。

2.存储嵌入

由于生成嵌入可能是一个昂贵的过程;因此,我们可以使用向量数据库来存储这些嵌入并基于不同的策略执行有关查询。

目前,已经存在几个向量数据库软件可以实现这项任务,但我将在本文中选择使用Qdrant,这是一个开源解决方案,它提供了可用于Python、Go和Typescript等多种流行编程语言的API支持。为了更好地比较这些向量数据库,请查看引文4来了解更多有关详情。

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(collectinotallow=[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()
 )

3.查询向量

现在,既然我们已经用向量存储满集合,接下来,我们就可以开始查询数据库了。我们可以通过多种方式输入信息来查询数据库,但我认为这两种非常有用的输入可以使用:

  • 输入文本
  • 输入向量ID

3.1 使用输入向量查询向量

假设我们已经成功构建了用于搜索引擎的上述向量数据库,我们希望用户的输入是一个输入文本,并且我们必须返回最相关的内容。

由于向量数据库中的所有操作都是使用向量来实现的,所以,我们首先需要将用户的输入文本转换为向量,这样我们就可以根据该输入找到类似的内容。回想一下,我们曾经使用句子转换器将文本数据编码到嵌入中;因此,我们也可以使用相同的编码器为用户的输入文本生成数字表示。

由于NPR包含了新闻文章,那么假设用户键入“Donald Trump”(唐纳德·特朗普)来了解美国大选信息:

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

一旦计算出输入查询向量,我们就可以搜索集合中最接近的向量,并定义我们希望从这些向量中得到什么样的输出,比如它们的newsId、标题和主题:

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
)

注意:默认情况下,Qdrant使用近似最近邻居算法来快速扫描嵌入,但是您也可以进行完全扫描,并带来准确的最近邻数据——请记住,这是一个更昂贵的操作。

运行上面的操作后,以下是生成的输出标题(为了更好地理解,翻译成了英语):

  • 输入句子:Donald Trump(唐纳德·特朗普)
  • 输出1:Paraguayans go to the polls this Sunday (30) to choose a new president(巴拉圭人将于本周日(30日)前往投票站选举新总统)
  • 输出2:Voters say Biden and Trump should not run in 2024, Reuters/Ipsos poll shows(路透社/益普索民意调查显示,选民表示拜登和特朗普不应在2024年参选)
  • 输出3:Writer accuses Trump of sexually abusing her in the 1990s(作家指责特朗普在20世纪90年代对她进行性虐待)
  • 输出4:Mike Pence, former vice president of Donald Trump, gives testimony in court that could complicate the former president(唐纳德·特朗普的前副总统迈克·彭斯在法庭上作证,这可能会给前总统带来不少麻烦)似乎除了带来与特朗普本人有关的新闻外,嵌入模型还成功地描述了与总统选举有关的话题。请注意,在第一个输出中,除了总统选举之外,没有直接引用输入术语“唐纳德·特朗普”。
    此外,我还省略了query_filter参数。如果您想指定输出必须满足某些给定条件,这是一个非常有用的工具。例如,在新闻门户网站中,通常只过滤最近的文章(比如从过去7天起),这是很重要的。因此,您可以查询满足最小发布时间戳的新闻文章。
    注意:在新闻推荐场景下,存在诸如公平性和多样性等多个需要考虑的方面。当然,这是一个开放的讨论主题;但是,如果您对这一领域感兴趣的话,不妨参阅NORMalize研讨会上的文章。

3.2 使用输入向量ID查询向量

最后,我们可以要求向量数据库“推荐”更接近某些所需向量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"]
)

运行上面的操作后,以下是已翻译的输出标题:

  • 输入项:Learn why Joe Biden launched his bid for re-election this Tuesday(了解乔·拜登本周二发起连任竞选的原因)
  • 输出1:Biden announces he will run for re-election(拜登宣布将竞选连任)
  • 产出2:USA: the 4 reasons that led Biden to run for re-election(美国:导致拜登竞选连任的4个原因)
  • 产出3:Voters say Biden and Trump should not run in 2024, Reuters/Ipsos poll shows(路透社/益普索民意调查显示,选民表示拜登和特朗普不应在2024年参选)
  • 输出4:Biden’s advisor’s gaffe that raised doubts about a possible second government after the election(拜登顾问的失态引发了人们对大选后可能成立第二届政府的怀疑)

结论

本文向您展示了如何将LLM和向量数据库结合起来构建一个新闻推荐系统。特别提到了,使用句子转换器来实现从NPR数据集中的文本新闻文章中生成数字表示(嵌入)的方法。一旦计算出这些嵌入,就可以用这些嵌入来填充例如Qdrant这样的向量数据库,Qdrant的使用将非常有助于通过多种策略来实现向量查询。

最后,您可以基于本文提供的基础示例进行大量进一步的改进,例如:

  • 测试其他嵌入模型
  • 测试其他距离指标
  • 测试其他向量数据库
  • 使用Go等基于编译型编程语言以获得更好的性能
  • 创建API支持的推荐系统

换言之,您可以提出许多想法来改进基于LLM推荐技术的机器学习工程。所以,如果您想分享您对这些改进的想法,请毫不犹豫地给我发信息吧。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/225367.html<

(0)
运维的头像运维
上一篇2025-04-16 21:03
下一篇 2025-04-16 21:04

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注