谷歌眼中的 Agent II:我们通往外部世界的三把钥匙

通过为 Agents 配备工具:扩展、函数和数据存储,我们释放了它们不仅能理解世界而且能对其采取行动的巨大潜力,为无数新应用和可能性打开了大门。

谷歌眼中的 Agent II:我们通往外部世界的三把钥匙
出处:数治网综合

虽然语言模型擅长处理信息,但它们缺乏直接感知和影响现实世界的能力。这限制了它们在需要与外部系统或数据交互的情况下的实用性。这意味着,在某种意义上,语言模型的好坏取决于它从训练数据中学到的东西。

但无论我们向模型输入多少数据,它们仍然缺乏与外部世界互动的基本能力。那么,我们如何让我们的模型能够与外部系统进行实时的、上下文感知的交互呢?函数 (Functions)、扩展 (Extensions)、数据存储 (Data Stores) 和插件 (Plugins) 都是为模型提供这种关键能力的方式。

虽然它们名称各异,但工具是在我们的基础模型和外部世界之间建🖂联系的东西。这种与外部系统和数据的连接使我们的 Agent 能够执行更广泛的任务,并且具有更高的准确性和可靠性。例如,工具可以使 Agents 能够调整智能家居设置、更新日历、从数据库中获取用户信息,或者根据一组特定的指令发送电子邮件。

截至发布之日,Google 模型能够与之交互的主要有三种工具类型:扩展 (Extensions)、函数 (Functions) 和数据存储 (Data Stores)。通过为 Agents 配备工具,我们释放了它们不仅能理解世界而且能对其采取行动的巨大潜力,为无数新应用和可能性打开了大门。

扩展 (Extensions)

理解扩展最简单的方法是将其视为以标准化方式弥合 API 和 Agent 之间差距的桥梁,允许 Agents 无缝地执行 API,而不管其底层实现如何。假设你构建了一个旨在帮助用户预订航班的 Agent。你知道你想使用 Google Flights API 来检索航班信息,但你不确定如何让你的 Agent 调用这个 API 端点。

一种方法是实现自定义代码,该代码将接收传入的用户查询,解析查询以获取相关信息,然后进行 API 调用。例如,在航班预订用例中,用户可能会说“我想预订从奥斯汀到苏黎世的航班。”在这种情况下,我们的自定义代码解决方案需要从用户查询中提取“奥斯汀”和“苏黎世”作为相关实体,然后才能尝试进行 API 调用。

但是,如果用户说“我想预订去苏黎世的航班”并且从未提供出发城市,会发生什么?API 调用会在没有所需数据的情况下失败,并且需要实现更多代码来捕获类似这样的边缘和角落情况。这种方法不可扩展,并且在任何超出已实现自定义代码范围的情况下都很容易崩溃。

一种更具弹性的方法是使用扩展。扩展通过以下方式弥合了 Agent 和 API 之间的差距:

  1. 使用示例教 Agent 如何使用 API 端点。
  2. 教 Agent 成功调用 API 端点需要哪些参数或参数。

扩展可以独立于 Agent 来创建,但应作为 Agent 配置的一部分提供。Agent 在运行时使用模型和示例来决定哪个扩展(如果有)适合解决用户的查询。这突出了扩展的一个关键优势,即它们内置的示例类型,允许 Agent 动态选择最适合任务的扩展。

可以将其想象成像软件开发人员决定在解决用户问题时使用哪个 API 端点一样。如果用户想预订航班,开发人员可能会使用 Google Flights API。如果用户想知道最近的咖啡店相对于他们的位置在哪里,开发人员可能会使用 Google Maps API。

以同样的方式,Agent / 模型堆栈使用一组已知的扩展来决定哪个最适合用户的查询。如果你想亲身体验扩展,可以在 Gemini 应用程序中尝试,方法是转到设置 > 扩展,然后启用你想要测试的任何扩展。例如,你可以启用 Google Flights 扩展,然后询问 Gemini “显示下周五离开奥斯汀前往苏黎世的航班。”

示例扩展

为了简化扩展的使用,Google 提供了一些开箱即用的扩展,可以快速导入到你的项目中并以最少的配置使用。例如,代码片段 1 中的代码解释器 (Code Interpreter) 扩展允许你根据自然语言描述生成并运行 Python 代码。

import vertexai
import pprint
PROJECT_ID = “YOUR_PROJECT_ID”
REGION = “us-central1”
vertexai.init(project=PROJECT_ID, location=REGION)

