微信扫码
与创始人交个朋友
我要投稿
本文深入探讨了生成式 AI 智能体的核心组件、工作原理、关键技术及其广泛应用。从智能体的定义到模型、工具和编排层的协同作用,再到认知架构的运作机制,本文揭示了智能体如何利用扩展、函数和数据存储等工具来执行复杂任务。此外,本文还介绍了如何通过定向学习提升模型性能,并展望了智能体在未来的发展趋势,特别是 Google 在该领域的探索和应用。
内容提纲:
人类擅长处理复杂的模式识别任务。然而,我们往往也需要借助工具——如书籍、Google 搜索或计算器——来补充我们的先验知识,从而做出最终的判断。正如人类一样,生成式 AI 模型也可以通过训练来使用工具,以获取实时信息或建议现实世界的行动。 例如,模型可以利用数据库检索工具来访问特定信息,如客户的购买历史,从而生成量身定制的购物推荐。或者,根据用户的查询,模型可以进行各种 API 调用,向同事发送电子邮件回复,或代表您完成一笔金融交易。为了做到这一点,模型不仅必须能够访问一组外部工具,还需要能够以自主的方式计划和执行任何任务。这种推理、逻辑和外部信息访问能力的结合,都与生成式 AI 模型相关联,从而引出了智能体 (Agent) 的概念,即一个扩展了生成式 AI 模型独立能力的程序。本白皮书将更详细地深入探讨所有这些方面及相关内容。
智能体是一个应用程序,它能够通过观察周围环境,并利用其可支配的工具来尝试实现预设的目标。 智能体具有自主性,可以独立于人类干预而行动,特别是在为其设定了明确的目标或任务的情况下。即使没有明确的指令,智能体也能主动地思考如何达成最终目标。虽然人工智能中智能体的概念相当宽泛且强大,但本白皮书着重于探讨在本文发表之时,生成式 AI 模型能够构建的特定类型的智能体。
智能体的行为、动作和决策由其内部的认知架构驱动。一个典型的智能体认知架构包含以下三个核心组件:
在智能体的范畴内,模型是指在智能体运行过程中充当核心决策者的语言模型 (LM)。 它可以是一个或多个不同规模(小型或大型)的 LM,并且能够理解并执行基于指令的推理和逻辑框架,如 ReAct、Chain-of-Thought 或 Tree-of-Thoughts。模型可以是通用的、多模态的,也可以根据特定智能体架构的需求进行微调。为了获得最佳的生产效果,应选择最适合目标应用的模型,并且该模型最好已经过与认知架构中计划使用的工具相关的数据签名的训练。
需要注意的是,模型通常不使用智能体的特定配置设置(即工具选择、编排/推理设置)进行训练。然而,可以通过向模型提供展示智能体能力的示例,包括智能体在各种上下文中使用特定工具或推理步骤的实例,来进一步改进模型以适应智能体的任务。
尽管基础模型在文本和图像生成方面表现出色,但它们仍受限于无法与外部世界交互。工具弥合了这一差距,使智能体能够与外部数据和服务进行交互,从而解锁超越模型本身的一系列操作。 工具可以有多种形式,并且具有不同的复杂程度,但通常与常见的 Web API 方法(如 GET、POST、 PATCH 和 DELETE)一致。例如,工具可以更新数据库中的客户信息,或获取天气数据以影响智能体提供的旅行建议。借助工具,智能体可以访问和处理现实世界的信息。这使它们能够支持更多专用系统,如检索增强生成 (RAG),这大大扩展了智能体的能力,使其超越了基础模型本身的能力。
编排层描述了一个循环过程,它控制着智能体如何获取信息、执行内部推理,并利用推理结果来指导下一步的行动或决策。 通常,这个循环会持续进行,直到智能体达到其目标或停止点。编排层的复杂性因智能体及其执行的任务而异。一些循环可能是简单的决策规则计算,而另一些可能包含链式逻辑、额外的机器学习算法或其他概率推理技术。
下表总结了智能体和模型之间的主要区别:
知识范围 | 通过工具连接到外部系统进行扩展 | |
推理方式 | 支持基于用户查询和编排层决策的多轮推理/预测,并管理会话历史记录(例如聊天历史) | |
工具使用 | 工具在智能体架构中得到原生支持 | |
逻辑层 | 具有原生的认知架构,使用 ReAct、CoT、ToT 等推理框架或 LangChain 等预构建的智能体框架,来进行复杂的提示工程。 |
如同在繁忙厨房中工作的厨师,智能体的目标是通过一系列的计划、执行和调整来为顾客创造美味佳肴。他们收集信息(例如顾客订单和现有食材),进行内部推理(例如构思菜品和口味搭配),然后采取行动(例如切菜、调味、烹饪)。在每个阶段,厨师都会根据需要进行调整,并根据先前的结果优化下一步计划。这种信息获取、计划、执行和调整的循环过程,构成了一种独特的认知架构。
与厨师类似,智能体利用认知架构来迭代处理信息、做出明智决策,并根据之前的输出优化后续行动,最终实现其目标。 编排层是智能体认知架构的核心,负责维护记忆、状态、推理和计划。它利用快速发展的提示工程领域及其相关框架来指导推理和计划,使智能体能够更有效地与其环境交互并完成任务。
图 1:通用智能体架构和组件 - 该图展示了智能体的典型架构,包括模型、编排层、工具和用户查询之间的交互关系。
目前,一些主流的提示工程框架和推理技术包括:
例如,一个被编程为使用 ReAct 框架来为用户查询选择正确行动和工具的智能体,其事件序列可能如下所示:
图 2:具有 ReAct 推理的智能体示例 - 该图展示了一个智能体使用 ReAct 框架与用户交互,并最终调用 "Flights" 工具查询航班信息的完整流程。
截至本文发布之日,Google 模型能够交互的主要工具类型有三种:扩展 (Extensions)、函数 (Functions) 和数据存储 (Data Stores)。 通过为智能体配备工具,我们释放了它们理解世界并对其采取行动的巨大潜力,为无数新的应用和可能性打开了大门。
扩展以标准化的方式桥接了 API 和智能体之间的鸿沟,使智能体能够无缝地执行 API,而无需考虑其底层实现。 可以将扩展理解为 API 和智能体之间的桥梁,它以标准化的方式使智能体能够无缝执行 API,而无需考虑 API 的底层实现。假设您构建了一个旨在帮助用户预订航班的智能体。您知道您想使用 Google Flights API 来检索航班信息,但不确定如何让您的智能体调用此 API 端点。
图 3:智能体如何与外部 API 交互?- 该图展示了在没有扩展的情况下,智能体需要自定义代码来解析用户查询并调用 API,这种方式难以扩展且容易出错。
一种方法可以是实现自定义代码,该代码将接收传入的用户查询,解析查询以获取相关信息,然后进行 API 调用。例如,在航班预订用例中,用户可能会说“我想预订从奥斯汀到苏黎世的航班”。在这种情况下,我们的自定义代码解决方案将需要在尝试进行 API 调用之前,从用户查询中提取“奥斯汀”和“苏黎世”作为相关实体。但是,如果用户说“我想预订飞往苏黎世的航班”而没有提供出发城市怎么办?在没有所需数据的情况下,API 调用将失败,并且需要实现更多代码才能捕获这样的边缘和极端情况。这种方法不可扩展,并且在任何超出已实现自定义代码的场景中都很容易出错。
一个更具弹性的方法是使用扩展。 扩展通过以下方式连接智能体和外部 API:
图 4:扩展将智能体连接到外部 API - 该图展示了扩展如何通过提供示例和参数信息,帮助智能体更便捷地调用外部 API。
扩展可以独立于智能体进行构建,但应作为智能体配置的一部分提供。智能体使用模型和示例在运行时决定哪个扩展(如果有)适合解决用户的查询。这凸显了扩展的一个关键优势,即其内置的示例类型,允许智能体动态地选择最合适的扩展来完成任务。
图 5:智能体、扩展和 API 之间的 1 对多关系 - 该图展示了一个智能体如何配置多个扩展,从而访问不同的 API,例如 Flights API、Maps API 和 Weather API。
为了简化扩展的使用,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
# 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.
"""
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. 代码解释器扩展可以生成和运行 Python 代码
函数可以被视为执行特定任务并可复用的自包含代码模块。 在软件工程领域,函数被定义为完成特定任务并且可以根据需要重复使用的自包含代码模块。当软件开发人员编写程序时,他们通常会创建许多函数来执行各种任务。他们还将定义调用 function_a 与 function_b 的逻辑,以及预期的输入和输出。
函数在智能体领域中的工作方式非常相似,但我们可以用模型替换软件开发人员。模型可以采用一组已知函数,并根据其规范决定何时使用每个函数以及函数需要哪些参数。函数与扩展的不同之处主要在于:
图 7:函数如何与外部 API 交互?- 该图展示了函数调用与扩展的区别,其中模型输出函数名和参数,由客户端负责执行函数并调用 API。
图 8:客户端控制与智能体端控制 - 该图对比了扩展和函数调用在控制流程上的差异,其中函数调用将 API 的实际调用放在了客户端。
模型可以用于调用函数,以便为最终用户处理复杂的客户端执行流程,在这种情况下,智能体开发人员可能不希望语言模型管理 API 执行(就像扩展的情况一样)。让我们考虑以下示例,其中一个智能体被训练成一个旅行礼宾员,与想要预订度假旅行的用户进行交互。目标是让智能体生成一个城市列表,我们可以在我们的中间件应用程序中使用该列表为用户的旅行计划下载图像、数据等。用户可能会说这样的话:
“我想和家人一起去滑雪旅行,但我不确定去哪里。”
在对模型的典型提示中,输出可能如下所示:
当然,以下是您可以考虑的家庭滑雪旅行城市列表:
虽然上述输出包含我们需要的数据(城市名称),但该格式并不适合解析。通过函数调用,我们可以教会模型以结构化样式(如 JSON)格式化此输出,这更便于另一个系统解析。 假设用户提供相同的输入提示,则来自函数的示例 JSON 输出可能如代码片段 5 所示。
{
"function_call":{
"name":"display_cities",
"args":{
"cities":[
"Crested Butte",
"Whistler",
"Zermatt"
],
"preferences":"skiing"
}
}
}
代码片段 5. 用于显示城市列表和用户偏好的示例函数调用负载
图 9:函数调用生命周期 - 该图详细展示了函数调用的各个步骤,包括模型生成 JSON 响应,客户端解析并调用 API,以及最终将结果返回给用户的完整流程。
为了从我们的滑雪度假场景中获得上述输出,让我们构建每个组件,使其与我们的 gemini-1.5-flash-001
模型一起使用。
首先,我们将 display_cities
函数定义为一个简单的 Python 方法。
from typing import List, Optional
def display_cities(cities: List[str], preferences: Optional[str] = None) -> List[str]:
"""根据用户的搜索查询和偏好提供城市列表。
Args:
preferences (str): 用户的搜索偏好,如滑雪、
海滩、餐馆、烧烤等。
cities (List[str]): 推荐给用户的城市列表。
Returns:
List[str]: 推荐给用户的城市列表。
"""
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 = "我想和家人一起去滑雪旅行,但我不确定去哪里。"
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. 构建工具,将其与用户查询一起发送到模型,并允许进行函数调用
数据存储可以被视为一个大型的、不断更新的知识库。 可以将数据存储想象成一个庞大的图书馆,其中包含其训练数据。但与不断获取新卷的图书馆不同,这个图书馆保持静态,仅保存最初训练时的知识。这提出了一个挑战,因为现实世界的知识在不断发展。数据存储通过提供对更动态和最新信息的访问来解决此限制,并确保模型的响应始终基于事实和相关性。 数据存储允许开发人员以其原始格式向智能体提供额外数据,从而无需耗时的数据转换、模型重新训练或微调。数据存储将传入文档转换为一组向量数据库嵌入,智能体可以使用这些嵌入来提取所需信息,以补充其下一个操作或对用户的响应。
图 10:智能体如何与结构化和非结构化数据交互?- 该图展示了智能体如何通过数据存储访问私有文档、网站和结构化数据等不同类型的数据源。
图 11:数据存储将智能体连接到各种类型的新实时数据源 - 该图展示了数据存储如何将智能体与私有文档、网站和结构化数据等数据源连接起来,从而实现 RAG 应用。
在生成式 AI 智能体的上下文中,数据存储通常被实现为向量数据库,它以向量嵌入的形式存储数据,这是一种高维向量或数据的数学表示。开发人员希望智能体在运行时能够访问此向量数据库。虽然我们不会在这里深入介绍向量数据库,但关键是要了解它们以向量嵌入的形式存储数据,向量嵌入是一种提供的数据的高维向量或数学表示。
近年来,将数据存储与语言模型结合使用的最丰富的示例之一是实现基于检索增强生成 (RAG) 的应用。 这些应用程序试图通过让模型访问各种格式的数据来扩展模型知识的广度和深度,例如:
图 12:智能体和数据存储之间的 1 对多关系 - 该图展示了一个智能体如何配置多个数据存储,从而访问各种类型的预索引数据,例如非结构化数据存储、网站数据存储和结构化数据存储。
每个用户请求和智能体响应循环的底层流程通常如图 13 所示建模。
SCaNN
这样的匹配算法将查询嵌入与向量数据库的内容进行匹配图 13:基于 RAG 的应用程序中用户请求和智能体响应的生命周期 - 该图详细展示了基于 RAG 的应用中,用户查询如何被转换为嵌入,并与向量数据库中的内容进行匹配,最终返回给用户检索到的内容。
图 14:基于 RAG 的应用示例 - 该图展示了一个基于 RAG 的智能体如何使用 ReAct 框架,通过查询数据存储来回答用户的关于“育儿假政策”的问题。
总而言之,扩展、函数和数据存储构成了智能体在运行时可以使用的几种不同工具类型。每种工具都有其自己的用途,并且可以根据智能体开发人员的判断一起使用或单独使用。
执行 | |||
用例 | • 当利用本机预构建扩展时非常有用(例如 Vertex Search、代码解释器等) • 多跳规划和 API 调用(即下一个智能体操作取决于上一个操作/API 调用的输出) | • 时序限制或操作顺序限制阻止智能体实时进行 API 调用。(即批处理、人工干预审查等) • 未暴露于互联网或 Google 系统无法访问的 API | - 来自预索引域和 URL 的网站内容 - PDF、Word 文档、CSV、电子表格等格式的结构化数据 - 关系/非关系数据库 - HTML、PDF、TXT 等格式的非结构化数据 |
有效利用模型的关键在于其选择正确工具的能力,尤其是在生产环境中大规模使用工具时。 虽然一般训练有助于模型发展这项技能,但现实世界的场景通常需要超出训练数据的知识。可以将其想象为基本烹饪技能和掌握特定菜系之间的区别。两者都需要基本的烹饪知识,但后者需要有针对性的学习才能获得更细致的结果。
为了帮助模型获得此类特定领域的知识,存在几种方法:
LangChain 和 LangGraph 是两个流行的开源库,允许用户通过将逻辑、推理和工具调用序列“链接”在一起来构建自定义智能体,以回答用户的查询。我们可以使用 gemini-1.5-flash-001
模型和一些简单的工具来快速构建一个智能体原型。例如,代码片段 8 展示了如何使用 LangChain 和 LangGraph 构建一个简单的智能体,该智能体可以利用 SerpAPI(用于 Google 搜索)和 Google Places API 来回答用户的多阶段查询。
代码片段 8. 基于 LangChain 和 LangGraph 的智能体及工具示例
执行该程序后,您可以在代码片段 9 中看到示例输出。
代码片段 9. 代码片段 8 中程序的输出
虽然本白皮书探讨了智能体的核心组件,但构建生产级应用程序需要将它们与其他工具(如用户界面、评估框架和持续改进机制)集成。Google 的 Vertex AI 平台提供了一个完全托管的环境,集成了上述所有基本元素,可以用于构建生产级的智能体应用。该平台提供了一套开发工具,可用于测试、评估、衡量智能体性能、调试和提高已开发智能体的整体质量。这使开发人员可以专注于构建和完善其智能体,而基础架构、部署和维护的复杂性则由平台本身管理。
在图 15 中,我们提供了一个在 Vertex AI 平台上构建的智能体的示例架构,该平台使用了诸如 Vertex 智能体构建器、Vertex 扩展、Vertex 函数调用和 Vertex 示例存储等各种功能。该架构包括许多生产就绪应用程序所需的各种组件。
图 15:基于 Vertex AI 平台的端到端智能体架构示例 - 该图展示了在 Vertex AI 平台上构建的智能体示例架构,包括用户界面、智能体、函数、扩展、模型以及与外部 API(如 Google Places API 和向量搜索 API)的交互。
智能体通过利用工具访问实时信息、建议现实世界的行动以及自主规划和执行复杂任务,扩展了语言模型的能力。智能体的核心是编排层,它利用各种推理技术来指导其行动。工具,如扩展、函数和数据存储,充当智能体通往外部世界的钥匙。
智能体的未来充满了令人兴奋的进步,我们才刚刚开始触及可能性的表面。随着工具变得更加复杂以及推理能力得到增强,智能体将有能力解决日益复杂的问题。“智能体链”的战略方法也将继续获得发展势头。通过结合各个领域的专业智能体,我们可以创造一种“智能体专家组合”的方法,能够在各个行业和问题领域提供卓越的结果。
构建复杂的智能体架构需要迭代的方法。实验和改进是为特定业务案例和组织需求找到解决方案的关键。通过利用这些基本组件中每一个的优势,我们可以创建有影响力的应用程序,扩展语言模型的能力并驱动现实世界的价值。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-05-28
2024-08-13
2024-04-26
2024-08-21
2024-06-13
2024-08-04
2024-07-09
2024-09-23
2024-04-11
2024-07-18