摘要
AI 的搜索用 alpha-beta 剪枝:在一个“窗口”(alpha 到 beta)里搜索,超出窗口的分支提前放弃,并把搜过的局面存进缓存(置换表)供以后复用。检查 deep 档为何太慢时,我们发现一个与性能无关的正确性错误:旧代码只看“本层有没有剪枝”来决定缓存是否精确,但子层可能已经按窗口剪枝,本层拿到的只是上界或下界。把它当精确值存下,之后用别的窗口查询就会得到错值。用一棵可以手算的小树复现了这个错误,修复后又补了一处等价的提前返回。开局 deep 决策从 90.481 秒降到 75.603 秒,选择和评分不变,但仍超过一分钟。
要回答的问题
缓存里存的“精确值”是否真的精确?修复会不会改变已有决策和历史存档?
复现
蓝方正确值应为 max(min(5, 1), min(4, 2)) = 2。先用 alpha = 10 搜索,两个子树分别在看到 5 和 4 后被剪枝,本层返回的 5 只是上界,本层自身却没有剪枝。旧实现把 5 存成精确值,随后开放窗口搜索错误地返回 5;红方视角同样应为 −2,旧实现返回 −5。新增的两个测试在修复前都实际失败。这是手算树的验证,不是游戏规则或真实战斗准确率的证据。
方法
- 记录调用时的原始 alpha / beta。只有本层没有剪枝、且返回分数严格落在原始窗口内部时,才写入精确缓存;落在边界上的分数也不当精确值。预算、候选排序、评估公式和公共接口都不变。
- 这会改变某些原本错误的决策,所以策略身份加上新标记 exact-window-cache-v1;旧存档事件仍按原身份读取,不改写历史报告。
- 同批的静态剪枝:quiescence(只继续搜攻击的“静止搜索”)原本即使静态分数已经让窗口闭合,仍会枚举并结算所有攻击。现在先用静态分数更新窗口,闭合则直接返回界限。取最大方的结果不会低于静态分数、取最小方不会高于它,因此不需要再算。没有降低深度、宽度或采样数。新增两侧边界测试在改动前同样失败(旧代码返回 ±12,而 ±10 已足以剪枝)。
结果
| 检查 | 结果 |
|---|---|
| 修复后搜索 / 法术投影 / 移动 / 预算测试 | 180 通过(11.81 秒) |
| 接入策略身份后六个文件 | 181 通过(258.55 秒),含旧事件兼容 |
| 静态剪枝后五个文件 | 183 通过 |
| 开局完整 deep 决策(缓存修复后) | 90.481 秒、8179 节点,仍选对 red:succubus 施加镜像,评分 20626.10120485714 |
| 加静态剪枝后 | 75.603 秒、7472 节点、8752 次缓存命中;所选动作、评分、全部候选排序与四个采样分数范围不变 |
另做了 30 秒离线采样,116 次非终局搜索中没有出现相同状态 / 预算的重访,因此没有再加上下界缓存。
局限
- 开局这一个样本与旧基线相同,不代表其他输入下旧缓存结果都正确。
- 75.603 秒是单次候选样本,仍超过一分钟,延迟目标没有验收通过;没有运行全仓测试。
结论与下一步
缓存正确性问题已修复并有可手算的回归测试;静态剪枝减少了无效工作而不改变选择。deep 档延迟仍需继续定位。
Comments