AI训练3D方块拾取游戏 – 完整开发复盘
从”假AI”到真正的强化学习,一路踩坑的实战记录
项目周期:2026-05-20 ~ 2026-05-22
作者:Ryan + OpenClaw AI助手
一、项目背景
1.1 初始目标
做一个3D方块拾取游戏,让AI通过强化学习自己学会:
- 找到方块 → 拾取 → 送到绿色目标区域
- 没有任何硬编码规则
- AI通过”眼睛”(视野感知)、”手脚”(移动+拾放)、”奖惩”(反馈机制)自主学习
1.2 技术栈
- 前端:Three.js (3D渲染) + TensorFlow.js (DQN神经网络)
- 算法:DQN (Deep Q-Network)
- 环境:Windows 10, 国内网络(需本地化CDN)
二、开发历程(时间线)
📅 Day 1 (2026-05-20):初版完成,发现根本问题
进展
- ✅ v1初版完成
- ✅ 基本玩法:AI移动、拾取方块、送到目标区
问题
- ❌ AI只是执行预设规则,不是真正学习
- 看起来像AI,实际上是if-else硬编码
决策
放弃硬编码规则,做真正的强化学习
理由:真正的AI应该自己发现策略,而不是执行人写的规则。
📅 Day 2 上午 (2026-05-21):核心机制设计
2.1 视野可扩大机制 (09:52)
决策:视野不是固定的,而是随成功扩大
- 初始:3×3 视野
- 每成功配送 +1(最大 9×9)
- 理由:正反馈循环,AI越做越好,看到的范围越大
2.2 识别奖励稀疏问题 (11:51)
问题:99%状态无反馈,AI学不到东西
分析:
- 只有”配送成功”给+20
- 其他时候都是0或-0.05
- 奖励太稀疏,AI不知道自己在进步
规划改进方案:添加渐进奖励(靠近目标时给小奖励)
2.3 Q-Table → DQN 转型 (14:19)
问题:Q-Learning表格法状态空间爆炸
- 5×5视野 = 25个格子
- 每个格子多种状态(空/方块/障碍/目标)
- Q-Table压缩后仍有67.4%无法压缩
决策:改用DQN神经网络
- 输入层:28维状态向量
- 隐藏层:128 → 64
- 输出层:9个动作(8方向移动 + 拾放)
- 经验回放容量:10000
- 目标网络同步:每100步
理由:状态空间太大,表格法存不下,必须用函数逼近(神经网络)
📅 Day 2 下午 (2026-05-21):调试与优化
2.4 修复CDN链接问题 (14:43)
问题:Three.js/TF.js从CDN加载,国内网络不稳定
解决:下载库文件到本地
libs/three.min.jslibs/tf.min.js
2.5 定位v6核心bug (15:28)
问题:init()定义位置在调用之后,导致初始化失败
解决:改为直接执行,不包装成函数
2.6 训练速度优化 (16:21)
优化:
- 每5步训练一次(而不是每步)
- 步速调至0ms(无延迟)
- 超时步数:200步(后来发现太低)
效果:训练速度提升10-12倍
2.7 修复刷分bug (17:27)
问题:已配送的方块没有标记delivered,导致可以重复配送刷分
解决:添加delivered标记,配送后方块消失
📅 Day 3 上午 (2026-05-22):奖励机制反复调试
3.1 问题:AI会卡机制、刷分
现象:每次添加渐进奖励,AI都会找到利用方法刷分,而不真正完成配送
调试过程(多次迭代):
| 时间 | 添加的奖励 | AI如何利用 | 结果 |
|---|---|---|---|
| 17:49 | 探索奖励 | 原地转圈刷探索分 | 删除 |
| 17:50 | 空手靠近方块奖励 | 来回走刷分 | 删除 |
| 17:59 | 带方块靠近目标渐进奖励 | 在绿色区边缘来回走 | 删除 |
| 08:59 | 拾取+3奖励 | 拾取后放下重复刷 | 删除 |
| 09:03 | 极简机制 | – | 采用 |
3.2 最终极简奖励机制 (09:03)
决策:只有配送才给正奖励,其他都是成本或惩罚
每步-0.05 | 撞墙-1 | 配送+20 | 硬捡-0.5 | 太远放下-1
理由:
- 渐进奖励都会被AI利用来刷分
- 只保留一个明确的目标(配送成功)
- 让AI自己探索策略,而不是引导它
3.3 修复avgReward虚高问题 (09:24)
问题:episodeRewards是扁平列表,每步reward都往里塞,+20直接拉高平均
解决:
- 每步累加到
episodeTotalReward - episode结束(成功 or 超时)才算一条记录
- avgReward反映”每局净赚多少”
3.4 DeepSeek建议 + 距离跟踪奖励 (09:39)
DeepSeek建议:
- ✅ 采纳:跟踪方块到目标的距离变化(扛着方块时,近了+0.5/格,远了-0.3/格)
- ✅ 采纳:拾起/放下同位置惩罚-5(防止AI原地拾放刷分)
- ❌ 不考虑:动作循环检测(太复杂)、首次拾起+10(太高)、硬终止规则
实现(09:50-10:00):
- 构造函数添加
pickupPos和lastCarriedDist - 拾取时记录初始距离
- 移动时跟踪距离变化
- 放下时检查是否同位置
- 成功配送后重置追踪变量
📅 Day 3 中午 (2026-05-22):语法错误大作战
3.5 文件损坏与修复 (10:00-11:26)
问题:多次用Node.js脚本编辑HTML,Windows \r\n换行符导致字符串匹配失败
后果:
- 构造函数被重复插入代码
executeAction函数结构损坏- 界面消失,无法显示
解决:
- 用
rewrite_func.js一次性重写整个executeAction函数 - 验证6/6检查全部通过
- 修复大括号/小括号不匹配
教训:
- ❌ 避免多次部分编辑
- ✅ 一次重写整个函数
- ✅ 每次编辑后验证括号匹配
- ✅ 备份第一:
copy file.html file.html.bak
3.6 修复agent初始化报错 (11:09)
问题:Uncaught ReferenceError: Cannot access 'agent' before initialization
原因:resetEpisode()引用agent变量,但agent用let声明,变量提升导致报错
解决:
let agent = null;→var agent = null;- 添加安全检查
if (!agent) return;
📅 Day 3 下午 (2026-05-22):效率优化
3.7 删除固定时间成本 (11:21)
问题:每步-0.05导致AI积极性低,成功率上升但奖励为负
解决:删除固定时间成本,改用方向引导奖励
- 空手朝最近方块走:+0.2/格
- 扛方块朝目标走:+0.5/格
- 扛方块后退:-0.3/格
效果:奖励变正,AI积极性提高 ✅
3.8 添加进度压力机制 (11:45)
问题:奖励变正后,AI”躺着也赚钱”,不急着完成任务
解决:每50步没配送扣2分
目的:逼AI尽快行动,不要赖着不走
3.9 添加步数效率奖励 (11:52)
问题:进度压力效果不如上一版本
解决:步数越少奖励越多
- 配送基础奖励:+20
- 效率奖励 = (MAX_STEPS – 实际步数) × 0.1
- 100步完成 → +70额外 → 总奖励90
- 700步完成 → +10额外 → 总奖励30
效果:AI拼命找最短路径 ✅
3.10 绿色区域限制 (11:57)
要求:只有放到绿色区域才给奖励,不在区域内再近也不给
解决:修改扛方块移动奖励逻辑
- 原:
if (diff > 0) reward += 0.5 * diff; - 新:
if (diff > 0 && currDist < 1.5) { reward += 0.5 * diff; }
效果:防止AI在边缘蹭分,必须真正进入绿色区域 👊
三、关键技术决策
3.1 为什么从Q-Learning转到DQN?
| 特性 | Q-Learning (表格) | DQN (神经网络) |
|---|---|---|
| 状态空间 | 离散、有限 | 连续、无限 |
| 泛化能力 | 无 | 有(相似状态共享权重) |
| 内存占用 | O(状态数×动作数) | O(网络参数) |
| 适用场景 | 小规模、离散 | 大规模、连续 |
本项目:5×5视野 + 携带状态 + 距离信息 = 28维状态向量
- 表格法:压缩后仍有67.4%无法压缩
- DQN:用神经网络近似Q函数,解决维度灾难
3.2 为什么奖励机制这么难设计?
核心矛盾:任何可度量的中间奖励,都会被AI利用来刷分
案例:
- 添加”靠近目标渐进奖励” → AI在绿色区边缘来回走刷分
- 添加”空手靠近方块奖励” → AI来回走刷分
- 添加”探索奖励” → AI原地转圈刷分
最终方案:只保留终极目标奖励(配送成功+20),让AI自己探索策略
补充机制:
- 距离跟踪奖励(近了+0.5/格)→ 但有绿色区域限制
- 步数效率奖励 → 鼓励快速完成
- 进度压力惩罚 → 防止拖延
3.3 为什么要用经验回放(Experience Replay)?
问题:连续样本高度相关,导致训练不稳定
解决:经验回放缓冲区(容量10000)
- 存储 (state, action, reward, next_state, done) 五元组
- 训练时随机采样batch(32条)
- 好处:
- 打破样本相关性
- 提高数据利用率(一条经验多次使用)
- 平滑训练分布
3.4 为什么要用目标网络(Target Network)?
问题:Q网络同时负责行动和评估,容易导致振荡
解决:两个神经网络
- Q网络(在线网络):负责选择动作
- Target网络(目标网络):负责评估Q值
- 每100步同步一次权重
好处:
- 稳定训练目标
- 减少振荡
- 提高收敛速度
四、踩过的坑(技术教训)
4.1 Windows换行符 \r\n 坑
问题:用Node.js读文件得到\r\n,但脚本里写\n会匹配失败
案例:
// 错误:匹配不到
c = c.replace('hello\nworld', 'hello\r\nworld');
// 正确:用正则或显式指定\r\n
c = c.replace(/hello\nworld/, 'hello\r\nworld');
// 或
c = c.replace('hello\r\nworld', 'new text');
解决方案:
- 脚本里用
\r\n匹配 - 或先统一换行符:
c = c.replace(/\r\n/g, '\n')
4.2 多次部分编辑导致文件损坏
问题:多次用脚本部分编辑HTML,导致重复代码、结构损坏
案例:
- 构造函数被重复插入
pickupPos = null executeAction函数大括号不匹配- 界面消失
解决方案:
- ❌ 避免多次部分编辑
- ✅ 一次重写整个函数
- ✅ 每次编辑前备份:
copy file.html file.html.bak - ✅ 每次编辑后验证括号匹配
4.3 正则表达式匹配到错误位置
问题:用[\s\S]*?贪婪匹配,可能匹配到错误位置
案例:
// 错误:可能匹配到文件后面的同名函数
c.replace(/oldFunc[\s\S]*?}/, 'newFunc');
// 正确:更精确的匹配
c.replace(/function oldFunc\(\) \{[\s\S]*?^\}/m, 'function newFunc() {}');
4.4 JavaScript变量提升坑
问题:let声明的变量不会提升,在初始化前访问会报错
案例:
// 错误
function resetEpisode() {
agent.xxx; // Uncaught ReferenceError: Cannot access 'agent' before initialization
}
let agent = new DQNAgent();
// 正确
var agent = new DQNAgent(); // var会提升
function resetEpisode() {
if (!agent) return;
agent.xxx;
}
五、最终方案(v6 DQN版)
5.1 文件结构
F:\R\R\AI Training\AI V6\
├── ai_v6_dqn.html (主文件)
├── libs\
│ ├── three.min.js
│ └── tf.min.js
└── dqn\
├── index.html
├── dqn-agent.js
├── game-environment.js
└── *.json (模型文件)
5.2 神经网络结构
输入层:28维
├── 5×5视野(25维)
├── 是否携带方块(1维)
├── 到最近方块距离(1维)
└── 到目标距离(1维)
隐藏层:128 → 64 (ReLU激活)
输出层:9维(8方向移动 + 拾放)
5.3 完整奖励机制
| 事件 | 奖励 | 说明 |
|---|---|---|
| 每步移动 | 0 | 无固定时间成本 |
| 空手朝方块走 | +0.2/格 | 方向引导 |
| 扛方块朝目标走(绿色区域内) | +0.5/格 | 只在dist<1.5时给 |
| 扛方块后退 | -0.3/格 | 鼓励前进 |
| 撞墙 | -1 | 惩罚 |
| 硬捡(无方块) | -0.5 | 惩罚错误动作 |
| 太远放下(dist≥1.5) | -1 | 惩罚错误动作 |
| 拾放同位置 | -5 | 防止刷分 |
| 配送成功 | +20 + 效率奖励 | 终极目标 |
| 超时空手 | -10 | 进度压力 |
| 超时拿方块 | -20 | 更重惩罚 |
| 每50步未配送 | -2 | 进度压力 |
效率奖励 = (MAX_STEPS – 实际步数) × 0.1
5.4 训练参数
epsilon: 0.3, // 探索率(前期0.5~0.8,后期0.05~0.1)
gamma: 0.99, // 折扣因子
learningRate: 0.001, // 学习率(前期0.01,后期0.0001)
replayCapacity: 10000,
batchSize: 32,
targetUpdateFreq: 100
六、项目收获
6.1 技术层面
- 强化学习奖励设计极其困难
- 任何可度量的中间奖励都会被AI利用
- 最好只保留终极目标奖励,让AI自己探索
- DQN适合大规模状态空间
- 表格法只适合小规模、离散状态
- 神经网络可以泛化到相似状态
- 经验回放 + 目标网络是DQN标配
- 稳定训练
- 提高数据利用率
6.2 工程层面
- 文件编辑要谨慎
- 备份第一
- 避免多次部分编辑
- 验证括号匹配
- Windows环境特殊坑
\r\n换行符- 路径分隔符
\ - 需要本地化CDN
- 调试工具很重要
- 括号匹配检查脚本
- 代码结构验证
- 控制台日志
6.3 产品层面
- AI训练需要耐心
- 前期avgReward为负很正常
- 要观察几百episode才能看到趋势
- 成功率比奖励更重要
- 奖励可以调整
- 成功率反映真实能力
- 用户反馈驱动迭代
- 老大多次提出机制问题
- 每次调整都让AI更智能
七、未来优化方向
7.1 算法层面
- [ ] Prioritized Experience Replay:优先回放重要样本
- [ ] Dueling DQN:分离状态价值和优势函数
- [ ] A3C/A2C:异步优势演员-评论家(更适合连续动作)
7.2 环境层面
- [ ] 动态障碍物:增加难度
- [ ] 多个方块:排序配送
- [ ] 更大地图:9×9 → 15×15
7.3 可视化层面
- [ ] 训练曲线实时绘制(TensorBoard)
- [ ] AI决策过程可视化(Q值热力图)
- [ ] 对比不同版本性能
八、总结
这个项目从”假AI”(硬编码规则)到真正的强化学习,经历了:
- 技术选型:Q-Learning → DQN
- 奖励机制:多次迭代,最终极简
- 工程调试:语法错误、文件损坏、环境兼容
- 效果优化:进度压力、效率奖励、绿色区域限制
核心教训:
真正的AI不是写出来的,是训练出来的。奖励机制设计比算法选择更重要。
当前状态:
- ✅ avgReward为正数
- ✅ 成功率持续上升
- ✅ AI学会高效配送策略
下一步:
- 继续训练观察稳定性
- 定期保存”AI大脑”
- 尝试更难的地图
项目仓库:F:\R\R\AI Training\AI V6\ai_v6_dqn.html
在线演示:https://ryanren.top/ (待部署)
写于 2026-05-22,济南
Ryan + OpenClaw AI助手 联合创作




