【指南】实现语义缓存:更快、更经济的GenAI工作流程

2024年06月14日 由 alex 发表 134 0

生成式人工智能是人工智能中发展迅速的一个分支,最近因其可能给各行各业带来变革而备受关注。GCP 坚定不移地致力于实现生成式人工智能的民主化,强调在严格的安全协议、有效的数据管理和可扩展性的支持下采用技术。GCP 的与众不同之处在于其综合产品,将可访问的基础模型、可扩展的基础设施以及一整套调整、部署和维护工具结合在一起。


生成式人工智能和 LLM 讨论中经常出现的一个关键术语是 "语义缓存",尤其是在谈到优化话题时。尽管已经有了 GPT Cache、LangChain 等开放式框架,但这一概念仍需引起注意。对于使用语言模型的开发人员来说,延迟和成本是巨大的挑战。高延迟会损害用户体验,而成本上升则会阻碍可扩展性。


请考虑以下场景: 你开发的 GenAI 应用程序获得了巨大的发展,每天都要处理大量的 API 调用。你注意到,用户经常会提出类似的查询,而这些查询之前都已处理过。然而,与 LLM 的每次交互都会产生多余令牌的成本,从而导致用户体验不佳。


这就是语义缓存的作用所在。它允许对重复的语义类似查询进行缓存响应,从而无需求助于人工智能提供商。这就节省了成本,减少了延迟。


语义缓存为 LLM 带来了几个关键优势。


  1. 通过存储预先计算的语义表征,可以加快查询的解决速度,从而缩短响应时间,提高资源利用效率。例如,对于我们的文档问题解答 RAG 管道(稍后将介绍),在没有缓存的情况下,检索时间约为 6504 毫秒。使用语义缓存后,检索时间缩短至约 1919 毫秒(提高了 3.4 倍)。对于精确匹配查询,改进幅度更大,检索时间缩短至 53 毫秒(提高了 123 倍)。这些数据基于我们将在本博文稍后进行的实验。我们稍后将深入探讨这个问题,探讨语义缓存在问答系统中的实施和优势。
  2. 减少计算需求的一个显著优势是随之降低了运营成本。这一点与完成应用程序接口(如 Gemini 1.0 Pro)尤其相关,后者通常根据输入和输出字符计算费用。这样的成本结构可能会给使用率较高的应用程序造成负担。相比之下,Vertex AI 的文本嵌入应用程序接口(text-embeddingAPIs)的成本结构明显较低。截至 2024 年 6 月,文本嵌入 API 的收费为每输出 1,000 个字符 0.000375 美元。相比之下,完成应用程序接口的费用明显更高。具体来说,Gemini 1.0 Pro 的文本输入费用为每 1,000 个字符 0.000125 美元,文本输出费用为每 1,000 个字符 0.000375 美元,合计费用为每 1,000 个字符 0.0005 美元。值得注意的是,这些数字不包括使用顶点人工智能矢量搜索和 Memorystore 等 GCP 服务编制嵌入索引和进行语义匹配的相关成本。不过,与嵌入文本的主要成本相比,这些费用预计会随着规模经济而减少。
  3. 此外,语义缓存通过有效管理更大的查询量来提高吞吐量,从而防止在高负载情况下出现性能瓶颈。受管 LLM 服务为调节资源消耗而设置的速率限制会给高吞吐量应用带来挑战。不过,嵌入式 API 提供的速率限制通常要比完成式 API 高得多。截至 2024 年 6 月,Vertex AI 的文本嵌入 API 允许每分钟处理 1,500 次请求(RPM),与 Gemini Pro 1.0 的 360RPM 限制形成鲜明对比,说明嵌入 API 具有更强的可扩展性。


这一系列优势使得语义缓存成为扩展和提高 LLM 应用程序或管道效率的重要优化策略。


缓存的演变--从标准向语义过渡

缓存是提高 LLM 或任何应用的速度和计算效率的关键技术。传统的缓存方法可存储并快速检索预生成的响应,用于 LLM 生成式人工智能的重复查询,从而大大减少计算负荷和响应时间。然而,在不断变化的人类语言领域,精确的查询匹配是很少见的。这就是语义缓存发挥作用的地方。


语义缓存通过解释和利用查询的基本语义来工作。它能识别并获取在语义上与输入查询相关的缓存响应,从而增加缓存命中的机会,改善响应时间和资源利用率。这种方法尤其适用于用户对类似查询使用不同措辞的情况,例如财务报告搜索。语义缓存可以避免多余的计算,快速准确地响应此类查询,从而提高 LM 应用程序的性能。