from vertexai.preview.extensions import Extension
extension_code_interpreter = Extension.from_hub(“code_interpreter”)
CODE_QUERY = “””Write a python method to invert a binary tree in O(n)
time.”””
response = extension_code_interpreter.execute(
operation_id = “generate_and_execute”,
operation_params = {“query”: CODE_QUERY}
)
print(“Generated Code:”)
pprint.pprint({response[‘generated_code’]})
# 上述代码片段将生成以下代码。
# …
# Generated Code:
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
# 接下⻚…

def invert_binary_tree(root):
“””
Inverts a binary tree.
Args:
root: The root of the binary tree.
Returns:
The root of the inverted binary tree.
“””
if not root:
return None
# Swap the left and right children recursively
root.left, root.right = \
invert_binary_tree(root.right), invert_binary_tree(root.left)
return root

# Example usage:
# Construct a sample binary tree
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
root.right.left = TreeNode(6)
root.right.right = TreeNode(9)
# Invert the binary tree
inverted_root = invert_binary_tree(root)
# …

代码片段1. 代码解释器扩展可以生成并运行 Python 代码

总而言之,扩展为 Agents 提供了一种以多种方式感知、交互和影响外部世界的方法。这些扩展的选择和调用由示例的使用来指导,所有这些都定义为扩展配置的一部分。

函数 (Functions)

在软件工程的世界里,函数被定义为完成特定任务并且可以根据需要重用的自包含代码模块。当软件开发人员编写程序时,他们通常会创建许多函数来完成各种任务。他们还将定义何时调用函数 a 与函数 b 的逻辑,以及预期的输入和输出。

函数在 Agent 的世界里工作方式非常相似,但我们可以用模型替换软件开发人员。模型可以接受一组已知的函数,并根据其规范决定何时使用每个函数以及函数需要哪些参数。函数与扩展在几个方面有所不同,最显著的是:

  1. 模型输出一个函数及其参数,但不进行实时的 API 调用。
  2. 函数在客户端 (client-side) 执行,而扩展在 Agent 端 (agent-side) 执行。

再次使用我们的 Google Flights 示例,一个简单的函数设置可能看起来像图 7 中的示例。

请注意,这里的主要区别在于函数和 Agent 都不直接与 Google Flights API 交互。那么 API 调用实际上是如何发生的呢?

通过函数,调用实际 API 端点的逻辑和执行被从 Agent 转移到了客户端应用程序,如图 8 和图 9 所示。这为开发人员提供了对应用程序中数据流的更精细控制。开发人员可能选择使用函数而不是扩展的原因有很多,但一些常见的用例是:

  • API 调用需要在应用程序堆栈的另一层进行,在直接 Agent 架构流之外(例如,中间件系统、前端框架等)
  • 安全或身份验证限制阻止 Agent 直接调用 API(例如,API 未暴露给互联网,或 Agent 基础设施无法访问)
  • 时间或操作顺序限制阻止 Agent 实时进行 API 调用。(例如,批处理操作、人工审核循环等)
  • 需要将额外的数据转换逻辑应用于 Agent 无法执行的 API 响应。例如,考虑一个不提供限制返回结果数量的过滤机制的 API 端点。在客户端使用函数为开发人员提供了执行这些转换的额外机会。
  • 开发人员希望在不部署用于 API 端点的额外基础设施的情况下迭代 Agent 开发(即函数调用可以充当 API 的“桩”或“模拟”)

虽然这两种方法之间的内部架构差异很微妙,如图 8 所示,但额外的控制和对外部基础设施的解耦依赖性使函数调用成为开发人员的一个有吸引力的选项。

用例

模型可用于调用函数以处理复杂的、客户端执行流程,面向最终用户,其中 Agent 开发人员可能不希望语言模型管理 API 执行(就像扩展的情况一样)。让我们考虑以下示例:一个 Agent 被训练为旅行礼宾,与想要预订度假旅行的用户互动。

目标是让 Agent 生成一个我们可以用于中间件应用程序的城市列表,以便为用户的旅行规划下载图像、数据等。用户可能会说:

我想和家人去滑雪旅行,但我不确定去哪里。

在对模型的典型提示中,输出可能如下所示:

当然,这里有一些你可以考虑的适合家庭滑雪旅行的城市列表:

  • Crested Butte, Colorado, USA
  • Whistler, BC, Canada
  • Zermatt, Switzerland

