Voyager:自动课程、技能库与可验证的开放式学习

原始来源

Guanzhi Wang 等,2023:Voyager: An Open-Ended Embodied Agent with Large Language Models,本页按 arXiv v2 阅读。

本页是原创学习导读,不含原文复刻;论文版权与完整内容以原始来源为准。

学完后你应该能做到什么

读完这一篇,你不只是能说出 Voyager 有“自动课程、技能库、迭代提示”三个模块,还应该能:

  1. 给定 Agent 的当前状态、成功史和失败史,解释自动课程为什么会提出某个下一任务。
  2. 从任务提出开始,完整追踪“检索技能—生成代码—执行—反馈—验证—入库”的状态变化。
  3. 区分环境反馈、程序执行错误和自我验证三类信号各自解决的问题。
  4. 说明技能库为什么不等于向量数据库,也不等于把全部对话历史保存下来。
  5. 说明论文证据只支持怎样的 Minecraft 高层控制场景,以及把它迁移到现实系统时还缺什么。

先把问题说清楚:没有终点的环境怎样学习

普通任务通常先给出一个清晰目标,例如“修复这个测试”或“订一张机票”。Minecraft 不一样:世界没有唯一的最终任务,Agent 可以采集、制作、探索或战斗。如果只给一句“尽可能多地发现东西”,模型很容易遇到三种问题:

  • 目标过大:它不知道先砍树还是先找钻石,直接尝试高难任务会不断失败。
  • 经验不累积:即使某一次成功制作木镐,下一次仍从头生成同一段行为。
  • 失败不可诊断:代码没有语法错误,不代表任务完成;拿错材料、走不到目标或误判完成都会让循环失效。

Voyager 的核心不是“让 GPT-4 玩游戏”,而是给开放式学习补上三个工程闭环:谁决定下一步学什么、成功经验怎样变成可执行资产、环境如何证明这一步真的学会了。

先认识几个术语:

  • 自动课程(automatic curriculum):根据能力边界动态提出下一项任务,不是预先写死的课程表。
  • 技能(skill):论文中主要指一段经过验证的可执行 JavaScript 程序,能够完成跨多个时间步的行为。
  • 技能库(skill library):保存技能描述、向量索引和程序本体的长期资产库。
  • 自我验证(self-verification):由另一个 GPT-4 角色根据任务和当前状态判断是否成功,并在失败时给出批评。
  • 开放式学习(open-ended learning):没有固定终点,系统持续发现新目标并扩展能力边界。

这里的“学习”不等于更新模型权重

Voyager 通过黑盒 API 调用 GPT-4,在提示上下文和外部技能库中积累能力。论文没有对 GPT-4 做梯度训练或参数微调,因此更准确的说法是“上下文中的终身学习”和“外部可执行记忆”。

机制契约:输入、输出和状态分别是什么

部分Voyager 中的内容初学者要抓住的意义
输入当前背包、装备、附近方块与实体、生物群系、时间、生命值、饥饿值、位置课程和代码生成必须知道“现在有什么、身处哪里”
历史已完成任务、失败任务、探索进度下一目标不能无视已经会什么、刚刚为什么失败
长期状态经过验证的技能程序及其描述向量成功经验跨任务保留,可以检索和组合
临时状态当前目标、候选代码、环境反馈、解释器错误、验证批评、尝试轮次一次任务内部不断更新的工作记忆
输出新完成的目标、已验证程序、新的技能描述与索引这轮学习产生可复用能力,而不只产生一段聊天
停止条件验证成功,或最多四轮代码生成后仍失败成功则入库并换目标;失败则暂时放弃,由课程以后再提

完整控制流如下:

flowchart TD
    S["读取世界状态、完成史与失败史"] --> C["Automatic Curriculum:提出下一目标"]
    C --> Q["根据目标、计划和环境反馈检索 Top-5 技能"]
    Q --> G["GPT-4 生成或修改可执行程序"]
    G --> X["通过 Mineflayer 高层 API 执行代码"]
    X --> F["收集环境反馈与解释器错误"]
    F --> V["Self-Verification:判断是否完成并给出批评"]
    V -->|"成功"| K["生成技能描述,程序写入技能库"]
    K --> S
    V -->|"失败且不足四轮"| G
    V -->|"四轮仍失败"| B["记录失败并暂时换任务"]
    B --> S

这张图有两个容易忽略的门:候选程序只有验证成功后才能入库;连续失败不会无限重试,而是把控制权交还给课程模块。

核心机制一:自动课程寻找“能力前沿”