它标志着从传统的基于关键字的缓存向考虑查询语义意图或上下文的方法过渡。例如,如果给出两个措辞不同但意图相同的提示--"给我看年度财务报告 "和 "我需要年度财务报表"--语义缓存会识别出相同的意图并提供相似的响应,这是传统缓存无法做到的。


语义缓存:高层视角

在本文中,我们将利用一系列 GCP 服务演示一个功能完备的语义缓存系统。生成式应用的效率取决于强大的高性能数据层。该层能以最小的延迟促进快速交易,确保无缝的用户交互。在我们的文章中,该数据层应缓存预先计算的响应或嵌入,保留先前交互的记录,并执行语义搜索以检索相关上下文或知识。


近年来,矢量数据库在各行各业的 LM 应用程序中发挥了重要作用,因此已成为数据层的有效解决方案。在架构设计中,我们将使用 Vertex AI 向量搜索。这将作为我们的矢量数据库,用于以下两方面:a) 创建金融文档集合的语义索引;b) 创建用户查询的语义索引。


我们将使用 Redis 支持的 Memorystore 作为标准缓存。我们将使用云存储(Cloud Storage)作为托管原始数据和处理过的数据以创建索引的首选登陆区。编码后的文档和查询存储在这里。我们将使用两种模型: 1/ 文本生成模型 Gemini 1.0 Pro,以及 2/ Vertex AI 的文本嵌入模型。


我们将首先定义数据集,然后使用 DocumentAI(其他 GCP 人工智能服务)对这些原始文档进行预处理。接下来,我们将了解使用矢量搜索创建语义索引的过程,并学习如何使用 Memorystore 上的 Redis 设置标准缓存。最后,我们将了解如何为整个系统布线,以建立一个可靠的机制。


只要需要调用文本生成的基础模型,语义缓存就可以用于多种生成任务。这些任务的范围可以从问题解答和总结到分类,也可以是自然语言理解/处理任务的任何变体,这些任务都需要可以进行语义推断的文本输入。


在本文中,我们将重点讨论文档问题解答用例。在这种情况下,我们针对经过处理的文档语料库提出一个复杂的问题,从而得出答案。这一过程由两个关键组件推动--一个检索组件和一个由 LLM 支持的生成组件。这就是文档问题解答的标准检索-增强生成(RAG)管道。


数据集

我们将用于实验的数据集包括三家科技公司的季度报告: Alphabet、亚马逊和微软。从 2021 年第一季度到 2023 年第四季度,这个数据集包含 36 份文件(每家公司 12 份),时间跨度为三年。


为便于实验,我们从这些文档中提取了 100 对问答。每对问答都直接链接到单个文档,建立了单跳问答场景。这些问题和答案经过精心设计,侧重于从表格和复杂段落中提取信息,对 RAG 系统提出了巨大挑战。PDF 金融季报数据集可在此处找到。显示问题-答案对数据集的基本事实可在数据文件夹中名为 ground_truth.csvin 的 CSV 文件中找到。


下面是 Alphabet 2020 年第一季度报告中的一个示例表格,总结了主要与营业收入和利润率相关的财务结果。


9


我们的基本真实 CSV 中的一个问题示例,以及从上表中得出的预期答案。


What was Google's operating income (in billions) at the end of March 2021, and
how did it compare to the same period of the previous year?


Google's operating income was $16.437 billion in Q1 2021. This was an increase
from $7.977 billion in Q1 2020.


文档处理

首先,让我们对财务报告数据集进行预处理。这将为我们的 RAG 管道摄取和索引做好准备。该工作流程的高级概览如下图所示。我们将每份 PDF 报告解析为页面文本,然后使用 DocumentAI 的专用处理器从各个页面中提取表格。然后,将 Markdown 格式的表格合并回这些 PDF 文档中每页提取的文本上下文中。


Google Cloud Document AI 是一个由机器学习驱动的平台,可简化从非结构化和半结构化文档中提取有价值的结构化数据的过程。它提供预建和可定制的模型以及 OCR 和 NLP 功能,可实现文档处理自动化、提高效率并增强决策能力。它可与其他谷歌云服务无缝集成,以便进一步分析和采取行动。


10


以下是 Alphabet 2021 年第一季度报告第 1 页的表格示例。


11