虽然上面的输出包含了我们需要的数据(城市名称),但格式不便于解 析。通过函数调用,我们可以教模型以结构化样式(如 JSON)格式化此输出,这种格式更方便另一个系统解析。给定来自用户的相同输入提示,来自函数的示例 JSON 输出可能看起来像代码片段 5。

Unset (应为 JSON 格式)

function_call {
name: “display_cities”
args: {
“cities”: [ “Crested Butte”, “Whistler”, “Zermatt”],
“preferences”: “skiing”
}
}

代码片段 5. 用于显示城市列表和用户偏好的示例函数调用负载

这个 JSON 负载由模型生成,然后发送到我们的客户端服务器,以执行我们想做的任何事情。在这个具体案例中,我们将调用 Google Places API 来获取模型提供的城市并查找图像,然后将它们作为格式化的富内容返回给我们的用户。考虑图 9 中的这个序列图,它逐步详细地展示了上述交互。

[序列图]

图 9 中示例的结果是,模型被用来“填空”,提供了客户端 UI 调用 Google Places API 所需的参数。客户端 UI 使用模型在返回的函数中提供的参数来管理实际的 API 调用。这只是函数调用的一个用例,但还有许多其他场景需要考虑,例如:

  • 你希望语言模型建议一个你可以在代码中使用的函数,但你不想在代码中包含凭据。因为函数调用不运行函数,所以你不需要在函数信息中包含代码中的凭据。
  • 你正在运行可能需要几秒钟以上的异步操作。这些场景与函数调用配合得很好,因为它是异步操作。
  • 你想在与生成函数调用及其参数的系统不同的设备上运行函数。

关于函数需要记住的一个关键点是,它们旨在为开发人员提供更多的控制权,不仅是对 API 调用的执行,而且是对整个应用程序中的数据流。在图 9 的示例中,开发人员选择不将 API 信息返回给 Agent,因为它与 Agent 可能采取的未来行动无关。

然而,根据应用程序的架构,将外部 API 调用数据返回给 Agent 以影响未来的推理、逻辑和行动选择可能是有意义的。最终,由应用程序开发人员选择什么适合特定的应用程序。

函数示例代码

为了从我们的滑雪度假场景中实现上述输出,让我们构建每个组件,使其与我们的 gemini-1.5-flash-001 模型一起工作。

首先,我们将把 display_cities 函数定义为一个简单的 Python 方法。

Python

from typing import Optional
def display_cities(cities: list[str], preferences: Optional[str] =
None):
“””Provides a list of cities based on the user’s search query and
preferences.
Args:
preferences (str): The user’s preferences for the search, like
skiing,
beach, restaurants, bbq, etc.
cities (list[str]): The list of cities being recommended to the
user.
Returns:
list[str]: The list of cities being recommended to the user.
“””
return cities

代码片段 6. 用于显示城市列表的函数的示例 python 方法。

接下来,我们将实例化我们的模型,构建工具 (Tool),然后将用户的查询和工具传递给模型。执行下面的代码将产生代码片段底部的输出。

Python

from vertexai.generative_models import GenerativeModel, Tool,
FunctionDeclaration

model = GenerativeModel(“gemini-1.5-flash-001”)

display_cities_function = FunctionDeclaration.from_func(display_cities) tool = Tool(function_declarations=[display_cities_function])

message = “I’d like to take a ski trip with my family but I’m not sure where to go.”
res = model.generate_content(message, tools=[tool]) print(f”Function Name:
{res.candidates[0].content.parts[0].function_call.name}”) print(f”Function Args:
{res.candidates[0].content.parts[0].function_call.args}”)
# > Function Name: display_cities
# > Function Args: {‘preferences’: ‘skiing’, ‘cities’: [‘Aspen’, ‘Vail’, ‘Park City’]}

代码片段 7. 构建一个工具,发送给带有用户查询的模型,并允许函数调用发生

总之,函数提供了一个直接的框架,使应用程序开发人员能够对数据流和系统执行进行细粒度控制,同时有效地利用 Agent/模型进行关键的输入生成。开发人员可以选择性地决定是否通过返回外部数据让 Agent “保持在循环中”,或者根据特定的应用程序架构要求省略它。

数据存储 (Data Stores)

想象一个语言模型就像一个藏有其训练数据的庞大图书馆。但与不断购入新书的图书馆不同,这个图书馆保持静态,只拥有最初训练时获得的知识。这带来了一个挑战,因为现实世界的知识在不断发展。数据存储通过提供对更动态、最新信息的访问来解决这个限制,并确保模型的响应保持基于事实和相关性。

