AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


Google AI Agents White Paper 中文翻译版
发布日期:2025-01-17 08:00:54 浏览次数: 1583 来源:开源阅读社

《Google AI Agents白皮书》重点总结了生成式AI代理(Agents)的核心概念、构建方法及其实际应用价值。白皮书指出,生成式AI代理是一种能够利用工具访问实时信息、执行现实世界任务,并自主规划和执行复杂任务的应用程序。它超越了传统生成式模型的局限,通过认知架构(包括模型、工具和编排层)实现智能决策。


书中详细介绍了代理的三大核心组件:模型作为决策中心,负责推理和逻辑处理;工具如扩展(Extensions)、函数(Functions)和数据存储(Data Stores),使代理能与外部系统交互,获取动态信息;编排层则管理代理的信息处理、推理和决策过程,确保代理按目标行动。亮点在于,白皮书提出了多种工具类型和认知架构,如ReAct、Chain-of-Thought等,帮助开发者构建高效、自主的代理。同时,强调了通过针对性学习(如上下文学习、检索式上下文学习和微调学习)提升模型性能的重要性。


实际应用方面,书中通过具体案例展示了代理在旅行规划、代码生成等领域的潜力,并介绍了如何使用LangChain等开源库快速构建代理原型。最后,探讨了Google Vertex AI平台如何简化代理的生产级应用,提供全面管理环境和开发工具。

目录

  • 引言
  • 什么是代理?
  •     2.1. 模型
  •     2.2. 工具
    •     2.3. 编排层
    •     2.4. 代理与模型的区别
    •     2.5. 认知架构:代理如何运作
  • 工具:我们通往外界的钥匙
  •     3.1. 扩展
  •     3.2. 示例扩展
  • 函数
  •     4.1.  用例
  •     4.2. 函数示例代码
  • 数据存储
  •     5.1. 实现与应用
  • 通过针对性学习提升模型性能
  • 使用LangChain快速启动代理
  • 使用Vertex AI代理进行生产应用
  • 总结

引言

人类在处理复杂模式识别任务方面表现出色。然而,在得出结论之前,他们常常依赖于工具——如书籍、谷歌搜索或计算器——来补充他们的先验知识。与人类类似,生成式AI模型也可以被训练成使用工具来访问实时信息或提出现实世界中的行动。例如,一个模型可以利用数据库检索工具来访问特定信息,如客户的购买历史,从而生成个性化的购物建议。或者,基于用户的查询,一个模型可以做出各种API调用,向同事发送电子邮件回复或代表您完成金融交易。为此,模型不仅需要访问一组外部工具,还需要具备以自我指导的方式规划和执行任何任务的能力。这种将推理、逻辑和访问外部信息与生成式AI模型相结合的概念,就引出了代理的概念,即一个程序,它超越了生成式AI模型独立运行的能力。本白皮书将更详细地探讨所有这些方面及相关内容。

什么是Agent?

从最基本的形式来看,一个生成式AI代理可以定义为一个应用程序,它通过观察世界并使用其可用的工具对其采取行动来尝试实现目标。代理是自主的,可以在没有人为干预的情况下独立行动,尤其是当它们被赋予明确的目标或需要实现的目的时。代理也可以采取积极主动的方式来实现其目标。即使在没有人类明确指令集的情况下,代理也可以推理出接下来应该做什么以实现其最终目标。尽管AI中代理的概念相当通用且强大,但本白皮书专注于发布时生成式AI模型能够构建的特定类型的代理。

为了理解代理的内部工作原理,让我们首先介绍驱动代理行为、行动和决策制定的基础组件。这些组件的组合可以描述为一个认知架构,并且可以通过这些组件的混合和匹配来实现多种这样的架构。专注于核心功能,代理的认知架构中有三个基本组件,如图1所示。

Figure 1. General agent architecture and components

模型