下面是使用 PyPDF 解析表格时的显示效果。


Quarter Ended March 31,
2020
2021
Revenues
$
41,159
$
55,314
Increase in revenues year over year
13 %
34 %
Increase in constant currency revenues year over year (1)
15 %
32 %
Operating income
Operating margin
Other income (expense), net
$
7,977
$
16,437
19 %
30 %
(220)
$
4,846
Net income
$
6,836 $
17,930
Diluted EPS
9.87 $
26.29
(1)


有了 DocumentAI,我们可以提取出同一文本的更简洁版本,同时保持空间信息和结构的完整性。然后,这个标记语言版本的表格会被合并回文档的提取文本中。


|    | ('',)                                                     | ('Quarter Ended March 31, 2020 2021',)   |
|---:|:----------------------------------------------------------|:-----------------------------------------|
|  0 | Revenues                                                  | 41,159 $ 55,314                          |
|  1 | Increase in revenues year over year                       | 13 % 34 %                                |
|  2 | Increase in constant currency revenues year over year (¹) | 15 % 32 %                                |
|  3 | Operating income                                          | SA 7,977 $ 16,437                        |
|  4 | Operating margin                                          | 19 % 30 %                                |
|  5 | Other income (expense), net                               | SA (220) 4,846                           |
|  6 | Net income                                                | $ 6,836 17,930                           |
|  7 | Diluted EPS                                               | $ 9.87 $ 26.29                           |


你可以先运行 create.py,创建 DocumentAI OCR 处理器。然后运行 parse.py 和 parse_tables.py。最后,运行 merge.py,将提取的页面文本内容与提取和转换的表格(markdown 格式)合并为每个页面的单个文本文件。


接下来,我们将探索如何从财务报告中提取处理过的页面,并使用 Vertex AI 的文本嵌入模型将其编码为嵌入式内容。更重要的是,我们将使用 Vertex AI 的向量搜索对嵌入进行语义索引。


组装语义索引管道

在开始索引过程之前,让我们先了解一下什么是 Vertex AI、什么是 Agent Builder 以及向量搜索在其中的作用。


Vertex AI Agent Builder 是一个全面的人工智能平台,可以简化人工智能代理的开发和部署,适用于各种应用。无论你需要对话界面、智能搜索功能还是自动化工作流,Agent Builder 都能提供创建定制解决方案的工具。


该平台与 Vertex AI Search、Vertex AI Conversation 和 Vector Search 等核心组件无缝集成。Vertex AI Search可对结构化和非结构化数据编制索引,从而无需大量人工即可开发复杂的问题解答系统和知识库。Vertex AI Conversation 可帮助创建聊天机器人多转弯,并与搜索和其他路由功能紧密集成。


对于更高级的搜索用例,Vertex AI 提供矢量搜索。它使开发人员能够构建基于嵌入式的自定义 RAG 管道,释放语义搜索和增强信息检索的潜力。将 Vector Search 视为一个可管理的矢量数据库,你可以在其中对嵌入进行索引和搜索。它提供应用程序接口,用于创建、上插、删除和刷新索引,以及与索引进行匹配。


Agent Builder 既适合技术用户,也适合非技术用户。它提供了直观的无代码工具,可轻松创建代理,同时还提供了用于定制和微调的编程访问。回复可基于特定的数据源,或通过谷歌搜索从网上获取实时信息。Agent Builder 具有企业级安全性,并与其他谷歌云服务无缝集成,是一个多功能、安全的平台,可用于构建各种智能代理,同时确保数据隐私和合规性。


在本文章中,我们将使用矢量搜索(Vector Search)为数据集中的预处理页面和数据存储库中基本真实评估集中的用户查询创建语义索引。


要创建文档页面的语义索引,我们首先要从文档处理步骤中处理过的页面开始。然后使用文本嵌入应用程序接口(Text Embedding API)将这些页面编码为页面嵌入(下图中的步骤 1)。编码后的数据被推送到云存储(步骤 2)。然后,我们利用用于矢量搜索的 Vertex AI API 来摄取这些数据并为页面嵌入建立索引(步骤 3)。


create.pyc 使用用户定义的配置创建空语义索引。然后,我们使用 batch_encode.py,将预处理过的页面批量编码为嵌入式内容。最后,我们运行 deploy.py 创建一个私有端点,用于匹配针对该索引的查询。该脚本还将编码数据部署到之前创建的语义索引中,用于文档搜索。


12


