代码作为技能的载体,技能库作为跨任务记忆——Voyager 在游戏里验证了这套思路
为什么选 Minecraft?
2023 年的 Voyager 论文(Wang et al., NeurIPS 2023)选择 Minecraft 作为实验场。Minecraft 有几个对 Agent 研究有价值的性质:
- 开放世界:没有固定终点,Agent 需要自主设定目标
- 层级任务:砍木头 → 做木板 → 做工作台 → 做石镐,技能之间有清晰的依赖链
- 可执行反馈:每一步操作都有明确的成功或失败信号
- API 可控:Mineflayer 提供 JavaScript API,Agent 的每个动作都是可执行的代码
这几个特性使得 Minecraft 成为研究终身学习 Agent 较合适的实验场。
系统架构:三个核心组件
Voyager 由三个模块协同工作:
┌─────────────────────────────────────────────────────┐
│ Voyager │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ 自动课程 │ │ 代码生成器 │ │ 技能库 │ │
│ │ Curriculum │→ │ Code Gen │→ │ Skill │ │
│ │ │ │ │ │ Library │ │
│ └─────────────┘ └──────────────┘ └───────────┘ │
│ ↑ │ │ │
│ └────────────────┴─────────────────┘ │
│ 执行反馈 │
└─────────────────────────────────────────────────────┘
1. 自动课程(Automatic Curriculum)
Agent 不等待人类给任务,它自己决定下一步要做什么。课程模块维护一个"任务状态图":
- 已解锁的资源(背包、周围环境)
- 已掌握的技能(技能库中的函数)
- 当前游戏阶段
基于这些状态,它向 GPT-4 提问:"我现在有这些资源和技能,接下来应该探索什么目标?"GPT-4 给出建议,课程模块评估可行性后发起任务,形成一个自主探索循环,而不是被动执行预定脚本。
2. 代码生成器(Code-as-Action)
Voyager 的每个动作都是一段 JavaScript 函数,由 GPT-4 生成,通过 Mineflayer API 在游戏中执行:
// 由 GPT-4 生成的技能:挖取石头
async function mineStone(bot) {
const stone = bot.findBlock({
matching: mcData.blocksByName.stone.id,
maxDistance: 32,
});
if (!stone) {
throw new Error("找不到石头,需要先探索");
}
await bot.tool.equipForBlock(stone);
const pos = stone.position;
await bot.dig(stone);
await bot.waitForTicks(5);
console.log(`成功挖取石头,位置:${pos}`);
}
代码的优势在于:
- 可组合:
craftWoodenPickaxe()可以复用collectWood()和makeWorkbench() - 可验证:执行报错立刻反馈,GPT-4 看到错误信息可以修正
- 可存储:函数是可持久化的技能单元
3. 技能库(Skill Library)
每次成功执行的代码函数,连同它的自然语言描述,都被存入技能库。技能库本质上是一个向量数据库:
# 技能存储结构
{
"name": "mineStone",
"description": "挖取石头,自动寻找最近的石块并使用合适的工具",
"code": "async function mineStone(bot) { ... }",
"embedding": [...], # 用于语义检索
"dependencies": ["equipTool", "findBlock"],
}
当 Agent 接到新任务时,它先检索技能库,把语义相关的历史技能放入 prompt 作为参考,然后生成新技能。新技能往往可以直接调用旧函数,技能随时间持续积累。
迭代调试:执行失败后重新生成
Voyager 的代码生成不是 one-shot 的。每次执行失败,Agent 收集错误信息,重新生成修正版本:
尝试 1:生成 mineIronOre()
→ 执行报错:"没有合适的镐子"
尝试 2:修正 → 先调用 craftStonePick(),再挖铁矿
→ 执行报错:"附近没有铁矿石"
尝试 3:修正 → 添加探索逻辑,扩大搜索范围后再挖矿
→ 执行成功,技能入库
这个模式和程序员写代码的过程类似:写→跑→看报错→改→再跑。每一轮的错误信息都是有效的监督信号,不需要额外的人工标注。
实验结果
论文在 Voyager 与 AutoGPT 等基线之间进行了对比:
| 指标 | Voyager | AutoGPT(基准) |
|---|---|---|
| 解锁科技树进度 | 3.3x | 1x |
| 获得唯一物品数 | 3.1x | 1x |
| 地图探索距离 | 2.1x | 1x |
Voyager 积累的技能库有迁移能力:将技能库迁移到一个全新的世界,Agent 能更快达成目标。技能不随环境重置而清空,这是终身学习的核心价值所在。
Voyager 的几个设计原则
代码作为技能表示:自然语言描述的技能难以精确复用,而函数可以被调用、被组合、被验证,是 Agent 长期记忆较合适的载体。
执行错误作为训练信号:不需要人类标注"哪步错了",运行时的 traceback 本身就是精确的反馈。这是代码执行比纯文本推理的一个优势。
课程而非固定任务列表:固定任务列表会让 Agent 遇到分布外问题。自主生成课程才能支持开放域探索。
技能库作为长期记忆:上下文窗口是短期记忆,技能库才是跨会话、跨任务的积累,是 Agent 区别于单次 LLM 调用的地方之一。
与后续工作的关系
Voyager 之后,CodeAct(第 05 篇)把"代码作为动作空间"的思路推广到了通用 Agent;OpenDevin 和 SWE-agent 则把类似架构应用于真实软件工程任务。Voyager 的技能库设计,也影响了 Skill-in-Context、ExpeL 等记忆增强 Agent 的工作。
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:04. Voyager:用代码探索开放世界的终身学习 Agent
本文链接:https://www.sshipanoo.com/blog/ai/code-agent-harness/04-Voyager/
本文最后一次更新为 天前,文章中的某些内容可能已过时!