# 2023 Wang et al.

Voyager: An Open-Ended Embodied Agent with Large Language Models

VOYAGER:基于大语言模型的开放式具身智能体 Guanzhi Wang$^{1, 2}$, Yuqi Xie$^3$, Yunfan Jiang$^{4 }$, Ajay Mandlekar$^{1 }$, Chaowei Xiao$^{1, 5}$, Yuke Zhu$^{1, 3}$, Linxi “Jim” Fan$^{1dagger}$, Anima Anandkumar$^{...

精粹译文

VOYAGER:基于大语言模型的开放式具身智能体

Guanzhi Wang1,2^{1, 2}, Yuqi Xie3^3, Yunfan Jiang4^{4*}, Ajay Mandlekar1^{1*}, Chaowei Xiao1,5^{1, 5}, Yuke Zhu1,3^{1, 3}, Linxi “Jim” Fan1^{1\dagger}, Anima Anandkumar1,2^{1, 2\dagger}

1^1NVIDIA, 2^2Caltech, 3^3UT Austin, 4^4Stanford, 5^5UW Madison

^*同等贡献,^\dagger同等指导,\boxtimes通讯作者

https://voyager.minedojo.org


摘要

我们介绍了 VOYAGER,这是首个在 Minecraft 中由大语言模型(LLM)驱动的具身终身学习智能体。它能够在无需人工干预的情况下持续探索世界、获取多种技能并做出新的发现。VOYAGER 由三个关键组件组成:1) 最大化探索的自动课程;2) 用于存储和检索复杂行为的可执行代码技能库;3) 一种结合环境反馈、执行错误和自我验证以改进程序的新型迭代提示机制。VOYAGER 通过黑盒查询与 GPT-4 交互,无需对模型参数进行微调。VOYAGER 开发的技能具有时间扩展性、可解释性和组合性,这使得智能体的能力能够迅速复合,并减轻了灾难性遗忘。实验表明,VOYAGER 展现了强大的上下文终身学习能力,并在玩 Minecraft 时表现出卓越的熟练度。与现有最先进技术(SOTA)相比,它获得的独特物品数量增加了 3.3×3.3\times,旅行距离增加了 2.3×2.3\times,解锁关键科技树里程碑的速度最高提升了 15.3×15.3\times。VOYAGER 能够在新的 Minecraft 世界中利用已学习的技能库从零开始解决新任务,而其他技术则难以实现泛化。

图 1:VOYAGER 通过自主探索不断发现新的 Minecraft 物品和技能,显著优于基线模型。X 轴表示提示迭代次数。


图 2:VOYAGER 由三个关键组件组成:用于开放式探索的自动课程、用于日益复杂行为的技能库,以及使用代码作为动作空间的迭代提示机制。

1 引言

构建能够在开放式世界中持续探索、规划和发展新技能的通用具身智能体是 AI 社区面临的一项重大挑战 [1–5]。经典方法采用强化学习(RL)[6, 7] 和模仿学习 [8–10],这些方法在原始动作上操作,对于系统性探索 [11–15]、可解释性 [16–18] 和泛化 [19–21] 来说可能具有挑战性。基于大语言模型(LLM)的智能体的最新进展利用预训练 LLM 中封装的世界知识来生成一致的动作计划或可执行策略 [16, 22, 19]。它们被应用于游戏和机器人等具身任务 [23–27],以及无具身的 NLP 任务 [28–30]。然而,这些智能体并非终身学习者,无法在较长的时间跨度内逐步获取、更新、积累和迁移知识 [31, 32]。

以 Minecraft 为例。与 AI 研究中的大多数其他游戏不同 [33, 34, 10],Minecraft 没有预定义的最终目标或固定的故事情节,而是提供了一个充满无限可能的独特游乐场 [23]。Minecraft 要求玩家探索广阔的、程序生成的 3D 地形,并利用收集到的资源解锁科技树。人类玩家通常从学习基础知识开始,例如挖掘木材和烹饪食物,然后转向更复杂的任务,如与怪物战斗和制作钻石工具。我们认为,一个有效的终身学习智能体应该具备与人类玩家相似的能力:(1) 根据其当前的技能水平和世界状态提出合适的任务,例如,如果它发现自己身处沙漠而不是森林,则先学习收获沙子和仙人掌,而不是铁;(2) 根据环境反馈改进技能,并将掌握的技能提交到记忆中以供在类似情况下重复使用(例如,与僵尸战斗类似于与蜘蛛战斗);(3) 以自主驱动的方式持续探索世界并寻找新任务。

为了实现这些目标,我们引入了 VOYAGER,这是首个由 LLM 驱动的具身终身学习智能体,旨在 Minecraft 中推动探索、掌握广泛的技能并持续做出新的发现,而无需人工干预。VOYAGER 通过三个关键模块实现(图 2):1) 最大化探索的自动课程;2) 用于存储和检索复杂行为的技能库;3) 一种生成用于具身控制的可执行代码的新型迭代提示机制。我们选择使用代码作为动作空间,而不是低级电机指令,因为程序可以自然地表示时间扩展和组合动作 [16, 22],这对于 Minecraft 中的许多长程任务至关重要。VOYAGER 通过提示和上下文学习 [36–38] 与黑盒 LLM(GPT-4 [35])交互。我们的方法绕过了对模型参数访问和显式基于梯度的训练或微调的需求。

更具体地说,VOYAGER 尝试解决由自动课程提出的难度逐渐增加的任务,该课程考虑了探索进度和智能体的状态。课程由 GPT-4 根据“尽可能多地发现多样化事物”这一总体目标生成。这种方法可以被视为一种上下文形式的新颖性搜索 [39, 40]。VOYAGER 通过存储有助于成功解决任务的动作程序,逐步构建技能库。

图 3:自动课程提出的任务。为简洁起见,我们仅显示部分提示。有关完整提示结构,请参阅附录 Sec. A.3。

每个程序都通过其描述的嵌入进行索引,可以在未来类似的情况下检索。复杂的技能可以通过组合更简单的程序来合成,这会随着时间的推移迅速复合 VOYAGER 的能力,并减轻其他持续学习方法中的灾难性遗忘 [31, 32]。

然而,LLM 难以一次性稳定地生成正确的动作代码 [41]。为了解决这一挑战,我们提出了一种迭代提示机制,该机制:(1) 执行生成的程序以从 Minecraft 模拟中获取观察结果(例如库存清单和附近的生物)以及来自代码解释器的错误跟踪(如果有);(2) 将反馈纳入 GPT-4 的提示中进行新一轮的代码改进;(3) 重复该过程,直到自我验证模块确认任务完成,此时我们将程序提交到技能库(例如 craftStoneShovel()combatZombieWithSword())并向自动课程查询下一个里程碑(图 2)。

实验表明,VOYAGER 展现了强大的上下文终身学习能力。它可以构建一个不断增长的动作程序技能库,这些程序是可重用的、可解释的,并且可以泛化到新任务中。我们在 MineDojo [23](一个开源 Minecraft AI 框架)中系统地评估了 VOYAGER 与其他基于 LLM 的智能体技术(例如 ReAct [29]、Reflexion [30]、AutoGPT [28])的性能。VOYAGER 优于之前的 SOTA,获得的独特物品增加了 3.3×3.3\times,解锁关键科技树里程碑的速度最高提升了 15.3×15.3\times,并且遍历距离增加了 2.3×2.3\times。我们进一步证明,VOYAGER 能够在新的 Minecraft 世界中利用已学习的技能库从零开始解决新任务,而其他方法则难以泛化。

2 方法

VOYAGER 由三个新颖组件组成:(1) 建议开放式探索目标的自动课程(Sec. 2.1),(2) 用于发展日益复杂行为的技能库(Sec. 2.2),以及 (3) 生成用于具身控制的可执行代码的迭代提示机制(Sec. 2.3)。完整提示在附录 Sec. A 中提供。

2.1 自动课程

具身智能体在开放式环境中会遇到各种不同复杂程度的目标。自动课程为开放式探索提供了诸多好处,确保了具有挑战性但可管理的学习过程,培养了智能体学习和探索的好奇心驱动的内在动机,并鼓励发展通用和灵活的解决问题策略 [42–44]。我们的自动课程利用 GPT-4 中包含的互联网规模知识,通过提示它提供源源不断的新任务或挑战。课程以自下而上的方式展开,对探索进度和智能体的当前状态具有相当大的适应性和响应能力(图 3)。随着 VOYAGER 向更难的自主驱动目标前进,它自然会学习各种技能,例如“挖掘钻石”。

图 4:技能库。上:添加新技能。每次 GPT-4 生成并验证一项新技能时,我们都会将其添加到技能库中,该库由向量数据库表示。键是程序描述的嵌入向量(由 GPT-3.5 生成),而值是程序本身。下:技能检索。当面对自动课程提出的新任务时,我们首先利用 GPT-3.5 生成解决任务的一般建议,并将其与环境反馈结合作为查询上下文。随后,我们执行查询以识别前 5 个相关技能。

GPT-4 的输入提示包含几个组件: (1) 鼓励多样化行为并施加约束的指令,例如“我的最终目标是尽可能多地发现多样化的事物……下一个任务不应该太难,因为我可能还没有必要的资源或没有学到足够的技能来完成它。”; (2) 智能体的当前状态,包括库存、装备、附近的方块和实体、生物群系、时间、健康和饥饿条以及位置; (3) 之前完成和失败的任务,反映了智能体的当前探索进度和能力前沿; (4) 额外上下文:我们还利用 GPT-3.5 根据智能体的当前状态和探索进度进行自问自答。由于预算考虑,我们选择使用 GPT-3.5 而不是 GPT-4 来处理标准 NLP 任务。

2.2 技能库

随着自动课程不断提出日益复杂的任务,拥有一个作为学习和进化基础的技能库至关重要。受程序的通用性、可解释性和普适性的启发 [45],我们用可执行代码表示每项技能,这些代码构建了用于完成自动课程提出的特定任务的时间扩展动作。