接下来,让我们为文档问题解答系统中的一些用户查询创建一个语义索引。为此,我们将使用位于此处的基本真实评估集中的问题。


这个工作流程与上文提到的文档页面索引创建类似,只不过我们使用的是问题而不是页面。


注意:如果我们没有任何预期的查询(问题),我们可以从一个空索引开始。一般建议查看系统的历史使用模式或分析,并编制一份最频繁、最多样化和最独特的查询列表,以便在流程开始时先行一步。一旦我们建立了语义缓存的端到端工作流程,你就会发现我们也会将新查询上载到该索引中。


考虑到我们需要将查询动态地插入该索引,我们创建索引时将其设置为流类型。通过流式更新,你可以在几秒钟内更新和查询你的索引。


编码查询、创建查询索引和索引端点的所有代码示例都封装在此代码库中。


13


一旦建立了文档(在我们的例子中是页面)索引和查询索引,我们就可以在 Vector Search 控制台中使用这两种索引,如下图所示。


14


15


标准缓存设置

接下来,让我们看看如何设置标准缓存来捕捉问答对。我们可以将其用于端到端整体架构。为此,我们将使用 Memorystore。


Google Cloud Memorystore 是一种完全托管的内存数据存储服务,擅长缓存数据以提高实时应用程序的性能和响应速度。通过将频繁访问的数据存储在内存中,Memorystore 可提供亚毫秒级的延迟和高可用性。它支持 Redis 和 Memcached 协议,可无缝扩展以处理不断增长的工作负载,同时与其他 GCP 服务顺利集成。


通过 GCP 控制台设置该缓存相对简单。请确保已启用必要的 API 进行设置。在我们的练习中,我们基本上可以设置一个不带任何副本、内存最小为 4GB 的基本实例。


16


我们还要用问题-答案对来填充缓存。我们将使用之前用来创建语义索引的、来自地面实况测试集的同一组问题。但现在,我们将不再对问题进行编码,而是创建问题的唯一哈希值。这个哈希值将作为键,而实际的原始问题(文本)将作为值插入缓存。


接下来,对问题使用相同的哈希值 id,但在哈希值中添加 "ans: "前缀。以此为键插入相关答案。下图说明了这一过程。


17


你可以执行位于 src/redis 目录中的 load.pyl,预加载包含问答对的标准缓存。


在 Google 云平台上连接 Memorystore 时,通常需要使用端口转发功能,以便从本地机器安全地访问 Redis 云实例。这个过程包括设置一个小型虚拟机,作为本地环境和远程 Memorystore 服务之间的桥梁。下面是设置方法:


首先,运行以下命令在谷歌云项目中创建一个新的计算实例:


$ gcloud compute instances create 'redis-forwarder' --machine-type=f1-micro --zone=us-central1-a --project=your-project-idcreate 'redis-forwarder' --machine-type=f1-micro --zone=us-central1-a --project=your-project-id


将 your-project-id 替换为实际的 Google 云项目 ID。该实例将作为转发器。


接下来,与实例建立安全的 SSH 连接,并将本地端口转发到 Memorystore Redis 实例:


$ gcloud compute ssh redis-forwarder --zone=us-central1-a -- -N -L 6379:[Memorystore_IP]:6379--zone=us-central1-a -- -N -L 6379:[Memorystore_IP]:6379


将 [Memorystore_IP] 替换为 Memorystore Redis 实例的 IP 地址。这条命令会将本地端口 6379 映射到 Memorystore Redis 实例的端口 6379,使你可以像在本地运行一样与 Redis 数据库交互。


这种使用端口转发的方法对于保持安全连接和确保数据交易受到保护至关重要,尤其是在从本地开发环境访问云资源时。


连接各点--协调端到端工作流程

如果你已经走到了这一步,那么你应该已经成功地设置了所有必要元素,以构建一个全面的端到端工作流程,在文档答疑系统的范围内实施语义缓存。这一整体工作流程可细分为两个主要途径:一个侧重于精确匹配,另一个侧重于语义匹配。


精确匹配

考虑这样一种情况:系统可能会再次遇到来自同一用户或不同用户的相同搜索查询(问题)。当搜索查询较短且重复出现的几率较高时,通常会出现这种情况。在这种情况下,如果新收到的查询与缓存中已有的查询完全匹配,我们就可以直接从标准缓存中获取答案,而不是按照常规流程对搜索查询进行编码并与文档索引进行语义匹配。下图说明了这一过程。