自动课程不是随机任务生成器。论文把几个部分放入给 GPT-4 的课程提示:

  1. 总方向与约束,例如尽可能发现多样事物,同时不要提出当前明显做不到的任务。
  2. 当前世界状态,包括背包、装备、附近环境和生存状态。
  3. 已完成和失败任务,用来估计探索进度与能力边界。
  4. 由 GPT-3.5 围绕当前状态自问自答得到的补充背景;作者用较便宜的模型完成这类标准语言任务。

课程的目标可以理解成:选择一个有新颖性、比现有能力稍难、但由当前资源和已有技能可以够到的任务。太简单只会重复;太难会耗尽调用预算;完全随机则可能要求一个刚出生的角色直接取得钻石。

失败记录也不是永久黑名单。一个任务现在失败,可能只是缺少前置资源或技能。Voyager 在一项任务最多进行四轮代码生成;仍未成功时先换任务,自动课程可以在能力增长后重新提出它。这就是“失败—绕行—升级—再挑战”的开放式进展。

核心机制二:技能库保存的是可执行行为

每当程序通过自我验证,系统让 GPT-3.5 生成技能描述,以描述的 embedding 作为检索键,以程序本体作为值。新任务到来时,系统先生成一般性解决建议,再把任务计划和环境反馈组成查询,检索最相关的五个技能放入代码生成提示。

因此技能库有三层:

层作用不能替代什么
描述说明技能做什么,帮助生成检索查询不证明程序可运行
向量索引从大量技能中找到语义相关候选不负责执行,也不保证候选适用
程序本体真正完成行为,可以被新程序调用仍依赖当前环境、控制 API 和验证

论文选择代码作为动作空间,而不是让模型逐个输出“向前一步、点击一次”。一段程序可以包含循环、条件和函数调用,所以能表达跨时间的行为;更复杂的技能也可以调用较简单的技能。例如“制作铁镐”可以组合采木、制作工作台、制作石镐、采矿和冶炼等已有程序。

不过,所谓“可组合”不是魔法。组合后的程序仍需在当前世界执行并重新验证;旧技能可能因为资源、地形、API 或前置条件不同而失败。向量搜索找到的是候选,不是正确性证明。

核心机制三:三类反馈把生成变成可修正循环

Voyager 不要求模型一次写对代码。每一轮执行后,它收集三类性质不同的反馈:

  1. 环境反馈:程序执行到了哪里、还缺什么。例如“无法制作铁胸甲,因为还缺 7 个铁锭”。它回答的是“世界状态为什么没有达到目标”。
  2. 执行错误:解释器或 API 抛出的语法错误、无效操作和不存在的函数。它回答的是“程序为什么没有正确运行”。
  3. 自我验证与批评:另一个 GPT-4 根据任务和当前状态判断是否成功;若失败,再建议下一轮如何修改。它回答的是“即使程序跑完,任务是否真的完成”。

只看异常会漏掉“程序正常退出但什么也没完成”;只看最终背包又可能不知道代码在哪一步出错。三类信号共同构成了从症状到原因再到验收的链路。

自我验证不是客观真相

论文也记录了验证器漏判的例子,例如未把蜘蛛丝识别为击败蜘蛛的成功信号。生产系统应优先使用可执行断言、测试、结构化状态查询和必要的人工审批;模型判断只应覆盖难以程序化的部分。

走完一次:从“已有木镐”到掌握“制作石镐”

下面是为了教学简化的轨迹,不是论文中的逐字运行日志,但每一步都对应论文机制。

轮次系统看到的状态发生的动作状态怎样变化
0背包有木板和木镐;“采木”已完成;“直接找钻石”失败过自动课程提出“制作一把石镐”建立当前目标,避免再次跳到钻石
1技能库有 mineWoodLog、craftCraftingTable检索相关技能,模型生成采石并制作石镐的程序得到候选程序,但尚未入库
1 执行附近没有可直接开采的石头程序运行,环境反馈显示没有取得足够圆石无语法异常,但任务状态未完成
1 验证背包里没有石镐验证器判定失败,建议先寻找暴露的石块形成下一轮批评
2上一轮代码、环境反馈和批评都在提示中程序加入探索和路径处理,再调用已有采集技能取得圆石并完成制作
2 验证背包出现石镐验证器判定成功生成通用描述并把程序写入技能库
下一轮完成史增加“制作石镐”,库中多一个技能自动课程可以提出“采集铁矿”等更高一级目标能力前沿向外移动

关键不是第二轮代码写得多漂亮,而是失败信息被保留、验收发生在执行之后、成功程序进入长期记忆、课程再据此升级目标。