在代理的范围内,模型指的是将用作代理过程中央决策者的语言模型(LM)。代理使用的模型可以是一个或多个任何大小(小/大)的语言模型,它们能够遵循基于指令的推理和逻辑框架,如ReAct、Chain-of-Thought或Tree-of-Thoughts。模型可以是通用的、多模态的或根据特定代理架构的需求进行微调的。为了获得最佳的生产结果,您应该利用一个最适合您期望的最终应用程序的模型,并且理想情况下,该模型已经在与您计划在认知架构中使用的工具相关的数据签名上进行了训练。重要的是要注意,模型通常不是用代理的特定配置设置(即工具选择、编排/推理设置)进行训练的。然而,通过向模型提供展示代理能力的示例(包括代理在各种上下文中使用特定工具或推理步骤的实例),可以进一步细化模型以完成代理的任务。

工具

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

编排层

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

Agents VS. Models

为了更清楚地理解代理和模型之间的区别,请考虑以下图表:


Model
Agent
知识范围
仅限于其训练数据中的知识
通过工具与外部系统连接来扩展知识
推理/预测
基于用户查询的单一推理/预测。
除非为模型明确实现,否则没有会话历史或连续上下文的管理(例如聊天历史)。
管理会话历史(例如聊天历史)以允许基于用户查询和在编排层中做出的决策进行多轮推理/预测。
在此上下文中,“轮”被定义为交互系统和代理之间的一次交互(例如,1个传入事件/查询和1个代理响应)。
工具实施
没有原生工具实施。
工具在代理架构中原生实现。
逻辑层
没有实现原生逻辑层。用户可以使用简单的问题或使用推理框架(如CoT、ReAct等)形成复杂的提示来指导模型进行预测。
使用诸如CoT、ReAct或其他预构建的代理框架(如LangChain)等推理框架的本机认知架构。

认知架构:代理如何运作

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

  • 他们收集信息,如顾客的订单和冰箱和食品柜中的食材。
  • 他们根据收集到的信息进行一些内部推理,确定可以制作哪些菜肴和风味特征。
  • 他们采取行动制作菜肴:切蔬菜、混合香料、煎肉。

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

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

  • ReAct,一种提示工程框架,为语言模型提供了一种思考过程策略,以便对用户查询进行推理并采取行动,无论是否有上下文示例。ReAct提示已显示出优于几种最先进的基线,并提高了大型语言模型(LLMs)的人类互操作性和可信度。
  • Chain-of-Thought(CoT),一种通过中间步骤启用推理能力的提示工程框架。CoT有多种子技术,包括自洽性、主动提示和多模态CoT,每种技术都有其优缺点,具体取决于特定的应用。
  • Tree-of-Thoughts(ToT),一种提示工程框架,非常适合探索或战略前瞻任务。它概括了链式思维提示,并允许模型探索各种思维链,这些思维链作为语言模型解决一般问题的中间步骤。

代理可以利用上述推理技术中的一种或多种来选择给定用户请求的下一个最佳行动。例如,让我们考虑一个被编程为使用ReAct框架为用户查询选择正确操作和工具的代理。事件的顺序可能如下:

  1. 用户向代理发送查询。
  2. 代理开始ReAct序列。
  3. 代理向模型提供一个提示,要求其生成下一个ReAct步骤及其相应的输出:
     a. 问题:来自用户查询的输入问题,随提示提供。
     b. 思考:模型关于接下来应该做什么的想法。
     c. 行动:模型关于接下来要采取什么行动的决策。
     i. 这就是选择工具的地方。
     ii. 例如,一个行动可能是[Flights, Search, Code, None]中的一个,其中前三个代表模型可以选择的已知工具,最后一个代表“没有工具选择”。
     d. 行动输入:模型关于要向工具提供什么输入(如果有的话)的决策。
     e. 观察:行动/行动输入序列的结果。
     i. 这个思考/行动/行动输入/观察可以根据需要重复N次。
     f. 最终答案:模型向原始用户查询提供的最终答案。
  4. ReAct循环结束,并向用户提供最终答案。

