先看一段没有记忆的运行
假设测试Agent的任务是:在虚构地图“灰烬回廊”中,验证“钥匙任务”在各种操作顺序下都能完成。它的框架是常见的“观察、推理、动作”循环,每一步只看当前画面和最近几步的对话。
下面是第1轮里一段被大幅精简的行动轨迹:
T001 地图=回廊入口 任务=钥匙(未接) 动作=与守卫对话 结果=任务接取 T014 地图=回廊二层 任务=钥匙(进行中) 动作=跳过缺口 结果=进入侧室 T015 地图=侧室 任务=钥匙(进行中) 动作=拾取箱子 结果=无反应 T016 地图=侧室 任务=钥匙(进行中) 动作=拾取箱子 结果=无反应 T017 地图=侧室 任务=钥匙(进行中) 动作=拾取箱子 结果=无反应 T031 地图=侧室 任务=钥匙(进行中) 动作=离开侧室 结果=回到二层 T044 地图=回廊二层 任务=钥匙(进行中) 动作=跳过缺口 结果=进入侧室
Agent在T044又跳进了侧室。它并不是愚蠢,而是每一步都只看到“有一个缺口、任务未完成”,缺乏“这个房间我已经试过,箱子无法交互”的记忆。这样的运行在长任务里会很常见,也是长时间运行的测试难做的原因之一:步数一多,早期信息就被挤出上下文。
两层记忆:短期上下文与长期轨迹
爱游戏测试Agent把记忆分成两层,两层的用途不同。
- 短期上下文:当前子目标、最近若干步的观察和动作、当前地图状态。它像工作台,容量有限,随时会被覆盖,服务于“下一步做什么”。
- 长期轨迹(Action Trace):全程的动作、状态变化和结果,按结构化字段存储:地图、角色、任务阶段、装备、动作、结果、时间顺序。它像实验记录,服务于“回头看发生了什么”,也是最终输出复现流程的原始材料。
两者不能混用。把全部轨迹塞进上下文,会撑爆窗口并稀释重点;只保留上下文而不存轨迹,则既无法反思,也无法在发现BUG后精确复现。
轨迹压缩:记住什么,丢掉什么
上面那段轨迹里,T015到T017是三次相同的无效动作。原样保存没有意义,压缩后应当变成一条:“侧室,拾取箱子,重复三次,均无反应”。压缩遵循几个原则:
- 合并连续重复的动作,保留次数。
- 保留状态发生变化的节点,如任务阶段切换、物品增减、地图跳转。
- 保留所有异常或意外结果,不做合并。
- 为每个区域维护简短摘要:已覆盖的动作类型、发现的问题、尚未尝试的动作。
压缩不能丢掉复现所需的信息。爱游戏的做法是双份存储:完整轨迹留在存储层,压缩版进入Agent可读的记忆层,需要复现时再从完整轨迹回放。
反思:输入与输出
第1轮结束后,反思模块开始工作。它的输入并不是“请你反思一下”这样的空泛提示,而是三份具体材料:本轮的压缩轨迹、本轮的目标与预期结果、当前的测试Oracle判定(发现了什么异常,哪些只是预期行为)。关于如何判断“是否为异常”,可以参考测试Oracle的分层做法。
输出也应是结构化的,而不是一段感想:
- 已被排除的假设:侧室的箱子在当前任务阶段不可交互,重复尝试无益。
- 未覆盖的区域:回廊三层、两个未进入的分支房间。
- 本轮的无效循环:T014与T044重复进入侧室。
- 下一轮的策略调整:先接取任务但不与守卫对话,改测另一个顺序;侧室暂时列入“已验证,不再重复”。
关键在于每一条反思都要能落到下一轮的具体改变上。如果一段反思读起来很有道理,却没有改变任何动作,那它只是一段文字。
第2轮:同一个场景,不同的行为
带着反思结果进入第2轮,规划器会拿到一张“已排除清单”和一张“待覆盖清单”。轨迹的开头就不再一样:
T001 地图=回廊入口 任务=钥匙(未接) 动作=绕过守卫直接取钥匙 结果=钥匙获得 T009 地图=回廊入口 任务=钥匙(未接) 动作=与守卫对话 结果=对话无反应
Agent这一次尝试了第一轮没有触碰的顺序,并立刻发现了一个疑似BUG:任务尚未接取时已取到钥匙,之后与守卫对话没有任何响应。接下来的步骤,是按照复现要求整理地图、任务状态与操作顺序,交给人工复核。
防止原地打转
反思本身也可能出错,比如反复得出“换个顺序再试”,却每次都选同一个顺序。可以从几方面设防:
- 状态访问计数:对同一个状态与动作的组合计数,超过阈值就强制换方向。
- 策略去重:新一轮策略要与前几轮策略比较,相似度过高就要求改写。
- 反思预算:反思也有轮数上限,避免Agent在无解的场景里无限重试。
- 终止条件:覆盖清单已清空、连续多轮没有新状态出现、或者耗尽资源预算时,Agent应当停止并输出报告,而不是继续。
记忆污染:错误的教训比没有教训更糟
长期记忆最大的风险是把错误当作事实存进去。比如第1轮里箱子无法交互,其实是因为当时任务阶段不对,并不是永久性问题;如果反思把它记成“侧室箱子永远不可交互”,后续所有轮次就都会跳过这个位置,真正的BUG就被永久掩盖了。
降低污染的办法包括:
- 给每条记忆标注来源(哪一轮、哪一步)、适用条件(任务阶段、游戏版本)和置信度。
- 把“观察”与“推断”分开存放:动作结果是观察,“箱子不可交互”是推断,推断需要带条件。
- 定期抽样,用新的实验去验证旧的结论,尤其是那些让Agent跳过某块区域的结论。
- 游戏版本更新后,相关记忆整体降级为“待验证”,而不是直接沿用。
说到底,爱游戏AI理解的反思不是让Agent变聪明的魔法,而是把失败变成可检验的假设,再让下一轮去检验。长期记忆存的应当是被验证过的东西,而不是Agent说服了自己的东西。