GPT-4 的输入提示包含以下组件: (1) 代码生成指南,例如“你的函数将被重用于构建更复杂的函数。因此,你应该使其通用且可重用。”; (2) 控制原始 API,以及从技能库中检索到的相关技能,这些对于上下文学习 [36–38] 的良好工作至关重要; (3) 上一轮生成的代码、环境反馈、执行错误和评论,GPT-4 可以据此进行自我改进(Sec. 2.3); (4) 智能体的当前状态,包括库存、装备、附近的方块和实体、生物群系、时间、健康和饥饿条以及位置;

图 5:左:环境反馈。GPT-4 意识到在制作木棍之前需要 2 个木板。右:执行错误。GPT-4 意识到它应该制作木斧而不是金合欢木斧,因为 Minecraft 中没有金合欢木斧。为简洁起见,我们仅显示部分提示。代码生成的完整提示结构在附录 Sec. A.4 中。

(5) 思维链提示 [46],在代码生成之前进行推理。

我们通过一种新颖的迭代提示机制(Sec. 2.3)迭代地改进程序,将其作为新技能纳入技能库,并按其描述的嵌入进行索引(图 4,上)。对于技能检索,我们使用自生成的任务计划和环境反馈的嵌入来查询技能库(图 4,下)。通过不断扩展和完善技能库,VOYAGER 可以在广泛的任务中学习、适应和超越,不断推动其在开放世界中能力的边界。

2.3 迭代提示机制

我们引入了一种迭代提示机制,通过三种类型的反馈进行自我改进:

(1) 环境反馈,说明程序执行的中间进度(图 5,左)。例如,“我无法制作铁胸甲,因为我需要:7 个更多的铁锭”突出了制作铁胸甲失败的原因。我们在控制原始 API 中使用 bot.chat() 来生成环境反馈,并提示 GPT-4 在代码生成期间也使用此函数; (2) 来自程序解释器的执行错误,揭示程序中的任何无效操作或语法错误,这些对于错误修复很有价值(图 5,右); (3) 用于检查任务成功的自我验证。我们没有为自动课程提出的每个新任务手动编写成功检查器,而是实例化了另一个 GPT-4 智能体进行自我验证。通过向 GPT-4 提供 VOYAGER 的当前状态和任务,我们要求它充当评论者 [47–49] 并告知我们程序是否完成了任务。此外,如果任务失败,它会通过建议如何完成任务来提供评论(图 6)。因此,我们的自我验证比自我反思 [30] 更全面,因为它既检查成功又反思错误。

在每一轮代码生成期间,我们执行生成的程序以从代码解释器获取环境反馈和执行错误,这些反馈和错误被纳入 GPT-4 的下一轮代码改进提示中。这个迭代过程重复进行,直到自我验证确认任务完成,此时我们将此新技能添加到技能库并向自动课程询问新目标(图 2)。如果智能体在 4 轮代码生成后卡住,那么我们向课程查询另一个任务。这种迭代提示方法显著改进了用于具身控制的程序合成,使 VOYAGER 能够在无需人工干预的情况下持续获取多种技能。

图 6:自我验证示例。为简洁起见,我们仅显示部分提示。有关完整提示结构,请参阅附录 Sec. A.5。

3 实验

3.1 实验设置

我们利用 OpenAI 的 gpt-4-0314 [35] 和 gpt-3.5-turbo-0301 [50] API 进行文本补全,以及 text-embedding-ada-002 [51] API 进行文本嵌入。我们将所有温度设置为 0,自动课程除外,它使用温度 = 0.1 以鼓励任务多样性。我们的模拟环境建立在 MineDojo [23] 之上,并利用 Mineflayer [52] JavaScript API 进行电机控制。更多详细信息,请参阅附录 Sec. B.1。

3.2 基线

由于没有现成的基于 LLM 的 Minecraft 智能体,我们尽最大努力选择了许多代表性算法作为基线。这些方法最初仅设计用于无具身的 NLP 任务,因此我们必须重新解释它们,使其在 MineDojo 中可执行并与我们的实验设置兼容:

ReAct [29] 通过 LLM 生成推理轨迹和动作计划,使用思维链提示 [46]。我们为它提供了我们的环境反馈和智能体状态作为观察结果。 Reflexion [30] 建立在 ReAct [29] 之上,通过自我反思来推断更直观的未来动作。我们为它提供了执行错误和我们的自我验证模块。 AutoGPT [28] 是一种流行的软件工具,它通过将高级目标分解为多个子目标并在 ReAct 风格的循环中执行它们来自动化 NLP 任务。我们通过使用 GPT-4 进行任务分解并为它提供智能体状态、环境反馈和执行错误作为子目标执行的观察结果来重新实现 AutoGPT。与 VOYAGER 相比,AutoGPT 缺乏用于积累知识的技能库、用于评估任务成功的自我验证以及用于开放式探索的自动课程。

请注意,我们不直接与以 Minecraft 屏幕像素为输入并输出低级控制的先前方法进行比较 [53–55]。这不会是苹果对苹果的比较,因为我们依赖高级 Mineflayer [52] API 来控制智能体。我们的工作重点是推动 GPT-4 在终身具身智能体学习方面的极限,而不是解决 3D 感知或感觉运动控制问题。VOYAGER 是正交的,可以与基于梯度的方法(如 VPT [8])结合使用,只要控制器提供代码 API。我们在表 A.2 中对 VOYAGER 和之前的 Minecraft 智能体进行了系统级比较。

表 1:科技树掌握情况。分数表示三次总试验中成功的试验次数。0/3 表示该方法在最大提示迭代次数 (160) 内未能解锁科技树的某个级别。数字是三次试验的平均提示迭代次数。迭代次数越少,方法越高效。

图 7:地图覆盖范围:Minecraft 地图的鸟瞰图。与基线相比,VOYAGER 能够遍历 2.3\times 更长的距离,同时穿越多样的地形。

3.3 评估结果

我们系统地评估了 VOYAGER 和基线在探索性能、科技树掌握、地图覆盖范围以及在新世界中对新任务的零样本泛化能力。

显著更好的探索。 探索性能的结果如图 1 所示。VOYAGER 的优越性体现在它能够持续取得新进展,在 160 次提示迭代内发现了 63 个独特物品,与其对应物相比,新颖物品数量增加了 3.3×3.3\times。另一方面,AutoGPT 在发现新物品方面明显滞后,而 ReAct 和 Reflexion 难以取得重大进展,因为开放式探索目标的抽象性质在没有适当课程的情况下很难执行。

一致的科技树掌握。 Minecraft 科技树测试了智能体制作和使用工具层次结构的能力。通过这棵树(木制工具 \rightarrow 石制工具 \rightarrow 铁制工具 \rightarrow 钻石工具)需要智能体掌握系统性和组合性技能。与基线相比,VOYAGER 解锁木制级别的速度快 15.3×15.3\times(就提示迭代次数而言),石制级别快 8.5×8.5\times,铁制级别快 6.4×6.4\times,并且 VOYAGER 是唯一解锁科技树钻石级别的智能体(图 2 和表 1)。这强调了自动课程的有效性,它始终提出适当复杂性的挑战,以促进智能体的进步。

广泛的地图遍历。 VOYAGER 通过穿越各种地形,能够导航比基线长 2.3×2.3\times 的距离,而基线智能体通常发现自己局限于局部区域,这严重阻碍了它们发现新知识的能力(图 7)。

表 2:对未见任务的零样本泛化。分数表示三次总尝试中成功的试验次数。0/3 表示该方法在最大提示迭代次数 (50) 内未能解决任务。数字是三次试验的平均提示迭代次数。迭代次数越少,方法越高效。

图 8:对未见任务的零样本泛化。我们可视化了每种方法在两个任务上的中间进度。有关其他两个任务,请参阅附录 Sec. B.4.3。我们没有绘制 ReAct 和 Reflexion,因为它们没有取得任何有意义的进展。

对未见任务的高效零样本泛化。 为了评估零样本泛化,我们清除了智能体的库存,将其重置为一个新实例化的世界,并用未见过的任务对其进行测试。对于 VOYAGER 和 AutoGPT,我们都利用 GPT-4 将任务分解为一系列子目标。表 2 和图 8 显示 VOYAGER 可以持续解决所有任务,而基线在 50 次提示迭代内无法解决任何任务。值得注意的是,我们从终身学习中构建的技能库不仅增强了 VOYAGER 的性能,还为 AutoGPT 提供了提升。这表明技能库作为一种多功能工具,可以很容易地被其他方法采用,有效地充当即插即用的资产来增强性能。

3.4 消融研究

我们在 VOYAGER 中消融了 6 个设计选择(自动课程、技能库、环境反馈、执行错误、自我验证和用于代码生成的 GPT-4),并研究了它们对探索性能的影响(有关每个消融变体的详细信息,请参阅附录 Sec. B.3)。结果如图 9 所示。我们强调以下关键发现:

  • 自动课程对智能体的持续进步至关重要。 如果课程被随机课程替换,发现的物品数量会下降 93%,因为某些任务如果乱序尝试可能会太具挑战性。另一方面,手动设计的课程需要大量的 Minecraft 专业知识,并且没有考虑智能体的实时情况。与我们的自动课程相比,它在实验结果中表现不佳。
  • 没有技能库的 VOYAGER 在后期阶段表现出平台期趋势。 这强调了技能库在 VOYAGER 中发挥的关键作用。它有助于创建更复杂的动作,并通过鼓励在旧技能的基础上构建新技能来稳步推动智能体的边界。

图 9:左:自动课程、技能库和 GPT-4 的消融研究。GPT-3.5 意味着用 GPT-3.5 替换 GPT-4 进行代码生成。VOYAGER 优于所有替代方案,证明了每个组件的关键作用。右:迭代提示机制的消融研究。VOYAGER 超过了所有其他选项,从而突出了迭代提示机制中每种类型反馈的重要意义。

图 10:VOYAGER 在人类反馈下构建 3D 结构。从左到右展示了整合人类输入的建筑设计进度。

  • 自我验证是所有反馈类型中最重要的一种。 移除该模块会导致发现的物品数量显著下降(73%-73\%)。自我验证是决定何时转向新任务或重新尝试之前未成功任务的关键机制。
  • GPT-4 在代码生成方面显著优于 GPT-3.5,获得的独特物品增加了 5.7×5.7\times,因为 GPT-4 在编码能力上表现出质的飞跃。 这一发现证实了文献中的最新研究 [56, 57]。

3.5 来自人类的多模态反馈