如图所示,用户首先提出一个问题。然后,我们计算问题的哈希值,并检查标准缓存中是否存在哈希键。如果存在,我们会重新使用带有 "ans: "前缀的相同哈希值,生成一个新的哈希 ID,用于直接从缓存中提取答案。如果密钥不存在,我们就会返回到下一个机制,为输入的查询寻找语义匹配候选,这将在下文中讨论。


18


语义匹配

现在,让我们来探讨一下整体工作流程,看看语义匹配是如何与之前讨论过的精确匹配场景整合在一起的。如下图所示,我们将逐步分解所有工作流程。


19


  1. 用户向系统提交问题。
  2. 然后使用文本嵌入模型将问题编码为1x768维度嵌入。
  3. 我们将传入的问题与之前创建的语义索引进行匹配,以找到最相似的问题以及置信度得分。对于我们的用例,我们使用余弦距离来测量两个问题(表示为向量)之间的相似度。它的计算方法是 1 减去余弦相似度。值的范围从 0(相同)到 2(完全相反),值越低表示相似度越大或距离越小。置信度得分的计算方法是 1 减去余弦距离。
  4. 我们将基于置信度得分的决策阈值设置为 0.98 的高值。根据此条件是否满足,我们将采取两种不同的路径之一。
  5. 如果条件满足,我们就知道用户提出的问题(查询)在语义上与语义索引中排名靠前的问题非常相似。然后,我们使用这个排名靠前的问题的哈希 ID 来检查此键是否已存在于 Memorystore 标准缓存中。
  6. 我们使用问题的哈希 ID 检查标准缓存中的映射键值对条目。如果找到,我们将检索到的答案返回给用户。如果未找到键,则表示出现错误,因为在语义索引中找到了键,但标准缓存中不存在映射键值对。我们可以使用错误处理机制来跟踪这些未命中。离线批处理可以重新计算此类查询的答案,并通过将它们插入标准缓存来修复错误。或者,也可以通过简单地将流程路由回步骤 7 来在线完成此操作,这将是使用文档(页面)语义索引而不是为过去的问题创建的索引的本机语义搜索。
  7. 当传入的问题不满足语义相似度的条件阈值时,我们将传入的问题向量与我们的文档(页面)索引进行匹配,并找到前 3 个匹配页面。然后我们将这些页面检索为文本。
  8. 接下来,我们将检索到的上下文连同传入的查询一起传递给 Gemini 1.0 Pro。这将根据这些页面的文本生成相关答案。然后将答案返回给用户。
  9. 无论传入的问题是否返回符合置信度阈值的最佳匹配,我们仍然会将查询插入到过去查询的语义索引中。
  10. 类似地,对于阈值检查的两种情况(无论通过还是失败),我们都会存储生成的答案。传入的问题也会添加到标准缓存中。Note:问题的哈希值充当两个条目(语义索引中的编码问题和标准缓存中的键值对)之间的连接链接。


qa.py包中的模块src/run说明了在一个工作编排中组合在一起的完整工作流程。


增强功能和附加功能

