M4:事件层(可按需排空的日志 + 游标)+ 16 项判据
新增 mcfold/events.py:EventLog(环形缓冲 + seq + 游标)
- 不做回调式推送:LLM 是回合制的,回调会让事件在两次观察之间静默丢失
- drain(limit) 只取本轮、剩余留待下次(不丢)
- 细分层(block_changed❌y:z)独立可查,不污染粗粒度流
- render_events() 输出紧凑文本行,省 token
session 接线:block_change / multi_block_change / chat / damage /
entity spawn·move·destroy / held_item_slot,并加 chat()/command() 发送
修的真 bug:
- dropped 恒 0:deque(maxlen=) 丢元素无声 ⇒ 改手动计数(事件丢了必须说)
- 事件键 to_state_id 与渲染器的 to 不一致 ⇒ 显示 None,改为解出方块名;
from 区分「未加载/界外」而非裸 None
- run_tests.sh 只数 ✓ 不数 ★ ⇒ 判据少报(98 修正为 110)
实测:/setblock 后事件正确报 grass_block→stone→air,与状态层一致
判据:110 项全通过;4 项变异全部被抓
This commit is contained in:
36
plan.md
36
plan.md
@ -564,7 +564,7 @@ shot.rough → ASCII + 线索(给 agent 看它为什么选了这个角度)
|
||||
| **M2** | **协议客户端**:连测试服 → configuration → registry_data → 进 play | M0 | ✅ |
|
||||
| | (这是最大缺口:现有只到 `login_start` 冒烟级) | | |
|
||||
| **M3** | **状态层**:World / entities / inventory 从**服务端真状态**来 | M2 | ✅ |
|
||||
| **M4** | **事件层**:粗粒度 + 细分层(照 mineflayer,省 token) | M2 | ⬜ |
|
||||
| **M4** | **事件层**:粗粒度 + 细分层(照 mineflayer,省 token) | M2 | ✅ |
|
||||
| **M5** | **操作层**:chat / look / move / dig / place(能改世界) | M2, M3 | ⬜ |
|
||||
| **M6** | **粗渲染**(常驻感知):基于 M3 的真状态 | M3 | ⬜ |
|
||||
| **M7** | **LLM 友好的 API 形状**(§1d):自省 / 可读返回 / 限量 | M3–M6 | ⬜ |
|
||||
@ -634,6 +634,40 @@ nearby 半径 6 → 3 种(dirt 338 / bedrock 169 / grass_block 169)
|
||||
★ 其中「未知方块静默映射」第一次变异**是空操作**(改错了文件)⇒ 假绿;
|
||||
核对变异是否真命中后重做,才确认判据有效。**变异必须先验它落地了**。
|
||||
|
||||
### M4 实测结论(2026-09-26)
|
||||
|
||||
新增 `mcfold/events.py`(事件日志)+ session 的事件接线。
|
||||
|
||||
**关键设计:不是回调,而是「环形缓冲 + 游标」**
|
||||
mineflayer 用回调(`bot.on('physicsTick')`),适合长跑机器人;
|
||||
但 LLM agent 是**回合制**的 —— 回调对它有三个坏处:事件在两次观察之间
|
||||
静默丢失、状态散在闭包里不可查、粒度不可控(physicsTick 20/s 烧穿 token)。
|
||||
⇒ 用可按需 `drain()` 的日志 + 单调 `seq`,agent 能问「我看过 seq=37 之后又发生了什么」。
|
||||
|
||||
**实测(连测试服,含真实世界改动)**:
|
||||
```
|
||||
/setblock -2 -61 -5 minecraft:stone
|
||||
#27 方块变化 @(-2,-61,-5) grass_block → stone
|
||||
#26 系统: commands.setblock.success
|
||||
以后 setblock ... air
|
||||
#33 方块变化 @(-2,-61,-5) stone → air
|
||||
状态层: stone(state_id=1) → air(state_id=0) ✓ 一致
|
||||
细分层可查: block_changed:-2:-61:-5 ✓
|
||||
```
|
||||
|
||||
**本轮修的真 bug(3 个)**:
|
||||
1. **`dropped` 恒为 0**:`deque(maxlen=)` 丢元素**完全无声**(实测 maxlen=4 塞 10 只剩
|
||||
[6,7,8,9])。这正是本层最不能犯的错 —— 事件丢了却不说,agent 以为世界没变。
|
||||
⇒ 改手动判满 + 显式计数。
|
||||
2. **事件键与渲染器不一致**:我发 `to_state_id`、渲染器读 `to` ⇒ 显示
|
||||
「grass_block → None」(看着有事件、其实没信息)。改为解出**方块名**,
|
||||
且 `from` 区分「未加载/界外」而不是裸 None(把 unloaded 读成 air 会让 agent 误判脚下)。
|
||||
3. **run_tests.sh 少报判据数**:只数 `^ ✓`,我特意用 `★` 标的回归判据没被计入
|
||||
(test_events 16 条只报 7 条)⇒ 少报也是撒谎。修后总数 98 → **110**。
|
||||
|
||||
**判据**:`tests/test_events.py` 16 项;4 项变异全部被抓
|
||||
(drain 不推游标 / limit 变丢弃 / 细分层混入粗流 / 实体增量不除 4096)。
|
||||
|
||||
**建议顺序:M0 → M1 → M2**。
|
||||
- M0/M1 是解阻断(M1 是我已经查到根因的那个 classpath bug)
|
||||
- **M2 是真正的门槛**:从「能渲染」到「能玩」,缺的不是渲染,是**完整协议层**。
|
||||
|
||||
Reference in New Issue
Block a user