VOYAGER 目前不支持视觉感知,因为在撰写本文时,可用的 GPT-4 API 版本仅支持文本。然而,VOYAGER 有潜力通过多模态感知模型 [58, 59] 进行增强,以实现更令人印象深刻的任务。我们证明,在人类反馈下,VOYAGER 能够在 Minecraft 中构建复杂的 3D 结构,例如下界传送门和房屋(图 10)。有两种整合人类反馈的方法:

(1) 人类作为评论者(相当于 VOYAGER 的自我验证模块):人类向 VOYAGER 提供视觉评论,允许它修改上一轮的代码。这种反馈对于纠正 VOYAGER 无法直接感知的 3D 结构空间细节中的某些错误至关重要。 (2) 人类作为课程(相当于 VOYAGER 的自动课程模块):人类将复杂的建筑任务分解为更小的步骤,指导 VOYAGER 逐步完成它们。这种方法提高了 VOYAGER 处理更复杂 3D 建筑任务的能力。

4 局限性和未来工作

成本。 GPT-4 API 产生巨大的成本。它比 GPT-3.5 贵 15×15\times。尽管如此,VOYAGER 需要 GPT-4 在代码生成质量上的质的飞跃(图 9),这是 GPT-3.5 和开源 LLM 无法提供的 [60]。

不准确性。 尽管有迭代提示机制,但仍有智能体卡住并无法生成正确技能的情况。自动课程有灵活性在稍后重新尝试此任务。偶尔,自我验证模块也可能失败,例如无法识别蜘蛛丝作为击败蜘蛛的成功信号。

幻觉。 自动课程偶尔会提出无法实现的任务。例如,它可能会要求智能体制作“铜剑”或“铜胸甲”,这些物品在游戏中并不存在。幻觉也会在代码生成过程中发生。例如,GPT-4 倾向于使用圆石作为燃料输入,尽管它是游戏中无效的燃料来源。此外,它可能会调用提供的控制原始 API 中不存在的函数,从而导致代码执行错误。

我们相信,GPT API 模型的改进以及微调开源 LLM 的新颖技术将在未来克服这些局限性。

5 相关工作

Minecraft 中的决策智能体。 Minecraft 是一个开放式的 3D 世界,具有极其灵活的游戏机制,支持广泛的活动。建立在著名的 Minecraft 基准测试 [23, 61–65] 之上,Minecraft 学习算法可以分为两类:1) 低级控制器:许多先前的工作利用分层强化学习从人类演示中学习 [66–68]。Kanitscheider 等人 [14] 设计了一个基于成功率的课程,但其目标仅限于策划的物品。MineDojo [23] 和 VPT [8] 利用 YouTube 视频进行大规模预训练。另一方面,DreamerV3 [69] 学习了一个世界模型来探索环境并收集钻石。2) 高级规划器:Volum 等人 [70] 利用 Codex [41] 进行少样本提示来生成可执行策略,但它们需要额外的人工交互。最近的工作利用 LLM 作为 Minecraft 中的高级规划器,通过遵循 Minecraft 配方将高级任务分解为几个子目标 [55, 53, 71],因此缺乏完全的探索灵活性。像这些后来的工作一样,VOYAGER 也通过提示 GPT-4 使用 LLM 作为高级规划器,并利用 Mineflayer [52] 作为低级控制器,遵循 Volum 等人 [70] 的方法。与先前工作不同,VOYAGER 采用了一种以自下而上方式展开的自动课程,由好奇心驱动,因此实现了开放式探索。

用于智能体规划的大语言模型。 受 LLM 强大的涌现能力(如零样本提示和复杂推理 [72, 37, 38, 36, 73, 74])的启发,具身智能体研究 [75–78] 见证了 LLM 在规划目的上的利用显著增加。最近的努力大致可以分为两组。1) 用于机器人学习的大语言模型:许多先前的工作应用 LLM 为机器人规划生成子目标 [27, 27, 25, 79, 80]。Inner Monologue [26] 将环境反馈纳入 LLM 的机器人规划中。Code as Policies [16] 和 ProgPrompt [22] 直接利用 LLM 生成可执行的机器人策略。VIMA [19] 和 PaLM-E [59] 微调预训练的 LLM 以支持多模态提示。2) 用于文本智能体的大语言模型:ReAct [29] 利用思维链提示 [46],并使用 LLM 生成推理轨迹和特定于任务的动作。Reflexion [30] 建立在 ReAct [29] 之上,通过自我反思来增强推理。AutoGPT [28] 是一种流行的工具,它通过制定多个子目标的课程来完成高级目标,同时结合了 ReAct [29] 的推理和行动循环,从而自动化 NLP 任务。DERA [81] 将任务框架化为两个 GPT-4 [35] 智能体之间的对话。Generative Agents [82] 利用 ChatGPT [50] 通过将智能体的经验存储为记忆并检索它们进行规划来模拟人类行为,但其智能体动作不可执行。SPRING [83] 是一项并发工作,它使用 GPT-4 从游戏手册中提取游戏机制,并据此回答排列在有向无环图中的问题并预测下一个动作。所有这些工作都缺乏用于发展更复杂行为的技能库,而这对于 VOYAGER 在终身学习中的成功至关重要。

带执行的代码生成。 代码生成一直是 NLP 中的一个长期挑战 [41, 84, 85, 73, 37],各种工作利用执行结果来改进程序合成。执行引导的方法利用中间执行结果来指导程序搜索 [86–88]。另一条研究路线利用多数投票根据执行性能选择候选者 [89, 90]。此外,LEVER [91] 训练了一个验证器,根据执行结果区分和拒绝不正确的程序。另一方面,CLAIRIFY [92] 生成用于规划化学实验的代码,并利用基于规则的验证器迭代地向 LLM 提供错误反馈。VOYAGER 通过将环境反馈、执行错误和自我验证(以评估任务成功)整合到用于具身控制的迭代提示机制中,从而与这些工作区分开来。

6 结论

在这项工作中,我们介绍了 VOYAGER,这是首个由 LLM 驱动的具身终身学习智能体,它利用 GPT-4 持续探索世界、发展日益复杂的技能,并在无需人工干预的情况下持续做出新的发现。VOYAGER 在发现新颖物品、解锁 Minecraft 科技树、遍历多样化地形以及将其学习到的技能库应用于新实例化的世界中的未见任务方面表现出卓越的性能。VOYAGER 是开发强大的通用智能体的起点,无需调整模型参数。

7 更广泛的影响

我们的研究是在 Minecraft 中进行的,这是一个安全且无害的 3D 视频游戏环境。虽然 VOYAGER 被设计为普遍适用于其他领域(如机器人技术),但其在物理机器人上的应用将需要额外的关注,并由人类实施安全约束,以确保负责任和安全的部署。

8 致谢

我们非常感谢 Ziming Zhu、Kaiyu Yang、Rafał Kocielnik、Colin White、Or Sharir、Sahin Lale、De-An Huang、Jean Kossaifi、Yuncong Yang、Charles Zhang、Minchao Huang 以及许多其他同事和朋友提供的有益反馈和深刻讨论。这项工作是在 Guanzhi Wang 在 NVIDIA 实习期间完成的。Guanzhi Wang 得到了 Caltech 计算与数学科学 Kortschak 奖学金的支持。


附录

A 方法

A.1 VOYAGER 算法

伪代码 1:VOYAGER 算法。

