Skip to content
shujianPublic

About

受限积木世界的理解测试台:env(测试者)与 testee(被测者)两个程序,按三段逐段判定理解

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

5 Commits

Folders and files

Repository files navigation

SHRDLU

全文分七部分:一、世界 | 二、对世界的理解 | 三、测试者与被测者的分工 | 四、测试者的设计思路 | 五、被测者的设计思路 | 六、交互的约定 | 七、项目结构与文档分工。

一句话概括:SHRDLU 通过对积木世界的提问和操作判定理解。测试者提供一个受限世界与一套问句;被测者观察这个世界,根据要求回答问题或执行操作等;测试者依据世界的当前状态判定被测者的理解程度。


1. 世界

世界是一个积木世界:一张桌面,加上若干物体。

每个物体有三个属性:形状、颜色、大小。属性的组合足以唯一确定一个物体。例如,"红色的大方块" 这样的描述可以唯一确定一个物体。

每个物体在任一时刻只处在以下三种位置状态中的一种:在桌面上、在另一个物体上、或者被拿起;同一时刻仅允许有一个物体被拿起。

物体可以被移动:拿起、放下、放到另一个物体上。移动只改变位置,不改变属性。


2. 对世界的理解

本项目关心的是被测者对世界的理解。

理解不能由被测者自述,只能从它在两类交互里的表现看出来。测试者把世界交给被测者,然后就这个世界向它提问,也要求它改变这个世界:

  • 提问:测试者就世界的当前状态发问,被测者作答,看它答得对不对。
  • 操作:测试者要求被测者改变世界。一条操作指令的落实分两件事:
    • 更新被测者自己那份世界认识(由被测者自行管理,并在后续回答提问时表现出来)
    • 回复一条形式化的操作调用(格式由测试者给定,测试者据此判定被测者对当前指令的理解)

更新状态而跟上世界的变化是更深一层的理解,而且与记忆有关。 测试开始时,测试者把世界的初始状态交给被测者;此后世界随操作而改变,测试者不再展示新的世界。被测者要记住自己做过什么、世界随之变成什么样,才能说清世界现在是什么样。


3. 测试者与被测者的分工

测试的载体是一份场景:初始世界的快照、一套操作,以及最初以哪种形式把世界交给被测者(图像或符号信息)。场景加上指令序列与题库,就是一份可用的考卷;自动出题使用固定种子,同一场景与同一种子必得同一份考卷。

测试台由两部分组成:测试者(env,程序 shrdlu-env)与被测者(testee,程序 shrdlu-testee)。

测试者掌握世界的当前状态,负责提问、要求操作、判分与记录。被测者在测试开始时得到世界的一份信息,此后由自己发出的调用推进自己对世界的认识。

交互分两部分,双方在其中的分工是:

  • 问答:测试者发问句,被测者回答句。
  • 操作:测试者发指令,被测者回操作调用或拒绝;测试者照这个调用执行,并把它施加到自己维护的那份 被测者通过操作表现出的世界状态上。

分工落在三条边界上:

  • 世界信息只交付一次:测试者在测试开始时把世界的初始状态交给被测者,此后发出的是问句与指令,世界在操作之后变成什么样,由被测者从自己发出的调用推出来。
  • 一问一答:测试者发一条、被测者回一条;它给出的操作调用由测试者照办,测试者不回话。
  • 判分只看两样:被测者发出的操作调用、它给出的回答。

4. 测试者的设计思路

4.1 定位

世界的当前状态的持有者 + 问句求值器 + 判卷者。

它自己维护两份世界状态:一份是 世界的当前状态(按考卷里的指令实际执行而演化),一份是 被测者通过操作表现出的世界状态(按被测者发来的调用演化)。判定时机械比对。

4.2 判定:三段

一次测试依次走完三段:先只提问(对初始状态)、再要求操作(逐条指令、逐条核对)、最后再提问一次(对变化后的状态)。提问与操作必须分开评:混在一批里时,一个操作做错之后被测者回答的是它自己那个已经偏离的状态,后面的问句就失去了意义。

