深度解读《谷歌智能体agent白皮书》
Google发布的《智能体Agent白皮书》深度解读
谷歌在2024年底编写了AI Agent(智能体)白皮书。随后这份白皮书于2025年1月初在twitter上发布,此后一直备受关注。它深入阐述了什么是AI智能体,它与AI模型有何不同,以及如何开始编写自己的agent代码。
本篇文章中,我将对该论文进行完整的翻译,并且结合本人最近两年所做的智能体相关工作,对论文内容进行简明的分析和总结。
英文原版:https://www.kaggle.com/whitepaper-agents
文章目录
1.引言
人类非常擅长处理复杂的模式识别任务。然而,他们经常依赖工具(tool) —— 如书籍、google搜索或计算器 —— 在得出结论之前补充他们的先验知识。
就像人类一样,生成式人工智能模型可以被训练使用工具(tool)来访问实时信息,或者对现实世界的行动计划提出建议。
例如:模型可以利用数据库检索工具访问特定信息,如客户的购买历史,因此它可以生成定制的购物建议。或者,基于用户的查询,模型可以进行各种 API 调用,向同事发送电子邮件回复。或者,代表您完成金融交易。
为此,模型不仅必须能够访问一组外部工具,还需要能够以自我导向的方式计划和执行任何任务。这种推理、逻辑和对外部信息的访问,都与生成式人工智能模型相关联,这些组合形成了Agent的概念。
本白皮书将详细地探讨所有的这些方面和相关内容。
2. 什么是智能体(Agent)?
从最基本的形式来看,生成式AI智能体可以定义为一种应用程序,它试图通过观察世界,并利用其可用的工具,对世界采取行动来实现目标。
智能体是自主的(autonomous),可以在无需人类干预的情况下行动,尤其是在为其设定了应实现的适当目标时。
智能体在实现目标的方式上也可以是主动的。即使在没有人类明确指令集的情况下(指令模糊),智能体也可以推断出接下来应该做什么来实现其最终目标。
虽然人工智能中智能体的概念相当宽泛且强大,但本白皮书聚焦于在发布之时生成式AI模型能够构建的特定类型的智能体。
为了理解智能体的内部运作,我们首先介绍驱动智能体行为、行动和决策的基本组成部分。这些组成部分的组合可以描述为一种认知架构(cognitive architecture),通过这些组成部分的混合和匹配,可以实现许多种这样的架构。
着眼于核心功能,如图1所示,智能体的认知架构中有三个基本组成部分。
2.1 模型(model)
在智能体的范畴内,模型(model)指的是语言模型(LM),它将作为智能体流程的核心决策器。
-
智能体使用的模型可以是一个或多个任意规模(小型/大型)的语言模型,这些模型需能够遵循基于指令的推理和逻辑框架,如ReAct、思维链(Chain-of-Thought)或思想树(Tree-of-Thought)。
-
模型可以是通用的、多模态的,也可以根据特定智能体架构的需求进行微调。
-
为获得最佳的实际应用效果,您应选用最适合预期最终应用的模型,理想情况下,该模型应在与您计划在认知架构中使用的工具相关的数据特征上进行过训练。需要注意的是,模型通常不会使用智能体的特定配置设置(即工具选择、编排/推理设置)进行训练。但是,通过向模型提供展示智能体能力的示例,包括智能体在各种场景中使用特定工具或推理步骤的实例,有可能针对智能体的任务进一步优化模型。
2.2 工具(tools)
基础模型尽管在文本和图像生成方面表现出色,但仍受限于无法与外部世界交互。工具弥补了这一差距,使智能体能够与外部数据和服务进行交互,同时解锁了比基础模型本身更广泛的操作。
工具可以有多种形式,复杂程度也各不相同,但通常情况下,与常用的网络API方法(如GET、POST、PATCH和DELETE)保持一致。例如,一个工具可以在数据库中更新客户信息,或者获取天气数据,以影响智能体向用户提供的旅行建议。
有了工具,智能体就可以访问和处理现实世界的信息。这使它们能够支持更专业的系统,如检索增强生成(RAG),显著扩展了智能体的能力,使其超越基础模型独自所能达到的水平。
我们将在下面更详细地讨论工具,但最重要的是要理解,工具弥合了智能体内部能力与外部世界之间的差距,开启了更广泛的可能性。
2.3 编排层(orchestration layer)
编排层描述了一个循环过程,该过程控制智能体如何接收信息、进行一些内部推理,并利用该推理为其下一个行动或决策提供依据。
-
一般来说,这个循环会持续进行,直到智能体达到其目标或某个停止点。
-
编排层的复杂程度会因智能体及其执行的任务而有很大差异。有些循环可能是带有决策规则的简单计算,而其他循环可能包含链式逻辑、涉及额外的机器学习算法,或采用其他概率推理技术。
我们将在认知架构部分进一步讨论智能体编排层的详细实现。
2.4 Agent与Model的区别
为了更清楚地理解智能体和语言模型之间的区别,参考下面的对比图表:
Model | Agent | |
---|---|---|
知识边界 | 知识局限于其训练数据中已有的内容。 | 通过工具与外部世界相连来扩展知识。 |
上下文会话 | 基于用户查询进行单次推理/预测。除非为模型专门实现,否则不存在会话历史或持续上下文(即聊天记录)管理。 | 管理会话历史(即聊天记录),以便基于用户查询和编排层做出的决策进行多轮推理 / 预测。在此情境下,“一轮” 被定义为交互系统与智能体之间的一次交互(即 1 个传入事件 / 查询和 1 个智能体响应 )。 |
原生工具 | 没有原生工具实现。 | 工具在智能体架构中是原生实现的。 |
原生逻辑层 | 未实现原生逻辑层。用户可以将提示构建为简单问题,或使用推理框架(如思维链、ReAct 等)构建复杂提示,以引导模型进行预测。 | 具有原生认知架构,使用思维链、ReAct 等推理框架,或其他像 LangChain 这样的预构建智能体框架。 |
2.5 认知架构:智能体如何工作?
想象一下,在一个繁忙的厨房里有一位厨师。他们的目标是为餐厅顾客制作美味的菜肴,这涉及到一系列的规划(planning)、执行(execution)和调整(adjustment)。
- 收集信息:比如顾客的订单,以及食品储藏室和冰箱里有哪些食材。
- 规划:根据刚刚收集到的信息,对自己能制作出哪些菜肴和风味进行一些内部推理。
- 执行:厨师动手制作这道菜,包括切菜、调配香料、煎肉。
在这个过程的每个阶段,厨师会根据需要进行调整,在食材耗尽或收到顾客反馈时完善他们的计划,并利用之前的一系列结果来确定下一个行动计划。
这种信息收集、规划、执行和调整的循环,描述了厨师为实现目标所采用的一种独特认知架构。
就像厨师一样,智能体可以使用认知架构,通过迭代处理信息、做出明智决策并根据先前的输出优化后续行动,来实现其最终目标。
-
智能体认知架构的核心是编排层,它负责维护记忆、状态、推理和规划(memory, state, reasoning and planning)。
-
编排层利用迅速发展的提示词工程,以及相关框架(prompt engineering and associated frameworks),来指导推理和规划,使智能体能够更有效地与环境互动并完成任务。
针对语言模型的提示词工程框架和任务规划领域的研究,正在迅速发展,产生了各种有前景的方法。
以下并非详尽无遗的列表,而是在本文发布时一些最流行的框架和推理技术:
-
ReAct,是一种提示词工程框架,它为语言模型提供了一种思维过程策略,使其能够针对用户查询进行推理并采取行动,无论是否有上下文示例。ReAct提示已被证明优于多个最先进的基线(SOTA baselines),并提高了大语言模型的人机互操作性和可信度。
-
思维链(Chain-of-Thought, CoT),是一种提示词工程框架,可通过中间步骤实现推理能力。思维链有多种子技术,包括自我一致性(self-consistency)、主动提示(active-prompt)和多模态思维链(multimodal CoT),每种技术根据具体应用场景各有优劣。
-
思维树(Tree-of_Thought,ToT),是一种提示词工程框架,非常适合探索性任务或具有前瞻性策略的任务。它是对思维链(CoT)的扩展,允许模型探索各种思维链,这些思维链是使用语言模型解决一般问题的中间步骤。
智能体可以利用上述推理技术之一,或许多其他技术,为给定的用户请求选择下一个最佳行动。
例如,假设有一个智能体被编程为使用ReAct框架,为用户查询选择正确的行动和工具。事件的顺序可能如下:
-
用户向智能体发送查询
-
智能体开始React sequence
-
智能体提示模型,要求其生成下一个ReAct步骤及其相应的输出:
a.问题(Question): 提示词 + 用户输入的问题
b.思考(Thought): 模型对于下一步该做什么的思考
c.行动(Action): 模型对下一步采取何种行动的决策
c.1 这里就是可以引入工具(tool choice)的地方,即工具调用。
c.2 动作可以是[Flights、Search、Code、None]中的一个,其中前三个代表模型可以选择的已知工具,最后一个代表“不选择工具”。
d. 行动输入(Action input): 模型对于向工具提供哪些输入(如果有的话)的决策
e. 观察结果(Observation): 行动/行动输入序列的结果
这种"思考/行动/行动输入/观察结果"可根据需要重复N次。
f. 最终答案(Final Answer): 提供给原始用户查询的模型最终答案
-
ReAct循环结束,并向用户提供最终答案。
如图2所示,模型、工具和智能体配置协同工作,根据用户的原始查询,向用户提供有依据且简洁的回复。
虽然模型本可以根据其先验知识猜测答案(产生幻觉),但它却使用了一个工具(航班查询工具)来搜索实时外部信息。这些额外信息被提供给模型,使其能够根据真实数据做出更明智的决策,并将这些信息总结后反馈给用户。
总之,智能体回复的质量可以直接与模型针对这些不同任务进行推理和行动的能力相关联,这包括选择正确工具的能力,以及对这些工具的定义是否完善。就像厨师用新鲜食材精心烹饪菜肴并留意顾客反馈一样,智能体依靠合理的推理和可靠的信息来提供最佳结果。
在下一节中,我们将深入探讨智能体连接新数据的各种方式。
3. 工具(tools):模型连接外部世界的关键
虽然语言模型在处理信息方面表现出色,但它们缺乏直接感知和影响现实世界的能力。这限制了它们在需要与外部系统或数据进行交互的场景中的实用性。
这意味着,从某种意义上说,语言模型的能力仅限于它从训练数据中学到的内容。但是,无论我们向模型输入多少数据,它们仍然缺乏与外部世界交互的基本能力。
那么,我们如何使模型能够与外部系统进行实时、上下文感知的交互呢?
函数(Functions)、扩展(Extensions)、数据存储(Data Stores)和插件(Plugins)都是为模型提供这一关键能力的途径。
虽然它们有许多不同的名称,但工具是在我们的基础模型与外部世界之间建立联系的桥梁。这种与外部系统和数据的联系,使我们的智能体能够执行更多种类的任务,并且执行起来更加准确可靠。
例如,工具可以让智能体调整智能家居设置、更新日历、从数据库中获取用户信息,或者根据一组特定指令发送电子邮件。
截至本白皮书发布之日,谷歌模型能够与之交互的主要工具类型有三种:**扩展程序(Extensions)、函数(Functions)和数据存储(Data Stores)。**通过为智能体配备工具,我们释放了它们巨大的潜力,使其不仅能够理解世界,还能对世界采取行动,为无数新应用和可能性打开了大门。
3.1 扩展(extensions)
理解扩展的最简单方法是将它们视为以标准化方式弥合API与智能体之间的差距,使智能体能够无缝执行API,无论其底层实现如何。假设你构建了一个旨在帮助用户预订航班的智能体。你知道想要使用谷歌航班API来检索航班信息,但不确定如何让你的智能体调用这个API端点。
一种方法是实现自定义代码, 该代码接收传入的用户查询,解析查询以获取相关信息,然后进行API调用。
例如,在航班预订用例中,用户可能会说“我想预订从奥斯汀到苏黎世的航班”。在这种情况下,我们的自定义代码解决方案需要在尝试进行API调用之前,从用户查询中提取“奥斯汀”和“苏黎世”作为相关实体。但是,如果用户说“我想预订去苏黎世的航班”,却没有提供出发城市,会发生什么情况呢?没有所需的数据,API调用将失败,因此需要实现更多代码来处理此类边缘和极端情况。这种方法不具备可扩展性,在任何超出已实现的自定义代码范围的场景中都很容易出现问题。
一种更具弹性的方法是使用扩展程序。 扩展程序通过以下方式弥合智能体与API之间的差距:
-
通过示例教智能体如何使用API端点。
-
教导智能体成功调用API端点需要哪些参数。
扩展可以独立于智能体进行构建,但应作为智能体配置的一部分提供。智能体在运行时使用模型和示例来决定哪个扩展(如果有的话)适合解决用户的查询。这凸显了扩展的一个关键优势,即其内置的示例类型,使智能体能够为任务动态选择最合适的扩展。
可以用软件开发人员在为用户解决问题并提出解决方案时,决定使用哪些API端点的方式来理解这一点。
如果用户想预订航班,开发人员可能会使用谷歌航班API。
如果用户想知道离他们位置最近的咖啡店在哪里,开发人员可能会使用谷歌地图API。
同样,智能体/模型堆栈会使用一组已知的扩展程序,来决定哪一个最适合用户的查询。如果你想看看扩展程序的实际应用,可以在Gemini应用程序中进行尝试,方法是进入“设置”>“扩展程序”,然后启用任何你想测试的扩展。
例如,你可以启用谷歌航班扩展,然后问Gemini“显示下周五从奥斯汀飞往苏黎世的航班”。
3.1.1 示例扩展
为简化扩展的使用,谷歌提供了一些开箱即用的扩展,可快速导入到您的项目中,并且只需最少的配置即可使用。例如,代码段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):
"""Inverts a 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)
总而言之,扩展为智能体提供了多种方式来感知、交互并影响外部世界。这些扩展的选择和调用以示例为指引,所有示例均作为扩展配置的一部分进行定义。
3.2 函数(functions)
在软件工程领域,函数被定义为独立的代码模块,它们完成特定的任务,并可根据需要重复使用。软件开发人员在编写程序时,通常会创建许多函数来执行各种任务。他们还会定义何时调用函数a而非函数b的逻辑,以及预期的输入和输出。
在智能体领域,函数的工作方式非常相似,但我们可以用模型取代软件开发人员。模型可以利用一组已知的函数,并根据其规范决定何时使用每个函数以及该函数需要哪些参数。函数与扩展在几个方面有所不同,最显著的是:
-
模型输出一个函数及其参数,但不进行实时API调用。
-
函数在客户端执行,而扩展在智能体端执行。
再次以我们的谷歌航班示例为例,函数的简单设置可能如图7中的示例所示。
请注意,这里的主要区别在于,无论是函数还是智能体都不会直接与谷歌航班API进行交互。那么,API调用实际上是如何发生的呢?
通过函数,调用实际API端点的逻辑和执行从智能体转移回客户端应用程序,如下图8和图9所示。这使开发人员能够更精细地控制应用程序中的数据流。开发人员可能出于多种原因选择使用函数而非扩展,以下是一些常见用例:
-
API调用需要在应用程序栈的另一层进行,不在直接的智能体架构流程内(例如,中间件系统、前端框架等)
-
安全或身份验证限制,阻止智能体直接调用API(例如,API未暴露在互联网上,或智能体基础设施无法访问)
-
时间安排或操作顺序方面的限制,导致智能体无法实时进行API调用。(例如批量操作、人工介入审核等。)
-
对于智能体无法执行的API响应,需要应用额外的数据转换逻辑。例如,假设有一个API端点没有提供用于限制返回结果数量的筛选机制。在客户端使用函数,为开发人员提供了进行这些转换的更多机会。
-
开发人员希望在不为API端点部署额外基础设施的情况下,对智能体开发进行迭代(即函数调用可以像API的“存根”一样工作)
虽然从图8中可以看出,这两种方法在内部架构上的差异很细微,但额外的控制以及对外部基础设施的解耦依赖,使得函数调用对开发者来说是一个有吸引力的选择。
3.2.1 用例
模型可用于调用函数,以便为终端用户处理复杂的客户端执行流程,在这种情况下,智能体开发者可能不希望语言模型管理API执行(扩展就是这种情况)。
让我们考虑以下示例,其中一个智能体被训练为旅行礼宾员,与想要预订度假旅行的用户进行交互。目标是让智能体生成一个城市列表,我们可以在中间件应用程序中使用该列表为用户的旅行规划下载图片、数据等。用户可能会这样说:
我想和家人去滑雪,但我不知道去哪里。
在向模型发出的典型提示prompt中,输出可能如下所示:
当然,以下是一些你可以考虑进行家庭滑雪旅行的城市列表:
美国科罗拉多州凤头峰
加拿大不列颠哥伦比亚省惠斯勒
瑞士采尔马特
虽然上述输出包含了我们需要的数据(城市名称),但其格式并不适合解析。通过函数调用,我们可以教会模型以结构化的样式(如JSON)来格式化此输出,这样另一个系统解析起来会更方便。对于用户给出的相同输入提示,一个函数输出的示例JSON可能如代码段5所示。
function_call { name: "display_cities" args: { "cities": ["Crested Butte", "Whistler", "Zermatt"], "preferences": "skiing" } }
这个JSON有效载荷由模型生成,然后发送到我们的客户端服务器,以便执行我们想做的任何操作。在这个特定的场景中,我们将调用谷歌地图API,获取模型提供的城市,并查找相关图片,然后将其作为格式化的富文本内容返回给用户。请参考图9中的序列图,该图详细展示了上述交互过程的每一步。
图9中示例的结果是,利用模型为客户端用户界面调用谷歌地图地点 API 所需的参数 “填空”。客户端用户界面使用模型在返回的函数中提供的参数来管理实际的 API 调用。这只是函数调用的一个用例,但还有许多其他场景需要考虑,例如:
-
你希望语言模型推荐一个可在代码中使用的函数,但又不想在代码中包含凭证。由于函数调用不会运行函数,因此你无需在代码中随函数信息一同包含凭证。
-
你正在运行可能需要花费数秒以上时间的异步操作。这些场景很适合使用函数调用,因为这也是一种异步操作。
-
你想在与生成函数调用及其参数的系统不同的设备上运行函数。
关于函数,需要记住的一个关键要点是,函数不仅旨在让开发人员更好地控制API调用的执行,还能更好地掌控整个应用程序中的数据流动。在图9的示例中,开发人员选择不将API信息返回给智能体,因为这些信息与智能体未来可能采取的行动无关。然而,根据应用程序的架构,为了影响未来的推理、逻辑和行动选择,将外部API调用数据返回给智能体可能是有意义的。最终,要由应用程序开发人员来选择最适合特定应用程序的方式。
3.2.2 函数示例代码
为了在我们的滑雪度假场景中实现上述输出,让我们构建每个组件,以便使其与我们的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
接下来,我们将实例化模型,构建工具,然后将用户的查询和工具传递给模型。执行以下代码将产生代码片段底部所示的输出。
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']}
总之,函数提供了一个简单明了的框架,使应用程序开发人员能够对数据流和系统执行进行细粒度控制,同时有效地利用智能体/模型生成关键输入。开发人员可以根据特定的应用程序架构要求,有选择地决定是通过返回外部数据让智能体 “参与其中”,还是忽略它。
3.3 数据存储(data stores)
想象一下,将语言模型比作一个巨大的图书馆,里面存放着它的训练数据。但与不断购置新书的图书馆不同,这个“图书馆”是静态的,只包含最初训练时所使用的知识。这就带来了一个挑战,因为现实世界的知识在不断发展。数据存储通过提供对更动态、最新信息的访问,并确保模型的回答始终基于事实且具有相关性,来解决这一限制。
考虑一个常见的场景,开发人员可能需要向模型提供少量额外数据,这些数据可能采用电子表格或PDF的形式。
数据存储使开发人员能够以原始格式向智能体提供额外数据,无需进行耗时的数据转换、模型重新训练或微调。数据存储会将传入的文档转换为一组向量数据库嵌入,智能体可以利用这些嵌入提取所需信息,以补充其下一步行动或对用户的响应。
3.3.1 实施和应用
在生成式人工智能智能体的背景下,数据存储通常被实现为一个向量数据库,开发人员希望智能体在运行时能够访问该数据库。虽然我们不会在此深入探讨向量数据库,但关键要理解的是,它们以向量嵌入的形式存储数据,这是一种高维向量或所提供数据的数学表示。近年来,语言模型使用数据存储的一个最常见示例是检索增强的实现。
基于生成式检索(RAG)的应用程序。这些应用程序试图通过让模型能够访问各种格式的数据,来扩展模型知识的广度和深度,使其超越基础训练数据的范围,这些数据格式例如:
- 网站内容
- 结构化数据,格式包括PDF、Word文档、CSV、电子表格等。
- 非结构化数据,格式如HTML、PDF、TXT等。
每个用户请求和智能体响应循环的底层过程通常如图13所示进行建模。
- 用户查询被发送到嵌入模型,以生成该查询的嵌入向量。
- 然后,使用诸如SCaNN之类的匹配算法,将查询嵌入与向量数据库的内容进行匹配。
- 从向量数据库中以文本格式检索匹配的内容,并将其发送回智能体。
- 智能体接收用户查询和检索到的内容,然后制定回复或行动。
- 向用户发送最终响应
最终结果是一个应用程序,它允许智能体通过向量搜索将用户查询与已知数据存储进行匹配,检索原始内容,并将其提供给编排层和模型进行进一步处理。下一步行动可能是向用户提供最终答案,或者执行额外的向量搜索以进一步优化结果。
图14展示了与一个结合了检索增强生成(RAG)与ReAct推理/规划的智能体的示例交互。
3.4 工具总结
总而言之,扩展、函数和数据存储构成了几种不同的工具类型,可供智能体在运行时使用。每种工具都有其自身的用途,智能体开发者可以酌情将它们一起使用或单独使用。
扩展 | 函数调用 | 数据存储 | |
---|---|---|---|
执行位置 | 智能体端执行 | 客户端执行 | 智能体端执行 |
使用场景 | - 开发人员希望智能体控制与 API 端点的交互。 - 当利用原生预构建扩展(如 Vertex Search、代码解释器等)时很有用。 - 多步规划和 API 调用(即智能体的下一个动作取决于前一个动作 / API 调用的输出)。 |
- 安全或身份验证限制阻止智能体直接调用 API - 时间限制或操作顺序限制阻止智能体进行实时 API 调用(例如批量操作、人工介入审核等)。 - 未暴露在互联网上或谷歌系统无法访问的 API。 |
- 开发人员希望使用以下任意数据类型实现检索增强生成(RAG) - 来自预索引域和 URL 的网站内容。如 PDF、Word 文档、CSV、电子表格等格式的结构化数据。 - 关系型 / 非关系型数据库。 如HTML、PDF、TXT等格式的非结构化数据。 |
4. 通过针对性学习提升模型性能
有效使用模型的一个关键方面是它们在生成输出时选择正确工具的能力,尤其是在生产环境中大规模使用工具时。虽然通用训练有助于模型培养这种技能,但现实场景往往需要训练数据之外的知识。可以将其想象为基本烹饪技能与精通特定菜系之间的区别。两者都需要基础烹饪知识,但后者需要有针对性的学习,以获得更细致入微的成果。
为帮助模型获取这类特定知识,有几种方法:
-
上下文学习:这种方法在推理时为通用模型提供提示、工具和少量示例,使其能够“即时”学习如何以及何时将这些工具用于特定任务。ReAct框架就是这种方法在自然语言中的一个例子。
-
基于检索的上下文学习:这种技术通过从外部存储器中检索最相关的信息、工具和相关示例,动态地将它们填充到模型提示中。这方面的一个例子是Vertex AI扩展中的“示例存储”,或者前面提到的基于RAG架构的数据存储。
-
基于微调的学习:这种方法包括在推理之前,使用更大的特定示例数据集对模型进行训练。这有助于模型在接收任何用户查询之前,理解何时以及如何应用某些工具。
为了对每种目标学习方法提供更多见解,让我们回顾一下烹饪的类比。
-
想象一下,一位厨师从顾客那里收到了一份特定的食谱(提示)、一些关键食材(相关工具)以及一些菜品示例(少样本示例)。基于这些有限的信息以及厨师对烹饪的一般知识,他们需要“即时”想出如何准备一道与食谱和顾客偏好最相符的菜肴。这就是上下文学习。
-
现在,让我们想象一下,我们的厨师身处一个食材储备丰富的厨房(外部数据存储),里面摆满了各种食材和烹饪书籍(示例和工具)。厨师现在能够从储备中动态选择食材和烹饪书籍,更好地契合顾客的食谱和喜好。这使得厨师能够利用现有的和新的知识,制作出更有见地、更精致的菜肴。这就是基于检索的上下文学习。
-
最后,我们假设让厨师回到学校学习一种或多种新菜系(在更大的特定示例数据集上进行预训练)。这样一来,厨师就能以更深入的理解去处理未来遇到的新顾客菜谱。如果我们希望厨师在特定菜系(知识领域)表现出色,这种方法堪称完美。这就是基于微调的学习。
这些方法中的每一种在速度、成本和延迟方面都有独特的优点和缺点。然而,通过在智能体框架中结合这些技术,我们可以利用各种优势并将其缺点降至最低,从而实现更强大、更具适应性的解决方案。
5. 使用LangChain快速创建智能体
为了提供一个智能体实际运行的真实可执行示例,我们将使用LangChain和LangGraph库构建一个快速原型。这些流行的开源库允许用户通过将逻辑、推理和工具调用序列 “链接” 在一起,以回答用户的查询,从而构建自定义智能体。我们将使用gemini - 1.5 - flash - 001模型和一些简单工具,来回答用户的多阶段查询,如代码片段8所示。
我们正在使用的工具是SerpAPI(用于谷歌搜索)和谷歌地图地点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): """Use the SerpAPI to run a Google Search."""
search = SerpAPIWrapper()
return search.run(query)
@tool
def places(query: str):
"""Use the Google Places API to run a Google Places Query."""
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()
输出如下:
=============================== 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.
虽然这是一个相当简单的智能体示例,但它展示了模型、编排和工具等基本组件协同工作以实现特定目标的过程。在最后一部分,我们将探讨这些组件如何在谷歌规模的托管产品(如Vertex AI智能体和生成式手册)中协同工作。
6. 使用Google Vertex AI Agent生产应用程序
虽然本白皮书探讨了智能体的核心组件,但构建生产级应用程序需要将它们与其他工具集成,如用户界面、评估框架和持续改进机制。谷歌的Vertex AI平台通过提供一个完全托管的环境,涵盖了前面提到的所有基本要素,简化了这一过程。开发人员可以使用自然语言界面快速定义其智能体的关键要素——目标、任务指令、工具、用于任务委派的子智能体以及示例——从而轻松构建所需的系统行为。此外,该平台还配备了一套开发工具,可用于测试、评估、衡量智能体性能、调试以及提高所开发智能体的整体质量。这使开发人员能够专注于构建和优化他们的智能体,而基础设施、部署和维护的复杂性则由平台本身管理。
在图15中,我们提供了一个智能体的示例架构,该智能体基于Vertex AI平台构建,使用了Vertex智能体构建器、Vertex扩展、Vertex函数调用和Vertex示例存储等多种功能。该架构包含了生产就绪应用所需的许多不同组件。
7. 总结
在本白皮书中,我们讨论了生成式人工智能智能体的基本构建模块、它们的组成结构,以及以认知架构形式实现它们的有效方法。本白皮书的一些关键要点包括:
-
智能体通过利用工具来获取实时信息、建议现实世界中的行动以及自主规划和执行复杂任务,从而扩展了语言模型的能力。智能体可以利用一个或多个语言模型来决定何时以及如何在不同状态之间转换,并使用外部工具来完成大量复杂任务,而这些任务对于模型自身而言可能很难或无法完成。
-
智能体运行的核心是编排层,这是一种认知架构,用于组织推理、规划、决策并指导其行动。诸如ReAct、思维链和思维树等各种推理技术,为编排层提供了一个框架,使其能够接收信息、进行内部推理,并生成明智的决策或回应。
-
工具,如扩展、函数和数据存储,是智能体连接外部世界的关键,使它们能够与外部系统交互并获取训练数据之外的知识。扩展在智能体和外部API之间架起了一座桥梁,使得能够执行API调用并检索实时信息。函数通过分工为开发者提供了更细致的控制,使智能体能够生成可在客户端执行的函数参数。数据存储使智能体能够访问结构化或非结构化数据,支持数据驱动的应用程序。
智能体的未来将取得令人振奋的进展,而我们才刚刚触及可能性的皮毛。随着工具变得更加复杂,推理能力得到增强,智能体将有能力解决越来越复杂的问题。此外,“智能体链式”的策略方法将继续获得发展动力。通过组合专门的智能体——每个智能体都擅长特定的领域或任务——我们可以创建一种“智能体专家组合”方法,能够在各个行业和问题领域取得卓越成果。
需要记住的是,构建复杂的智能体架构需要采用迭代的方法。试验和优化是针对特定业务场景和组织需求找到解决方案的关键。由于支撑其架构的基础模型具有生成性,没有两个智能体是完全相同的。然而,通过利用这些基础组件各自的优势,我们可以创建有影响力的应用程序,扩展语言模型的能力并创造实际价值。
感谢您的阅读。原创不易,如您觉得有价值,请点赞,关注。
更多推荐
所有评论(0)