Figure 2. Example agent with ReAct reasoning in the orchestration layer

如图2所示,模型、工具和代理配置共同工作,根据用户的原始查询向用户提供基于事实的简洁响应。虽然模型可以根据其先验知识猜测答案(幻觉),但它反而使用了一个工具(航班)来搜索实时外部信息。这个额外的信息被提供给模型,使其能够根据真实事实数据做出更明智的决策,并将这些信息总结回给用户。
总而言之,代理响应的质量可以直接与模型选择各种任务工具的能力以及工具定义的完善程度相关联。就像厨师用新鲜食材制作菜肴并关注顾客反馈一样,代理依赖健全的推理和可靠的信息来提供最佳结果。在下一节中,我们将深入探讨代理如何与新鲜数据建立联系的各种方式。

工具:我们通往外界的钥匙

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

虽然它们有不同的名称,但工具是创建基础模型与外部世界之间联系的关键。这种与外部系统和数据的联系使我们的代理能够执行更广泛的任务,并以更高的准确性和可靠性完成任务。例如,工具可以使代理调整智能家居设置、更新日历、从数据库中获取用户信息或根据特定指令发送电子邮件。

截至本出版物发布之日,Google模型能够与三种主要工具类型进行交互:扩展、函数和数据存储。通过为代理配备工具,我们解锁了它们不仅能够理解世界,而且能够对其采取行动的巨大潜力,为新的应用和可能性打开了大门。

扩展

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

Figure 3. How do Agents interact with External APIs?

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

一种更具弹性的方法是使用扩展。扩展通过以下方式在代理和API之间建立桥梁:

  1. 使用示例教授代理如何使用API端点。
  2. 教授代理成功调用API端点所需的参数或参数。

Figure 4. Extensions connect Agents to External APIs

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

Figure 5. 1-to-many relationship between Agents, Extensions and APIs

请想象一下,这就像一个软件开发人员在解决用户问题时决定使用哪个API端点。如果用户想预订航班,开发人员可能会使用Google Flights API。如果用户想知道离他们位置最近的咖啡店在哪里,开发人员可能会使用Google Maps API。以同样的方式,代理/模型堆栈使用一组已知的扩展来决定哪个扩展最适合用户的查询。如果您想查看扩展的实际应用,可以在Gemini应用程序的“设置”>“扩展”中启用它们进行测试。例如,您可以启用Google Flights扩展,然后询问Gemini“向我展示从奥斯汀到苏黎世下周起飞的航班。” ## 示例扩展

为了简化扩展的使用,Google提供了一些现成的扩展,这些扩展可以快速导入到您的项目中,并使用最少的配置进行使用。例如,代码解释器扩展(如代码片段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 = """编写一个Python方法,以O(n)时间复杂度反转二叉树。"""

response = extension_code_interpreter.execute(
    operation_id="generate_and_execute",
    operation_params={"query": CODE_QUERY}
)

print("生成的代码:")
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)

Snippet 1. Code Interpreter Extension can generate and run Python code

总而言之,扩展为代理提供了一种以多种方式感知、交互和影响外界的方式。这些扩展的选择和调用由扩展配置中定义的示例指导。

函数(Functions)

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

在代理的世界中,函数的工作方式非常相似,但我们可以将软件开发人员替换为模型。模型可以采取一组已知的函数,并基于其规范决定何时使用每个函数以及该函数需要什么参数。函数与扩展在以下几个方面有所不同:

  1. 模型输出一个函数及其参数,但不进行实时API调用。
  2. 函数在客户端执行,而扩展在代理端执行。

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

Figure 7. How do functions interact with external APIs?

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