接下来,让我们研究一下可以对架构进行哪些改进。这些改进可能包括可以以不同方式实现的内容或对当前状况的改进。我们还建议进行额外的练习以更好地阐明这些内容。


  • 目前,我们以两种方式处理用户查询(问题):精确匹配或语义相似。我们还可以引入第三个类别,称为词汇或句法相似。这将捕获仅在有限的标点符号、停用词或不影响含义的细微变化上有所不同的类似查询。可以轻松检查这些查询并将其路由到与标准缓存的精确匹配,从而避免更长的语义匹配路径。我们可以在散列之前实施规范化清理步骤来标准化这一点。但是,这在很大程度上取决于传入问题的性质。挑战在于区分这两个类别并设计匹配的约束和规则。Note:在我们的设置中,除精确匹配之外的任何内容都被视为语义匹配。
  • 添加额外的 LLM 实体提取和检查可以确保与传入查询相关的数字和时间段的准确性。例如,我们需要确保不会将“截至 2021 年 3 月底,谷歌的营业收入是多少(以十亿美元计)?”和“截至 2022 年 3 月底,谷歌的营业收入是多少(以十亿美元计)”等问题归类为语义相似。通过结合 Gemini (LLM) 促进的实体识别步骤,我们可以执行预匹配步骤。在这里,我们提取时间段并将其与顶部匹配的时间段进行比较,以验证它是否真正相似。这有助于防止基于数字实体(例如时间段)有时非常不同的语义相似查询。
  • 在我们现有的架构中,当存储问题和相关的预先存在的答案(从标准缓存中检索)时,我们可以将问题的哈希映射到答案的哈希,而不是直接将问题的哈希映射到答案。这种方法也需要对答案进行哈希处理。为了找到答案,我们现在可以将问题哈希 ID 映射到答案哈希 ID。这使我们能够避免为答案存储重复的条目。这也使我们能够更好地解释问题。我们可以检查日志和跟踪,以查看不同的查询如何映射到同一个答案。Note:为了简单起见,当前架构中未实现此功能。
  • 在我们当前的设置下,我们根据反复试验对阈值置信度进行硬编码。理想情况下,为了确定这个临界值,我们可以在预热练习中检查路由答案的质量。这需要从一组测试查询开始,这些查询被保留下来,不包含在标准缓存或为过去的问题创建的语义索引中。这些查询通过系统以固定值(通常很高,比如 0.9)运行,以捕获相应的答案。然后,我们可以手动或使用所选的 LLM 将这些答案与预期答案进行比较,以得出评估指标和成功标准。之后,在清除测试候选的标准缓存和语义索引后,我们动态增加阈值并重复练习。这样,我们就可以得到一个更符合我们要求的阈值。
  • 在内存受限且需要管理数十亿个查询的情况下,为了优化缓存效率,利用基于缓存命中的 TTL(生存时间)调整是一种战略方法。通过根据 Redis 键的访问频率动态修改其 TTL,你可以优先保留经常访问的键,同时让较少使用的键过期,从而更有效地管理内存。这需要实施一个监控系统来记录每个键的缓存命中。通过为每个键维护一个命中计数器并根据这些指标调整 TTL,我们可以确保内存分配与数据的实时需求和访问模式保持一致。这使你可以专注于数据流和业务逻辑,而不必担心复杂的清理任务。计数器还可以为我们提供进一步增强的见解。


进行测试:验证工作流程

现在我们了解了架构,并设置了问答 RAG 管道的所有先决条件,并使用语义缓存进行了优化,我们可以开始测试系统了。我们已经取得了重大进展!


让我们开始测试各种场景,以评估系统的精确匹配和语义匹配能力。此过程应包括预期结果以及系统如何处理极端情况的考虑。


测试 1

对于test 1,我们从基本事实问答对中的一个简单问题开始——“截至 2021 年 3 月底,谷歌的营业收入是多少(十亿美元),与去年同期相比如何? ” 这个问题已经填充到标准缓存中,也是我们之前设置的语义索引中的问题列表的一部分。根据我们的端到端架构,我们要做的第一件事是在标准缓存中寻找完全匹配。我们对问题进行哈希处理,并在内存存储中检查密钥。由于我们已经有了这个密钥,我们会立即检索答案并将其返回给用户。这个过程在上面的完全匹配部分中已经讨论过。在这种情况下,检索时间是最快的,大约为53 ms。


2024-06-07 12:05:48,703 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: What was Google's operating income (in billions) at the end of March 2021, and how did it compare to the same period of the previous year? - Hash: 56fda240d018fdf8c73436229d47454e
2024-06-07 12:05:48,755 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: Answer retrieved for hash 56fda240d018fdf8c73436229d47454e: Google's operating income was $16.437 billion in Q1 2021. This was an increase from $7.977 billion in Q1 2020.
2024-06-07 12:05:48,755 [INFO] [exact] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/exact.py]: Redis retrieval time = 52.86216735839844 ms
{'question': "What was Google's operating income (in billions) at the end of March 2021, and how did it compare to the same period of the previous year?", 'closest_question': 'NA', 'match_type': 'EXACT', 'confidence': 'NA', 'answer': "Google's operating income was $16.437 billion in Q1 2021. This was an increase from $7.977 billion in Q1 2020.", 'execution_time': 52.92701721191406}


测试 2

接下来,我们利用 Gemini 创建用于 的相同问题的语义变体test 1。鉴于这个变体问题不是完全匹配,我们期望它在语义上与前一个问题相似。此问题导致缓存未命中,然后对其进行散列、编码,并与过去问题的语义索引进行匹配。我们期望最佳匹配与用于 的问题相同test 1。获得这个最佳匹配后,我们将使用问题的哈希 ID 从标准缓存中检索答案作为完全匹配。我们发现返回答案的总时间略高,大约1919 ms(~2 秒),因为我们正在进行一次语义匹配和两次完全匹配调用。请注意,只有当通过语义匹配的最佳匹配等于或超过我们设置的置信度阈值时,我们才会启动第二次完全匹配调用。


