谷歌Agent白皮书中文译文

518 阅读35分钟

本文翻译自2024年Google团队发布的Agents白皮书,作者为Julia Wiesinger、Patrick Marlow和Vladimir Vuskovic。翻译过程借助了智能Agent应用完成,译文中难免存在错误或因内容更新而过时的情况,若有疑问,建议查阅Agents白皮书原文。如需转载,请务必注明出处。

近期,DeepSeek备受瞩目,其推理成本极低,为Agent的广泛普及奠定了极为坚实的技术基础,提供了强有力的支持。Agent时代已然来临,今年的主要发展方向是将其与现有应用深度融合,从而进一步提升生产效率。

全文感受:本文只是提供了一些基本概念介绍,与OpenAI的文档介绍相比还是有所不足,建议结合OpenAI文档langchain从零编写Agent应用,或者使用coze平台或者天翼云智能体应用平台构建Agent。

1. 引言

人类在处理复杂的模式识别任务方面非常出色。然而,他们在得出结论之前,常常依赖工具 —— 比如书籍、谷歌搜索或计算器 —— 来补充他们的先验知识。就像人类一样,生成式人工智能模型可以被训练使用工具来获取实时信息或建议现实世界的行动。例如,一个模型可以利用数据库检索工具来获取特定信息,如客户的购买历史,从而生成量身定制的购物推荐。或者,根据用户的查询,一个模型可以进行各种 API 调用,代表用户向同事发送电子邮件回复或完成金融交易。要做到这一点,模型不仅必须能够使用一组外部工具,还需要有以自我导向的方式规划和执行任何任务的能力。这种推理、逻辑以及对外部信息的获取的结合 —— 它们都与生成式人工智能模型相连接 —— 引出了 “Agent” 的概念,或者说是一个超越了生成式人工智能模型独立能力的程序。本白皮书将更详细地探讨所有这些及相关方面。

2. 什么是agent?

在其最基本的形式中,生成式人工智能Agent可以被定义为一种应用程序,它试图通过观察世界并利用其可用的工具对其采取行动来实现一个目标。Agent是自主的,可以独立于人类干预而行动,特别是在被赋予它们要实现的适当目标或目的时。Agent在实现目标的方法上也可以是主动的。即使在没有来自人类的明确指令集的情况下,Agent也可以推理出下一步应该做什么来实现其最终目标。虽然人工智能中Agent的概念相当普遍和强大,但本白皮书重点关注在发布时生成式人工智能模型能够构建的特定类型的Agent。

为了理解Agent的内部工作原理,首先介绍驱动Agent行为、行动和决策的基本组件。这些组件的组合可以被描述为一种认知架构,通过这些组件的混合和匹配可以实现许多这样的架构。聚焦于核心功能,Agent的认知架构中有三个基本组件,如图 1 所示。

图1:Agent的基本架构与组成部分

2.1 模型

在Agent的范畴内,模型指的是将被用作Agent流程的集中决策者的语言模型(LLM)。Agent所使用的模型可以是一个或多个任何规模(小 / 大)的能够遵循基于指令的推理和逻辑框架(如 ReAct、思维链或思维树)的 LLM。模型可以是通用的、多模态的,也可以根据您特定的Agent架构的需求进行微调。为了获得最佳的生产结果,您应该利用最适合您所需的最终应用的模型,理想情况下,该模型是在与您计划在认知架构中使用的工具相关的数据特征上进行训练的。需要注意的是,模型通常不是在Agent的特定配置设置(即工具选择、编排 / 推理设置)下进行训练的。然而,可以通过向模型提供展示Agent能力的示例,包括Agent在各种情境中使用特定工具或推理步骤的实例,来进一步为Agent的任务优化模型。

2.2 工具