段 考的是 判定
第一步:只回答问题 对初始状态的理解 答句归一后与世界的当前状态给出的答案比对
第二步:做若干操作,每个操作之后核对状态 操作是否理解、状态是否按语义演化 逐条指令按"该做/不该做 × 做了/拒绝了"判(合法指令必须执行,非法指令拒绝了才算对,去执行非法操作直接判不理解);每个操作之后对拍两份世界状态(对拍用来定位从第几个操作起、在哪些物体上不同,不额外扣分)
第三步:再回答问题 对状态变化的理解 以 被测者通过操作表现出的世界状态为准;同时也与世界的当前状态比一次,这一次比较只作记录

三条规则:

  • 段内严格:一段里全部答对才算这一段理解。P0 的题都是封闭式、答案唯一;定指不唯一的题不计入分母,并提示出题方。
  • 段与段互不连累:第三步以被测者自己的状态为准,所以前面做错的操作不会让后面的问句失去意义。唯一的例外是执行非法操作:那是明确的不理解,直接给结论。
  • 结论逐段呈现:整次测试另有一个结论,它是三段结论的合取;呈现形式是"第一步 10/10 理解、第二步 4/4 理解、第三步 5/10 不理解"这样的分段清单,而不是只给一个总判定。

两轮问什么题由测试者决定:现行做法是把同一份题库问两遍,两轮答案成对,才能把"没看懂交来的世界"与"没跟上世界的变化"分开;两轮不必相同,题目如何分配属于出题设计。

接口层面的失败(初始观察就崩、回报不是合法 JSON)不属于任何一段,会让整次测试作废并单独记录;段内的协议错误只算该段出错。

4.3 关键约束

  • 求值器是机械的:只做"问句语法 → 对状态求值",不做推理、规划或学习。这是测试者与"世界模型"的区别:测试者的状态是执行出来的,它不需要推断。
  • 测试者不判断被测者的"思路":它不知道、也不猜被测者内部记着什么,只比对回答与世界的当前状态。

5. 被测者的设计思路

5.1 定位

被判断者。声称理解这个世界,通过回答问题来证明。

5.2 只负责响应两条消息

测试开始时它收到一次观察,只有这一次;此后要响应的只有两条消息:提问与操作。这两条消息各自要做什么,见 §2;线上形态见 §6。

5.3 关键约束

  • 它交出的只有回答与操作调用:测试者判分只看这两样(这条边界见 §3);它不必交出任何状态,也不要求它导出自己的世界模型(导出会强制符号化)。

6. 交互的约定

6.1 通信与函数调用

测试者与被测者是两个各自独立的程序(也允许同处一个进程),两边不共享内存,因此每一次交互都要序列化成一行一个 JSON 对象:UTF-8 文本,一行一条消息,以换行结束。

这些消息与函数调用一一对应:消息类型就是函数名,消息里的其余字段就是入参,回复就是返回值。

函数调用 线上形态
函数名 消息的 type 字段:observe / question / command
入参 消息的其余字段:state(或 image)、text
返回值 回复那一条消息的 type 与字段:answer / action / refuse
测试者 → 被测者 入参 被测者 → 测试者
observe state:世界的初始状态,或 image:一张图 没有回复;整次测试只发一次
question text:一个问句 answer:text 为封闭式答句
command text:一条指令 action:op 与 args;或 refuse:reason

约定:

  • 一问一答:每条消息恰好得到一条回复,次序与发送次序一致;observe 是唯一没有回复的消息。调用栈由这个配对关系替代:测试者发一条,就停下来等被测者回一条。
  • 拒绝也算回复:拒绝要带 reason。不回、回空、回一行不是 JSON 的内容,都按没有回复计(判定见 §4.2)。
  • 指称用 id:线上出现的对象标识一律是 id(observe 的状态里、action 的 args 里);问句与指令是自然语言描述,被测者负责把描述对应到自己那份模型里的 id 上。
  • 被测者不必交出状态:它发出的 action 就是对那一步操作的答复,测试者照这个调用执行;它自己那份认识不进入判定。
  • 用什么语言实现都可以,只要按上表收发消息。

字段级规范(字段名、取值、边界情形)见 docs/设计协议.md §5。

6.2 Python 绑定