python
def voyager( environment, # 使用代码作为动作空间的环境 curriculum_agent, # 用于提出下一个任务的课程智能体 action_agent, # 用于代码生成的动作智能体 critic_agent, # 用于自我验证的评论智能体 skill_manager, # 用于添加新技能和技能检索的技能管理器 ): agent_state = environment.reset() while True: exploration_progress = ( curriculum_agent.get_exploration_progress( curriculum_agent.get_completed_tasks(), curriculum_agent.get_failed_tasks(), ) ) task = curriculum_agent.propose_next_task( agent_state, exploration_progress ) code = None environment_feedback = None execution_errors = None critique = None success = False # 在转向下一个任务之前最多尝试 4 轮 for i in range(4): skills = skill_manager.retrieve_skills( task, environment_feedback ) code = action_agent.generate_code( task, code, environment_feedback, execution_errors, critique, skills, ) ( agent_state, environment_feedback, execution_errors, ) = environment.step(code) success, critique = critic_agent.check_task_success( task, agent_state ) if success: break if success: skill_manager.add_skill(code) curriculum_agent.add_completed_task(task) else: curriculum_agent.add_failed_task(task)
A.2 提示

GPT-4 和 GPT-3.5 为用户提供了在三个选项中指定每个提示消息角色的能力:

  • 系统 (System):指导整个对话中模型行为的高级指令。它设定了交互的总体基调和目标。
  • 用户 (User):指导助手进行下一次立即响应的详细指令。
  • 助手 (Assistant):模型生成的响应消息。

有关更多详细信息,请参阅 https://platform.openai.com/docs/guides/chat/introduction。 为了节省令牌使用量,我们不是进行多轮对话,而是连接系统提示和用户提示以获得每个助手的响应。

A.3 自动课程
A.3.1 提示中的组件

GPT-4 的输入提示包含几个组件: (1) 鼓励多样化行为并施加约束的指令(以便提出的任务是可实现和可验证的):请参阅 Sec. A.3.4 获取完整提示; (2) 智能体的当前状态:

  • 库存 (Inventory):物品计数的字典,例如,{'cobblestone': 4, 'furnace': 1, 'stone_pickaxe': 1, 'oak_planks': 7, 'dirt': 6, 'wooden_pickaxe': 1, 'crafting_table': 1, 'raw_iron': 4, 'coal': 1};
  • 装备 (Equipment):智能体装备的盔甲或武器;
  • 附近方块 (Nearby blocks):智能体 32 个方块距离内的一组方块名称,例如,'dirt', 'water', 'spruce_planks', 'grass_block', 'dirt_path', 'sugar_cane', 'fern';
  • 最近看到的其他方块 (Other blocks that are recently seen):不在附近或库存中的方块;
  • 附近实体 (Nearby entities):智能体 32 个方块距离内的一组实体名称,例如,'pig', 'cat', 'villager', 'zombie';
  • 智能体看到的箱子列表 (A list of chests that are seen by the agent):箱子是智能体可以存放物品的外部容器。如果箱子之前未打开,其内容为“Unknown”。否则,每个箱子内的物品都会显示给智能体。
  • 生物群系 (Biome):例如,'plains', 'flower_forest', 'meadow', 'river', 'beach', 'forest', 'snowy_slopes', 'frozen_peaks', 'old_growth_birch_forest', 'ocean', 'sunflower_plains', 'stony_shore';
  • 时间 (Time):'sunrise', 'day', 'noon', 'sunset', 'night', 'midnight' 之一;
  • 健康和饥饿条 (Health and hunger bars):最大值为 20;
  • 位置 (Position):智能体在 Minecraft 世界中的 3D 坐标 (x,y,z)(x, y, z); (3) 之前完成和失败的任务; (4) 额外上下文:请参阅 Sec. A.3.2; (5) 思维链提示 [46] 作为响应:我们要求 GPT-4 首先推理当前进度,然后建议下一个任务。
A.3.2 额外上下文

我们利用 GPT-3.5 进行自问自答以提供额外上下文。每个问题都与一个概念配对,该概念用于从维基知识库 [23] 中检索最相关的文档。我们将文档内容提供给 GPT-3.5 进行自问自答。在实践中,使用维基知识库是可选的,因为 GPT-3.5 已经对 Minecraft 游戏机制有很好的理解。但是,如果 GPT-3.5 没有在该特定领域进行预训练,外部知识库就会变得有利。请参阅 Sec. A.3.4 获取完整提示。

A.3.3 预热计划

在实践中,我们采用预热计划,根据智能体完成的任务数量,逐步将智能体的状态和额外上下文纳入提示中。这确保了提示在探索过程中接触到越来越多的信息,从而从基本技能开始,逐步向更复杂和多样化的技能推进。我们在所有实验中使用的预热设置如表 A.1 所示。

提示中的信息完成多少任务后
核心库存(仅包括 log, planks, stick, crafting table, furnace, dirt, coal, pickaxe, sword, 和 axe)0
装备0
附近方块0
位置0
附近实体5
完整库存
最近看到的其他方块10
生物群系10
健康条15
饥饿条15
时间15
额外上下文15

A.3.4 完整提示

提示 1:自动课程的完整系统提示。问答对列表代表额外上下文。

text
你是一个乐于助人的助手,告诉我接下来在 Minecraft 中要做的直接任务。我的最终目标是尽可能多地发现多样化的事物,完成尽可能多样的任务,并成为世界上最好的 Minecraft 玩家。 我将为你提供以下信息: 问题 1:... 答案:... 问题 2:... 答案:... 问题 3:... 答案:... ... 生物群系:... 时间:... 附近方块:... 最近看到的其他方块:... 附近实体(从近到远):... 健康:高于 15 表示我处于健康状态。 饥饿:高于 15 表示我不饿。 位置:... 装备:如果我的库存中有更好的盔甲,你应该要求我装备它。 库存 (xx/36):... 箱子:你可以要求我从这些箱子中存入或取出物品。可能还有一些未知的箱子,你应该要求我打开并检查未知箱子内的物品。 到目前为止完成的任务:... 太难而失败的任务:... 你必须遵循以下标准: 1) 你应该充当导师,根据我目前的学习进度指导我完成下一个任务。 2) 请非常具体地说明我需要收集什么资源、需要制作什么,或者需要杀死什么生物。 3) 下一个任务应遵循简洁的格式,例如“挖掘 [数量] [方块]”、“制作 [数量] [物品]”、“冶炼 [数量] [物品]”、“杀死 [数量] [生物]”、“烹饪 [数量] [食物]”、“装备 [物品]”等。它应该是一个短语。不要同时提出多个任务。不要提及其他任何事情。 4) 下一个任务不应该太难,因为我可能还没有必要的资源或没有学到足够的技能来完成它。 5) 下一个任务应该是新颖且有趣的。我应该寻找稀有资源,使用更好的材料升级我的装备和工具,并发现新事物。我不应该一遍又一遍地做同样的事情。 6) 如果我需要收集更多资源来完成更困难的任务,我有时可能需要重复一些任务。仅在必要时重复任务。 7) 即使在晚上,也不要让我建造或挖掘避难所。我想探索世界并发现新事物。我不想待在一个地方。 8) 应避免需要玩家状态之外的信息来验证的任务。例如,“放置 4 个火把”和“挖掘一个 2x1x2 的洞”并不理想,因为它们需要屏幕上的视觉确认。应避免所有放置、建造、种植和交易任务。不要提出以这些关键词开头的任务。 你只能按照以下描述的格式进行响应: 响应格式: 推理:根据我上面列出的信息,推理下一个任务应该是什么。 任务:下一个任务。 这是一个示例响应: 推理:库存现在是空的,砍倒一棵树以获得一些木头。 任务:获得一个原木。

提示 2:提问的完整系统提示。我们提供好和坏的示例作为少样本范例。

text
你是一个乐于助人的助手,通过提问来帮助我决定接下来在 Minecraft 中要做的直接任务。我的最终目标是尽可能多地发现事物,完成尽可能多的任务,并成为世界上最好的 Minecraft 玩家。 我将为你提供以下信息: 生物群系:... 时间:... 附近方块:... 最近看到的其他方块:... 附近实体(从近到远):... 健康:... 饥饿:... 位置:... 装备:... 库存 (xx/36):... 箱子:... 到目前为止完成的任务:... 太难而失败的任务:... 你必须遵循以下标准: 1) 你应该至少提出 5 个问题(但不多于 10 个问题)来帮助我决定接下来要做的直接任务。每个问题后面都应跟上该问题所涉及的概念。 2) 你的问题应该针对 Minecraft 中的一个概念。 坏示例(问题太笼统): 问题:玩 Minecraft 的最好方法是什么? 概念:未知 坏示例(斧头仍然笼统,你应该指定斧头的类型,例如木斧): 问题:使用斧头收集资源有什么好处? 概念:斧头 好示例: 问题:如何制作木镐? 概念:木镐 3) 你的问题应该是自包含的,不需要任何上下文。 坏示例(问题需要我当前生物群系的上下文): 问题:我可以在我当前的生物群系中找到什么方块? 概念:未知 坏示例(问题需要我当前库存的上下文): 问题:你目前最需要什么资源? 概念:未知 坏示例(问题需要我当前库存的上下文): 问题:你有任何黄金或绿宝石资源吗? 概念:黄金 坏示例(问题需要我附近实体的上下文): 问题:你能看到附近有什么动物可以杀死作为食物吗? 概念:食物 坏示例(问题需要我附近方块的上下文): 问题:附近有水源吗? 概念:水 好示例: 问题:我可以在稀疏丛林中找到什么方块? 概念:稀疏丛林 4) 不要问关于建筑任务的问题(例如建造避难所),因为它们对我来说太难了。 假设你当前的生物群系是稀疏丛林。你可以问这样的问题: 问题:我可以在稀疏丛林中找到什么物品? 概念:稀疏丛林 问题:我可以在稀疏丛林中找到什么生物? 概念:稀疏丛林 假设你看到附近有一个苦力怕,而你之前没有击败过苦力怕。你可以问这样的问题: 问题:如何击败苦力怕? 概念:苦力怕 假设你上次完成的任务是“制作木镐”。你可以问这样的问题: 问题:制作木镐后我可以做哪些建议的任务? 概念:木镐 这里还有更多问题和概念示例: 问题:我可以在稀疏丛林中找到什么矿石? 概念:稀疏丛林 (上面的概念不应该是“矿石”,因为我需要查找“稀疏丛林”页面以找出我在稀疏丛林中可以找到什么矿石) 问题:如何在稀疏丛林中获得食物? 概念:稀疏丛林 (上面的概念不应该是“食物”,因为我需要查找“稀疏丛林”页面以找出我在稀疏丛林中可以获得什么食物) 问题:你如何使用熔炉来升级你的装备并制作有用的物品? 概念:熔炉 问题:如何获得钻石矿石? 概念:钻石矿石 问题:使用石镐比木镐有什么好处? 概念:石镐 问题:你可以使用木板和木棍制作什么工具? 概念:木板 你只能按照以下描述的格式进行响应: 响应格式: 推理:... 问题 1:... 概念 1:... 问题 2:... 概念 2:... 问题 3:... 概念 3:... 问题 4:... 概念 4:... 问题 5:... 概念 5:... ...

提示 3:回答问题的完整系统提示。上下文代表来自维基知识库的可选内容。

text
你是一个乐于助人的助手,回答我关于 Minecraft 的问题。 我将为你提供以下信息: 问题:... 你将根据上下文(仅在可用且有帮助时)和你自己对 Minecraft 的知识来回答问题。 1) 以“答案:”开始你的回答。 2) 如果你不知道答案,回答“答案:未知”。

A.4 技能库

A.4.1 提示中的组件