用伪代码把控制流钉死

completed, failed, skill_library = [], [], []
 
while exploration_budget_remaining():
    state = observe_world()
    task = curriculum.propose(state, completed, failed)
    feedback = errors = critique = None
 
    for attempt in range(4):
        plan = make_general_plan(task, state, feedback)
        skills = skill_library.retrieve(plan, feedback, top_k=5)
        program = generate_program(
            task=task,
            state=state,
            retrieved_skills=skills,
            previous_feedback=feedback,
            previous_errors=errors,
            previous_critique=critique,
        )
        feedback, errors = execute_in_minecraft(program)
        state = observe_world()
        success, critique = verifier.check(task, state)
 
        if success:
            skill_library.add(describe(program), program)
            completed.append(task)
            break
    else:
        failed.append(task)

这段伪代码刻意表现了两个状态层次:feedback/errors/critique 服务于当前任务的短循环;completed/failed/skill_library 跨任务保留,服务于长期探索。

证据该怎么看:支持机制,不等于证明通用自主性

论文在基于 MineDojo 的 Minecraft 环境中,用 Mineflayer JavaScript API 做高层控制,并将 ReAct、Reflexion 和 AutoGPT 改造到相同设置。作者报告:在最多 160 次提示迭代的探索实验中,Voyager 发现 63 种独特物品,是基线的 3.3 倍;行进距离是基线的 2.3 倍;若以提示迭代数衡量,若干技术树里程碑最快达到 15.3 倍加速。新世界、清空背包后的未见任务实验也显示技能库能够被复用。

消融结果更直接地支持机制:随机课程替代自动课程后,发现物品数下降 93%;移除自我验证后下降 73%;没有技能库的版本在后期更容易停滞。这里应读成“三个模块在作者设置中都贡献了长期进展”,不能读成某个百分比会在其他领域复现。

证据边界同样重要:

  • 基线是为 Minecraft 重新解释和适配的文本 Agent,并非原封不动的通用实现。
  • 实验通过高层 API 控制角色,不比较像素感知、3D 视觉或低层运动能力。
  • 论文中的关键技术树结果只有少量重复试验,不能把单一游戏结果直接外推到机器人或企业系统。
  • API 成本、模型版本和 Minecraft 环境都属于当时的实验条件,不是机制永久不变的性能承诺。

失败模式与调试顺序

失败现象可能根因应先检查什么
课程提出不存在的物品模型幻觉、世界规则没有被充分约束用能力目录或规则校验候选任务
程序反复调用不存在的函数控制 API 描述不清或代码生成幻觉暴露真实 schema,并把解释器错误原样回传
程序正常结束但目标未完成只检查进程退出,没有检查世界状态为任务建立明确成功断言
错误技能进入库后持续污染验证器误判、入库门槛太低重新验证、增加版本和回归样例、支持失效处理
总在简单任务中循环课程没有新颖性或能力边界信息检查完成史、失败史及难度策略
复杂技能调用旧技能后失败前置条件变化、环境或 API 版本漂移给技能记录适用条件、依赖和失败语义

历史贡献与今天的工程解释

论文在 2023 年直接提出并验证的贡献,是把自动课程、可执行技能库和带三类反馈的迭代提示组合成 Minecraft 中的开放式终身学习 Agent,而且无需修改黑盒 LLM 权重。

今天可以迁移的工程解释,是把长期 Agent 设计成两层循环:内层用真实执行反馈把一个任务做对,外层用能力状态选择下一项可达任务;只有通过验收的产物才能成为可复用资产。这可以映射到数据分析、代码维护或运维自动化,但映射不等于论文已经验证了这些领域。

现实系统还必须补上论文游戏环境弱化的部分:权限、不可逆操作审批、成本预算、并发状态、技能版本、依赖锁定、数据隐私和人工接管。尤其不能把“另一个模型说成功了”当成支付、删除或生产部署的唯一门禁。

自测:确认你真的掌握了机制

  1. 为什么自动课程必须同时看到当前状态、完成史和失败史?少任何一项分别会怎样?
  2. 一个技能的向量检索结果很相关,为什么仍不能直接执行并判定成功?
  3. 环境反馈、执行错误和自我验证分别能发现哪一类失败?请各举一例。
  4. Voyager 连续四轮没有完成当前任务后会怎样?为什么这比无限重试更适合开放式探索?
  5. 如果把 Voyager 思路用于代码 Agent,哪些部分可以直接映射,哪些安全条件必须新增?

上一篇:Reflexion · 下一篇:AutoGen · 返回 里程碑原典目录