不是所有智能都需要大模型:俄罗斯方块 AI 的启示

57 阅读9分钟

image.png

不是所有智能都需要大模型:俄罗斯方块 AI 的启示

我最近给俄罗斯方块写了几个 AI 玩家:一个可以调参的贪心 AI、一个追求极致高分的「最佳实践」AI,还讨论过一个只停留在纸面上的"大模型玩家"。同一个游戏、同一套规则,三种完全不同的"智能"——这个过程让我想通了一个被大模型热潮掩盖的话题:智能是有层次的,规则和算法在特定领域依然是王者,大模型应该去做它真正擅长的事,而最高级的形态是让它们组合起来。

一、先看事实:200 行算法打爆"通用智能"

「最佳实践」AI 的全部代码不到 200 行:一个两层搜索加一个评估函数。它在仿真里一局能打约 5000 块、消上千行、拿下千万分,3 行和 4 行的消行占比是贪心版的 18 倍。

如果换大模型来玩会怎样?把棋盘编码成文字喂给它,让它决定落点——每步一次 API 调用(几百毫秒延迟),棋力大概率远不如这两百行代码(大模型的空间精确推理是众所周知的弱项),还按 token 烧钱。

在俄罗斯方块这个领域,"智能"的桂冠属于搜索算法,不属于大模型。 这不是大模型不行,而是赛道不对。

二、智能的本质:在环境里做出好决策

把"智能"这个词从神坛上请下来,它的工程定义朴素得很:感知环境,做出让目标最大化的决策。 至于用什么实现,取决于问题的性质:

问题的性质适合的"智能"实现例子
状态可精确枚举、规则确定、目标明确搜索 + 评估函数棋类、俄罗斯方块、路径规划、排班调度
有明确数学结构、可求导或可递推优化算法推荐排序、广告竞价、物流装箱
规则能写成清晰的条件规则引擎风控拦截、报销审批、工单路由
语义开放、需要知识和语言、输入模糊大模型理解意图、写文案、总结、对话、代码生成

判断标准可以浓缩成三个问题:能枚举吗?目标能写成公式吗?环境确定吗? 三个"是",就别请大模型——一把精尺量得准的事,不需要请一位博学的教授来目测。

大模型的真正强项在另一侧:它把人类语言和知识变成了可编程的接口。理解一句模糊的投诉、把需求翻译成方案、在没见过的领域给出常识判断——这些"开放世界"任务里它无可替代,但它不擅长也不该擅长大规模精确计算。

三、1 + 1 > 2:组合才是现代答案

实践中最有生命力的从来不是"谁取代谁",而是分工组合。几个已经被验证的模式:

1. 大模型理解意图,算法负责执行。 用户说"帮我把上个月华北大区的销量拉出来"——大模型把这句话翻译成受控 SQL,数据库(几十年沉淀的查询算法)毫秒级返回。让大模型直接"算"出答案?又慢又不可靠。智能客服里也是同理:大模型理解问题,关键词规则决定是否转人工。

2. 大模型生成候选,算法验证筛选。 AI 编程领域最成熟的闭环:大模型写代码,编译器和测试用例当考官,不过关就打回重写。生成的"创造力"加上验证的"严谨",各自做擅长的一半。

3. 算法产生精彩,大模型负责讲述。 想象给搜索 AI 配一个解说员:算法每落一子,大模型实时讲解"它留这一列井是因为在等 I 块凑 Tetris"。算法保证棋力,大模型提供叙事——精确性与可理解性,各取所长

4. 检索算法 + 语言模型 = RAG。 最流行的组合形态:向量检索(算法)从知识库里找到相关资料,大模型照着资料组织答案。一个管"找得准",一个管"说得好"。

你会发现一个规律:组合的粘合剂往往是一个清晰的接口——就像下面要讲的,我的俄罗斯方块架构里那条"这块放哪"的窄接口。

四、「最佳实践」模式是怎么实现的(架构篇)

tetris-ai-architecture.png

4.1 第一刀:把"游戏"和"玩家"分开

整个实现最重要的决定不是任何一行算法,而是一刀架构切分:游戏引擎是纯逻辑,不知道谁在玩;决策器是纯函数,不知道游戏长什么样。 看左图的分层:

  • 引擎层:棋盘、碰撞、旋转、消行、计分——一堆纯函数,move / rotate / hardDrop / tick,给它指令它就推进,谁给指令一律平等;
  • 玩家层:可插拔的决策器。人类键盘是一个玩家(按方向键产生指令),贪心 AI 是一个玩家(评估函数产生指令),最佳实践 AI 是一个玩家(两层搜索产生指令)。三者共用同一个引擎、同一套计分——成绩才有可比性。

两个玩家之间的接口窄到只有一句话:"这个局面下,这块放哪?" 输入棋盘和方块,输出目标旋转和目标列。因为接口够窄,换玩家、测玩家、给玩家做仿真,都不用碰引擎一行代码。

