plan.md:立起最顶层目的 —— 给 agent 一副能在 MC 里感知与行动的工具包

用户定调:插件目的是「让 agent 可以借助我们提供的工具包去玩我的世界」。

推论三条(改变工程重心):
  ① API 形状要照 LLM 用法设计,不是照程序员用法
     (mineflayer 是给写 bot 的人用的库;我们面向 LLM 直接调用)
  ② 感知 + 行动缺一不可 ⇒ 状态/事件/操作三层是正式骨架
  ③ 渲染是工具之一,不是全部 —— 之前把它当主线是重心错了

新增:
  §1c  空白测试服(不用现役服;现役 world 15G + mods 64,测不出边界)
  §1d  面向 LLM 的 API 形状(自省 / 可读返回 / 限量 / 失败要说清为什么)
  §6   里程碑重排:M0 测试服 → M1 修构建 → M2 协议客户端(真正的门槛)
       细渲染降到 M8(已能跑,只是接不上服务端真数据)
       拍照降为 M9(验证工具包的用例,不是工具包本身)

已核实的关键事实(写入 plan):
  · mineflayer 自述 'create minecraft bots with a stable, high level API'
    41 个 plugins 全是动作与感知,grep 行为树/目标选择 = 0 命中
    ⇒ 它是给 bot 开发者的库;决策在它之外,那是我们该留给 agent 的部分
This commit is contained in:
JianFeeeee
2026-09-26 10:50:21 +08:00
parent 7c7297ebad
commit c80b06552f

124
plan.md
View File