使用函数时,调用实际API端点的逻辑和执行从代理转移回客户端应用程序,如图8和图9所示。这为开发人员提供了对数据在应用程序中流动的更细粒度的控制。开发人员选择使用函数而不是扩展有许多原因,但一些常见用例包括:

  • API调用需要在应用程序堆栈的另一层进行,不在代理架构流程的直接范围内(例如,中间件系统、前端框架等)。
  • 安全或身份验证限制阻止代理直接调用API(例如,API未暴露在互联网上,或代理基础设施无法访问)。
  • 时序或操作顺序约束阻止代理实时进行API调用。(即批处理操作、人工审核循环等)。
  • 需要对API响应进行额外的数据转换逻辑,而代理无法执行。例如,考虑一个不提供用于限制返回结果数量的过滤机制的API端点。在客户端使用函数为开发者提供了对这些转换进行额外操作的机会。
  • 开发人员希望在不部署额外基础设施的情况下迭代开发代理(即,函数调用可以充当API的“存根”)。 尽管这两种方法的内部架构差异如图8所示很微妙,但额外的控制和对外部基础设施的解耦依赖使函数调用成为开发人员的理想选择。


    Figure 8. Delineating client vs. agent side control for extensions and function calling

用例

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

用户可能会说:“我想和家人一起去滑雪旅行,但我不知道去哪里。”

在通常情况下,向模型提出的提示的输出可能如下所示:

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

  • 科罗拉多州克雷斯泰德比特
  • 加拿大不列颠哥伦比亚省惠斯勒
  • 瑞士采尔马特”

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

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

Snippet 5. Sample Function Call payload for displaying a list of cities and user preferences

该JSON有效负载由模型生成,然后发送到我们的客户端服务器执行,我们想用它做什么都可以。在本例中,我们将调用谷歌Places API来获取模型提供的城市并查找图像,然后提供格式化后的图像 丰富的内容返回给我们的用户。考虑图9中显示上述内容的序列图一步一步详细的交互。

Figure 9. Sequence diagram showing the lifecycle of a Function Call

图9中示例的结果是,模型被利用来“填补空白”,为客户端UI提供调用Google Places API所需的参数。客户端UI使用模型返回的函数中的参数来管理实际的API调用。这只是函数调用的一个用例,但还有许多其他场景需要考虑,例如:
  • 你希望语言模型建议一个可以在你的代码中使用的函数,但你不希望在代码中包含凭据。由于函数调用不运行函数,因此你不需要在包含函数信息的代码中包含凭据。
  • 你正在运行可能需要几秒钟以上的异步操作。这些场景非常适合函数调用,因为它是一个异步操作。
  • 你希望在不同的设备上运行函数,这些设备与生成函数调用及其参数的系统不同。

关于函数的一个重要点是,它们旨在为开发人员提供对数据流和整个应用程序执行流程的更多细粒度控制,同时有效地利用代理/模型进行关键输入生成。开发人员可以有选择地决定是否让代理“参与循环”,通过返回外部数据,或者基于特定应用程序架构要求省略它。

函数示例代码

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

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

def display_cities(cities: list[str], preferences: Optional[str] = None):
    """根据用户的搜索查询和偏好提供城市列表。
    
    参数:
    preferences (str): 用户的搜索偏好,如滑雪、海滩、餐厅、烧烤等。
    cities (list[str]): 推荐给用户的城市列表。
    
    返回:
    list[str]: 推荐给用户的城市列表。
    """

    return cities

Snippet 6. Sample python method for a function that will display a list of cities.

接下来,我们将实例化我们的模型,构建工具,然后将用户查询和工具传递给模型。执行以下代码将导致输出如代码片段底部所示。
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 = "我想和家人一起去滑雪旅行,但我不知道去哪里。"
res = model.generate_content(message, tools=[tool])

print(f"函数名称: {res.candidates[0].content.parts[0].function_call.name}")
print(f"函数参数: {res.candidates[0].content.parts[0].function_call.args}")

> 函数名称: display_cities
> 函数参数: {'preferences''skiing''cities': ['Aspen''Vail''Park City']}

Snippet 7. Building a Tool, sending to the model with a user query and allowing the function call to take place

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

数据存储(Data Stores)

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

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

Figure 10. How can Agents interact with structured and unstructured data?