基础模型尽管在文本和图像生成方面令人印象深刻,但仍然受到无法与外部世界交互的限制。工具弥补了这一差距,使Agent能够与外部数据和服务进行交互,同时解锁了比基础模型本身更广泛的行动范围。工具可以有多种形式,复杂程度也各不相同,但通常与常见的网络 API 方法(如 GET、POST、PATCH 和 DELETE)一致。例如,一个工具可以在数据库中更新客户信息,或者获取天气数据以影响Agent向用户提供的旅行推荐。有了工具,Agent可以访问和处理现实世界的信息。这使它们能够支持更专业的系统,如检索增强生成(RAG),这大大扩展了Agent的能力,超出了基础模型自身所能实现的范围。我们将在下面更详细地讨论工具,但最重要的是要理解,工具弥合了Agent的内部能力与外部世界之间的差距,开启了更广泛的可能性。

2.3 编排层

编排层描述了一个循环过程,该过程控制着Agent如何接收信息、进行一些内部推理,并利用该推理来决定其下一个行动或决策。一般来说,这个循环将持续进行,直到Agent达到其目标或一个停止点。编排层的复杂性可能会因Agent及其执行的任务而有很大差异。有些循环可能是带有决策规则的简单计算,而其他循环可能包含链式逻辑、涉及额外的机器学习算法或实施其他概率推理技术。我们将在认知架构部分更多地讨论Agent编排层的详细实现。

2.4 Agents vs. models

为了更清楚地理解 Agent 和模型之间的区别,二者对比的表格,

模型Agent
知识局限于其训练数据中可用的内容。知识通过工具与外部系统的连接得以扩展(RAG,联网搜索等)。
基于用户查询进行单次推理/预测。除非为该模型明确实现,否则不存在会话历史记录或连续上下文的管理(即聊天记录)。管理会话历史记录(即聊天记录),以便基于用户查询和在编排层做出的决策进行多轮推理/预测。在此情境下,“一轮”被定义为交互系统与智能体之间的一次交互(即1个传入事件/查询和1个智能体响应)。
没有原生工具实现。工具在智能体架构中进行原生实现。
未实现原生逻辑层。用户可以将提示表述为简单问题,或者使用推理框架(思维链(CoT)、反应式行动(ReAct)等)来形成复杂提示,以指导模型进行预测。采用思维链(CoT)、反应式行动(ReAct)等推理框架或像LangChain这样的其他预构建智能体框架的原生认知架构。

2.5 认知架构:Agent如何操作的?

想象一下一位厨师在繁忙的厨房里。他们的目标是为餐厅的顾客制作美味的菜肴,这涉及到一些规划、执行和调整的循环。

  • 收集信息,比如顾客的订单以及食品储藏室和冰箱里有哪些食材。

  • 根据刚刚收集到的信息进行一些内部推理,思考可以制作哪些菜肴和风味特色。

  • 采取行动来制作菜肴:切蔬菜、混合香料、煎肉。

在这个过程的每个阶段,厨师根据需要进行调整,随着食材的消耗或收到顾客的反馈来完善他们的计划,并利用之前的一系列结果来确定下一个行动计划。这种信息摄入、规划、执行和调整的循环描述了厨师为实现目标所采用的独特认知架构。

就像厨师一样,Agent可以通过反复处理信息、做出明智的决策,并根据之前的输出改进下一步行动来使用认知架构来实现其最终目标。Agent认知架构的核心是编排层,负责维护记忆、状态、推理和规划。它利用迅速发展的提示工程领域和相关框架来指导推理和规划,使Agent能够更有效地与环境互动并完成任务。语言模型的提示工程框架和任务规划领域的研究正在迅速发展,产生了各种有前途的方法。虽然这不是一个详尽的列表,但以下是在本出版物发布时可用的一些最流行的框架和推理技术:

  • ReAct,一种提示工程框架,为语言模型提供了针对用户查询进行推理和采取行动的思维过程策略,无论是否有上下文示例。ReAct 提示已被证明优于多个最先进的基线,并提高了大语言模型的人类互操作性和可信度。
  • 思维链(CoT),一种提示工程框架,通过中间步骤实现推理能力。CoT 有各种子技术,包括自我一致性、主动提示和多模态 CoT 等,每种技术根据具体应用都有其优缺点。
  • 思维树(ToT),一种提示工程框架,非常适合探索或战略前瞻任务。它对思维链提示进行了概括,并允许模型探索各种思维链,这些思维链可作为语言模型解决一般问题的中间步骤。