GPT-4 的输入提示包含以下组件: (1) 代码生成指南:请参阅 Sec A.4.2 获取完整提示; (2) 我们实现的控制原始 API:这些 API 具有双重目的:它们演示了 Mineflayer API 的用法,并且可以直接由 GPT-4 调用。

  • exploreUntil(bot, direction, maxTime = 60, callback):允许智能体在固定方向上探索 maxTime。callback 是由智能体实现的停止条件,用于确定何时停止探索;
  • mineBlock(bot, name, count = 1):挖掘并收集 32 个方块距离内指定数量的方块;
  • craftItem(bot, name, count = 1):在附近有工作台的情况下制作物品;
  • placeItem(bot, name, position):将方块放置在指定位置;
  • smeltItem(bot, itemName, fuelName, count = 1):使用指定的燃料冶炼物品。附近必须有熔炉;
  • killMob(bot, mobName, timeout = 300):攻击生物并收集其掉落的物品;
  • getItemFromChest(bot, chestPosition, itemsToGet):移动到指定位置的箱子并从箱子中获取物品;
  • depositItemIntoChest(bot, chestPosition, itemsToDeposit):移动到指定位置的箱子并将物品存入箱子; (3) Mineflayer 提供的控制原始 API:
  • await bot.pathfinder.goto(goal):前往特定位置。请参阅下文了解如何设置目标;
  • new GoalNear(x, y, z, range):将机器人移动到指定方块指定范围内的方块;
  • new GoalXZ(x, z):用于没有特定 Y 级别的长程目标;
  • new GoalGetToBlock(x, y, z):不进入方块,而是直接邻近它。对于钓鱼、耕作、装满桶和使用床很有用;
  • new GoalFollow(entity, range):在指定范围内跟随指定的实体;
  • new GoalPlaceBlock(position, bot.world, {}):定位机器人以放置方块;
  • new GoalLookAtBlock(position, bot.world, {}):路径指向一个位置,在该位置可以看到方块的一个面;
  • bot.isABed(bedBlock):如果 bedBlock 是床,则返回 true;
  • bot.blockAt(position):返回位置处的方块;
  • await bot.equip(item, destination):将物品装备到指定目的地。目的地必须是“hand”、“head”、“torso”、“legs”、“feet”、“off-hand”之一;
  • await bot.consume():消耗机器人手中的物品。你必须先装备物品才能消耗。对于吃食物、喝药水等很有用;
  • await bot.fish():让机器人钓鱼。在调用此函数之前,你必须先到达水方块并装备钓鱼竿。机器人在钓到鱼后会自动停止钓鱼;
  • await bot.sleep(bedBlock):睡到日出。你必须先到达床方块;
  • await bot.activateBlock(block):这与游戏中的右键点击方块相同。对于按钮、门等很有用。你必须先到达方块;
  • await bot.lookAt(position):看向指定位置。在看向它之前,你必须靠近该位置。要用水桶装水,你必须先看向它;
  • await bot.activateItem():这与右键点击以使用机器人手中的物品相同。对于使用水桶等很有用。你必须先装备物品才能激活;
  • await bot.useOn(entity):这与右键点击游戏中的实体相同。对于剪羊毛等很有用。你必须先到达实体; (4) 从技能库中检索到的技能; (5) 上一轮生成的代码; (6) 环境反馈:提示中的聊天记录; (7) 执行错误; (8) 来自自我验证模块的评论; (9) 智能体的当前状态:请参阅 Sec. A.3.1 获取智能体状态的每个元素; (10) 自动课程提出的任务; (11) 任务上下文:我们提示 GPT-3.5 询问关于如何解决任务的一般建议。在实践中,这部分由自动课程处理,因为它有一个系统的问答机制(Sec. A.3.2); (12) 思维链提示 [46] 作为响应:我们要求 GPT-4 首先解释上一轮代码失败的原因,然后给出完成任务的分步计划,最后生成代码。请参阅 Sec. A.4.2 获取完整提示。

A.4.2 完整提示

提示 4:代码生成的完整系统提示。

text
你是一个乐于助人的助手,编写 Mineflayer javascript 代码来完成我指定的任何 Minecraft 任务。 这里有一些用 Mineflayer API 编写的有用程序。 /* 探索直到找到铁矿石,使用 Vec3(0, -1, 0),因为铁矿石通常在地下 await exploreUntil(bot, new Vec3(0, -1, 0), 60, () => { const iron_ore = bot.findBlock({ matching: mcData.blocksByName["iron_ore"].id, maxDistance: 32, }); return iron_ore; }); 探索直到找到猪,使用 Vec3(1, 0, 1),因为猪通常在地面上 let pig = await exploreUntil(bot, new Vec3(1, 0, 1), 60, () => { const pig = bot.nearestEntity((entity) => { return ( entity.name === "pig" && entity.position.distanceTo(bot.entity.position) < 32 ); }); return pig; }); */ async function exploreUntil(bot, direction, maxTime = 60, callback) { /* 此函数的实现已省略。 direction: Vec3,只能包含 -1, 0 或 1 的值 maxTime: number,探索的最大时间 callback: function,早期停止条件,每秒调用一次,如果返回值不为 null,探索将停止 Return: 如果探索超时则返回 null,否则返回 callback 的返回值 */ } // 挖掘 3 个圆石:mineBlock(bot, "stone", 3); async function mineBlock(bot, name, count = 1) { const blocks = bot.findBlocks({ matching: (block) => { return block.name === name; }, maxDistance: 32, count: count, }); const targets = []; for (let i = 0; i < Math.min(blocks.length, count); i++) { targets.push(bot.blockAt(blocks[i])); } await bot.collectBlock.collect(targets, { ignoreNoPath: true }); } // 从 2 个原木制作 8 个橡木板(执行该配方 2 次): craftItem(bot, "oak_planks", 2); // 在调用此函数之前,你必须放置一个工作台 async function craftItem(bot, name, count = 1) { const item = mcData.itemsByName[name]; const craftingTable = bot.findBlock({ matching: mcData.blocksByName.crafting_table.id, maxDistance: 32, }); await bot.pathfinder.goto( new GoalLookAtBlock(craftingTable.position, bot.world) ); const recipe = bot.recipesFor(item.id, null, 1, craftingTable)[0]; await bot.craft(recipe, count, craftingTable); } // 在玩家附近放置一个工作台,Vec3(1, 0, 0) 只是一个示例,你不应该总是使用它:placeItem(bot, "crafting_table", bot.entity.position.offset(1, 0, 0)); async function placeItem(bot, name, position) { const item = bot.inventory.findInventoryItem(mcData.itemsByName[name].id); // 找到一个参考方块 const faceVectors = [ new Vec3(0, 1, 0), new Vec3(0, -1, 0), new Vec3(1, 0, 0), new Vec3(-1, 0, 0), new Vec3(0, 0, 1), new Vec3(0, 0, -1), ]; let referenceBlock = null; let faceVector = null; for (const vector of faceVectors) { const block = bot.blockAt(position.minus(vector)); if (block?.name !== "air") { referenceBlock = block; faceVector = vector; break; } } // 你必须先前往你想放置的方块位置 await bot.pathfinder.goto(new GoalPlaceBlock(position, bot.world, {})); // 你必须在调用 placeBlock 之前装备物品 await bot.equip(item, "hand"); await bot.placeBlock(referenceBlock, faceVector); } // 使用 1 个橡木板作为燃料将 1 个铁矿石冶炼成 1 个铁锭: smeltItem(bot, "raw_iron", "oak_planks"); // 在调用此函数之前,你必须放置一个熔炉 async function smeltItem(bot, itemName, fuelName, count = 1) { const item = mcData.itemsByName[itemName]; const fuel = mcData.itemsByName[fuelName]; const furnaceBlock = bot.findBlock({ matching: mcData.blocksByName.furnace.id, maxDistance: 32, }); await bot.pathfinder.goto( new GoalLookAtBlock(furnaceBlock.position, bot.world) ); const furnace = await bot.openFurnace(furnaceBlock); for (let i = 0; i < count; i++) { await furnace.putFuel(fuel.id, null, 1); await furnace.putInput(item.id, null, 1); // 等待 12 秒让熔炉冶炼物品 await bot.waitForTicks(12 * 20); await furnace.takeOutput(); } await furnace.close(); } // 杀死一只猪并收集掉落的物品:killMob(bot, "pig", 300); async function killMob(bot, mobName, timeout = 300) { const entity = bot.nearestEntity( (entity) => entity.name === mobName && entity.position.distanceTo(bot.entity.position) < 32 ); await bot.pvp.attack(entity); await bot.pathfinder.goto( new GoalBlock(entity.position.x, entity.position.y, entity.position.z) ); } // 获取箱子 (30, 65, 100) 处的火把:getItemFromChest(bot, new Vec3(30, 65, 100), {"torch": 1}); // 无论机器人离箱子多远,此函数都能工作。 async function getItemFromChest(bot, chestPosition, itemsToGet) { await moveToChest(bot, chestPosition); const chestBlock = bot.blockAt(chestPosition); const chest = await bot.openContainer(chestBlock); for (const name in itemsToGet) { const itemByName = mcData.itemsByName[name]; const item = chest.findContainerItem(itemByName.id); await chest.withdraw(item.type, null, itemsToGet[name]); } await closeChest(bot, chestBlock); } // 将火把存入箱子 (30, 65, 100):depositItemIntoChest(bot, new Vec3(30, 65, 100), {"torch": 1}); // 无论机器人离箱子多远,此函数都能工作。 async function depositItemIntoChest(bot, chestPosition, itemsToDeposit) { await moveToChest(bot, chestPosition); const chestBlock = bot.blockAt(chestPosition); const chest = await bot.openContainer(chestBlock); for (const name in itemsToDeposit) { const itemByName = mcData.itemsByName[name]; const item = bot.inventory.findInventoryItem(itemByName.id); await chest.deposit(item.type, null, itemsToDeposit[name]); } await closeChest(bot, chestBlock); } // 检查箱子 (30, 65, 100) 内的物品: checkItemInsideChest(bot, new Vec3(30, 65, 100)); // 你只需要调用此函数一次,无需任何动作即可完成检查箱子内物品的任务。 async function checkItemInsideChest(bot, chestPosition) { await moveToChest(bot, chestPosition); const chestBlock = bot.blockAt(chestPosition); await bot.openContainer(chestBlock); // 如果被要求打开箱子,你必须在打开后关闭它 await closeChest(bot, chestBlock); } await bot.pathfinder.goto(goal); // 一个非常有用的函数。此函数可能会改变你的主手装备。 // 以下是一些你可以使用的目标: new GoalNear(x, y, z, range); // 将机器人移动到指定方块指定范围内的方块。'x', 'y', 'z', 和 'range' 是 'number' new GoalXZ(x, z); // 用于没有特定 Y 级别的长程目标。'x' 和 'z' 是 'number' new GoalGetToBlock(x, y, z); // 不进入方块,而是直接邻近它。对于钓鱼、耕作、装满桶和床很有用。'x', 'y', 和 'z' 是 'number' new GoalFollow(entity, range); // 在指定范围内跟随指定的实体。'entity' 是 'Entity', 'range' 是 'number' new GoalPlaceBlock(position, bot.world, {}); // 定位机器人以放置方块。'position' 是 'Vec3' new GoalLookAtBlock(position, bot.world, {}); // 路径指向一个位置,在该位置可以看到方块的一个面。'position' 是 'Vec3' // 这些是你可以使用的其他 Mineflayer 函数: bot.isABed(bedBlock); // 如果 'bedBlock' 是床,则返回 true bot.blockAt(position); // 返回 'position' 处的方块。'position' 是 'Vec3' // 这些是你可以使用的其他 Mineflayer 异步函数: await bot.equip(item, destination); // 将物品装备到指定目的地。'item' 是 'Item', 'destination' 只能是 "hand", "head", "torso", "legs", "feet", "off-hand" await bot.consume(); // 消耗机器人手中的物品。你必须先装备物品才能消耗。对于吃食物、喝药水等很有用 await bot.fish(); // 让机器人钓鱼。在调用此函数之前,你必须先到达水方块并装备钓鱼竿。机器人在钓到鱼后会自动停止钓鱼 await bot.sleep(bedBlock); // 睡到日出。你必须先到达床方块 await bot.activateBlock(block); // 这与游戏中的右键点击方块相同。对于按钮、门、使用锄头等很有用。你必须先到达方块 await bot.lookAt(position); // 看向指定位置。在看向它之前,你必须靠近该位置。要用水桶装水,你必须先 lookAt。'position' 是 'Vec3' await bot.activateItem(); // 这与右键点击以使用机器人手中的物品相同。对于使用水桶等很有用。你必须先装备物品才能激活 await bot.useOn(entity); // 这与右键点击游戏中的实体相同。对于剪羊毛、装备挽具等很有用。你必须先到达实体 {retrieved_skills} 在每一轮对话中,我将给你 上一轮的代码:... 执行错误:... 聊天记录:... 生物群系:... 时间:... 附近方块:... 附近实体(从近到远): 健康:... 饥饿:... 位置:... 装备:... 库存 (xx/36):... 箱子:... 任务:... 上下文:... 评论:... 你随后应该用以下内容回复我 解释(如果适用):你的计划中是否有遗漏的步骤?为什么代码没有完成任务?聊天记录和执行错误意味着什么? 计划:如何分步完成任务。你应该注意库存,因为它告诉你你有什么。任务完成度检查也基于你的最终库存。 代码: 1) 编写一个以 bot 为唯一参数的异步函数。 2) 尽可能多地重用上述有用程序。 - 使用 'mineBlock(bot, name, count)' 来收集方块。不要直接使用 'bot.dig'。 - 使用 'craftItem(bot, name, count)' 来制作物品。不要直接使用 'bot.craft'。 - 使用 'smeltItem(bot, name, count)' 来冶炼物品。不要直接使用 'bot.openFurnace'。 - 使用 'placeItem(bot, name, position)' 来放置方块。不要直接使用 'bot.placeBlock'。 - 使用 'killMob(bot, name, timeout)' 来杀死生物。不要直接使用 'bot.attack'。 3) 你的函数将被重用于构建更复杂的函数。因此,你应该使其通用且可重用。你不应该对库存做出强假设(因为它可能会在稍后改变),因此你应该始终在检查是否拥有所需物品后再使用它们。如果没有,你应该先收集所需的物品并重用上述有用程序。 4) "上一轮的代码"部分中的函数将不会被保存或执行。不要重用那里列出的函数。 5) 函数外部定义的任何内容都将被忽略,在函数内部定义所有变量。 6) 调用 'bot.chat' 来显示中间进度。 7) 当你找不到东西时,使用 'exploreUntil(bot, direction, maxDistance, callback)'。在挖掘方块或杀死生物之前,你应该经常调用此函数。你应该每次随机选择一个方向,而不是一直使用 (1, 0, 1)。 8) 对于 'bot.findBlocks' 和 'bot.findBlock','maxDistance' 应该始终为 32。不要作弊。 9) 不要编写无限循环或递归函数。 10) 不要使用 'bot.on' 或 'bot.once' 来注册事件监听器。你绝对不需要它们。 11) 以有意义的方式命名你的函数(可以从名称中推断出任务)。 你只能按照以下描述的格式进行响应: 响应格式: 解释:... 计划: 1) ... 2) ... 3) ... ... 代码: ```javascript // 辅助函数(仅在需要时,尽量避免使用它们) ... // 辅助函数之后的主函数 async function yourMainFunctionName(bot) { // ... }