数据存储允许开发人员以原始格式向代理提供额外数据,从而消除了耗时的数据转换、模型重新训练或微调的需要。数据存储将传入的文档转换为向量数据库嵌入,代理可以使用这些嵌入来提取所需的信息,以补充其下一个操作或响应用户。

Figure 11. Data Stores connect Agents to new real-time data sources of various types.

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

实现与应用

在生成式AI代理的上下文中,数据存储通常被实现为开发人员希望代理在运行时访问的矢量数据库。虽然我们不会在这里深入介绍矢量数据库,但要理解的关键点是它们以矢量嵌入的形式存储数据,这是一种高维矢量或所提供数据的数学表示。最近将数据存储与语言模型结合使用的最丰富的例子之一是基于检索增强生成(Retrieval Augmented Generation, RAG)的应用程序的实现。这些应用程序寻求扩展广度和通过给模型提供基础训练数据以外的模型知识深度访问各种格式的数据,例如:

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


    Figure 12. 1-to-many relationship between agents and data stores, which can represent various types of pre-indexed data

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

  1. 用户查询被发送到嵌入模型以生成查询的嵌入
  2. 查询嵌入然后使用如SCaNN等匹配算法与向量数据库的内容进行匹配
  3. 从向量数据库中检索匹配的内容,并以文本格式发送回代理
  4. 代理接收用户查询和检索到的内容,然后制定响应或操作
  5. 向用户发送最终响应

Figure 13. The lifecycle of a user request and agent response in a RAG based application

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

与使用ReAct推理/计划实现RAG的代理的示例交互可以如图14所示。 

Figure 14. Sample RAG based application w/ ReAct reasoning/planning

总而言之,扩展、函数和数据存储构成了几种不同的工具类型可供代理在运行时使用。每一个都有自己的目的,它们可以被使用由代理开发商自行决定共同或独立完成。


Extensions
Function Call
Data Stores
执行
方式
Agent端执行
客户端执行
Agent端执行
用例
- 开发人员希望代理控制与API端点的交互
- 在利用本机预构建扩展(即顶点搜索,代码解释器等)时非常有用。
- 多跳规划和API调用(即下一个代理动作取决于前一个动作/ API调用的输出)
- 安全或身份验证限制阻止代理直接调用API
- 阻止代理实时进行API调用的时间约束或操作顺序约束。(即批处理操作、人工循环审核等)
- 没有暴露给internet的API,或者谷歌系统无法访问的API
开发人员希望使用以下任何数据类型实现检索增强生成(RAG):

- 网站内容从预索引域和url
- PDF、Word文档、CSV、电子表格等格式的结构化数据。
- 关系/非关系数据库
HTML、PDF、TXT等格式的非结构化数据。

通过针对性学习提升模型性能

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

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

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

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

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

为了为每种针对性学习方法提供额外见解,让我们回顾一下我们的烹饪类比。

• 想象一位厨师收到了一份特定食谱(提示)、一些关键食材(相关工具)和一些示例菜肴(少量示例)来自一位顾客。基于这有限的信息和厨师对烹饪的一般了解,他们将需要根据食谱和顾客的喜好“即时”想出如何准备菜肴。这是上下文学习。

• 现在,想象我们的厨师在一个装备齐全的厨房里(外部数据存储),里面装满了各种食材和食谱书(示例和工具)。厨师现在能够从储藏室中动态选择食材和食谱书,以更好地符合顾客的食谱和喜好。这允许厨师利用现有和新知识创造出更知情和精致的菜肴。这是基于检索的上下文学习。

• 最后,想象我们送这位厨师回学校学习新的菜系或一系列菜系(在更大数据集上的特定示例上进行预训练)。这允许厨师在未来面对未见过的顾客食谱时拥有更深的理解。如果我们希望厨师在特定菜系(知识领域)中表现出色,这种方法非常有效。这是基于微调的学习。