Agent可以利用上述推理技术中的一种,或者许多其他技术,为给定的用户请求选择下一个最佳行动。例如,假设一个Agent被编程使用 ReAct 框架为用户查询选择正确的行动和工具。事件的顺序可能是这样的:

  1. 用户向Agent发送查询

  2. Agent开始 ReAct 序列

  3. Agent向模型提供提示,要求它生成下一个 ReAct 步骤之一及其相应的输出:

    a. 问题:来自用户查询的输入问题,随提示提供

    b. 思考:模型关于下一步应该做什么的想法

    c. 行动:模型关于下一步采取什么行动的决定

  •      这是可以进行工具选择的地方
         例如,行动可以是 [Flights, Search, Code, None]之一,其中前 3 个代表模型可以选择的已知工具,最后一个代表“不选择工具” 
    

    d. 行动输入:模型关于向工具(如果有)提供什么输入的决定

    e. 观察:行动/行动输入序列的结果

  •      这种思考/行动/行动输入/观察可能根据需要重复 N 次
    

    f. 最终答案:模型提供给原始用户查询的最终答案

  1. ReAct 循环结束,并向用户提供最终答案

图2:在编排层中使用ReAct 推理的Agent示例

如图2所示,模型、工具和Agent配置共同协作,根据用户的原始查询为用户提供有根据、简洁的回复。虽然模型本可以根据其先验知识猜测答案(产生幻觉),但它却使用了一个工具(Flights)来搜索实时的外部信息。这些额外的信息被提供给模型,使其能够根据真实的事实数据做出更明智的决策,并将这些信息总结反馈给用户。

总之,Agent响应的质量可以直接与模型对这些各种任务进行推理和行动的能力相关联,包括选择正确工具的能力,以及工具的定义完善程度。就像一位厨师用新鲜的食材精心制作菜肴并关注顾客的反馈一样,Agent依靠合理的推理和可靠的信息来提供最佳结果。在下一节中,我们将深入探讨Agent与新数据连接的各种方式。

3. Tools:通向外部世界的钥匙

虽然语言模型在处理信息方面表现出色,但它们缺乏直接感知和影响现实世界的能力。这限制了它们在需要与外部系统或数据交互的情况下的实用性。这意味着,从某种意义上说,语言模型的好坏仅取决于它从训练数据中学到的东西。但无论我们向模型输入多少数据,它们仍然缺乏与外部世界交互的基本能力。那么,我们如何使我们的模型能够与外部系统进行实时、上下文感知的交互呢?函数、扩展、数据存储和插件都是为模型提供这种关键能力的方式。

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

在本出版物发布之时,谷歌模型能够与之交互的主要工具类型有三种:Extensions(扩展), Functions(函数),和Data Stores(数据存储)。通过为Agent配备工具,它们显示出了巨大的潜力,使它们不仅能够理解世界,还能够对其采取行动,为无数新的应用和可能性打开了大门。

3.1 扩展(Extensions)

理解扩展的最简单方式是将它们视为以标准化方式弥合 API 和Agent之间的差距,使Agent能够无缝地执行 API,无论其底层实现如何。假设您构建了一个旨在帮助用户预订航班的Agent。您知道您想使用谷歌航班 API 来检索航班信息,但您不确定如何让您的Agent向此 API 端点发出调用。

图 3. Agent如何与外部 API 交互?

