Google发布AI智能体白皮书
这份 Google 白皮书探讨了生成式AI智能体的概念、架构和应用。它阐述了智能体如何通过整合语言模型、工具(扩展、函数、数据存储)和协调层来实现目标,并解释了各种推理框架(如ReAct、Chain-of-Thought、Tree-of-Thoughts)的作用。白皮书还介绍了增强模型性能的定向学习方法,以及LangChain和Vertex AI等平台如何辅助代理的构建和部署,最终目的是构建能够自主执行复杂任务的AI智能体。
智能体
作者: Julia Wiesinger, Patrick Marlow 及 Vladimir Vuskovic
2024年9月
目录
简介 什么是智能体。 模型 工具 协调层 智能体与模型的比较 认知架构:智能体的运行机制 工具:我们连接外部世界的桥梁 实现与应用 使用案例 函数示例代码 示例扩展 扩展 函数 数据存储 工具总结 通过目标学习提升模型性能 使用 LangChain 快速上手智能体 借助 Vertex AI 智能体实现生产应用 总结 参考文献
这种推理、逻辑能力及对外部信息的访问相结合,并与生成式AI模型的能力相辅相成,引出了“智能体”这一概念
简介
人类擅长处理复杂的模式识别任务,但通常需要依赖工具(如书籍、谷歌搜索或计算器)来补充已有的知识,以最终得出结论。同样,生成式AI模型可以通过训练使用工具来获取实时信息或建议现实世界中的操作。例如,一个模型可以利用数据库检索工具访问特定信息(如客户的购买历史),从而生成个性化的购物推荐。再如,根据用户的指令,一个模型可通过调用API完成多项任务,例如发送电子邮件回复给同事或代表用户执行金融交易。
为实现这些功能,模型不仅需要具备访问外部工具的能力,还需拥有自主规划与执行任务的能力。这种推理、逻辑能力与对外部信息的获取相结合,并结合生成式AI模型的能力,引出了智能体的概念——一种超越生成式AI模型独立能力的程序。本白皮书将深入探讨这些问题及其延伸领域,以期为相关研究提供更全面的视角。
“智能体”是什么?
从最基本的形式来看,生成式人工智能 (GenAI) 智能体可被定义为一种通过观察世界并使用其可用工具采取行动以实现目标的应用程序。智能体具备自主性,能够在被赋予明确的目标或任务时独立于人类干预采取行动。智能体在实现目标的过程中还可表现出主动性。即便在缺乏明确的人类指令集时,智能体也能够推理出应采取的下一步行动以实现最终目标。尽管在人工智能 (AI) 领域中,智能体的概念广泛且强大,但本白皮书主要聚焦于当前生成式人工智能模型所能构建的特定类型的智能体。
为了深入了解智能体的内部运作机制,我们首先介绍驱动智能体行为、行动以及决策过程的核心组件。这些组件的组合可以描述为一种认知架构,通过对这些组件的灵活组合与匹配,可以建立多种类型的认知架构。从核心功能的角度来看,智能体的认知架构由三个基本组成部分构成,如图 1 所示。
图 1. 通用智能体架构与其组成部分
模型
在智能体的上下文中,模型指的是作为智能体流程核心决策者的语言模型 (LM)。智能体使用的模型可以是一个或多个任意规模(如小型或大型)的语言模型,这些模型能够遵循基于指令的推理与逻辑框架,例如 ReAct 方法、Chain-of-Thought 技术或 Tree-of-Thoughts 框架。模型可以是通用型、多模态,也可以根据特定智能体架构的需求进行微调。为达最优实践效果,应选择最适合目标应用的模型,并且理想情况下,该模型已针对与认知架构中计划使用工具相关的数据特性进行训练。需要指出的是,模型通常不会根据智能体的特定配置与参数设置(例如工具选择、编排或推理设置)进行直接训练。不过,可以通过提供展示智能体能力的示例对模型进行进一步优化,这些示例包括例如智能体在不同上下文中使用特定工具或完成推理步骤的实际操作场景,从而提升模型对智能体任务的适应性。
工具简介
尽管基础模型在生成文本和图像方面表现卓越,但其仍然受限于无法与外部世界进行交互的能力不足。工具弥补了这一差距,使智能体能够与外部数据和服务进行交互,同时使其能够执行超出基础模型自身能力范围的更多任务。工具可以以多种形式存在,复杂程度各不相同,但通常与常见的 Web API 方法(例如 GET、POST、PATCH 和 DELETE)相一致。例如,某个工具可以用于更新数据库中的客户信息,或者获取天气数据,从而影响智能体为用户提供的旅行建议。借助工具,智能体可以获取并处理现实世界中的信息。这使其能够支持一些更加专业化的系统,例如检索增强生成(RAG),显著扩展了智能体超越基础模型在独立运作情况下的能力。我们将在下文中更详细地讨论工具,但最重要的是要理解,工具弥补了智能体内部能力与外部世界之间的差距,拓展了更加广泛的可能性。
编排层 (orchestration layer)
编排层描述了一个循环过程,用于控制智能体如何获取信息、执行内部推理,并根据推理的结果指导其下一步行动或决策。通常,这一循环将不断重复,直到智能体达成目标或到达某个停止点。编排层的复杂性可能因智能体及其所执行的任务不同而呈现出显著差异。一些循环可能是基于决策规则的简单计算,而另一些则可能包含链式逻辑、涉及补充性的机器学习算法,或使用其他概率推理技术实施推断。我们将在认知架构部分进一步详细探讨智能体编排层的具体实现方式。
智能体与模型的对比
为了更清晰地理解智能体与模型之间的区别,请参考以下对比表:
模型 | 智能体 |
---|---|
认知架构:智能体的运行机制
想象一位在繁忙厨房中的厨师。他的目标是为餐厅顾客制作美味的菜肴,这需要经历计划、执行和调整的循环。
他们收集信息,例如顾客的点餐需求,并检查储藏室和冰箱中的食材种类。 他们基于刚刚收集的信息进行一定程度的内部推理,以确定可制作的菜肴及其风味特征。 他们采取行动制作菜肴,包括切割蔬菜、调配香料以及煎制肉类。
在每个阶段,厨师根据需要进行调整,在食材逐渐耗尽或收到客户反馈后对其计划进行优化,并通过利用之前的结果来制定下一步的行动计划。这一信息获取、规划、执行和调整的循环,描述了厨师为了实现目标所采用的一种独特的认知架构。
智能体就像厨师一样,能够通过使用认知架构,迭代处理信息、制定明智决策,并基于先前的输出优化后续行动,从而实现其最终目标。智能体认知架构的核心是编排层,它主要负责管理记忆、状态、推理和规划功能。该层借助快速发展的提示工程领域及其相关框架,指导推理与规划,从而使智能体能够更高效地与环境交互并完成任务。
关于提示工程框架和语言模型任务规划的研究正在迅速推进,提出了多种具有前景的方法。截至本出版物发布时,以下列出了一些最受欢迎的框架和推理技术(尽管该列表并不全面):
ReAct 是一种提示工程框架,为语言模型提供了一种思维过程策略,使其能够在有或无上下文示例的情况下,对用户查询进行推理并采取相应行动。ReAct 提示已被证明优于多个 SOTA(当前最先进)基准,同时提升了大型语言模型(LLM)的互操作性和可信性。
思维链 Chain-of-Thought (CoT) 是一种提示优化框架,通过借助中间步骤实现推理能力。CoT 包括多种子技术,例如自一致性(self-consistency)、主动提示(active-prompt)以及多模态 CoT(multimodal CoT)。这些子技术根据具体的应用场景,表现出各自的优点和局限性。
思维树(Tree-of-thoughts, ToT),一种特别适用于探索性或战略前瞻任务的提示工程框架。它扩展并泛化了链式思维(Chain-of-thought, CoT)提示方法,使模型能够探索多种思维链,这些思维链充当了基于语言模型进行通用问题解决的中间步骤。
智能体可以利用上述推理技术之一,或其他许多技术,为给定的用户请求选择最佳的下一步行动。例如,考虑一个被编程使用 ReAct(Reasoning + Acting)框架的智能体,它通过选择正确的行动和工具来处理用户查询。事件的顺序可能如下:
用户将查询发送给智能体 智能体开始 ReAct 推理序列 智能体向模型提供一个提示,要求其生成下一个 ReAct 步骤及其对应的输出:
a. 问题 Question:用户查询中的输入问题,与提示一起提供
b. 思考 Thought:模型对于下一步该做什么的思考
c. 行动 Action:模型决定下一步采取的行动
1. 此处可能需要选择工具
2. 例如,一个行动可以是 [Flights, Search, Code, None] 中的一个,其中前三者代表模型可以选择的已知工具,最后一个代表“不选择工具”
d. 行动输入 Action input:模型决定提供给工具的输入(如果有的话)
e. 观察 Observation:行动/行动输入序列的结果
1. 这一“思考/行动/行动输入/观察”过程可以根据实际需要重复 次,直至满足生成最终答案的条件
f. 最终答案 Final Answer:模型向原始用户查询提供的最终答案ReAct 循环结束,并向用户提供最终答案
图 2. 在协调层中使用 ReAct 推理的示例智能体
从图 2 可以看出,模型、工具与智能体的配置密切协作,旨在基于用户的原始查询生成一个有事实依据且简明的响应。尽管模型可能根据其先前的知识生成一个推测答案(即幻觉式回答),它选择了使用工具(Flights)来获取实时外部信息。这一附加信息被提供给模型,使其能够基于真实的事实数据做出更明智的决策,并将这些信息总结反馈给用户。
总之,智能体的响应质量可以直接与模型针对各项任务进行推理和行动的能力相关,包括选择正确工具的能力,以及工具定义的准确性。就像一位厨师用新鲜的食材精心制作菜肴并倾听客户反馈一样,智能体依赖于严谨的推理和可靠的信息来提供最佳结果。下一部分中,我们将探讨智能体如何与新数据建立联系的多种方式。
工具:我们通往外界的钥匙
尽管语言模型擅长处理信息,但它们缺乏直接感知和影响外部环境的能力。这限制了它们在需要与外部系统或数据交互时的应用价值。这意味着,语言模型的能力在某种程度上仅限于其从训练数据中学到的知识。即使为模型提供更多数据,它们仍然缺乏与外界进行实时、情境感知交互的核心能力。那么,我们如何赋予模型与外部系统进行实时、情境感知交互的能力呢?函数、扩展、数据存储和插件模块是赋予模型这种关键能力的重要途径。
虽然它们有许多名称,但工具是连接我们基础模型与外部世界的重要纽带。这种与外部系统和数据的链接,使自主式人工智能系统能够执行更为多样化的任务,并以更高的准确性和可靠性达成任务目标。例如,工具可以支持自主式人工智能系统调整智能家居参数、更新日程表、从数据库提取用户信息,或依据具体指令发送电子邮件。
截至本出版物发布之日,Google 模型当前能够交互的三种主要工具类型为扩展工具 (Extensions)、功能工具 (Functions)、以及数据存储工具 (Data Stores)。通过为智能体配备这些工具,不仅为其理解世界解锁了巨大潜力,还使其具备执行相应行为的能力,从而为实现众多新的应用场景和可能性铺平了道路。
扩展
理解扩展可以通过将其视为在 API 和智能体之间充当标准化桥梁来简化描述,使智能体能够无缝调用 API,而不受其底层实现方式的限制。假设您构建了一个以帮助用户预订航班为目标的智能体。您知道需要使用 Google Flights API 来获取航班信息,但尚未确定如何让智能体调用该 API 的接口端点。
图 3. 智能体(Agent)如何与外部 API 进行交互?
一种方法是通过实现自定义代码来处理传入的用户查询,解析查询中的相关信息,并完成 API 调用。例如,在航班预订的应用场景中,用户可能会说,“我想预订从 Austin(奥斯汀)飞往 Zurich(苏黎世)的航班。”此时,自定义代码需要从用户查询中提取“Austin”和“Zurich”这两个相关实体,以尝试调用 API。但是,如果用户说“我想预订飞往 Zurich 的航班”,却未提供出发城市,该如何处理?在没有所需数据的情况下,API 调用将失败,并且需要编写额外代码以应对此类边缘或极端情况。这种方法并不具备可扩展性,一旦出现超出已编写自定义代码范围的情况,可能导致系统失效。
一种更具韧性的方式是使用扩展。扩展通过以下方式填补智能体与 API 之间的功能差距:
使用示例教授智能体如何调用 API 端点。 通过教学使智能体理解成功调用 API 端点所需的参数及其具体值。
图 4. 扩展将智能体连接至外部 API
扩展可以独立于智能体开发,但应作为智能体配置中的一部分进行提供。智能体在运行时依据模型和示例来判定哪些扩展(如果存在)适合解决用户的查询。这突显了扩展的一个关键优势,即其内置示例类型,从而使智能体能够动态选择最适合当前任务的扩展。
图 5. 智能体、扩展与 API 之间的一对多关系
这可以被类比为软件开发人员在为用户解决问题时选择使用哪些 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 = """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'])
# The above snippet will generate the following code.
Generated Code:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
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.
"""
ifnot root:
returnNone
# 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. Code Interpreter 扩展可以生成并运行 Python 代码
综上所述,扩展(Extensions)为智能体提供了多种感知、交互并影响外部世界的途径。这些扩展的选择和调用由示例(Examples)引导,而这些示例均作为扩展配置的一部分定义。
函数
在软件工程领域中,函数被定义为可以独立完成特定任务的代码模块,并且能够根据需要重复使用。当软件开发人员编写程序时,他们通常会创建许多函数来完成各种任务。他们还会定义相应的逻辑,以确定何时调用 function_a 或 function_b,并规定相应的输入和预期输出。
在智能体的领域中,智能体函数的工作方式非常相似,但我们可以用模型来代替软件开发人员。模型可以基于一组已知函数,并根据功能规范确定何时使用每个函数以及所需的参数。智能体函数与扩展在以下几个方面存在差异,具体包括:
模型生成一个函数及其参数,但不会实际调用实时的 API。
函数在 客户端 执行,而扩展则在 智能体端 执行。
再次以 Google Flights 为例,函数的基本设置如图 7 所示。
图 7. 函数如何与外部 API 交互?
需要注意的是,这里的主要区别是,无论是函数(Function)还是智能体(Agent),都不会直接与 Google Flights API 交互。那么 API 调用实际上是如何实现的呢?
对于函数而言,调用实际 API 端点的逻辑与执行被转移至客户端应用程序,而不由智能体负责,如下图 8 和图 9 所示。这种方式使开发者能够更细粒度地控制应用程序中数据流的流程。开发者选择使用函数而非扩展的原因有很多,常见的使用场景包括:
API 调用需要在应用程序堆栈的其他层级完成,而不是在智能体架构的直接流程中(例如,中间件系统、前端框架等)。
安全性或身份验证的限制可能导致智能体无法直接调用 API(例如,API 未通过互联网暴露,或智能体基础设施无法访问)。
时间或操作顺序的限制可能阻碍智能体实时进行 API 调用(例如,批处理操作、人为干预审查等)。
API 的响应结果可能需要额外的数据转换逻辑,而这些转换智能体无法完成。例如,某些 API 端点可能无法提供限制返回结果数量的过滤机制。在客户端使用函数,能够为开发者提供更多机会执行数据转换。
开发者希望无需部署额外的 API 端点基础设施即可迭代智能体开发(即,Function Calling 可以用作 API 的“模拟调用”)。
如图 8 所示,两种方法在内部架构上的差异虽然仅为细微调整,但 Function Calling 提供了更高的控制权,并弱化了与外部基础设施的耦合关系,因此对开发者而言是一个值得考虑的选项。
图 8. 为扩展功能与函数调用划分客户端与智能体端的控制权
应用场景
通过函数调用,模型能够处理复杂的客户端执行流程,为终端用户提供支持。在这种情况下,智能体开发者可能更倾向于由其他机制而非语言模型(如 GPT 等)来直接管理 API 的执行(如在扩展功能的应用中)。以下示例展示了一个被训练为旅游顾问的智能体,在与希望预订度假旅行的用户进行交互时的工作示例。目标是让智能体生成一份城市列表,我们可以在中间件应用中使用这些城市名称来为用户的旅行规划下载图片、数据等。用户可能会说:
“我想和家人一起去滑雪旅行,但我不知道该去哪里。”
通常情况下,如果直接向模型提供提示,输出可能如此:
以下是适合家庭滑雪旅行的一些推荐城市:
克雷斯特德比尤特(Crested Butte),科罗拉多,美国 惠斯勒(Whistler),不列颠哥伦比亚,加拿大 策马特(Zermatt),瑞士
虽然以上输出包含了我们所需的数据(城市名称),但其格式不够理想,难以便于解析。通过函数调用,我们可以教会模型以更结构化的格式(例如 JSON)输出,这种格式更适合其他系统进行解析。对于用户相同的输入提示,通过函数调用的示例 JSON 输出可能类似于代码片段 5 中的内容。
function_call {
name: "display_cities"
args: {
"cities": ["Crested Butte", "Whistler", "Zermatt"],
"preferences": "skiing"
}
}
代码片段 5. 用于显示城市列表及用户偏好的函数调用负载示例
此 JSON 负载由模型生成,然后发送到客户端服务器以执行所需任务。在此特定情况下,我们将调用 Google Places API,基于模型提供的城市信息检索相关图片,并以格式化的富内容形式返回给用户。图 9 中的序列图详细展示了上述交互过程的每一步。
图 9. 显示函数调用生命周期的序列图
图 9 中的示例结果是利用模型“补全必要信息”,为 Client 端 UI 提供调用 Google Places API 所需的参数。Client 端 UI 根据模型返回的函数所提供的参数来管理实际的 API 调用。这仅为函数调用的一个使用案例,但还有许多其他场景值得探讨,例如:
您希望语言模型为代码推荐适用的函数,但又不希望在代码中包含认证信息。由于函数调用并不实际运行函数,因此无需在代码中包含与函数信息相关的认证信息。
您正在运行可能需要数秒甚至更长时间的异步操作。在这些场景中,使用函数调用非常适合,因为它能够很好地支持异步操作。
您希望在与生成函数调用及其参数值的系统不同的设备上执行该函数。
关于函数需要记住的一个关键点是,函数旨在为开发者提供对 API 调用的执行过程以及整个应用程序数据流更大的掌控力。在图 9 中的示例中,开发者决定不将 API 信息返回给智能体,因为这些信息对智能体未来可能采取的行动并无直接相关性。然而,根据应用程序的架构,将外部 API 调用数据返回给智能体可能更为合理,以影响其未来的推理、逻辑和行动选择。最终,应用程序开发者需根据具体应用程序场景选择最优方案。
函数示例代码
接下来,我们将从滑雪度假场景出发,通过完整地构建各组件,使其与我们的 gemini-1.5-flash-001 模型协同工作。
首先,我们将定义一个名为 display_cities
的简单 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
代码片段 6:用于显示城市名称列表的 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. 构建一个 Tool,通过用户查询发送至模型并允许函数调用执行
总之,函数提供了一个简洁明了的框架,使应用程序开发者能够对数据流和系统运行进行精细控制,同时充分利用模型和智能体以生成关键输入。开发者可以根据特定的应用架构需求,选择是否使智能体“参与环路”以处理外部数据,或者在需要时忽略其参与。
数据存储
可以假设大规模语言模型是一个承载其训练数据的庞大图书馆。然而,与不断扩充新书籍的图书馆不同,这个图书馆是静态的,仅保留其初始训练时的知识。这带来了一个挑战,因为现实世界的知识体系在持续演进。数据存储旨在解决这一局限,通过提供更加动态及最新的信息,确保模型的回答具备事实性与相关性。
考虑一个常见的场景,开发者可能需向模型提供少量额外数据,例如电子表格或 PDF 文件。
图 10. Agent 如何与结构化和非结构化数据交互?
Data Store 允许开发者以原始格式向 Agent 提供额外的数据,从而无需耗时的数据转换、模型再训练或微调。Data Store 将传入文档转换为一组向量数据库的嵌入表示,Agent 可利用这些嵌入提取所需信息,从而辅助其下一步操作或对用户问题的响应。
图 11. 数据存储库将智能体连接到各种新类型实时数据源。
实现与应用
在生成式人工智能 (GenAI) 智能体的应用环境中,数据存储库通常以向量数据库的形式实现,开发者希望智能体在运行时能够访问该数据库。虽然我们在这里不会深入探讨向量数据库,但需要理解的关键在于,它以向量嵌入的形式存储数据,这是一种用于表示数据的高维向量或数学表现形式。
近年来,数据存储库与语言模型结合使用的一个最广泛的例子是基于检索增强生成 (RAG, Retrieval Augmented Generation) 的应用。这些应用通过让模型访问以各种格式存在的数据,从而扩展模型在基础训练数据范围外的知识广度与深度,例如:
网站内容 结构化数据,例如 PDF、Word 文档、CSV 文件、电子表格等 非结构化数据格式,例如 HTML、PDF、TXT 等文件格式
图 12. 智能体与数据存储之间的一对多关系,可以表示支持多种类型的已预索引数据
每个用户请求与智能体响应循环的基本处理流程通常建模为经典的如图 13 所示。
将用户查询发送至嵌入模型,以生成与该查询相关的嵌入向量。 随后利用例如 SCaNN 等匹配算法,将查询嵌入向量与向量数据库中的内容进行匹配。 将匹配到的内容以文本格式从向量数据库中提取,并返回至智能体。 智能体接收用户查询和检索到的内容,然后生成响应或执行操作。 将最终响应发送至用户。
图 13. 基于 RAG 的应用系统中用户请求与智能体响应的处理流程
最终结果是一个应用系统,该智能体能够通过向量搜索将用户查询与已知的数据存储匹配,检索原始内容,并将其交由编排层和模型以进行后续处理。后续步骤可能包括向用户提供最终答案,或进行额外的向量搜索以进一步提升结果质量。
一个实现基于 ReAct 推理与规划的 RAG 智能体的交互示例可以在图 14 中看到。
图 14. 基于 RAG 的应用示例:结合 ReAct 推理与规划
工具回顾
总之,扩展、函数和数据存储构成了智能体在运行时可用的几类工具。各有用途,可供智能体开发者根据需要选择组合使用或单独使用。
执行 | 智能体端执行 | 客户端端执行 | 智能体端执行 |
用例 |
通过有针对性的学习提升模型性能
有效使用模型的一个关键方面在于模型在生成输出时选择合适工具的能力,特别是在大规模生产中使用工具时。尽管通用训练能帮助模型发展这一技能,但在实际场景中,往往需要超越训练数据的知识。这可以比作基本烹饪技巧与掌握特定菜系的区别。两者都需要基础烹饪知识,但后者需要有针对性的学习,以实现更细致入微的结果。
为了帮助模型获取此类特定知识,可采用多种方法:
基于上下文的学习(In-context learning):该方法在推理阶段为通用模型提供一个提示、相关工具以及少量示例,使其能够即时学习如何以及何时使用这些工具来完成特定任务。该方法在自然语言处理中的一项应用实例是 ReAct 框架。
基于检索的上下文学习方法:该方法通过从外部存储中检索最相关的信息、工具及相关示例,动态更新模型提示内容。例如,可见于 Vertex AI 扩展中的“示例存储”,或先前提到的基于 RAG 架构的数据存储库。
基于微调的学习:这种方法是在推理之前,使用包含更多特定示例的数据集来训练模型。这能够帮助模型在用户提出任何查询之前,明确何时以及如何使用某些工具。
为了进一步阐释每种目标学习方法,我们可以通过回顾烹饪类比来进一步说明。
想象一位厨师收到了一份特定的菜谱(提示)、一些关键食材(相关工具)以及一些示例菜品(少样本例子)来自顾客。根据这些有限的信息和厨师对烹饪的一般知识,他们需要临场准备一道最符合菜谱和顾客喜好的菜品。这便是上下文学习(_in-context learning_)的一个典型例子。
现在,让我们想象一下我们的厨师在一个存储丰富的储藏室(外部数据存储)的厨房中,这里储备了各种食材和菜谱(示例和工具)。厨师现在能够灵活选择储藏室中的食材和菜谱,并且可以更好地满足顾客的配方需求和个人喜好。以此,厨师可以同时利用已有知识和新获取的知识,制作出基于更丰富信息的精致菜肴。这就是基于检索的情境学习。
最后,假设我们让这位厨师重新回到学校,学习一种新料理或一系列料理(在更大的特定示例数据集上接受预训练)。这使得厨师能够以更深刻的理解,应对未来从未见过的顾客菜谱。如果我们希望厨师在特定料理(知识领域)中表现卓越,这种方法是非常适合的。这正是微调学习。
上述每种方法在速度、成本和延迟方面各有其独特的优缺点。然而,通过将这些技术整合于智能体框架中,我们可以发挥各自优势,尽可能弥补其不足,从而实现更为强大和灵活的解决方案。
基于 LangChain 的智能体快速入门
为了提供一个在实际场景中可执行的智能体示例,我们将使用 LangChain 和 LangGraph 库构建一个简易原型。这些广受欢迎的开源库允许用户通过将逻辑、推理和工具调用链接起来,创建用于回答用户查询的定制智能体。我们将结合使用 gemini-1.5-flash-001
模型和一些简单的工具,来解答用户提出的多步骤查询,如代码片段 8 中所示。
我们使用的工具是 SerpAPI(用于 Google 搜索)和 Google 地点 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 地点 API 执行查询。"""
places = GooglePlacesTool()
return places.run(query)
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?"
agent = create_react_agent(model, tools)
input = {"messages": [("human", query)]}
for s in agent.stream(input, stream_mode="values"):
message = s["messages"][-1]
if isinstance(message, tuple):
print(message)
else:
message.pretty_print()
片段 8. 基于 LangChain 和 LangGraph 的工具支持示例智能体
=============================== 人类消息 ================================
Who did the Texas Longhorns play in football last week? What is the address
of the other team's stadium?
================================= AI 消息 =================================
工具调用:search
参数:
query: Texas Longhorns football schedule
================================ 工具消息 ================================
名称:search
{...结果:"NCAA Division I Football, Georgia, Date..."}
================================= AI 消息 =================================
上周,Texas Longhorns 对阵 Georgia Bulldogs。
工具调用记录:places
查询参数:Georgia Bulldogs 体育馆
================================ 工具消息 ================================
名称:places
{...Sanford 体育馆地址:100 Sanford...}
================================= AI 消息 ================================
Georgia Bulldogs 体育馆(Sanford Stadium)的具体地址为 100 Sanford Dr,Athens,GA 30602,USA。
代码片段 9:关于代码片段 8 的程序输出
虽然这是一个较为简单的自主式人工智能示例,但它展示了模型、任务编排和工具的基础组成部分如何共同协作实现特定目标。在最后一部分中,我们将探讨这些组件如何在 Google 规模的托管产品中结合,例如 Vertex AI 自主式人工智能智能体和生成式剧本。
使用 Vertex AI 智能体进行生产级应用
尽管本白皮书探讨了智能体的核心组件,但生产级应用的构建还需结合用户界面、评估框架及持续改进机制等额外工具。Google 的 Vertex AI 平台通过提供一个完全托管的环境,涵盖了前文提到的所有基础元素,从而简化了这一流程。通过 _自然语言界面_,开发者能够迅速定义智能体的关键要素,如目标、任务指令、工具、任务委派的子智能体以及示例,从而便捷地实现预期的系统行为。此外,该平台还提供了一套开发工具,可用于测试、评估、性能测量、调试以及优化智能体的整体质量。这使开发者能够专注于智能体的构建与优化,而基础设施、部署及维护的复杂性则由平台管理。
在图 15 中,本文展示了一种智能体的示例架构,该架构基于 Vertex AI 平台构建,采用了多种功能,涵盖 Vertex Agent Builder、Vertex Extensions、Vertex Function Calling 和 Vertex Example Store,仅举几例。该架构包含众多生产环境准备的应用所必需的不同组件。
图 15. 基于 Vertex AI 平台构建的样例端到端智能体体系结构
您可以在我们的官方文档中试用此预构建智能体体系结构的样例。
总结
在这份白皮书中,我们讨论了生成式人工智能 (GenAI) 智能体的基础构建模块、其组成方式,以及如何以认知体系结构的形式有效实现这些智能体。本白皮书的若干关键结论包括:
智能体通过使用工具访问实时信息、提供现实世界中的决策建议,并自主规划和执行复杂任务,从而扩展了语言模型的功能。
智能体能够借助一个或多个语言模型,自动决策何时及如何在不同状态间切换,并调用外部工具完成那些单靠语言模型难以或无法实现的复杂任务。
智能体运作的核心是调度层,它是一种认知架构,用于结构化推理、规划与决策,并指导其具体行动。各种推理技术,例如 ReAct、链式思维(Chain-of-Thought)和树状思维(Tree-of-Thoughts),为调度层提供了一个框架,使其能够接收外部信息,进行内部推理过程,并生成有依据的决策或响应。
工具(如扩展模块、函数模块和数据存储库)是智能体接入外部世界的重要手段,使它们能够与外部系统交互并访问超出其训练数据范围的知识。扩展模块为智能体与外部 API 架起桥梁,使其可以执行 API 调用并获取实时信息。函数模块通过职责分离为开发者提供了更精细的控制,允许智能体生成可在客户端执行的参数。数据存储库为智能体提供了访问结构化或非结构化数据的能力,从而实现对数据驱动型应用的支持。
智能体的未来充满了振奋人心的进展,而我们才刚刚开始探索其中的可能性。随着工具日益复杂化和推理能力不断增强,智能体将更加胜任解决日益复杂问题的任务。此外,“智能体联动式策略”将进一步发展。
结合专用智能体——每个智能体均在特定领域或任务中展现卓越表现——我们可以创建一种“智能体专家混合”(以下简称“混合方法”)的方法,以提供卓越成果,适用于各个行业和问题领域。
需要注意的是,构建复杂的智能体架构需要一种迭代方法。实验和优化是探索解决方案、满足特定业务场景和组织需求的关键步骤。由于生成式基础模型的特性所致,每个智能体的构造方式各不相同。然而,通过整合每个基础模块的优势,我们可以开发出具有深远影响的应用程序,进一步扩展与应用语言模型的能力边界,并有效推动现实世界中的价值创造。
参考文献
Shafran, I., Cao, Y. 等人,2022,"ReAct: 在语言模型中协同推理与行动"。参见: https://arxiv.org/abs/2210.03629。 Wei, J., Wang, X. 等人,2023,"链式思维提示促进大型语言模型中的推理能力"。参见: https://arxiv.org/pdf/2201.11903.pdf。 Wang, X. 等人,2022,"自一致性改进了语言模型中的链式思维推理"。参见: https://arxiv.org/abs/2203.11171。 Diao, S. 等人,2023,"基于链式思维的大型语言模型的主动提示"。参见: https://arxiv.org/pdf/2302.12246.pdf。 Zhang, H. 等人,2023,"多模态链式思维推理在语言模型中的应用"。参见: https://arxiv.org/abs/2302.00923。 Yao, S. 等人,2023,"思维树:利用大型语言模型进行深思熟虑的解决问题"。参见: https://arxiv.org/abs/2305.10601。 Long, X., 2023,"大型语言模型引导的思维树"。参见: https://arxiv.org/abs/2305.08291。 Google,"Google Gemini 应用程序"。参见: http://gemini.google.com。 Swagger,"OpenAPI Specification"。参见: https://swagger.io/specification/。 Xie, M., 2022,"上下文学习如何运作?理解其与传统监督学习差异的框架"。参见: https://ai.stanford.edu/blog/understanding-incontext/。 Google Research,"ScaNN(可扩展最近邻算法)"。参见: https://github.com/google-research/google-research/tree/master/scann。 LangChain,"LangChain"。参见: https://python.langchain.com/v0.2/docs/introduction/。
请先 登录后发表评论 ~