考虑一个常见的场景:开发人员可能需要向模型提供少量额外数据,也许是以电子表格或 PDF 的形式。

数据存储允许开发人员以其原始格式向 Agent 提供额外数据,无需进行耗时的数据转换、模型重新训练或微调。数据存储将传入的文档转换为一组向量数据库嵌入(vector database embeddings),Agent可以使用这些嵌入来提取所需信息,以补充其下一步行动或对用户的响应。

实现与应用

在生成式 AI Agent 的背景下,数据存储通常实现为开发人员希望 Agent 在运行时能够访问的向量数据库(vector database)。虽然我们不会在这里深入探讨向量数据库,但关键点是要理解它们以向量嵌入的形式存储数据,这是一种所提供数据的高维向量或数学表示。近年 来,语言模型使用数据存储最普遍的例子之一是检索增强生成
(Retrieval Augmented Generation, RAG) 的实现。

基于 RAG 的应用程序旨在通过让模型访问各种格式的数据来扩展模型的知识广度和深度,使其超越基础训练数据。如:

  • 网站内容
  • 结构化数据,格式如 PDF、Word 文档、CSV、电子表格等。
  • 非结构化数据,格式如 HTML、PDF、TXT 等。

每个用户请求和 Agent 响应循环的底层过程通常建模如图 13 所示。

  1. 用户查询被发送到一个嵌入模型以生成查询的嵌入。
  2. 然后使用匹配算法(如 SCANN)将查询嵌入与向量数据库的内容进行匹配。
  3. 匹配的内容以文本格式从向量数据库中检索出来,并发送回 Agent。
  4. Agent 接收用户查询和检索到的内容,然后制定响应或行动。
  5. 最终响应被发送给用户。

[流程图]

最终结果是一个应用程序,它允许 Agent 通过向量搜索将用户的查询匹配到已知的数据存储,检索原始内容,并将其提供给编排层和模型进行进一步处理。下一步行动可能是向用户提供最终答案,或者执行额外的向量搜索以进一步细化结果。

一个实现了 RAG 并结合 ReAct 推理/规划的 Agent 的示例交互可以在图 14 中看到。

总结一下,扩展 (Extensions)、函数 (Functions) 和数据存储 (Data Stores) 构成了 Agent 在运行时可用的几种不同工具类型。每种都有其自身的用途,可以由 Agent 开发人员酌情决定一起使用或独立使用。

结语

在技术狂飙的时代,我们需要保持清醒的头脑,以数据驱动的方式去思考和决策。《AI 商业进化论》为我们提供了一个宝贵的视角,让我们能够更好地理解 AI 技术的发展趋势,提升自己的数据 + AI 素养。

为了帮助大家更好地理解和应用书中的内容,数治网院 iDigi 特推出《数据 + AI 素养双效提升》体系课程:《利用 AI 优化业务流程综合指南》、《AI 工具职场应用与效能提升指南》、《职场 AI 进化:从工具人到 AI 指挥官》等,深入解读《AI 商业进化论》的核心思想,结合 AI 技术的应用趋势、数据驱动的决策方法、全场景的实现路径以及职场 AI 进化的策略等。

  • 通过学习《利用 AI 优化业务流程综合指南》这门课程,你将系统掌握 AI 在业务流程中的应用,全面了解 AI 如何优化每个环节,解决实际业务痛点,推动智能化转型。
  • 《AI 工具职场应用与效能提升指南》聚焦 AI 工具在企业中的全场景深度应用,从运营管理到人力资源,你将全面了解 AI 工具如何提升企业效能,推动企业从经验向数据驱动的决策模式转变。
  • 而《职场 AI 进化:从工具人到 AI 指挥官》这门课程,以数据思维与 AI 素养为核心,培养人机协作时代的 AI 指挥官能力。通过多维度教学组合,从方法到实践全面掌握AI驱动业务增长的关键路径。

升级你的职业“防护盾”,扫码申请素养测评,即可15分钟AI适配搭建微学习、微专业,开启“一人一表”“一人一课”。即日起只需¥199开卡体验单课时即赠《AI 商业进化论》一本,激活完成自主学习、预约导师开讲、Q小治答疑、实操练习、分享心得等任务,参与评选“学习显眼包”赢数治Pro学习卡、盲盒!


来源:《智能体(Agents)》,谷歌,作者:Julia Wiesinger, Patrick Marlow 和 Vladimir Vuskovic,AI 翻译:魔云兽。图片:Growtika,Unsplash

发条评论

你的电邮不会被公开。有*标记为必填。