一种方法可能是实现自定义代码,该代码将接收传入的用户查询,解析查询以获取相关信息,然后进行 API 调用。例如,在航班预订用例中,用户可能会说 “我想预订从奥斯汀到苏黎世的航班”。在这种情况下,我们的自定义代码解决方案需要在尝试进行 API 调用之前,从用户查询中提取 “奥斯汀” 和 “苏黎世” 作为相关实体。但是,如果用户说 “我想预订去苏黎世的航班” 但从未提供出发城市会怎样?没有所需的数据,API 调用将会失败,并且需要实现更多的代码来处理像这样的边缘和极端情况。这种方法不可扩展,并且在任何超出已实现的自定义代码的场景中都很容易出错。

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

  1. 使用示例教导Agent如何使用 API 端点。

  2. 教导Agent成功调用 API 端点所需的参数或参数值。

图 4. 扩展将Agent连接到外部 API

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

图 5. Agent、扩展和 API 之间的一对多关系

可以这样想,就像软件开发人员在为用户解决问题时决定使用哪个 API 端点一样。如果用户想要预订航班,开发人员可能会使用谷歌航班 API。如果用户想知道离他们所在位置最近的咖啡店在哪里,开发人员可能会使用谷歌地图 API。同样,Agent/模型栈使用一组已知的扩展来决定哪一个最适合用户的查询。如果您想看到扩展的实际应用,可以在 Gemini 应用程序中通过前往设置>扩展,然后启用任何您想要测试的扩展来尝试。例如,您可以启用谷歌航班扩展,然后问 Gemini“给我显示下周五从奥斯汀到苏黎世的航班”。

3.1.1 Extension使用示例

为了简化扩展的使用,谷歌提供了一些开箱即用的扩展,可以快速导入到您的项目中,并只需最少的配置即可使用。例如,代码解释器扩展(如代码片段 1 所示)允许您根据自然语言描述生成并运行 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']})

# 上述代码片段将生成以下代码。
```
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):
        """
        反转二叉树。
        参数:
        root: 二叉树的根节点。
        返回:
        反转后的二叉树的根节点。
        """

        if not root:
            return None

        # 递归地交换左右子节点
        root.left, root.right = \
            invert_binary_tree(root.right), invert_binary_tree(root.left)

        return root

# 示例用法:
# 构建一个示例二叉树
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)

# 反转二叉树
inverted_root = invert_binary_tree(root)
```

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

3.2 函数(function)

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

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

  1. 模型输出一个函数及其参数,但不进行实时的 API 调用。

  2. 函数在客户端执行,而扩展在Agent端执行。

再次使用我们的谷歌航班示例,函数的一个简单设置可能如图 7 所示。

图 7. 函数如何与外部 API 交互?

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

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

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

虽然如图 8 所示,这两种方法在内部架构上的差异很细微,但对外部基础设施的额外控制和解耦依赖使得函数调用成为开发人员一个有吸引力的选择。 图 8. Agent中扩展调用和函数调用对比

3.2.1 使用场景

模型可用于调用函数,以便为最终用户处理复杂的客户端执行流程,在这种情况下,Agent开发人员可能不希望语言模型管理 API 执行(如扩展的情况)。让我们考虑以下示例,其中一个Agent被训练为旅行顾问,与想要预订度假旅行的用户进行交互。目标是让Agent生成一个城市列表,我们可以在我们的中间件应用程序中使用该列表为用户的旅行计划下载图像、数据等。用户可能会说这样的话:

我想和我的家人一起去滑雪旅行,但我不知道去哪里。

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

  • 美国科罗拉多州的克雷斯特德比特

  • 加拿大不列颠哥伦比亚省的惠斯勒

  • 瑞士的采尔马特

当然,以下是您可以考虑的适合家庭滑雪旅行的城市列表:

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

# 片段5
function_call {
  "name": "display_cities",
  "args": {
    "cities": ["Crested Butte", "Whistler", "Zermatt"],
    "preferences": "skiing"
  }
}