2024-06-07 12:05:49,908 [INFO] [qa] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/run/qa.py]: Query variant => What was Google's operating income (in billions) for the first quarter of 2021, and how did it compare to the first quarter of 2020?
2024-06-07 12:05:49,909 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: What was Google's operating income (in billions) for the first quarter of 2021, and how did it compare to the first quarter of 2020? - Hash: a8445ce20d1d270dde869f309ffa9ae4
2024-06-07 12:05:49,959 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: No answer found for hash a8445ce20d1d270dde869f309ffa9ae4
2024-06-07 12:05:51,617 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/match/utils.py]: Neighbors found successfully.
2024-06-07 12:05:51,618 [INFO] [semantic] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/semantic.py]: Top match found: {'confidence': 0.956, 'query': "What was Google's operating income (in billions) at the end of March 2021, and how did it compare to the same period of the previous year?"}
2024-06-07 12:05:51,618 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: What was Google's operating income (in billions) at the end of March 2021, and how did it compare to the same period of the previous year? - Hash: 56fda240d018fdf8c73436229d47454e
2024-06-07 12:05:51,670 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: Answer retrieved for hash 56fda240d018fdf8c73436229d47454e: Google's operating income was $16.437 billion in Q1 2021. This was an increase from $7.977 billion in Q1 2020.
2024-06-07 12:05:51,670 [INFO] [exact] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/exact.py]: Redis retrieval time = 51.931142807006836 ms
2024-06-07 12:05:51,670 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: What was Google's operating income (in billions) for the first quarter of 2021, and how did it compare to the first quarter of 2020? - Hash: a8445ce20d1d270dde869f309ffa9ae4
2024-06-07 12:05:51,827 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: Question and answer stored successfully under hash: a8445ce20d1d270dde869f309ffa9ae4
{'question': "What was Google's operating income (in billions) for the first quarter of 2021, and how did it compare to the first quarter of 2020?", 'closest_question': "What was Google's operating income (in billions) at the end of March 2021, and how did it compare to the same period of the previous year?", 'match_type': 'SEMANTIC', 'confidence': 0.956, 'answer': "Google's operating income was $16.437 billion in Q1 2021. This was an increase from $7.977 billion in Q1 2020.", 'execution_time': 1918.9109802246094}


测试 3

在下一个测试中,我们重复使用相同的语义变体问题 — 根据下面的日志,我们可以看到我们从 Memorystore 获得了精确匹配,并且立即返回了答案。这是因为我们在上一步中将上一个测试中的变体问题与检索到的答案(我们使用了与变体最匹配的问题)一起插入到标准缓存中。


52 ms由于我们直接从 MemoryStore 获取答案,因此这次答案检索速度更快。


2024-06-07 12:05:51,828 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: What was Google's operating income (in billions) for the first quarter of 2021, and how did it compare to the first quarter of 2020? - Hash: a8445ce20d1d270dde869f309ffa9ae4
2024-06-07 12:05:51,879 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: Answer retrieved for hash a8445ce20d1d270dde869f309ffa9ae4: Google's operating income was $16.437 billion in Q1 2021. This was an increase from $7.977 billion in Q1 2020.
2024-06-07 12:05:51,879 [INFO] [exact] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/exact.py]: Redis retrieval time = 51.53799057006836 ms
{'question': "What was Google's operating income (in billions) for the first quarter of 2021, and how did it compare to the first quarter of 2020?", 'closest_question': 'NA', 'match_type': 'EXACT', 'confidence': 'NA', 'answer': "Google's operating income was $16.437 billion in Q1 2021. This was an increase from $7.977 billion in Q1 2020.", 'execution_time': 51.631927490234375}


测试 4

在最后的测试中,我们选择一个完全不在真实测试集内的全新查询。此查询既不存在​​于标准缓存中,也不存在于语义缓存中。接下来,查询将经过前面的步骤,首先检查标准缓存中是否有完全匹配项。然后对其进行编码并与过去问题的语义索引进行匹配,以找到最匹配的类似问题。此查询是特意选择的,与测试集中的先前查询不同且独一无二。因此,它未能达到置信度阈值。因此,它将通过本机路径从页面的语义索引中找到前 3 个匹配页面。然后,它使用问题和上下文通过 Gemini 生成答案。