用 Python 实现时不必自己收发 JSON:接口的完整约定见 shrdlu/testee/api.py,实现其中的 Testee 即可,基类负责与线上协议互转。用 --testee 模块:类(或 shrdlu-testee --impl 模块:类)运行。

from shrdlu.testee.api import Action, Observation, Refuse, Testee

class MyTestee(Testee):
    def observe(self, observation: Observation) -> None: ...
    def question(self, text: str): return "yes"
    def command(self, text: str): return Action("put_on", ("a", "b"))

6.3 为什么是问句协议

要求 是否规定实现方式
让双方导出世界模型 否决:规定了实现方式(必须符号化)
让双方回答受约束的问句 采纳:不规定实现方式(视觉模型可不建符号世界,看图回答即可)

6.4 问句集

取 SHRDLU 自身的问句库,全部可由测试者机械求值。

实际实现的是封闭式的五类:attr(属性:颜色/大小/形状)、rel(关系是否:on / on the table / clear / supported)、count、exists、all。下表中的位置类("绿块在哪里?" → 关系描述)与指称类("红块上面是什么?" → 对象描述)不做:它们的答句是开放式的,与 §6.4"格式需可机械比对"冲突。要做得先定出一套关系描述/指称的规范答句格式。

6.5 答句要求

  • 必须表态:拒答 / 含糊视为答错(防止用回避换取过关)。
  • 格式需可机械比对(见 §6.4 的答句形态)。

7. 项目结构与文档分工

七个命令行程序各管一段:

  • shrdlu-env:主持一次测试并判分,退出码给出结论。
  • shrdlu-testee:把某个被测者实现当作程序来跑(自带一个最小示例;真正的实现由使用者自己写)。
  • shrdlu-scene:生成场景,并检查一份场景是否合格。
  • shrdlu-exam:给场景配上指令序列与题库,产出一份可用的考卷。
  • shrdlu-play:逐步观看测试过程,每一步停下来显示两份世界状态,可暂停与插话。
  • shrdlu-render:把场景画成等轴测图(SVG 或 PNG)。
  • shrdlu-report:把整次测试写成一个自足的 HTML 文件。

代码分三层:

  • shrdlu/:共享的世界模型与线上协议(world / snapshot / protocol / ops / questions / settings / transport)。
  • shrdlu/env/:测试者一侧(host 主循环与逐段判分、answers 判分、commands 指令生成、scenario / generator / worldgen / authoring 出题、render 渲染、webreport 报告、impls 选实现,以及六个命令行程序 cli/)。
  • shrdlu/testee/:被测者一侧(api 接口、example 最小示例、nlp 英文解析、registry 实现名册,以及 cli/testee_main.py)。

需要更细的内容时按上表查找;命令行用法与参数见 README-env.md,规范细节见 docs/设计协议.md,测试者的能力与保证见 docs/env功能介绍.md,编写被测者见 docs/testee开发需求.md。

写法:同一内容只在它的落点里完整陈述;其他文档最多一段摘要,并注明"见 X §N"。规范与现状冲突时,以 docs/设计协议.md 与代码为准。

文档 面向谁 公开范围 唯一落点(只在这里完整写)
本文(README.md) 想了解项目的人与维护者 公开 世界与判定的正式介绍、项目结构、设计决策与理由
README-env.md 使用者 公开 七个程序如何运行:参数、退出码、例子与速查
docs/设计协议.md 双方实现者 公开 规范:线上格式、世界模型、操作、问句、测试结构与判分规则、记录字段
docs/env功能介绍.md 运行测试的人 公开 测试者提供什么、保证什么、不提供什么、稳定性承诺与边界
docs/testee开发需求.md 编写被测者的人 公开 契约:按消息顺序要做什么、自由度、接入骨架、自测与常见错误
shrdlu.ini 使用者 公开 常设参数与默认值(带注释);命令行只说这一次要什么
LICENSE 使用者 公开 MIT 许可证文本
公开的六份(本文、README-env.md、docs/设计协议.md、docs/env功能介绍.md、docs/testee开发需求.md 与 shrdlu.ini)构成对外正式材料。

本项目以 MIT 许可证发布,全文见 LICENSE。

About

受限积木世界的理解测试台:env(测试者)与 testee(被测者)两个程序,按三段逐段判定理解

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages