Skip to content

评价体系与基线 ​

状态:草案 · 最后更新 2026-11-08 · 可执行配置见 evals/ · 日志格式见 evals/log-format.md

比基线表本身更重要的是:我们允许自己被什么结果推翻。 所以下面每条主张都对应一个可以测出"我错了"的指标。

先分清:主张配置 vs 消融基线 ​

本系统自己的配置是 full(什么也不关,见 sim/baseline.py)。 下面四条 yaml 基线都是它的消融版本——所以正确的对照是 full vs B1、full vs B2, 而不是拿 B1 当"我们的系统"去比。早期版本把 B1 误当全开,已在 ADR-0003 纠正。

四条基线 ​

编号名称行为决策来源是否依赖 LLM用途
B0LLM 中心决策全部经 LLM是,断线即停对照组:当前主流做法
B0′行为树基线传统行为树否对照组:工业界现状
B1无情绪调制L1/L2/L4 保留,移除 L3 调制L4 用检验"情绪调制"是否真的有用
B2保留需求生成但移除 L1 抢占L1 生成需求但不抢占L4 用检验"抢占权"是否真的必要

配置在 evals/baselines/,字段含义见 evals/README.md。

为什么是这四条 ​

  • 缺 B0,就无法回答"和现在的做法比好在哪";
  • 缺 B0′,就无法回答"比不用 LLM 的传统方案好在哪";
  • 缺 B1/B2,就无法回答"情绪和抢占是不是多余的装饰"——这是本项目最容易被攻击的两点, 所以它们必须能被单独关掉。

G1-full:人形基线(2026-11-08 新增) ​

上面四条都是胶囊上的消融。g1-full 不是第五条消融,它是换身体的参照配置: 开关逐项等于 full,身体换成 Unitree G1(29-DOF)。配置在 evals/baselines/g1-full.yaml; 为什么另立一档、代价是什么,见 ADR-0008。

口径 ​

项值
命令server/.venv/Scripts/python.exe -m sim.main --body g1 --baseline g1-full --duration 30 --no-render
身体 / 场景G1(29-DOF)· stage1 静态房间(9 件家具,没有会动的东西)
时长 / 频率30 s × 100 Hz;时间基相对误差上限 1%(超了 exit 2)
日志核对点.meta.json 里的 baseline_file / body / baseline_sha256
可比性不可与胶囊数字直接比:出生点、drive_toward 的物理含义(推力 vs 命令速度)、推通道、充电桩全不一样

跑法(n≥5,不许报单次值) ​

bash
for s in 7 8 9 10 11; do
  server/.venv/Scripts/python.exe -m sim.main --body g1 --baseline g1-full --duration 30 --no-render --seed $s
done

n=5 实测分布(2026-11-08 · seed 7–11 各 1 次 · 同一份 g1-full.yaml) ​

指标meanminmax标准差(n−1)n
平均速度(m/s)0.21780.21200.22300.00515
净位移(m)3.13883.07303.17200.03875
z_min(m,pelvis 最低点;≤0.50 判摔)0.71220.71000.71480.00175
L2 否决次数1.0110.05
L4 决策数2.2230.44725

逐次数字、日志 sha256、冻结的原始 JSONL 见 evals/g1-full/README.md。

两条口径必须一起看 ​

同一初始状态 + 默认 seed 连跑 5 次,5 份日志的 sha256 全同(逐位相同)。所以「n≥5」在这里 不是「取平均消噪声」,而是「用跨 seed 的扰动看离散度」:--seed 只喂 mock LLM 的延迟抽签, 抽签决定 plan 在哪一刻被采纳,轨迹与站桩时长跟着变;判据、阈值、场景参数一个没动。

30 s 步行对初始坐标浮点敏感(出生点挪 1e-9 m,walk_30s 从 0.5711 变 0.5752 m/s)。 所以跨版本只允许比「机制是否生效」(否决次数、决策数、有没有摔), 不允许比 0.00x m/s 的快慢——那个量级落在分布里,不构成证据。

三处语义不成立(照写 TBD,不伪造信号) ​

  1. L1.charging:房间没有充电桩,靠近 C.CHARGER_POS 那个地面点就被判成「在充电」 —— 实测 1471 个控制周期(14.71 s / 30 s)被判充电,电量最终 100.0%,这条回升没有物理依据。
  2. L3.hold_charge:由第 1 条生出来的动机(没有桩就没有「保持充电」)。
  3. L2.push:人形没有「推底盘」通道,否决在 main.py 接成速度层后退; 所以 overrides=1 的那一次没有测到 L2 的推力通路(push_ignored=0,push 分支没被调用)。

与本节「统计要求」的 ≥20 次仍有差距:n=5 是下限,够报分布、不够报区间(n<8 一律不给 95% 区间)。 想要更硬的结论得做出生点/参数扫描——那属于场景变更版本,未做。

指标 ​

指标B0B0′B1B2测量方法
LLM 断线存活时长0(所有行为经 LLM)高(不依赖 LLM)同 B0′同 B0′固定任务集,断 LLM 后计时
需求驱动行为占比000保留生成,不触发抢占分母 = 全部行为决策数
情绪调制可观测性不适用不适用无显著差异同 B1同一任务改变情绪向量,统计检验行为参数
异常自恢复率低中同 B0′同 B0′注入失败,记录无人工干预修正成功率
抢占正确率不适用不适用不适用无抢占(对照)事后规则判定"该抢"比例
发育曲线平坦平坦平坦平坦长期运行中同类任务成功率/耗时趋势

表中的"高/中/低/平坦"是预期方向,不是已测得的数值。真实数值待 v0.1 仿真产出。 任何把预期写成实测的文档,都算数据造假。

关键判定规则 ​

"该抢"怎么判:抢占事件发生后,若无抢占则 1 s 内会发生力超阈值 / 碰撞 / 人进入安全距离, 则判定"该抢"。这条规则是事后判定的,所以必须有人工复核的抽样比例(TBD)。

"抢占正确率"现在有实现了:sim/counterfactual.py 按本节的"若没抢则 1 s 内会撞"做 反事实推演(克隆物理状态、假设没听见否决、跑 1 秒),日志里留 CF counterfactual 记录。 早期版本的"1 - 碰撞/否决"只是代理,已废弃。

"需求驱动行为占比"怎么算:分母为全部行为决策;分子为 L1 稳态偏离触发且非外部指令触发的决策。 依赖 goal_candidate.source_need 字段(见 interfaces.md)——这就是为什么它必填。

"LLM 断线存活"怎么测:固定任务集 + 固定断线时点 + 计时到系统进入安全稳态。 任务集与时长定义在 evals/README.md,改任务集必须同步改基线版本号。

统计要求 ​

项要求状态
每项指标重复次数≥ 20 次(草案)TBD
显著性检验方法参数/非参数待定;情绪调制建议配对检验TBD
报告格式均值 + 置信区间 + 原始日志链接见 log-format

我们不打算做的评价 ​

  • 不做 demo 视频评分。好看不等于对。
  • 不做单一任务的 SOTA 比较。这是架构提案,不是 benchmark 选手。
  • 不把阶段 2 指标当近期承诺。v0.1–v0.3 只留观测钩子。

待补 ​

  • [ ] 固定任务集的具体清单与版本化方式
  • [ ] 各指标的通过线(不是"提高",而是"高于多少算成立")
  • [ ] 失败注入的注入器设计(断电、打滑、遮挡、人闯入)
  • [ ] 抢占正确率的人工复核协议与抽样率

Apache-2.0 · v0.1 Design RFC · 四层神经系统是工程隐喻,不是生物等价声明