此 JSON 有效负载由模型生成,然后发送到我们的客户端服务器,以进行我们想要对其进行的任何操作。在这个特定的案例中,我们将调用谷歌地点 API,获取模型提供的城市并查找图片,然后将其作为格式化的丰富内容提供回我们的用户。请考虑图 9 中的这个序列图,它逐步详细地展示了上述交互。

图 9. 展示函数调用生命周期的序列图

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

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

关于函数,有一件关键的事情要记住,它们旨在为开发人员提供不仅对 API 调用的执行,而且对整个应用程序中的整个数据流程的更多控制。在图 9 的示例中,开发人员选择不将 API 信息返回给Agent,因为它与Agent未来可能采取的行动无关。然而,根据应用程序的架构,将外部 API 调用数据返回给Agent以影响未来的推理、逻辑和行动选择可能是有意义的。最终,由应用程序开发人员来选择什么对特定的应用程序是正确的。

3.2.2 函数使用示例

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

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

# 代码片段 6. 用于显示城市列表的函数的示例 Python 方法。 
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

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

# 片段 7
from vertexai.generative_models import GenerativeModel, Tool, FunctionDeclaration

# 定义 Gemini 模型实例
model = GenerativeModel("gemini-1.5-flash-001")

# 将 display_cities 函数转换为 FunctionDeclaration 对象
display_cities_function = FunctionDeclaration.from_func(display_cities)

# 创建工具对象,将 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}")

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

4. 数据存储(data stores)

想象一下语言模型就像一个巨大的图书馆,里面存放着它的训练数据。但与不断获取新书的图书馆不同,这个模型是静态的,只拥有最初训练时的知识。这就带来了一个挑战,因为现实世界的知识在不断演变。数据存储通过提供对更动态和最新信息的访问来解决这一限制,并确保模型的响应仍然基于事实和相关性。

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

图 10. Agent如何与结构化和非结构化数据交互?

数据存储允许开发人员以原始格式向Agent提供额外的数据,

省去了耗时的数据转换、模型重新训练或微调的需要。数据存储将来文文档转换为一组向量数据库嵌入,Agent可以使用这些嵌入来提取补充其下一个动作或对用户响应所需的信息。

图 11. 数据存储将Agent连接到各种类型的新实时数据源。

4.1 实现与应用

在生成式人工智能Agent的背景下,数据存储通常被实现为一个向量数据库,开发人员希望Agent在运行时能够访问。虽然我们在这里不会深入介绍向量数据库,但需要理解的关键点是,它们以向量嵌入的形式存储数据,这是所提供数据的一种高维向量或数学表示形式。近来语言模型使用数据存储最丰富的例子之一是基于检索增强生成(RAG)的应用程序的实现。这些应用程序试图通过让模型访问各种格式的数据,如:

  • 网站内容

  •   诸如 PDF、Word 文档、CSV、电子表格等格式的结构化数据

  •   诸如 HTML、PDF、TXT 等格式的非结构化数据

来扩展模型知识的广度和深度,超越基础训练数据。

图 12. Agent与数据存储之间的一对多关系

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

  1. 用户查询被发送到嵌入模型以生成查询的嵌入

  2. 然后使用像 SCaNN 这样的匹配算法将查询嵌入与向量数据库的内容进行匹配

  3. 从向量数据库以文本格式检索匹配的内容并发送回Agent

  4. Agent接收用户查询和检索到的内容,然后制定响应或动作

  5. 最终响应发送给用户

图 13. 基于 RAG 的应用程序中用户请求和Agent响应的生命周期

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

在图 14 中可以看到与实现带有 ReAct 推理 / 规划的 RAG 的Agent的示例交互。

图 14. 带有 ReAct 推理/规划的基于 RAG 的示例应用程序

5. 回顾

总之,扩展、函数和数据存储构成了几种不同的工具类型,可供Agent在运行时使用。每种工具都有其自身的用途,Agent开发人员可以自行决定将它们一起使用或单独使用。