4.2 第二刀:两层搜索——在 1600 个平行世界里挑最好的

贪心 AI 的短视在于"只看当前这一块"。最佳实践 AI 的解法直白得近乎暴力(看右图):

  1. 枚举平行世界:当前块有若干种旋转、十来个落点;下一块(引擎本来就预知)同样如此。两两组合约 1600 种"两步下法",每一种都在棋盘的内存副本上完整落定、消行、结算——就像同时推开 1600 扇门看一眼门后的世界;
  2. 给每个世界打分:两步的真实消行得分,加上终局局面的评估——高度低加分、无空洞加分、表面平加分、留一口单列井加分(那是给 I 块预留的 Tetris 通道);
  3. 回到现实:执行分数最高的那个世界的第一步。下一块真的来临时,重新搜索。

为什么它就能"忍一手等四行"?因为消行分是超线性的(4 行 800 分,是 4 个单行的 8 倍),两层搜索又真的算得出"下一块是 I、现在留井能拿 800"。它不是学会了策略,而是算穿了策略

还有一处工程上的"保险丝":当堆高接近警戒线,消行的评估权重自动放大 5 倍——紧急泄洪,防止 AI 为了囤一个完美的 Tetris 把自己囤死。

4.3 核心代码走读(不到 40 行的精髓)

评估函数——把四种直觉写成一行加权求和:

function bestEval(board) {
  const f = boardFeatures(board)   // 高度、洞、起伏、井深、最高列
  return -0.04 * f.agg      // 总高度:堆得越低越好
       + -3.0  * f.holes    // 空洞:重罚,尽量不埋洞
       + -0.15 * f.bump     // 起伏:表面越平越好
       +  1.4  * Math.min(f.well, 4)  // 单列井:留给 I 块的通道,封顶4格
       + -0.6  * f.maxH     // 最高列:防囤死
}

两层搜索主循环——四个 for 循环,一场平行世界巡游:

function bestPlacement2(engine) {
  // 高压时消行收益 ×5,紧急泄洪
  const pts = boardFeatures(engine.board).maxH >= 11 ? 0.03 * 5 : 0.03
  let best = null
  for (const r1 of rotations(engine.piece))       // 当前块每种旋转
    for (const x1 of allColumns()) {              // 每个落点
      const s1 = simulateDrop(engine.board, r1, x1)   // 平行世界①:落定+消行
      if (!s1) continue
      let innerBest = -Infinity
      for (const r2 of rotations(engine.next))    // 下一块每种旋转
        for (const x2 of allColumns()) {          // 每个落点
          const s2 = simulateDrop(s1.board, r2, x2)   // 平行世界②
          if (!s2) continue
          // 终局局面分 + 下一块的真实消行分
          innerBest = Math.max(innerBest, bestEval(s2.board) + LINE_PTS[s2.cleared] * pts)
        }
      // 当前这步的得分 = 下一层最优 + 当前步真实消行分
      const total = innerBest + LINE_PTS[s1.cleared] * pts
      if (!best || total > best.score) best = { score: total, ...r1, targetX: x1 }
    }
  return best
}

simulateDrop 在棋盘的副本上模拟一次落子并结算消行——真棋盘毫发无损,这就是"平行世界"的全部实现。每块决策约 1600 次模拟、不到 5 毫秒,浏览器里毫无压力。

4.4 这套架构给了我们什么

  • 公平:多种玩家共用一个引擎一个计分,成绩才有含义;
  • 可测:决策器是纯函数,不启动页面也能在 Node 里一夜跑完上万局仿真——本文开头的战绩就是这么调出来的;
  • 可扩展:想加大模型玩家?写一个"输入棋盘文字描述、输出落点"的决策器插上去即可,引擎和其他玩家一行不改。

五、结语:智能是分层的,选对层比追新更重要

回到开头的问题。俄罗斯方块教给我们的不是"算法比大模型强",而是一个更完整的图景:

  • 反应层用规则——毫秒级、零成本、绝对可靠;
  • 优化层用搜索与算法——在可枚举的世界里逼近最优;
  • 认知层用大模型——处理语言、知识与开放世界的模糊性。

一个成熟的系统往往三层俱全:智能客服(规则转人工 + 检索算法 + 大模型回答)、AI 编程助手(大模型生成 + 编译验证)都是活例子。判断一个任务该用哪层,比学会调用哪个模型 API 更接近智能的本质。

下次面对需求,先问那三个问题:能枚举吗?目标能写成公式吗?环境确定吗?三个"是",写 200 行算法;出现了模糊、语义、开放世界——那才是大模型出场的时候。而当你需要两者兼备时,记得那条窄接口的启示:把系统切开,让每种智能只做它最擅长的事。