每种方法都在速度、成本和延迟方面提供独特的优势和劣势。然而,通过在代理框架中结合这些技术,我们可以利用各自的优势并最小化其劣势,从而提供一个更健壮和适应性强的解决方案。

使用LangChain快速启动代理

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

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

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

os.environ["SERPAPI_API_KEY"] = "XXXXX"
os.environ["GPLACES_API_KEY"] = "XXXXX"

@tool
def search(query: str):
    """使用SerpAPI运行Google搜索。"""
    search = SerpAPIWrapper()
return search.run(query)

@tool
def places(query: str):
    """使用Google Places API运行Google地点查询。"""
    places = GooglePlacesTool()
return places.run(query)

model = ChatVertexAI(model="gemini-1.5-flash-001")
tools = [search, places]

query = "德克萨斯长角牛队上周在足球比赛中对阵了哪支球队?对方球队体育场的地址是什么?"
agent = create_react_agent(model, tools)
input = {"messages": [("human", query)]}

for s in agent.stream(input, stream_mode="values"):
    message = s["messages"][-1]
ifisinstance(message, tuple):
print(message)
else:
        message.pretty_print()

Snippet 8. Sample LangChain and LangGraph based agent with tools

============ 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.

Snippet 9. Output from our program in Snippet 8

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

使用Vertex AI代理进行生产应用

虽然本白皮书探讨了代理的核心组件,但构建生产级应用程序需要将它们与附加工具(如用户界面、评估框架和持续改进机制)集成在一起。Google的Vertex AI平台简化了这一过程,提供了一个完全托管的环境,其中包含了前面提到的所有基本元素。使用自然语言接口,开发者可以快速定义代理的关键元素——目标、任务说明、工具、用于任务委派的子代理和示例——以轻松构建所需的系统行为。此外,该平台还提供了一套开发工具,允许进行测试、评估、衡量代理性能、调试和改进开发代理的整体质量。这允许开发者专注于构建和精炼他们的代理,而基础设施、部署和维护的复杂性则由平台本身管理。

在图15中,我们提供了一个在Vertex AI平台上构建的代理的示例架构,该架构使用了各种功能,如Vertex Agent Builder、Vertex Extensions、Vertex Function Calling和Vertex Example Store等。该架构包含了许多生产就绪应用程序所需的各种组件。

Figure 15. Sample end-to-end agent architecture built on Vertex AI platform

您可以从我们的官方文档中尝试这个预构建的代理架构示例。

总结

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

  1. 代理通过利用工具访问实时信息、提出现实世界中的操作以及自主计划和执行复杂任务,从而扩展了语言模型的能力。代理可以利用一个或多个语言模型来决定何时以及如何过渡到不同状态,并使用外部工具完成任何数量的复杂任务,这些任务对于模型自身来说难以或无法单独完成。

  2. 代理操作的核心是编排层,这是一种认知架构,它结构化推理、规划、决策制定并指导其行动。各种推理技术,如ReAct、Chain-of-Thought和Tree-of-Thoughts,为编排层提供了一个框架,以接收信息、执行内部推理并生成知情的决策或响应。

  3. 工具,如扩展、函数和数据存储,是代理与外部世界交互的钥匙,使它们能够与外部系统交互并访问超出其训练数据的知识。扩展在代理和外部API之间提供了一座桥梁,使API调用得以执行并检索实时信息。函数为开发者提供了更细致的控制,通过分工合作,使代理能够生成函数参数,这些参数可以在客户端执行。数据存储为代理提供对结构化或非结构化数据的访问,使数据驱动的应用程序成为可能。

代理的未来充满了令人兴奋的进步,而我们才刚刚触及可能性的表面。随着工具变得更加复杂,推理能力得到增强,代理将被赋予解决日益复杂问题的能力。此外,“代理链接”的战略方法将继续获得动力。通过结合在特定领域或任务中表现出色的专业化代理,我们可以创建一种“代理专家混合”方法,能够在各种行业和问题领域提供卓越的结果。

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


53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询