扩展函数调用数据存储
执行Agent端执行客户端执行Agent端执行
用例- 开发者希望控制Agent与 API 端点的交互
- 当利用原生内置扩展(如 Vertex Search、代码解释器等)时很有用
- 多跳规划和 API 调用(即下一个Agent操作取决于前一个操作 / API 调用的输出)
- 安全或身份验证限制阻止Agent直接调用 API
- 时间限制或操作顺序限制,使Agent无法实时进行 API 调用(例如批量操作、人工介入审核等)
- 未向互联网公开或谷歌系统无法访问的 API
- 开发者希望使用以下任何数据类型实现检索增强生成(RAG):
- 来自索引域和 URL 的网站内容
- 诸如 PDF、Word 文档、CSV、电子表格等格式的结构化数据
- 关系型 / 非关系型数据库
- 诸如 HTML、PDF、TXT 等格式的非结构化数据

6. 通过有针对性的学习提升模型性能

有效使用模型的一个关键方面是它们在生成输出时选择正确工具的能力,尤其是在生产中大规模使用工具时。虽然一般训练有助于模型发展这种技能,但现实世界的场景往往需要训练数据之外的知识。可以把这想象成基本烹饪技能和精通特定菜系之间的区别。两者都需要基础烹饪知识,但后者需要有针对性的学习才能获得更细微的结果。

为了帮助模型获取这种特定类型的知识,存在几种方法:

  • 上下文学习:这种方法在推理时为通用模型提供提示、工具和少量示例,使其能够“即时”学习如何以及何时将这些工具用于特定任务。ReAct 框架是自然语言中这种方法的一个例子。

  • 基于检索的上下文学习:这种技术通过从外部存储器中检索最相关的信息、工具和相关示例,动态填充模型提示。这方面的一个例子是 Vertex AI 扩展中的“示例存储”或前面提到的数据存储 RAG 架构。

  • 基于微调的学习:这种方法涉及在推理之前使用大量特定示例的数据集训练模型。这有助于模型在收到任何用户查询之前理解何时以及如何应用某些工具。

为了对每种有针对性的学习方法提供更多见解,让我们再次回顾我们的烹饪类比。

  • 想象一位厨师从顾客那里收到了一份特定的食谱(Prompt)、一些关键食材(Tools)和一些示例菜肴(少量示例)。基于这些有限的信息和厨师对烹饪的一般知识,他们需要“即时”弄清楚如何准备与食谱和顾客偏好最接近的菜肴。这就是上下文学习。

  • 现在想象我们的厨师在一个厨房中,有一个储备充足的食品储藏室(data stores),里面装满了各种食材和食谱(示例和工具)。厨师现在能够从食品储藏室动态选择食材和食谱,并更好地与顾客的食谱和偏好保持一致。这使厨师能够利用现有知识和新知识创作出更有见地和精致的菜肴。这就是基于检索的上下文学习。

  • 最后,想象一下我们把厨师送回学校去学习一种新的菜系或一组菜系(在大量特定示例的数据集上进行预训练)。这使厨师能够以更深入的理解来处理未来未曾见过的顾客食谱。如果我们希望厨师在特定菜系(知识领域)上表现出色,这种方法是完美的。这就是基于微调的学习。

这些方法中的每一种在速度、成本和延迟方面都有独特的优点和缺点。然而,通过在Agent框架中结合这些技术,我们可以利用各种优势并最小化它们的劣势,从而实现更强大和适应性更强的解决方案。

7. 使用 LangChain 快速启动Agent

为了提供一个Agent实际运行的真实可执行示例,我们将使用 LangChain 和 LangGraph 库构建一个快速原型。这些流行的开源库允许用户通过“链接”一系列逻辑、推理和工具调用的序列来构建客户Agent,以回答用户的查询。我们将使用我们的 gemini-1.5-flash-001 模型和一些简单的工具来回答用户的多阶段查询,如代码片段 8 所示。

