假期的清晨,小蒙攥着一张皱巴巴的游乐园地图,傻眼了。这座乐园太大了——入口有九个岔路,每个岔路又分九条支路,支路里还有支路。他反复翻看地图,也算不出“半天时间到底怎么玩才最值”。这就像游戏AI面临的难题:围棋每一步有约两百种走法,要下上百手,把所有可能全算一遍,比宇宙里的原子还多,传统“每条路都走到底”的办法根本走不完。 但小蒙灵机一动:既然算不完,不如“随机试玩”!他先去路人中打听口碑,挑一条路线走下去,看到新项目就快速试玩一把,然后把游玩感受记在小本本上——沿途每个项目的“好评次数”和“试玩次数”都更新一遍。回到入口,看着小本本,决定下一轮往哪走。就这样循环一个上午,他只玩了很少的项目,却已经能自信地向游客们推荐“今天必玩榜”。 这套思路,正是蒙特卡洛树搜索(Monte Carlo Tree Search,MCTS)。它不追求算尽天下,而是用“选择—扩展—模拟—回溯”四步循环,靠有限次随机试玩逼近最优决策。下棋、打策略游戏、驱动游戏NPC,靠的都是它——这也是 AI 从业者从“规则脚本”走向“会思考的AI”的必经一站。
对 AI 从业者而言,MCTS 是游戏 AI 与强化学习之间的桥梁:理解它,你就能设计出会“思考”的 NPC 与棋类 AI,也拿到了读懂 AlphaGo 等顶尖系统的钥匙。
可视化演示
展示MCTS选择扩展模拟回传四阶段循环、UCB1公式平衡利用与探索的节点选择、搜索树迭代生长访问次数收敛及棋类博弈落子评估决策,含流动波形背景动画。
本节配有交互动效(进入视口后自动加载,约 3KB)。
蒙特卡洛思想
小蒙没有把乐园地图上每条路都走一遍——那要走上好几年。他另辟蹊径:在人流量最大的出口拦住五十位刚玩完的游客,挨个问“刚才那个项目好玩吗”。五十个答案里,四十一人说好玩。他据此拍板:这片园区值得去。这就是“用少量抽样推断整体”,先试再议,不必尽知。
蒙特卡洛(Monte Carlo)本是摩纳哥的赌城名字,科学家借用它指代“用随机实验做统计计算”的方法。比如要算一块不规则图形的面积,可以往图形上随机撒豆子,数一数落在图形里的豆子比例,乘以总区域面积,就能近似得到真实面积。豆子撒得越多,答案越准。AI 里的蒙特卡洛方法同理:反复随机模拟,把结果平均,用统计逼近真相。
在游戏 AI 中,我们想评估某个局面 s 到底“偏谁赢”。精确评估需要遍历所有后续可能,做不到;蒙特卡洛方法则随机模拟 N 局(比如随机走棋直到分出胜负),把每局结果记下来取平均,得到局面价值的估计值。这就是“以少代多”的统计决策。
小蒙没有走遍乐园,却对园区有了大致判断;MCTS 也用同样的“以少代多”思想,让 AI 在算不完的棋局里,也能估计出哪一步更可能通向胜利——这就是蒙特卡洛思想的核心魔法。
- 状态 s当前游戏局面,比如棋盘上已经落下的所有棋子,对应小蒙眼中“园区某个区域”
- 模拟次数 N随机试验的总次数,对应小蒙拦住游客询问的人数
- 单次回报 R_i第 i 次随机模拟的最终结果(赢=1、输=0、平=0.5),对应一位游客回的一句“好玩/不好玩”
- 取平均把所有回报加起来除以 N,得到状态价值的估计值
树搜索框架
有了“随机试玩”的底气,小蒙开始画“探索地图”。他把园区画成一棵树:树根是他现在站的位置,每根树枝对应一条岔路,岔路尽头又是一个新的小广场,再分出新的岔路。玩过、见过的路口,他就在树上标一个点;没见过的,先空着。地图不是一次画完的,而是边逛边补。
游戏 AI 里的“搜索树”正是这样:节点(Node)表示一个局面状态,边(Edge)表示一步动作。从根节点出发,沿着边走到子节点,就是对局向前推进了一步。注意,MCTS 不是一次性把整棵树建好——那叫穷举——而是边玩边画,每轮迭代只在树上“长出”一点点。
搜索树的规模由分支因子 b 和深度 d 决定。围棋的分支因子 b≈250、对局深度 d≈150,若穷举所有路径,状态数会指数爆炸,主流计算机几万年也算不完。MCTS 只挑有希望的路径反复走,所以它的树“长得高但很窄”。
小蒙明白了一个道理:在巨大的乐园里,把地图画完本身就是不可能的。与其纠结“全画完”,不如先画一棵“够用”的小树,再让它在实践中慢慢长大——这正是搜索树交给 MCTS 的使命。
- 分支因子 b每个局面平均有多少种合法走法,对应园区一条路能分出的岔路数量
- 深度 d一局游戏最多走多少步,对应小蒙从入口走到最远端项目的步数
- 等比数列求和从第 0 层到第 d 层所有节点数相加
- 指数爆炸b 和 d 稍大,总状态数就超出可计算范围
选择与UCB
小蒙的小本本越来越厚,每个路口都记着“试玩次数”和“好评次数”。下一次该往哪走?他心里有个小算盘:既想去“大家都说好”的网红项目(利用),又想去“还没几个人去过、说不定有宝藏”的冷门角落(探索)。两条腿走路,才不辜负半天时间。
这就是 MCTS 的“选择(Selection)”阶段:从根节点出发,沿着树往下,逐步选一个最有潜力的子节点。但“最有潜力”不能只看胜率——一个只试玩过 1 次、胜率 100% 的项目,未必比试玩过 100 次、胜率 80% 的项目更靠谱。样本太少的统计结果,信不过。
于是科学家设计了 UCB(Upper Confidence Bound,置信上界)打分公式:每个子节点 j 的分数 = 已知平均胜率 + 一个“未知加分”。被访问次数越少的节点,加分越高。选择时永远挑分数最大的子节点往下走。这既尊重既有口碑,又鼓励探索新鲜角落。
小蒙恍然大悟:原来“口碑好”和“新鲜感”要一起算账。正是这个公式,让 AI 在“利用已知优势”与“探索未知可能”之间保持动态平衡,既不死磕一个项目,也不漫无目的地乱逛。
- 平均胜率 X̄_j节点 j 累计胜场除以访问次数,代表已知口碑
- 父节点访问次数 N当前节点总共被访问的次数,代表整体探索规模
- 子节点访问次数 n_j候选子节点 j 被访问的次数,越小探索项越大
- 探索常数 c调大更爱尝鲜,调小更偏保守
扩展与模拟
选定一条路后,小蒙走到小广场,发现旁边有条没标注过的岔路,通向一个他从没见过的新项目。他小心翼翼地把它画上地图,标上“待试玩”。这就是“扩展(Expansion)”:给搜索树添一个全新节点,代表一个新的可达局面。
画完新节点,小蒙决定“快速试玩”:冲进项目,以最快的速度体验完整流程,心里默默打个分。在 MCTS 里这叫作“模拟(Simulation)”,也叫快速走子(Rollout):从新节点出发,双方随机走棋,一直走到分出胜负为止。模拟的结果,就是这次扩展的“试玩报告”。
注意,模拟虽然是“随机”,但通常会用“快速走子策略”让它更合理:优先吃对方棋子、抢占中心位置、避免自杀式送子等启发式规则。模拟策略越贴近真实对局,模拟结果的参考价值就越高——这正是“模拟策略改进”的核心思路:给随机性装上经验的翅膀。
小蒙发现,试玩并不是瞎玩,玩得越贴近真实游客的感受,记录越有价值。MCTS 的模拟策略也因此从“纯随机”一步步进化为“带经验的快速走子”,让 AI 的估计变得越来越靠谱。
- 状态动作对 (s,a)在局面 s 下选择动作 a,对应小蒙刚发现的新项目
- 模拟次数 K对这个动作做的随机对局次数
- 第 k 次模拟回报 z_k一次随机对局打完的结果值
- 均值Q 帽是动作价值的估计,决定这个节点值不值得继续被访问
回溯与更新
试玩结束,小蒙拿着分数回到小本本前:不只是新项目要记一笔,从入口一路走过来的每一个路口,全都得更新!毕竟新项目好不好玩,也会影响游客对这条路线整体的判断。他沿着来路,一级一级地往回改记录。
这就是“回溯(Backpropagation)”:把模拟结果沿着刚才选择的那条路径,从叶子节点一路传回根节点。路径上每个节点的访问次数加 1,胜场按模拟结果累加。这样一来,上层节点对“这半边园区值不值得去”的印象,也会被一并刷新。
回溯的本质是维护统计量:每个节点用“胜场/访问次数”记录胜率。假设某个第二层节点原本 3 胜 7 负,这次模拟赢了,它就变成 4 胜 8 负,胜率从 30% 升到 33.3%。下次选择时,UCB 公式就能用到这份新数据——小本本上的每一个数字,都在为明天做铺垫。
每一次试玩,都是对小本本的一次“全链路刷新”。小蒙越来越熟练,他也终于明白:MCTS 从不下“一个死结论”,而是不断用新数据修正旧印象——这正是它在动态博弈中保持灵活的关键。
- 子节点访问次数 N(s,a)每个子动作被选择的次数
- 总访问次数 N(s)所有子节点访问次数之和,代表这个区域被探索的总量
- 胜场 W(s,a)该节点累计带回的获胜次数
- 胜率 Q(s,a)胜场除以访问次数,就是该节点在小本本上的“口碑分”
应用与对比
几个月后,小蒙成了游乐园的“民间攻略王”。他用小本本上的经验,给无数游客推荐了最值得玩的项目。可有一天他发现,有些项目自己明明没怎么玩过,推荐却特别准——因为他学会了“在口碑之外看新鲜感”,这正是探索的力量在起作用。
MCTS 在真实游戏 AI 中战绩斐然。2016 年 AlphaGo 击败李世石,核心引擎之一就是“MCTS + 深度神经网络”:用策略网络指导选择和模拟、用价值网络评估局面,大幅替代耗时随机的模拟走子。今天,从围棋、象棋、五子棋到《星际争霸》式的策略游戏,MCTS 已是游戏 AI 的标配。
传统搜索(如极大极小搜索)需要人工设计精确的评估函数,面对巨大分支因子时常力不从心;MCTS 则几乎不需要领域知识,靠随机模拟和统计就能干活,还能随时用启发式规则、神经网络“打辅助”。它用“只采样 M 条完整路径”代替“穷举全部状态”,这就是它能在巨型博弈里存活的原因。
小蒙合上小本本,望向那座熟悉又陌生的乐园。他终于明白:完整的信息从来不是决策的前提,聪明的抽样和持续的修正才是。从游乐园到围棋棋盘,MCTS 用同一种智慧,让 AI 在巨大的不确定性中,一步步打出好牌。
- 模拟局数 M每次决策允许的随机对局次数
- 单局长 L每局随机走棋的平均步数
- 总成本 M×L所有模拟消耗的计算量总和
- 远小于符号 ≪ 表示与爆炸式的 b 的 d 次方相比,采样成本可以忽略不计
AI 应用场景
棋类游戏人机对战
阶段:决策规划
解决的问题:传统棋类人机用极大极小搜索加手工评估函数,评估函数难调,分支一大就卡顿;MCTS 用随机模拟自动估计局面价值,不需要手写“这个位置值几分”的评分表,就能在有限时间内选出稳妥落子,小白开发者也能快速上手。
具体案例:某五子棋小游戏接入 MCTS:每回合分配 500 毫秒、运行约 1500 次迭代,最终落子是根节点下访问次数最多的子节点。上线后玩家反馈“AI 会进攻也会防守”,研发周期从两周压缩到两天。
策略游戏NPC决策
阶段:行为决策
解决的问题:即时战略和回合制游戏中,NPC 的“出兵、建城、升级”选择组合爆炸,行为树写死脚本会显得死板;把 MCTS 放在行为树的动作选择层,让 NPC 通过“随机预演未来”选择当下最优行动,行为会更灵活多变。
具体案例:某自研回合制策略游戏 mod 中,NPC 每回合用 MCTS 模拟 300 次“未来十回合”的发展路径,比较造兵、建城、研究科技三类行动的价值并动态调整权重。玩家惊喜地发现“NPC 会针对我的打法变招了”。
卡牌对战AI
阶段:在线决策
解决的问题:卡牌游戏中手牌、站位、目标组合数爆炸,且对手策略未知;MCTS 擅长在“不完全可预测”的环境中做决策,通过随机模拟对手的可能响应,选出胜率期望最高的出牌组合,比固定脚本 AI 更抗针对。
具体案例:某自研卡牌游戏的困难人机:每回合迭代 800 次,模拟时用“优先解场、估算斩杀线”等规则加速终局判断,AI 胜率从脚本 AI 的 35% 提升到 62%,玩家匹配等待时间也明显缩短。
Python 演示
import mathimport random class Node: def __init__(self, state, action=None, parent=None): self.state = state # 当前棋盘局面 self.action = action # 到达该节点所走的落子 self.parent = parent # 父节点 self.children = [] # 子节点列表 self.wins = 0 # 累计获胜次数 self.visits = 0 # 被访问次数 def ucb(self, c=1.4): if self.visits == 0: return float('inf') return self.wins / self.visits + c * math.sqrt( math.log(self.parent.visits) / self.visits) def get_legal_moves(board): return [i for i, v in enumerate(board) if v == 0] def apply_move(board, move, player): nb = board[:] nb[move] = player return nb def check_winner(board): lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]] for a, b, c in lines: if board[a] != 0 and board[a] == board[b] == board[c]: return board[a] return 0 def turn_of(board): return 1 if len(get_legal_moves(board)) % 2 == 1 else 2 def rollout(board): b = board[:] while check_winner(b) == 0 and 0 in b: p = turn_of(b) b = apply_move(b, random.choice(get_legal_moves(b)), p) w = check_winner(b) if w == 1: return 1.0 if w == 0: return 0.5 return 0.0 def backprop(node, result): while node is not None: node.visits += 1 node.wins += result node = node.parent def select(node): while node.children: node = max(node.children, key=lambda ch: ch.ucb()) return node def expand(node): for move in get_legal_moves(node.state): node.children.append( Node(apply_move(node.state, move, turn_of(node.state)), move, node)) return random.choice(node.children) def best_move(board, iterations=800): root = Node(board) for _ in range(iterations): leaf = select(root) if check_winner(leaf.state) == 0 and get_legal_moves(leaf.state): leaf = expand(leaf) result = rollout(leaf.state) backprop(leaf, result) best = max(root.children, key=lambda ch: ch.visits) return best.action def human_move(board): while True: try: m = int(input('输入落子位置(0-8): ')) if m in get_legal_moves(board): return m except ValueError: pass print('位置无效, 请重试') def play_game(): board = [0] * 9 print('AI(X)先手, 你执O. 位置编号 0-8:') while check_winner(board) == 0 and 0 in board: if turn_of(board) == 1: board = apply_move(board, best_move(board), 1) print('AI 落子:', board) else: board = apply_move(board, human_move(board), 2) print('棋盘:', board) w = check_winner(board) if w == 0: print('平局') else: print('AI 获胜' if w == 1 else '你赢了') if __name__ == '__main__': play_game()
return self.wins / self.visits + c * math.sqrt(...)UCB 打分:利用项(口碑分)+ 探索项(新鲜感加分)。node = max(node.children, key=lambda ch: ch.ucb())选择阶段:沿 UCB 分数最高的子节点一路下行。node.children.append(Node(..., move, node))扩展阶段:把所有合法落子都挂成新子节点。result = rollout(leaf.state)模拟阶段:从叶子节点随机走子到终局,返回回报值。backprop(leaf, result)回溯阶段:把结果沿父链传回根节点,更新访问次数与胜场。return max(root.children, key=lambda ch: ch.visits)决策:不再看胜率,而是选访问次数最多的子节点,这也是 MCTS 的标准做法。
常见误区
误区我总觉得 MCTS 只要把迭代次数调大,AI 就会越来越无敌,把次数拉到几万次肯定能赢;如果输了,肯定是次数还不够大。
正解模拟次数确实提升决策质量,但收益是收敛的:从 100 次到 1000 次提升明显,从 10000 次到 20000 次几乎无差别。MCTS 的精髓是在有限预算内用 UCB 平衡探索与利用,而不是盲目堆次数。好比小蒙有半天时间,把时间全花在一个项目上反复排队,反而错过其他好项目。
为何常见:直觉上“看得多=看得准”,加上计算资源越来越便宜,容易让人觉得堆算力就能解决一切,忽略了统计方法的收敛性与边际收益递减规律。
误区UCB 选择不就是看子节点胜率吗?谁胜率高选谁,这样最稳妥,为什么还要加一个奇怪的带根号的公式?
正解纯贪心选胜率会导致“早期偶然赢了一次的项目被反复选中”,而真正的好项目因为样本太少、胜率没来得及体现,永远不被发现。UCB 的探索项会在访问次数少时额外加分,逼着 AI 去“尝鲜”。就像小蒙既要光顾网红项目,也得去冷门角落转转,才可能发现黑马项目。
为何常见:“利用”是最符合直觉的策略,人们天然倾向确定性收益;而探索的价值需要长期才能体现,初学者很难直观感受到,所以容易把 UCB 简化成“选胜率最高”。
误区MCTS 的模拟阶段既然是随机的,那就像掷骰子一样完全摆烂,跟乱下没区别,走子质量好坏无所谓。
正解随机模拟的“随机”是必要的不确定性,但通常会用快速走子策略注入领域常识:先吃子、占中心、避免自杀、优先解威胁。模拟策略越接近真实对局,模拟结果参考价值越高。好比小蒙试玩时会按“大多数人的玩法”体验项目,而不是故意乱按按钮。
为何常见:名字里带“随机”容易让人误解为“随意”;实际上随机只是手段,统计收敛才是目的,模拟策略的改进恰恰是 MCTS 最重要的优化方向之一。
误区MCTS 厉害的地方就是啥都不用管,随便模拟几万次就能赢,根本不需要写评估函数,也不需要懂游戏规则以外的知识。
正解MCTS 确实大幅降低了对人工评估函数的依赖,但“不需要领域知识”是夸大。扩展时的合法动作、模拟时的快速走子策略、UCB 的探索常数 c,都在注入领域知识;AlphaGo 更是把深度神经网络直接嵌进 MCTS。领域知识越丰富,MCTS 收敛越快,好比小蒙熟悉乐园地图后,探索效率远超闭眼乱闯的游客。
为何常见:对比传统搜索,MCTS 的“少依赖”被包装成“零依赖”,加上网上教程反复强调“免评估函数”,初学者容易以偏概全,误以为它不需要任何先验信息。
面试题
Q1. MCTS 四阶段循环的正确顺序是?
- A.选择→扩展→模拟→回溯← 正确答案
- B.模拟→回溯→选择→扩展
- C.扩展→模拟→选择→回溯
- D.回溯→选择→扩展→模拟
答案:A。MCTS 的标准流程是选择→扩展→模拟→回溯。先沿 UCB 分数高的路径下行(选择),为树加入新节点(扩展),随机对局评估(模拟),最后把结果沿路径传回(回溯)。其余顺序都违背了“先探路、再开枝、先试玩、最后记账”的逻辑。
Q2. UCB 公式中探索项的设计意图是什么?
- A.只偏好已多次访问的节点
- B.平衡探索与利用两方面← 正确答案
- C.只奖励快速随机的模拟
- D.压缩整个搜索树的深度
答案:B。探索项让访问次数少的子节点获得额外加分,从而平衡探索与利用。A 只偏好访问多的节点正是利用项的反向误解;C 只奖励模拟结果是结果反馈而非设计意图;D 压缩树深度与 UCB 公式无关,探索项的核心是“给冷门节点一个被看到的机会”。
Q3. MCTS 的模拟阶段最准确的说法是?
- A.暴力穷举所有局面分支
- B.随机快速走子直到终局← 正确答案
- C.用神经网络做精确打分
- D.只搜索一层子节点树
答案:B。模拟阶段从当前节点开始,按快速走子策略随机走到终局(分出胜负或平局)。A 是穷举而非模拟;C 是 AlphaGo 引入神经网络后的增强手段,不属于基础模拟本身;D 只搜一层不符合“一直走完一整局”的模拟定义。
Q4. 回溯阶段需要更新哪些数据?
- A.只更新根节点的数据
- B.只更新叶子节点的数据
- C.更新整条路径的统计数据← 正确答案
- D.只更新子节点的数量值
答案:C。回溯会把模拟结果从叶子节点一路传回根节点,路径上每个节点的访问次数加 1、胜场按结果累加。A 只更新根节点、B 只更新叶子节点都会让中间层统计失真;D 更新子节点数量不是 MCTS 的统计目标,真正要维护的是胜场与访问次数。
Q5. 与传统深度搜索相比,MCTS 的优势有哪些?
- A.无需设计精确的评估函数← 正确答案
- B.适合分支巨大的棋类局面← 正确答案
- C.必定能搜索到全局最优解
- D.计算过程完全不消耗资源
答案:AB。MCTS 靠随机模拟统计估计局面价值,不需要手写评估函数,特别适合分支因子巨大的棋类博弈。但它是近似算法,不保证找到全局最优;计算也存在成本。C 的“必定最优”和 D 的“完全不消耗资源”都是错误夸大,选项 A、B 才是 MCTS 的实打实优势。
Q6. UCB 公式 $\mathrm{UCB}(j)=\bar{X}_j+c\sqrt{\ln N/n_j}$ 中 N 指什么?
- A.全部子节点的访问总次数
- B.当前父节点的访问次数← 正确答案
- C.搜索树的当前最大深度
- D.随机模拟获胜的累计次数
答案:B。UCB 公式中 N 是当前节点的总访问次数(即父节点访问次数),$\ln N$ 随探索整体规模缓慢增长,衡量“全局已经探索了多少”。A 是子节点访问之和,C 是树深度,D 是胜场数,三者都不是 N 的定义,记住“N 是父、n 是子”即可。
Q7. 当某子节点访问次数 n_j 无限增大时,探索项如何变化?
- A.无限增大直至正无穷
- B.逐渐减小并趋向于零← 正确答案
- C.保持恒定不变的常数
- D.在正负值之间来回震荡
答案:B。探索项 $c\sqrt{\ln N/n_j}$ 中,n_j 在分母上。当 n_j 无限增大时,整个根式趋于 0,即“这个节点已被摸透,不再享受新鲜感加分”。A 方向反了;C 与“分母增大、分数减小”矛盾;D 描述的是震荡行为,而这是单调趋零的正值项。
Q8. 下列选项中,属于 MCTS 四阶段的是?
- A.选择与扩展两个阶段← 正确答案
- B.模拟与回溯两个阶段← 正确答案
- C.剪枝与哈希两个阶段
- D.打表与置换两个阶段
答案:AB。MCTS 四阶段是选择、扩展、模拟、回溯,因此 A 和 B 正确。C 的“剪枝”是 Alpha-beta 剪枝中的概念;D 的“打表与置换”属于开局库或置换表技术,都与 MCTS 的四阶段结构无关。
Q9. 将模拟策略从纯随机改为启发式合理走子,效果如何?
- A.决策质量一定会变差
- B.决策质量通常显著提升← 正确答案
- C.决策质量不发生任何变化
- D.搜索树将无法继续生长
答案:B。纯随机走子太“瞎”,加入启发式规则(如优先吃子、占中心)后,模拟结果更接近真实对局,统计出来的胜率更可信,决策质量通常明显提升。A 与主流实践结论相反;C 忽视了模拟质量对估计的影响;D 错误——树照常生长,只是模拟的真实性不同。
Q10. AlphaGo 中 MCTS 与深度学习结合,哪些说法正确?
- A.用穷举搜索替代随机模拟
- B.用策略网络指导模拟过程← 正确答案
- C.完全放弃探索与利用平衡
- D.用价值网络评估叶子局面← 正确答案
答案:BD。AlphaGo 的关键改进是:用策略网络让模拟走子更接近人类棋谱(B 对),用价值网络直接评估局面、替代部分随机模拟(D 对)。A 错——它没有穷举;C 错——它依然保留 UCB 式的探索与利用平衡,只是让模拟和评估更“聪明”。