2024-06-07 12:05:51,879 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: How did Alphabet's adjustment in the estimated useful lives of servers and network equipment affect its financial results for the fourth quarter of 2023? - Hash: bae6d9a678dc687767ab1148c7d36255
2024-06-07 12:05:51,932 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: No answer found for hash bae6d9a678dc687767ab1148c7d36255
2024-06-07 12:05:53,653 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/match/utils.py]: Neighbors found successfully.
2024-06-07 12:05:53,654 [INFO] [semantic] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/semantic.py]: Top match found: {'confidence': 0.8316, 'query': "How did Alphabet's non-marketable securities (assets) in Q4 2021 compare to Q4 2020?"}
2024-06-07 12:05:55,265 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/match/utils.py]: Neighbors found successfully.
2024-06-07 12:05:56,744 [INFO] [semantic] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/semantic.py]: Answer generated successfully.
2024-06-07 12:05:57,255 [INFO] [upsert] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/index/query/upsert.py]: Index instance created successfully.
2024-06-07 12:05:57,255 [INFO] [encode] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/index/query/encode.py]: Encoding question: How did Alphabet's adjustment in the estimated useful lives of servers and network equipment affect its financial results for the fourth quarter of 2023?
2024-06-07 12:05:57,256 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: How did Alphabet's adjustment in the estimated useful lives of servers and network equipment affect its financial results for the fourth quarter of 2023? - Hash: bae6d9a678dc687767ab1148c7d36255
2024-06-07 12:05:57,698 [INFO] [upsert] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/index/query/upsert.py]: Query encoded into embeddings.
2024-06-07 12:05:57,700 [INFO] [base] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/.vai-semantic-cache/lib/python3.11/site-packages/google/cloud/aiplatform/base.py]: Upserting datapoints MatchingEngineIndex index: projects/390991481152/locations/us-central1/indexes/8030608628903837696
2024-06-07 12:05:58,225 [INFO] [base] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/.vai-semantic-cache/lib/python3.11/site-packages/google/cloud/aiplatform/base.py]: MatchingEngineIndex index Upserted datapoints. Resource name: projects/390991481152/locations/us-central1/indexes/8030608628903837696
2024-06-07 12:05:58,225 [INFO] [upsert] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/index/query/upsert.py]: Datapoint upserted successfully.
2024-06-07 12:05:58,225 [INFO] [utils] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/cache/utils.py]: MD5 hash generated for input: How did Alphabet's adjustment in the estimated useful lives of servers and network equipment affect its financial results for the fourth quarter of 2023? - Hash: bae6d9a678dc687767ab1148c7d36255
2024-06-07 12:05:58,382 [INFO] [manager] [/Users/arunpshankar/Desktop/Projects/VertexAI-Semantic-Caching/src/redis/manager.py]: Question and answer stored successfully under hash: bae6d9a678dc687767ab1148c7d36255
{'question': "How did Alphabet's adjustment in the estimated useful lives of servers and network equipment affect its financial results for the fourth quarter of 2023?", 'closest_question': 'NA', 'match_type': 'NATIVE', 'confidence': 'NA', 'answer': 'The change in accounting estimate resulted in a reduction in depreciation expense of $983 million and an increase in net income of $765 million, or $0.06 per basic and $0.06 per diluted share for the three months ended December 31, 2023.', 'execution_time': 6503.555059432983}


从日志中可以看到,该测试运行时间最长,答案检索耗时约 6504 毫秒(约 6 秒)。


值得注意的是,在我们的实现中,作为语义和本地匹配流程的一部分,我们在返回答案之前分别向语义缓存和标准缓存进行了上插和插入操作。理想情况下,这应该发生在返回答案之后,并且可以并发执行。还要注意的是,计时包括记录步骤的时间。在实际应用中,这应该会运行得更快。显示数字的目的是显示比较差异,而不是测量精确数字。


总结

总而言之,本篇文章主要讨论了在 RAG 管道中为问题解答任务实现功能完备的语义缓存机制。不过,通过重新思考其中的一些组件,所讨论的概念可以很容易地扩展到更多的 NLP/NLU 任务。我们讨论了建立这一架构所需的各个方面,包括设计和代码。


文章来源:https://medium.com/google-cloud/implementing-semantic-caching-a-step-by-step-guide-to-faster-cost-effective-genai-workflows-ef85d8e72883
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消