我们使用的工具是 SerpAPI(用于谷歌搜索)和谷歌地点 API。在执行代码片段 8 中的程序后,您可以在代码片段 9 中看到示例输出。

# 片段 8
import os
from langgraph.prebuilt import create_react_agent
from langchain_core.tools import tool
from langchain_community.utilities import SerpAPIWrapper
from langchain_community.tools import GooglePlacesTool
from langchain_google_genai import ChatVertexAI

# 设置环境变量,这里需要替换为你自己的真实 API 密钥
os.environ["SERPAPI_API_KEY"] = "XXXXX"
os.environ["GPLACES_API_KEY"] = "XXXXX"


# 定义搜索工具函数,使用 SerpAPI 进行谷歌搜索
@tool
def search(query: str):
    """Use the SerpAPI to run a Google Search."""
    search = SerpAPIWrapper()
    return search.run(query)


# 定义地点查询工具函数,使用 Google Places API 进行地点查询
@tool
def places(query: str):
    """Use the Google Places API to run a Google Places Query."""
    places = GooglePlacesTool()
    return places.run(query)


# 初始化 ChatVertexAI 模型,指定使用 gemini-1.5-flash-001
model = ChatVertexAI(model="gemini-1.5-flash-001")

# 创建工具列表,包含搜索和地点查询工具
tools = [search, places]

# 定义用户查询,注意这里修正了字符串换行问题
query = "Who did the Texas Longhorns play in football last week? What is the address of the other team's stadium?"

# 创建基于 ReACT 框架的Agent
agent = create_react_agent(model, tools)

# 准备输入数据,以键值对形式包含用户消息
input = {"messages": [("human", query)]}

# 以流的方式获取Agent的响应并进行处理
for s in agent.stream(input, stream_mode="values"):
    message = s["messages"][-1]
    if isinstance(message, tuple):
        print(message)
    else:
        message.pretty_print()
# 片段 9,片段 8 的输出
=============================== Human Message ================================
Who did the Texas Longhorns play in football last week? What is the address
of the other team's stadium?

================================= Ai Message =================================
Tool Calls: search
Args:
  query: Texas Longhorns football schedule

================================ Tool Message ================================
Name: search
{...Results: "NCAA Division I Football, Georgia, Date..."}

================================= Ai Message =================================
The Texas Longhorns played the Georgia Bulldogs last week.
Tool Calls: places
Args:
  query: Georgia Bulldogs stadium

================================ Tool Message ================================
Name: places
{...Sanford Stadium Address: 100 Sanford...}

================================= Ai Message =================================
The address of the Georgia Bulldogs stadium is 100 Sanford Dr, Athens, GA 30602, USA.

虽然这是一个相当简单的Agent示例,但它展示了模型、编排和工具的基础组件共同工作以实现特定目标。在最后一节中,我们将探讨这些组件如何在像 Vertex AI Agent和生成式剧本这样的谷歌规模托管产品中协同工作。

8. 使用 Vertex AI Agent的生产应用

虽然本白皮书探讨了Agent的核心组件,但构建生产级应用需要将它们与其他工具(如用户界面、评估框架和持续改进机制)集成。谷歌的 Vertex AI 平台通过提供一个涵盖了前面提到的所有基本元素的完全托管环境简化了这一过程。使用自然语言界面,开发人员可以快速定义其Agent的关键元素 - 目标、任务指令、工具、用于任务委托的子Agent和示例 - 轻松构建所需的系统行为。此外,该平台带有一组开发工具,允许进行测试、评估、测量Agent性能、调试和提高开发的Agent的整体质量。这使开发人员能够专注于构建和优化他们的Agent,而基础设施、部署和维护的复杂性由平台本身管理。

在图 15 中,我们提供了一个在 Vertex AI 平台上使用各种功能(如 Vertex Agent构建器、Vertex 扩展、Vertex 函数调用和 Vertex 示例存储等)构建的Agent的示例架构。该架构包括生产就绪应用所需的许多不同组件。