@ -5,7 +5,37 @@
---
## 0. 目标(用户定向,按时间顺序)
## 0. 目的(最顶层,2026-09-26 用户定调)
> 因为我们的这个插件目的就是为了**让 agent 可以借助我们提供的工具包去玩我的世界**。
★ **这是最顶层的目的,下面所有东西都是为它服务的手段。**
```
我们提供:一副「能在 MC 世界里感知 + 行动」的**工具包**
agent 提供:决策(该干什么、去哪、为什么)—— 我们**不替它决定**
```
推论(三条,改变工程重心):
1. **工具形状要照 LLM 的用法设计,不是照程序员的用法。**
mineflayer 是 `create minecraft bots with a stable, high level API` ——
它是给**写 bot 的人**用的库;我们面向的是 **LLM 直接调用**。
差别很实:参数要自解释、返回要可读、错误要说清"为什么不行",
而不是抛个异常让调用者去读栈。
2. **「能感知 + 能行动」两者缺一不可。**
只有感知(渲染)⇒ agent 是个观众;
只有行动(操作)⇒ agent 是瞎子。
所以 §1b 的「状态 / 事件 / 操作」三层是**工具包的正式骨架**,
不是"以后再补"。
3. **渲染是工具之一,不是全部。**
细渲染(出图)是工具;粗渲染(常驻感知)是工具;
`move` / `dig` / `place` / `chat` 也是工具。
之前把它当主线,是重心错了。
---
## 0b. 目标(用户定向,按时间顺序)
1. **照相机式渲染**:给一个世界(存档数据 / 服务端),渲染出图。
- 用户原话(2026-09-25):「不起完整客户端」——抽出 MC 的**渲染能力**,
@ -167,6 +197,57 @@ bot.saveScreenshot WorldRenderer.screenshot() 细渲染(单次调
---
## 1c. 空白测试服(用户 2026-09-26 定向)
> 我觉得可以**起一个空白新服**用来测试功能,而不是用现在的服。
**理由(不只是"干净")**:
- 现有服 `/home/minecraft`:world 15G、mods 64 个、neoforge 1.21.1 ——
任何协议层改动都可能污染它,且**测不出边界**(模组太多、状态太杂)。
- 我们要验的是**协议与行为**,需要**可预期**的环境:已知方块集、已知出生点、
可重置的世界。
**形态(待定,需你定)**:
| 项 | 选项 |
|---|---|
| 版本 | vanilla 1.21.1(最简,协议最干净) / neoforge 1.21.1(与现有一致) |
| 模组 | 先 0 个(验协议)→ 再逐个加(验 mod 差异) |
| 端口 | 25565(避开现役) / 25566+ |
| 目录 | 与 `/home/minecraft` **同级**(版本隔离:内容根 / 实例 / 运行期) |
| 世界 | 全新生成,固定种子(可预期) |
★ 磁盘:/home 尚有 136G ⇒ 放得下(现役 world 已 15G,空白服初期只占几十 M)。
**它同时是「版本隔离」策略的第二个实例**:
`store/vanilla-1.21.1/` + `instances/test-server/` + `runtime/test-server/`
—— 与我们给 agent 建的实例同一套口径。
---
## 1d. 面向 LLM 的 API 形状(§0 推论 1 的落点)
mineflayer 的 API 面向**程序员**;我们面向 **LLM**。具体差别与对策:
| 维度 | 程序员友好的做法 | LLM 需要的 | 我们的对策 |
|---|---|---|---|
| 参数 | 位置参数 + 选项对象 | **全命名、少量必填** | `find_blocks(matching=..., max_distance=...)` |
| 返回 | 原始对象/布尔 | **可读摘要 + 关键字段** | 附 `describe()`(`BlockHit` 已有) |
| 失败 | 抛异常 | **说清"为什么不行 + 怎么办"** | `source="unloaded"` / `"unknown-state"` 那种自述 |
| 规模 | 返回全部 | **限量 + 计数**(省 token) | 默认 `count=10`,另给 `total` |
| 发现 | 读文档 | **可自省** | `bot.describe()` 列出可用操作与必需参数 |
★ 已有可借鉴的样本:`BlockHit.describe()` —— 明确区分
「未加载」/「超出世界高度」/「unknown(id),本机注册表无此 state id,
可能来自 mod 方块」/ 正常。**这正是 LLM 需要的说法**:
不是报错,而是告诉它「这个方块你暂时看不到,为什么」。
⚠️ `unknown(id)` 这一点尤其关键(§0 推论):mod 方块的 state id **只有服务端知道**,
客户端本机注册表里没有 ⇒ 粗渲染遇到它必须**如实说"我不认识"**,不能瞎猜一个。
这与「与服务端 mod 物品交互」那条线直接相关。
---
## 2. 已完成(可复用,有提交)
### 2.1 渲染桥(P8/P9)
@ -453,27 +534,36 @@ shot.rough → ASCII + 线索(给 agent 看它为什么选了这个角度)
---
## 6. 里程碑(建议顺序)
## 6. 里程碑(按 §0 目的重排)
★ 重心:**「让 agent 能玩」** = 工具包(感知 + 行动)。
  渲染是工具之一,不是主线;机位/拍照是用例,不是目的。
| # | 内容 | 依赖 | 状态 |
|---|---|---|---|
| M1 | 修 G1(build.sh 编译 CP 加 Fabric 库),1.21.1 构建跑通 | — | 🔄 |
| M2 | **抽象模型骨架**:状态/事件/操作三层(照 mineflayer 形状) | — | ⬜ |
| M2a | └ `rough.py` 常驻粗渲染(World 视图 + DDA 视线 + ASCII/线索) | M2 | ⬜ |
| M2b | └ 事件总线(粗粒度 + 细分层) | M2 | ⬜ |
| M3 | 粗渲染自身判据(构造场景;**不要求预测细渲染**) | M2a | ⬜ |
| M4 | `capture_photo()`(**作为第一个用例**:粗搜机位 → 细出图) | M2a, M2b, M3 | ⬜ |
| M5 | 服务端交互(configuration / registry_data / 物品表) | M1 | ⬜ |
| M6 | 聊天框 → agent → 拍照 全链(§5) | M1, M4, M5 | ⬜ |
| **M0** | 起**空白测试服**(§1c),版本隔离三件套 | — | ⬜ |
| **M1** | 修 build.sh 编译 CP(加 Fabric 库)⇒ 1.21.1 构建跑通 | — | 🔄 |
| **M2** | **协议客户端**:连测试服 → configuration → registry_data → 进 play | M0 | ⬜ |
| | (这是最大缺口:现有只到 `login_start` 冒烟级) | | |
| **M3** | **状态层**:World / entities / inventory 从**服务端真状态**来 | M2 | ⬜ |
| **M4** | **事件层**:粗粒度 + 细分层(照 mineflayer,省 token) | M2 | ⬜ |
| **M5** | **操作层**:chat / look / move / dig / place(能改世界) | M2, M3 | ⬜ |
| **M6** | **粗渲染**(常驻感知):基于 M3 的真状态 | M3 | ⬜ |
| **M7** | **LLM 友好的 API 形状**(§1d):自省 / 可读返回 / 限量 | M3–M6 | ⬜ |
| **M8** | **细渲染**(单次调用):出图,带光影 | M2 | ⬜ |
| **M9** | 第一个用例:`capture_photo()`(粗搜机位 → 细出图) | M6, M8 | ⬜ |
**建议先做 M1 + M2**:M1 解阻断;M2 是**主线**(抽象模型骨架),
拍照只是它的第一个用例。M2 做完后 agent 就有常驻感知能力了,
而这正是"日常游玩"的地基。
★ M3 特意**不叫**"一致性判据":按用户口径粗/细服务于不同问题,
不要求粗渲染预测细渲染的像素。M3 只验粗渲染**自己**对日常感知问题的正确性
(构造简单场景,人工可推算)。
**建议顺序:M0 → M1 → M2**。
- M0/M1 是解阻断(M1 是我已经查到根因的那个 classpath bug)
- **M2 是真正的门槛**:从「能渲染」到「能玩」,缺的不是渲染,是**完整协议层**。
mineflayer 的 41 个 plugins 全建立在它之上,我们目前只到 `login_start`。
---
★ M8(细渲染)**不是**早期优先级 —— 它已经能跑(Iris 光影 + 地形,
`colors=113546` 是实测),只是**接不上服务端真数据**。等 M2/M3 通了,
它自然就在链路上。
★ M9(拍照)放最后 —— 它是**验证工具包立不立得住**的用例,
不是工具包本身。
## 7. 工程纪律(本项目已确立的口径)