提示 5:生成函数描述的完整系统提示。这在向技能库添加新技能时使用。我们在提示中给出了一个单样本示例。

```text
你是一个乐于助人的助手,编写用 Mineflayer javascript 代码编写的给定函数的描述。
1) 不要提及函数名称。
2) 不要提及关于 'bot.chat' 或辅助函数的任何内容。
3) 主函数之前可能有一些辅助函数,但你只需要描述主函数。
4) 尝试用不超过 6 句话总结该函数。
5) 你的响应应该是一行文本。

例如,如果函数是:
async function mineCobblestone(bot) {
    // 检查木镐是否在库存中,如果不在,制作一个
    let woodenPickaxe = bot.inventory.findInventoryItem(mcData.itemsByName["wooden_pickaxe"].id);
    if (!woodenPickaxe) {
        bot.chat("Crafting a wooden pickaxe.");
        await craftWoodenPickaxe(bot);
        woodenPickaxe = bot.inventory.findInventoryItem(mcData.itemsByName["wooden_pickaxe"].id);
    }
    // 如果木镐存在,则装备它
    if (woodenPickaxe) {
        await bot.equip(woodenPickaxe, "hand");
        // 探索直到找到石块
        await exploreUntil(bot, new Vec3(1, -1, 1), 60, () => {
            const stone = bot.findBlock({
                matching: mcData.blocksByName["stone"].id,
                maxDistance: 32
            });
            if (stone) {
                return true;
            }
        });
        // 使用木镐挖掘 8 个圆石方块
        bot.chat("Found a stone block. Mining 8 cobblestone blocks.");
        await mineBlock(bot, "stone", 8);
        bot.chat("Successfully mined 8 cobblestone blocks.");
        // 保存挖掘 8 个圆石的事件
        bot.save("cobblestone_mined");
    } else {
        bot.chat("Failed to craft a wooden pickaxe. Cannot mine cobblestone.");
    }
}
主函数是 'mineCobblestone'。
那么你会写:
该函数是关于使用木镐挖掘 8 个圆石。首先检查木镐是否在库存中。如果不在,制作一个。如果木镐可用,将其装备在手中。接下来,探索环境直到找到石块。一旦找到石块,使用木镐挖掘总共 8 个圆石方块。

A.4.3 示例

技能库示例 1:craftWoodenPlanks

javascript
async function craftWoodenPlanks(bot) { const logNames = ["oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log"]; const plankNames = ["oak_planks", "birch_planks", "spruce_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "mangrove_planks"]; const logInInventory = logNames.find(logName => bot.inventory.count(mcData.itemsByName[logName].id) > 0); if (!logInInventory) { bot.chat("No wooden log in inventory. Mining a wooden log..."); await mineWoodLog(bot); } const logIndex = logNames.indexOf(logInInventory); const plankName = plankNames[logIndex]; bot.chat(`Crafting 4 ${plankName}...`); await craftItem(bot, plankName, 1); bot.chat(`4 ${plankName} crafted.`); }

技能库示例 2:mineTenCobbledDeepslateBelowY0

javascript
async function mineTenCobbledDeepslateBelowY0(bot) { // 装备铁镐 const ironPickaxe = bot.inventory.findInventoryItem(mcData.itemsByName["iron_pickaxe"].id); await bot.equip(ironPickaxe, "hand"); // 寻找 Y=0 以下的深板岩圆石方块 const cobbledDeepslateBlocks = await exploreUntil(bot, new Vec3(1, -1, 1), 60, () => { const cobbledDeepslate = bot.findBlock({ matching: mcData.blocksByName["cobbled_deepslate"].id, maxDistance: 32, position: pos => pos.y < 0 }); return cobbledDeepslate; }); // 挖掘 10 个深板岩圆石方块 await mineBlock(bot, "cobbled_deepslate", 10); bot.chat("10 cobbled_deepslate mined below Y=0."); }

技能库示例 3:smeltFiveRawIronV2

javascript
async function findSuitablePosition(bot) { const offsets = [new Vec3(1, 0, 0), new Vec3(-1, 0, 0), new Vec3(0, 0, 1), new Vec3(0, 0, -1)]; for (const offset of offsets) { const position = bot.entity.position.offset(offset.x, offset.y, offset.z); const block = bot.blockAt(position); if (block.name === "air") { return position; } } return null; } async function smeltFiveRawIron(bot) { // 检查库存中是否有熔炉 const furnaceItem = bot.inventory.findInventoryItem(mcData.itemsByName.furnace.id); // 如果没有,使用可用的圆石制作一个熔炉 if (!furnaceItem) { await craftFurnace(bot); } // 找到一个合适的位置放置熔炉 const furnacePosition = await findSuitablePosition(bot); if (!furnacePosition) { bot.chat("Could not find a suitable position to place the furnace."); return; } // 将熔炉放置在合适的位置 await placeItem(bot, "furnace", furnacePosition); // 使用可用的煤炭作为燃料冶炼 5 个铁矿石 await smeltItem(bot, "raw_iron", "coal", 5); bot.chat("5 raw iron smelted."); }

技能库示例 4:fillBucketWithWater

javascript
async function fillBucketWithWater(bot) { // 寻找附近的水方块 const waterBlock = await exploreUntil(bot, new Vec3(1, 0, 1), 60, () => { const water = bot.findBlock({ matching: mcData.blocksByName.water.id, maxDistance: 32 }); return water; }); if (!waterBlock) { bot.chat("Could not find water."); return; } // 前往水方块 const adjacentBlock = waterBlock.position.offset(0, 1, 0); await bot.pathfinder.goto( new GoalGetToBlock(adjacentBlock.x, adjacentBlock.y, adjacentBlock.z) ); // 看向水方块 await bot.lookAt(waterBlock.position, true); // 装备水桶 const bucket = bot.inventory.findInventoryItem(mcData.itemsByName.bucket.id); await bot.equip(bucket, "hand"); // 激活水桶以收集水 await bot.activateItem(); bot.chat("Filled the bucket with water."); }

技能库示例 5:catchFiveFishSafely

javascript
async function catchFiveFishSafely(bot) { // 检查机器人库存中是否有钓鱼竿 let fishingRod = bot.inventory.findInventoryItem(mcData.itemsByName.fishing_rod.id); if (!fishingRod) { await craftFishingRod(bot); fishingRod = bot.inventory.findInventoryItem(mcData.itemsByName.fishing_rod.id); .id); } // 寻找附近的水方块 let waterBlock; while (!waterBlock) { waterBlock = await exploreUntil(bot, new Vec3(1, 0, 1), 60, () => { const foundWaterBlock = bot.findBlock({ matching: mcData.blocksByName.water.id, maxDistance: 32 }); return foundWaterBlock; }); if (!waterBlock) { bot.chat("No path to the water block. Trying to find another water block..."); } } // 移动到与水方块相邻的方块 const adjacentBlock = waterBlock.position.offset(0, 1, 0); await bot.pathfinder.goto(new GoalBlock(adjacentBlock.x, adjacentBlock.y, adjacentBlock.z)); // 看向水方块 await bot.lookAt(waterBlock.position); // 装备钓鱼竿 await bot.equip(fishingRod, "hand"); // 在水中钓鱼 5 次 for (let i = 0; i < 5; i++) { try { await bot.fish(); bot.chat(`Fish ${i + 1} caught.`); } catch (error) { if (error.message === "Fishing cancelled") { bot.chat("Fishing was cancelled. Trying again..."); i--; // 重试同一次迭代 } else { throw error; } } } }

A.5 自我验证

A.5.1 提示中的组件

GPT-4 的输入提示包含以下组件: (1) 智能体的状态:我们从智能体的状态中排除了最近看到的其他方块和附近实体,因为它们对于评估任务的完成度没有用处。请参阅 Sec. A.3.1 获取智能体状态的每个元素; (2) 自动课程提出的任务; (3) 任务上下文:我们提示 GPT-3.5 询问关于如何解决任务的一般建议。在实践中,这部分由自动课程处理,因为它有一个系统的问答机制(Sec. A.3.2); (4) 思维链提示 [46] 作为响应:我们要求 GPT-4 最初推理任务的成功或失败,然后输出一个布尔变量指示任务的结果,最后在任务失败时向智能体提供评论。 (5) 用于上下文学习的少样本示例 [36–38]。

A.5.2 完整提示

提示 6:自我验证的完整系统提示。

text
你是一个评估我玩 Minecraft 进度并提供有用指导的助手。 你被要求评估我是否达到了任务要求。超过任务要求也被视为成功,而未能达到要求则需要你提供评论以帮助我改进。 我将为你提供以下信息: 生物群系:任务执行后的生物群系。 时间:当前时间。 附近方块:周围的方块。这些方块尚未收集。但是,这对于某些放置或种植任务很有用。 健康:我当前的健康状况。 饥饿:我当前的饥饿水平。对于进食任务,如果我的饥饿水平为 20.0,那么我成功吃了食物。 位置:我当前的位置。 装备:我最终的装备。对于制作任务,我有时会装备制作好的物品。 库存 (xx/36):我最终的库存。对于挖掘和冶炼任务,你只需要检查库存。 箱子:如果任务要求我将物品放入箱子,你可以在这里找到箱子信息。 任务:我需要完成的目标。 上下文:任务的上下文。 你只能按照以下描述的 JSON 格式进行响应: { "reasoning": "推理", "success": boolean, "critique": "评论", } 确保响应可以被 Python 'json.loads' 解析,例如:没有尾随逗号,没有单引号等。 这里有一些示例: 输入: 库存 (2/36):{'oak_log':2, 'spruce_log':2} 任务:挖掘 3 个原木 响应: { "reasoning": "你需要挖掘 3 个原木。你有 2 个橡木原木和 2 个云杉原木,加起来是 4 个原木。", "success": true, "critique": "" } 输入: 库存 (3/36):{'crafting_table': 1, 'spruce_planks': 6, 'stick': 4} 任务:制作一个木镐 响应: { "reasoning": "你有足够的材料来制作一个木镐,但你没有制作它。", "success": false, "critique": "使用工作台和 3 个云杉木板以及 2 个木棍制作一个木镐。" } 输入: 库存 (2/36):{'raw_iron': 5, 'stone_pickaxe': 1} 任务:挖掘 5 个铁矿石 响应: { "reasoning": "在 Minecraft 中挖掘铁矿石会得到铁矿石。你的库存中有 5 个铁矿石。", "success": true, "critique": "" } 输入: 生物群系:平原 附近方块:石头,泥土,草方块,草,耕地,小麦 库存 (26/36):... 任务:种植 1 个小麦种子。 响应: { "reasoning": "对于种植任务,库存信息是无用的。在附近的方块中,有耕地和小麦,这意味着你成功种植了小麦种子。", "success": true, "critique": "" } 输入: 库存 (11/36):{..., 'rotten_flesh': 1} 任务:杀死 1 个僵尸 上下文:... 响应 { "reasoning": "你的库存中有腐肉,这意味着你成功杀死了一个僵尸。", "success": true, "critique": "" } 输入: 饥饿:20.0/20.0 库存 (11/36):... 任务:吃 1 ... 上下文:... 响应 { "reasoning": "对于所有进食任务,如果玩家的饥饿度为 20.0,则玩家成功吃了食物。", "success": true, "critique": "" } 输入: 附近方块:箱子 库存 (28/36):{'rail': 1, 'coal': 2, 'oak_planks': 13, 'copper_block': 1, 'diorite': 7, 'cooked_beef': 4, 'granite': 22, 'cobbled_deepslate': 23, 'feather': 4, 'leather': 2, 'cooked_chicken': 3, 'white_wool': 2, 'stick': 3, 'black_wool': 1, 'stone_sword': 2, 'stone_hoe': 1, 'stone_axe': 2, 'stone_shovel': 2, 'cooked_mutton': 4, 'cobblestone_wall': 18, 'crafting_table': 1, 'furnace': 1, 'iron_pickaxe': 1, 'stone_pickaxe': 1, 'raw_copper': 12} 箱子: (81, 131, 16):{'andesite': 2, 'dirt': 2, 'cobblestone': 75, 'wooden_pickaxe': 1, 'wooden_sword': 1} 任务:将无用的物品存入 (81, 131, 16) 处的箱子 上下文:... 响应 { "reasoning": "存入后你的库存中有 28 个物品,这超过了 20 个。你需要从你的库存中存入更多物品到箱子中。", "success": false, "critique": "存入更多无用的物品,例如铜块、闪长岩、花岗岩、深板岩圆石、羽毛和皮革,以满足库存中只有 20 个占用槽位的要求。" }

A.6 VOYAGER 与先前工作的系统级比较

我们在表 A.2 中进行了系统级比较。Voyager 脱颖而出,成为唯一结合了自动课程、迭代规划和技能库的方法。此外,它学习玩 Minecraft 而无需任何梯度更新。

VPT [8]DreamerV3 [69]DECKARD [53]DEPS [55]Plan4MC [71]VOYAGER
演示视频视频
奖励稀疏密集稀疏密集
观察仅像素像素 & 元数据像素 & 库存反馈 & 库存像素 & 元数据反馈 & 元数据 & 库存
动作键盘 & 鼠标离散键盘 & 鼠标键盘 & 鼠标离散代码
自动课程✓ (上下文 GPT-4 建议)
迭代规划✓ (3 种反馈)
技能库✓ (预定义)✓ (自生成)
无梯度

B 实验

B.1 实验设置

我们的模拟环境建立在 MineDojo [23] 之上,并利用 Mineflayer [52] JavaScript API 进行电机控制(Sec. A.4.2)。此外,我们将许多 bot.chat() 合并到 Mineflayer 函数中,以提供丰富的环境反馈,并实现各种条件检查以及用于连续执行的 try-catch 异常。如果机器人死亡,它会在最近的地面附近复活,并且其库存被保留以进行不间断的探索。机器人在程序执行后回收其工作台和熔炉。有关详细实现,请参阅我们的代码库。

B.2 基线

ReAct [29] 通过 LLM 生成推理轨迹和动作计划,使用思维链提示 [46]。我们为它提供了我们的环境反馈和智能体状态作为观察结果。ReAct 从零开始进行一轮代码生成,随后进行三轮代码改进。然后重复此过程,直到达到最大提示迭代次数。

Reflexion [30] 建立在 ReAct [29] 之上,通过自我反思来推断更直观的未来动作。我们为它提供了环境反馈、智能体状态、执行错误和我们的自我验证模块。与 ReAct 类似,Reflexion 从零开始进行一轮代码生成,随后进行三轮代码改进。然后重复此过程,直到达到最大提示迭代次数。

AutoGPT [28] 是一种流行的软件工具,它通过将高级目标分解为多个子目标并在 ReAct 风格的循环中执行它们来自动化 NLP 任务。我们通过使用 GPT-4 进行任务分解并为它提供智能体状态、环境反馈和执行错误作为子目标执行的观察结果来重新实现 AutoGPT。与 VOYAGER 相比,AutoGPT 缺乏用于积累知识的技能库、用于评估任务成功的自我验证以及用于开放式探索的自动课程。在每个子目标执行期间,如果没有发生执行错误,我们认为子目标已完成并继续进行下一个。否则,我们改进程序,直到完成三轮代码改进(相当于总共四轮代码生成),然后移动到下一个子目标。如果连续三个子目标没有导致获得新物品,我们通过重新运行任务分解来重新规划。

所有基线的任务都是“探索世界并获得尽可能多的物品”。

ReAct [29]Reflexion [30]AutoGPT [28]VOYAGER
思维链 [46]
自我验证
环境反馈
执行错误
智能体状态
技能库
自动课程

表 A.3:VOYAGER 与基线的比较。

图 A.1:Minecraft 物品图标及对应名称。

B.3 消融

我们在 VOYAGER 中消融了 6 个设计选择(自动课程、技能库、环境反馈、执行错误、自我验证和用于代码生成的 GPT-4),并研究了它们对探索性能的影响。

  • 手动课程:我们用手动设计的挖掘钻石课程替换自动课程:“挖掘 3 个原木”、“制作 1 个工作台”、“制作 1 个木镐”、“挖掘 11 个圆石”、“制作 1 个石镐”、“制作 1 个熔炉”、“挖掘 3 个铁矿石”、“冶炼 3 个铁矿石”、“制作 1 个铁镐”、“挖掘 1 个钻石”。手动课程需要人力设计,且无法扩展用于开放式探索。
  • 随机课程:我们策划了 VOYAGER 获得的 101 个物品,并通过随机选择一个物品作为下一个任务来创建随机课程。
  • 无技能库:我们移除技能库,消除了代码生成的技能检索。
  • 无环境反馈:我们在代码生成的提示中排除了环境反馈(聊天记录)。
  • 无执行错误:我们在代码生成的提示中排除了执行错误。
  • 无自我验证:对于每个任务,我们在没有自我验证的情况下生成代码,并迭代改进程序 3 轮(总共相当于 4 轮代码生成)。
  • GPT-3.5:我们用 GPT-3.5 替换 GPT-4 进行代码生成。我们保留 GPT-4 用于自动课程和自我验证模块。

B.4 评估结果

B.4.1 显著更好的探索

图 1 中每个图标的含义如图 A.1 所示。 我们为每种方法运行三次试验。VOYAGER 在每次试验中收集的物品是

  • 试验 1:'iron_ingot', 'stone_shovel', 'iron_leggings', 'fishing_rod', 'pufferfish', 'oak_log', 'cooked_mutton', 'green_dye', 'flint', 'chest', 'iron_sword', 'string', 'ender_pearl', 'raw_copper', 'crafting_table', 'cactus', 'lapis_lazuli', 'iron_pickaxe', 'copper_ingot', 'stone_pickaxe', 'wooden_hoe', 'scaffolding', 'stick', 'porkchop', 'copper_block', 'gravel', 'grass_block', 'white_bed', 'bone', 'dirt', 'mutton', 'white_wool', 'oak_sapling', 'coal', 'bamboo', 'wooden_pickaxe', 'rotten_flesh', 'cooked_porkchop', 'cod', 'iron_boots', 'lightning_rod', 'diorite', 'water_bucket', 'shears', 'furnace', 'andesite', 'granite', 'bucket', 'wooden_sword', 'sandstone', 'iron_helmet', 'raw_iron', 'sand', 'acacia_log', 'cooked_cod', 'oak_planks', 'azure_bluet', 'iron_shovel', 'acacia_planks', 'shield', 'iron_axe', 'iron_chestplate', 'cobblestone';
  • 试验 2:'iron_ingot', 'tuff', 'stone_shovel', 'iron_leggings', 'fishing_rod', 'cooked_mutton', 'spruce_planks', 'gunpowder', 'amethyst_shard', 'chest', 'string', 'cooked_salmon', 'iron_sword', 'raw_copper', 'crafting_table', 'torch', 'lapis_lazuli', 'iron_pickaxe', 'copper_ingot', 'stone_pickaxe', 'wooden_hoe', 'stick', 'amethyst_block', 'salmon', 'calcite', 'gravel', 'white_bed', 'bone', 'dirt', 'mutton', 'white_wool', 'spyglass', 'coal', 'wooden_pickaxe', 'cod', 'iron_boots', 'lily_pad', 'cobbled_deepslate', 'lightning_rod', 'snowball', 'stone_axe', 'smooth_basalt', 'diorite', 'water_bucket', 'furnace', 'andesite', 'bucket', 'granite', 'shield', 'iron_helmet', 'raw_iron', 'cobblestone', 'spruce_log', 'cooked_cod', 'tripwire_hook', 'stone_hoe', 'iron_chestplate', 'stone_sword';
  • 试验 3:'spruce_planks', 'dirt', 'shield', 'redstone', 'clock', 'diamond_sword', 'iron_chestplate', 'stone_pickaxe', 'leather', 'string', 'chicken', 'chest', 'diorite', 'iron_leggings', 'black_wool', 'cobblestone_wall', 'cobblestone', 'cooked_chicken', 'feather', 'stone_sword', 'raw_gold', 'gravel', 'birch_planks', 'coal', 'cobbled_deepslate', 'oak_planks', 'iron_pickaxe', 'granite', 'tuff', 'crafting_table', 'iron_helmet', 'stone_hoe', 'iron_ingot', 'stone_axe', 'birch_boat', 'stick', 'sand', 'bone', 'raw_iron', 'beef', 'rail', 'oak_sapling', 'kelp', 'gold_ingot', 'birch_log', 'wheat_seeds', 'cooked_mutton', 'furnace', 'arrow', 'stone_shovel', 'white_wool', 'andesite', 'jungle_slab', 'mutton', 'iron_sword', 'copper_ingot', 'diamond', 'torch', 'oak_log', 'cooked_beef', 'copper_block', 'flint', 'bone_meal', 'raw_copper', 'wooden_pickaxe', 'iron_boots', 'wooden_sword'.

ReAct [29] 在每次试验中收集的物品是

  • 试验 1:'bamboo', 'dirt', 'sand', 'wheat_seeds';
  • 试验 2:'dirt', 'rabbit', 'spruce_log', 'spruce_sapling';
  • 试验 3:'dirt', 'pointed_dripstone';

Reflexion [30] 在每次试验中收集的物品是

  • 试验 1:'crafting_table', 'orange_tulip', 'oak_planks', 'oak_log', 'dirt';
  • 试验 2:'spruce_log', 'dirt', 'clay_ball', 'sand', 'gravel';
  • 试验 3:'wheat_seeds', 'oak_log', 'dirt', 'birch_log', 'sand'.

AutoGPT [28] 在每次试验中收集的物品是

  • 试验 1:'feather', 'oak_log', 'leather', 'stick', 'porkchop', 'chicken', 'crafting_table', 'wheat_seeds', 'oak_planks', 'dirt', 'mutton';
  • 试验 2:'wooden_pickaxe', 'iron_ingot', 'stone', 'coal', 'spruce_planks', 'string', 'raw_copper', 'crafting_table', 'diorite', 'andesite', 'furnace', 'torch', 'spruce_sapling', 'granite', 'iron_pickaxe', 'stone_pickaxe', 'wooden_axe', 'raw_iron', 'stick', 'spruce_log', 'dirt', 'cobblestone';
  • 试验 3:'wooden_shovel', 'wooden_pickaxe', 'iron_ingot', 'stone', 'cod', 'coal', 'oak_log', 'flint', 'raw_copper', 'crafting_table', 'diorite', 'furnace', 'andesite', 'torch', 'granite', 'lapis_lazuli', 'iron_pickaxe', 'stone_pickaxe', 'raw_iron', 'stick', 'gravel', 'oak_planks', 'dirt', 'iron_axe', 'cobblestone'.

图 A.2:地图覆盖范围:两个 Minecraft 地图的鸟瞰图。与基线相比,VOYAGER 能够遍历 2.3\times 更长的距离,同时穿越多样的地形。轨迹是根据每个智能体与 GPT-4 交互的位置绘制的。

B.4.2 广泛的地图遍历

地图覆盖范围的智能体轨迹如图 A.2 所示。图 7 是基于图 A.2 绘制的,通过绘制包围每个轨迹的最小圆。VOYAGER 在每次试验中遍历的地形是

  • 试验 1:'meadow', 'desert', 'river', 'savanna', 'forest', 'plains', 'bamboo_jungle', 'dripstone_caves';
  • 试验 2:'snowy_plains', 'frozen_river', 'dripstone_caves', 'snowy_taiga', 'beach';
  • 试验 3:'flower_forest', 'meadow', 'old_growth_birch_forest', 'snowy_slopes', 'frozen_peaks', 'forest', 'river', 'beach', 'ocean', 'sunflower_plains', 'plains', 'stony_shore'.

ReAct [29] 在每次试验中遍历的地形是

  • 试验 1:'plains', 'desert', 'jungle';
  • 试验 2:'snowy_plains', 'snowy_taiga', 'snowy_slopes';
  • 试验 3:'dark_forest', 'dripstone_caves', 'grove', 'jagged_peaks'.

Reflexion [30] 在每次试验中遍历的地形是

  • 试验 1:'plains', 'flower_forest';
  • 试验 2:'snowy_taiga';
  • 试验 3:'old_growth_birch_forest', 'river', 'ocean', 'beach', 'plains'.

AutoGPT [28] 在每次试验中遍历的地形是

  • 试验 1:'plains', 'dripstone_caves', 'savanna', 'meadow';
  • 试验 2:'snowy_taiga';
  • 试验 3:'plains', 'stony_shore', 'forest', 'ocean'.

B.4.3 对未见任务的高效零样本泛化

对未见任务的零样本泛化结果在图 A.3 中呈现。与图 8 类似,VOYAGER 持续解决了所有任务,而基线无法在 50 次提示迭代内解决任何任务。我们的技能库由终身学习构建,不仅增强了 VOYAGER 的性能,还为 AutoGPT [28] 提供了提升。

图 A.3:对未见任务的零样本泛化。我们可视化了每种方法在其他两个任务上的中间进度。我们没有绘制 ReAct 和 Reflexion,因为它们没有取得任何有意义的进展。

B.4.4 准确的技能检索

我们对我们的技能检索进行了评估(总共 309 个样本),结果在表 A.4 中。96.5% 的前 5 名准确率表明我们的检索过程是可靠的(请注意,我们在合成新技能的提示中包含了前 5 名相关技能)。

Top-1 AccTop-2 AccTop-3 AccTop-4 AccTop-5 Acc
80.2 ± 3.089.3 ± 1.893.2 ± 0.795.2 ± 1.896.5 ± 0.3

表 A.4:技能检索准确率。

B.4.5 对模型变化的鲁棒性

在主论文中,Voyager 的所有实验都是用 gpt-4-0314 进行的。我们额外用 gpt-4-0613 进行了新实验,发现性能大致相同(图 A.4)。这证明了 Voyager 对模型变化具有鲁棒性。

图 A.4:VOYAGER 使用 GPT-4-0314 和 GPT-4-0613 的性能。

硬核测试

正确率:0 / 5
1

VOYAGER 智能体主要由哪三个关键组件构成?

2

VOYAGER 在 Minecraft 中使用代码作为动作空间的主要原因是什么?

3

在 VOYAGER 的迭代提示机制中,自我验证模块的作用是什么?

4

与现有最先进技术(SOTA)相比,VOYAGER 在实验中表现出的性能优势不包括以下哪项?

5

VOYAGER 如何处理技能库的检索与存储?