图 15. 在 Vertex AI 平台上构建的端到端Agent架构示例

9. 总结

在本白皮书中,我们讨论了生成式人工智能Agent的基础构建模块、它们的组成以及以认知架构的形式实现它们的有效方法。本白皮书的一些关键要点包括:

  1. Agent通过利用工具访问实时信息、建议现实世界的行动以及自主规划和执行复杂任务来扩展语言模型的能力。Agent可以利用一个或多个语言模型来决定何时以及如何在状态之间转换,并使用外部工具完成模型自身难以或无法完成的任意数量的复杂任务。

  2. Agent操作的核心是编排层,这是一种构建推理、规划、决策并指导其行动的认知架构。各种推理技术,如 ReAct、思维链和思维树,为编排层提供了一个框架,用于接收信息、进行内部推理并生成明智的决策或响应。

  3. 工具,如扩展、函数和数据存储,是Agent通向外部世界的关键,允许它们与外部系统交互并访问超出其训练数据的知识。扩展在Agent和外部 API 之间提供了桥梁,实现了 API 调用的执行和实时信息的检索。函数通过分工为开发人员提供了更细致的控制,允许Agent生成可以在客户端执行的函数参数。数据存储为Agent提供对结构化或非结构化数据的访问,实现数据驱动的应用。

Agent的未来有着令人兴奋的进步,我们才刚刚开始触及可能的表面。随着工具变得更加复杂和推理能力的增强,Agent将有能力解决日益复杂的问题。此外,“Agent链”的战略方法将继续获得发展动力。通过组合专门的Agent - 每个Agent在特定领域或任务中表现出色 - 我们可以创建一种“Agent专家的混合”方法,能够在各个行业和问题领域提供卓越的结果。

重要的是要记住,构建复杂的Agent架构需要迭代的方法。实验和改进是为特定业务案例和组织需求找到解决方案的关键。由于支撑其架构的基础模型的生成性质,没有两个Agent是完全相同的。然而,通过利用这些基础组件的优势,我们可以创建有影响力的应用程序,扩展语言模型的能力并推动现实世界的价值。

10. 引用

  1. Shafran, I., Cao, Y. et al., 2022, 'ReAct: Synergizing Reasoning and Acting in Language Models'. Available at:

arxiv.org/abs/2210.03…

  1. Wei, J., Wang, X. et al., 2023, 'Chain-of-Thought Prompting Elicits Reasoning in Large Language Models'.

Available at: arxiv.org/pdf/2201.11….

  1. Wang, X. et al., 2022, 'Self-Consistency Improves Chain of Thought Reasoning in Language Models'.

Available at: arxiv.org/abs/2203.11….

  1. Diao, S. et al., 2023, 'Active Prompting with Chain-of-Thought for Large Language Models'. Available at:

arxiv.org/pdf/2302.12….

  1. Zhang, H. et al., 2023, 'Multimodal Chain-of-Thought Reasoning in Language Models'. Available at:

arxiv.org/abs/2302.00….

  1. Yao, S. et al., 2023, 'Tree of Thoughts: Deliberate Problem Solving with Large Language Models'. Available at:

arxiv.org/abs/2305.10….

  1. Long, X., 2023, 'Large Language Model Guided Tree-of-Thought'. Available at:

arxiv.org/abs/2305.08….

  1. Google. 'Google Gemini Application'. Available at: gemini.google.com.

  2. Swagger. 'OpenAPI Specification'. Available at: swagger.io/specificati….

  1. Xie, M., 2022, 'How does in-context learning work? A framework for understanding the differences from

traditional supervised learning'. Available at: ai.stanford.edu/blog/unders….

  1. Google Research. 'ScaNN (Scalable Nearest Neighbors)'. Available at:

github.com/google-rese….

  1. LangChain. 'LangChain'. Available at: python.langchain.com/v0.2/docs/i….