你有没有注意到,你的最爱杂货店似乎总能猜到你想要什么?一周前,意大利美食成了主角,意大利面、酱料和葡萄酒摆满了货架。而刚一出现春天的迹象,自行车和园艺工具就神奇般地占据了显眼的位置。这可不是巧合——零售商们精通季节性趋势和消费者心理,从而影响你的购物体验。
在VertexAI上使用Google Imagen 3生成
同样的原则也适用于搜索结果。有时候,仅仅依靠用户查询的语义相关性可能不够。如果有人搜索“便宜的酒店”,仅仅向他们展示最便宜且几乎没有任何附加服务的选项可能不是最好的策略。他们可能更满意那些既实惠又有一定舒适度的中档酒店。向他们展示高端套房可能会让他们另寻他处,因为竞争对手可能更懂他们的需求。“便宜”这个词提供了他们期望的关键线索,但这个词可能不会显式出现在你目录中酒店的介绍里。这表明仅靠语义相关性可能会失败。这也说明需要一种额外的方法来随时调整搜索结果的排序,确保最适合的选项能够脱颖而出。我们称之为提升。
Boosting 让你能够通过除了相关性之外的其他信号重新排列搜索结果。这就像实时调整搜索结果,根据更具体的规则来定制,以便在你需要时精准控制哪些项目显示在前面。这对推广、特别优惠或需要根据实时事件或趋势优先显示特定项目的情况特别有用。
在这篇博客文章中,我们将深入探讨提升:这是使用Agent Builder构建的搜索应用程序中内置的功能之一。我们将探讨如何为所有搜索请求设置提升规则,以及如何根据用户上下文覆盖这些规则,从而提供更个性化的响应。
让我们来点实际的吧!我们将使用Agent Builder创建一个点菜搜索微服务,以便顾客点菜。它将具有一个REST API,以便与网页或移动应用轻松对接。
每个工程师都知道数据很重要,所以我们先为我们的应用生成一些虚拟数据吧。
为此,我们将启动Vertex AI Colab Enterprise,这会给我们一个直接在浏览器里的协作编码环境。可以将其视为一个超级本,我们可以在里面编写和运行代码,玩转数据,甚至模拟搜索应用。
准备好了,开始吧!
咱们开始写代码吧!
以下是开始之前需要遵循的4个步骤,准备好深入探讨提升。
- 使用 Gemini 生成菜谱列表。
- 将数据加载到 BigQuery 表中。
- 从 BigQuery 表创建一个 Agent Builder 数据存储。
- 创建一个 Agent Builder 搜索应用,并将它与第 3 步中的数据存储关联起来。
虽然许多在线演示项目使用英语,但Gemini在超过100种语言上表现出色。这表明在很多情况下,它甚至超越了专门为个别语言设计的模型,如其在波兰语语言和文化能力基准测试中的第一名所示。
为了展示这一点,我将用Gemini生成一个波兰菜的菜单。你可以轻松地将其调整为你喜欢的语言。
我们需要100道菜,每道菜都包含名称、评分、食材、价格、上月订单数和准备时间等信息。为了确保输出是一个有效的JSON数组,我将利用Gemini的受控生成功能,该功能严格遵循预定义的JSON模式要求。以下是我要使用的模式示例:
RESPONSE_SCHEMA = {
"type": "ARRAY",
"items": {
"type": "OBJECT",
"properties": {
"name": {
"type": "STRING",
"description": "菜名"
},
"average_score": {
"type": "NUMBER",
"format": "float",
"description": "菜品平均得分"
},
"ingredients": {
"type": "ARRAY",
"items": {
"type": "STRING"
},
"description": "菜品所用原料"
},
"price": {
"type": "NUMBER",
"format": "float",
"description": "菜品售价"
},
"is_vegan": {
"type": "BOOLEAN",
"description": "菜品是否为纯素"
},
"number_of_orders": {
"type": "INTEGER",
"description": "菜品订购次数"
},
"preparation_time": {
"type": "INTEGER",
"description": "准备菜品所需时间(分钟)"
}
},
"required": [
"name",
"average_score",
"ingredients",
"price",
"is_vegan",
"number_of_orders",
"preparation_time"
]
},
"property_ordering": [
"name",
"ingredients",
"average_score",
"price",
"is_vegan",
"number_of_orders",
"preparation_time"
]
}
然后我就用 Vertex AI 来初始化 session。
导入 vertexai # `vertexai` 是 Google 的 AI 服务库
从 vertexai.generative_models 导入 GenerativeModel, Part, SafetySetting # 这些是生成模型中的相关类和设置
vertexai.init(project=vertexai_project_id, location=vertexai_region) # 初始化 `vertexai`,设置项目ID和位置
助手函数 generate()
封装了调用 Gemini 所需的一切,包括提示、模型声明、生成配置(其中定义了响应模式配置)及其安全过滤器设置。
def generate():
prompt = """生成一个包含25道菜的列表,这些菜可以在美食应用的目录中找到。
每道菜应包含:
- 名称
- 平均评分(满分5分)
- 配料
- 价格
- 是否为素食
- 订单数量
- 准备时间(分钟)
"""
model = GenerativeModel(
"gemini-1.5-flash-002",
##system_instruction=[system_instruction]
)
generation_config = {
"max_output_tokens": 8192,
"temperature": 1,
"top_p": 0.95,
"response_mime_type": "application/json",
"response_schema": RESPONSE_SCHEMA,
}
safety_settings = [
SafetySetting(
category="仇恨言论",
threshold="关闭"
),
SafetySetting(
category="危险内容",
threshold="关闭"
),
SafetySetting(
category="色情内容",
threshold="关闭"
),
SafetySetting(
category="骚扰",
threshold="关闭"
),
]
response = model.generate_content(
[f"提示:{prompt}"],
generation_config=generation_config,
safety_settings=safety_settings,
stream=False,
)
# 返回响应文本
return response.text
我的提示要求每次请求生成25道菜,以高效利用Gemini的8000个令牌限额。因此,我需要做4次请求来生成一个包含100道菜的菜品列表。
number_of_calls = 4
# 初始化一个空列表来存储项目
items = []
# 循环调用次数,每次调用生成响应并解析JSON
for i in range(number_of_calls):
resp = generate()
elements = json.loads(resp)
for item in elements:
items.append(item)
为了将来可能再用,我决定把这份列表保存成 JSON 文件。
将 items 转换为 JSON 格式,并设置缩进为 2。
打开一个名为 'dishes.json' 的文件用于写入,并将转换后的 JSON 数据写入文件。
接下来,我可以将数据加载到 DataFrame 这个数据框中并查看几个记录的预览。
import pandas as pd
# 从文件中读取JSON数据
with open(f"dishes.json", "r") as f:
data = json.load(f)
# 将数据转换为Pandas DataFrame
df = pd.DataFrame(data)
print(df.head()) # 打印前五行
使用 BigQuery 的 BigFrames 可以简化将 DataFrame 数据加载到 BigQuery 表中的过程。具体操作如下:
import bigframes # 引入 bigframes 库
import bigframes.pandas # 引入 bigframes.pandas 子库
BQ_TABLE_URI = f"{vertexai_project_id}.{BQ_DATASET_ID}.{BQ_TABLE_NAME}" # 定义 BigQuery 表的 URI
session = bigframes.connect( # 建立 bigframes 的连接
bigframes.BigQueryOptions( # 使用 bigframes 的 BigQuery 选项
project=vertexai_project_id, # 指定项目 ID
location=BQ_LOCATION, # 指定位置
)
)
df.to_gbq(BQ_TABLE_URI, if_exists="replace") # 将 DataFrame 写入 BigQuery 表,如果表已存在则替换
运行此代码后,几秒钟后就能使用数据了,您的BigQuery表格中就会有数据可用。
Boosting 可以用于包含结构化、非结构化或网页数据的通用搜索应用。一个例子是 BigQuery 表,它是结构化的数据。首先,前往 Agent Builder,然后选择“创建 DataStore”选项(DataStore 是数据存储的一种)。
选择从 BigQuery 表中索引数据的选项:结构化 — 带有您自定义模式的 BigQuery 表。
指定您的BigQuery表格,点击“创建”按钮后,索引将会开始。索引过程需要几分钟,完成后,您将看到以文档形式列出的索引菜品。
可以把 Datastore 想象成一个管理型向量数据库。现在,我们需要创建一个使用这个 Datastore 的搜索应用。为此,请进入 Agent Builder,点击“新建应用”按钮,并选择“通用搜索”功能。
当应用准备好了之后,你可以预览结果,并看看语义搜索如何在我们菜品目录索引上工作。比如,当你搜索“鱼”时,你会看到相关的文档。
现在,让我们深入到主要话题:提升。虽然语义搜索虽然能很好地找到相关文档,但它通常需要一些帮助。我们需要一种方法利用更具体的规则来定制搜索。在Agent Builder中,这些定制设置通过_控制_实现。
你可以将多个服务控件(如按钮或菜单)连接到单个搜索应用程序上:
服务控制类型有几种,包括提升、同义词、过滤和推广。在未来的文章中我们会详细探讨这些选项,本文将仅专注于提升。
为了简化,我们将创建一个单次服务的控件来提升不太受欢迎的菜品或商品。我们将利用这个属性来优先展示过去一个月订单数少于200的菜品或商品,具体来说就是那些订单数少于200的菜品或商品。对于这个控件,接下来,我们将创建一个新的“Boost”控件,命名为 boost_when_number_of_orders_is_less_than_200
。
服务控制可以对所有用户查询生效,或者仅仅对包含特定关键词或短语的查询生效。
我们会把这个设置留空,这样它就适用于所有的查询。
我们也可以设定一个时间段,在这个特定时间段内实施这种服务管控。
在我们的例子中,我们不会采用这一时间限制,因此我们的服务管控将始终保持激活。
现在,Agent Builder中的通用搜索支持混合型搜索,允许我们将多个数据存储附加到单个应用。搜索将在所有附加的数据存储之间进行。因此,在定义服务策略时,我们必须指定适用的数据存储。由于我们的数据存储是基于我们自己的BigQuery表构建的,它是唯一理解number_of_orders
属性的数据存储的。
我们会利用这个属性来筛选订单数量少于200份的相关菜肴。
最后,我们需要指定如果识别出这样的项目我们要怎么做。Boost/bury值滑块用于设置一个介于-1和+1之间的数值。该数值将用于决定把符合条件的项目向下或向上调整。比如,选择0.7表示我们将把满足条件的项目推到前面。
既然我们的服务已经创建好了,我们来看看它怎么运行。以下代码会帮我们向搜索应用发送认证请求。
从 google.auth 模块导入 default 和 transport
import requests
class DatastoreService:
def __init__(self):
creds, project_id = default()
auth_req = transport.requests.Request() # 在这里使用 google.auth
creds.refresh(auth_req)
access_token = creds.token
self.access_token = access_token
def search(self, project_id, app_engine, query):
# 定义 API 端点和请求头
url = f"https://discoveryengine.googleapis.com/v1alpha/projects/{vertexai_project_id}/locations/global/collections/default_collection/engines/{app_engine}/servingConfigs/default_search:search"
headers = {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json"
}
data = {
"query": f"{query}",
"pageSize": 50, # 设置每页显示的结果数量
"queryExpansionSpec": {"condition": "AUTO"},
"spellCorrectionSpec": {"mode": "AUTO"},
}
# 发送一个 POST 请求
response = requests.post(url, headers=headers, json=data)
return response.json()
此代码定义了一个名为 DatastoreService
的类,用于与 Google Cloud Vertex AI 搜索 API 进行交互。首先,它进行身份验证并获取访问令牌。search
方法然后构建一个发送到 API 的搜索请求体,包括项目 ID、搜索引擎 ID 以及用户的查询。它通过携带访问令牌并在请求体中携带搜索参数来发送 POST 请求。最后,它返回一个 JSON 响应,其中包含从 API 获取的搜索结果。
现在,我们将创建我们 DatastoreService
类的一个实例,并用它来查找「ryba」(波兰语中的“鱼”这个词):
datastore = DatastoreService()
results = datastore.search(vertexai_project_id,
agent_builder_search_app_id,
"ryba")
这将包含应用了哪些服务管控的信息:
响应确认我们已应用了boost_when_number_of_orders_is_less_than_200
控制。现在,让我们遍历这些结果,只显示每道菜的名称及其订单数:
# 遍历结果列表中的每个条目
for result_item in results["results"]:
# 打印文档名称
print(result_item["document"]["structData"]["name"])
# 打印订单数量
print(result_item["document"]["structData"]["number_of_orders"])
我们将看到分配的加权值帮助有150个订单(小于200)的菜品把该菜品排在列表的最前面。
让我们考虑一个场景,你有一个客户数据平台,并希望进行 A/B 测试。你想要测量当某个特定用户群体看到订单量介于 200 到 270 之间的菜品出现在搜索结果顶部时,对收入产生的影响。如何根据用户群体而不是商品属性来实施这条规则?这可以通过带有自定义条件的请求加权来实现。为此,我们可以在搜索请求中添加一个 boostSpec
部分:
# 定义带有查询占位符的请求数据
data = {
"query": f"{query}",
"pageSize": 50, ## 设置每页显示多少条结果---
"queryExpansionSpec": {"condition": "AUTO"},
"spellCorrectionSpec": {"mode": "AUTO"},
"boostSpec": {
"条件增强规格": {
"condition": condition,
"boost": 0.7
}
},
"相关性阈值": relevance
}
对于参与A/B测试分段的用户,我们会向这些用户发送带有满足测试条件的boostSpec
的搜索请求。例如,在boostSpec.condition
属性中,我们将使用条件"number_of_orders > 200 AND number_of_orders < 270"
。
results = datastore.search(vertexai_project_id,
agent_builder_search_app_id,
"ryba",
"number_of_orders > 200 AND number_of_orders < 270"
)
重要的是,这个 boostSpec
不会禁用我们搜索应用上已有的控制。我们可以通过检查响应的 appliedControls
字段来验证这一点。
你看,我们的 boost_when_number_of_orders_is_less_than_200
控制依然有效。看到返回的菜品,寿司菜品,拥有150个订单,排在列表的第二位。接着,搜索请求中的 boostSpec
开始起作用,将拥有250个订单的菜品推到最前面,因为它是唯一一个符合订单数大于200且小于270条件的菜品。
这篇文章只是简单地介绍了Agent Builder搜索的一些提升和隐藏功能。除此之外,你可以通过考虑文档的新鲜度和计算的属性等因素来自定义搜索结果。要了解更多高级选项,官方文档是最佳选择。
增强搜索结果的云生成式AI应用构建器文档 https://cloud.google.com/generative-ai-app-builder/docs/boost-search-results
总结:这篇博客文章着眼于仅仅依赖语义搜索的不足,并介绍了boosting作为一种技术,可以实时优化搜索结果。就像杂货店会战略性地展示季节性商品以吸引顾客一样,boosting允许你根据其他因素优先展示搜索结果。这在推广特定产品、突出特别优惠或迎合当前趋势时特别适用。
我们展示了如何利用Agent Builder自带的“加强”功能来精细调整搜索结果。我们介绍了两种关键方法。
- 全局提升规则: 这些规则应用于所有搜索请求,确保所有搜索请求中哪些项目优先展示的一致性。我们通过创建一条规则来优先展示例如不太受欢迎的菜品,以我们示例餐厅应用程序为例,确保点单数少于200的菜品将被优先显示。
- 按请求提升: 这允许根据用户上下文或特定搜索参数动态地进行个性化提升。我们展示了如何为个别搜索覆盖全局规则,实现例如A/B测试或针对用户群体的定向推广等场景。
这篇文章提供了一个实用的指南,通过使用Agent Builder逐步介绍如何构建一个菜品订购搜索微服务的步骤。我们首先使用Gemini生成一个合成的菜品数据集,并将其导入到BigQuery中。随后,我们创建一个Datastore以及一个搜索应用,并将其链接,以便启用语义搜索。
最后,我们深入探讨了提升机制,演示了如何创建和应用服务控制策略。我们展示了如何根据订单量等属性提升项目,并验证这些提升规则是否正确实施。我们还解释了如何使用自定义条件实现按需提升,从而实现对搜索结果的高度针对性调整。
通过这个示例,我们展示了 Agent Builder 中的增强功能提供了一种灵活而强大的方法来控制搜索结果的显示,确保最相关和最理想的项目始终突出显示。
本文由Lukasz Olejniczak_—— Google Cloud 的客户工程师 Lukasz Olejniczak 撰写。文中观点仅代表作者个人,不一定反映 Google 的观点。
如果喜欢这篇文章,请给它点个赞或鼓掌。如果你想了解更多关于谷歌云、数据科学、数据工程和AI/ML的信息,请在我的LinkedIn上关注我。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章