想象你是一位美食猎人,被空投到一座从未探索过的陌生美食城。你的目标只有一个:找到全城最好吃的隐藏餐厅。你手里没有攻略,只有一张手绘地图,上面标注了几个街口和零星的店铺。你会怎么逛? 最聪明的做法,不是闷头一条巷子一条巷子地走完,而是边逛边做笔记:每到一处,快速判断“这条巷子看起来有戏,还是没戏”,然后决定下一步往哪钻。尝到好吃的店就记下来,回来后在地图上给沿途每个路口都贴一张评分便利贴。这张地图会在你的探索中慢慢“长出”新的分支——它越来越精细,越来越准确,最终成为一张专属于你的觅食宝典。 这就是蒙特卡洛树搜索(MCTS, Monte Carlo Tree Search)的直觉。它把“一连串好决策”的问题,变成“如何高效绘制并更新一张决策地图”。近年来,MCTS不仅统治了围棋等博弈战场,更成为大模型推理的关键引擎——让AI不再只凭“第一直觉”直接作答,而是先在思维地图里反复推演,再给出最可靠的答案。

岗位关联

掌握MCTS,你就掌握了AI在复杂决策中“系统化推演”的钥匙——这是从“会答”到“会想”的进阶技能,也是当前推理模型的底层引擎之一。

目录
  1. 可视化演示
  2. 核心原理:一张会生长的美食地图
  3. 四步循环:逛城的固定套路
  4. UCB公式:口碑加好奇的打分法
  5. 探索与利用:好奇心的天平
  6. 应用场景:从围棋棋盘到自动驾驶
  7. 大模型结合:当MCTS遇上LLM
  8. 局限与展望:地图的边界
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

核心原理:一张会生长的美食地图

美食猎人阿蒙的地图不是普通地图,而是一棵“决策树”:每个街口是一个节点,通往不同方向的路是边。地图上的每个节点都贴着一张便利贴,记着两行数字——“来过几次”和“吃到好吃的次数”。而且,地图不是一开始就画好全部街道的,它只在阿蒙实际探索过的地方生长:去过的街口才有记录,没去过的就保持空白。

MCTS(蒙特卡洛树搜索)的本质,就是一整套“画地图”的策略:用一个不断生长的树结构表示决策空间,每个节点保存“访问次数、累计胜率”这对统计量。树的生长不是均匀展开的,而是“不对称”的——看起来更有希望的岔口会被反复深耕,希望渺茫的区域则被迅速搁置。这种不对称性,让有限的搜索预算花在刀刃上。

从AI视角看,MCTS把“在巨大推理空间里找好解”变成了“高质量的采样与评估”。它不枚举所有可能性,只随机模拟其中一小部分路径,再用统计结果指导下一步生长方向。这像极了阿蒙的做法:与其把全城每条巷子都走一遍,不如让地图自己长成“口碑图”——去过的地方知道好坏,没去过的地方保持好奇。

所以理解MCTS,先记住三个关键词:树、统计量、不对称生长。这是一张活的地图,每一轮探索都在让地图变得更聪明。

四步循环:逛城的固定套路

拿到地图的阿蒙决定这样逛城:每次行动都走四步。第一步“选择”,站在当前路口,扫一眼周围几条路的便利贴,挑出最有“搞头”的一条,一路走下去,直到走到一个还没记录完整的街口。第二步“扩展”,在这个街口往没探索过的方向新增一条路,让地图长出新的一截。第三步“模拟”,派一个分身,沿着新路随机乱逛,吃到一家店就评判一下好不好吃,一路跑到巷子尽头。第四步“回溯”,分身回来后,把好吃或不好吃的评分从新街口一路传回起点,沿途每个路口都更新便利贴。

技术上,这四步的名字分别是选择(Selection)、扩展(Expansion)、模拟(Simulation/Rollout)、回溯(Backpropagation)。它们是MCTS的主循环,每次“逛城”就跑一遍这四步,重复几千次几万次。选择阶段用“树策略”(Tree Policy)决定往哪走;模拟阶段用“默认策略”(Default Policy)快速随机推进到终局;回溯阶段把模拟得到的标量回报(胜/负/平)沿路径累加到每个节点的统计量中。

这里的关键是:四步循环构成了一个完整的经验闭环。选择加扩展对应“决定往哪探索”,模拟对应“快速评估这条路值不值”,回溯对应“把评估结果写回所有经过的地点”。循环几千轮后,地图上每个节点的统计量就接近真实的“这条路好吃的概率”。

阿蒙不用真的吃遍全城——只要循环跑得足够多,地图上的数字自己会说话,最终指引他找到最值得去的店。

UCB公式:口碑加好奇的打分法

那么“选择”阶段到底怎么挑路?阿蒙发现,纯粹看“好吃率”不靠谱:一家只去过一次的店,可能只是运气好;一家被光顾过一百次、好评率70%的店,才是真口碑。反过来,完全只看口碑也不行——那些从没被尝试过的新巷子,可能藏着绝世美味。于是阿蒙用了一个古老而聪明的打分公式:

当某个节点还没被访问过时,UCB直接取无穷大,保证“每个新节点至少尝一次鲜”。在学术上这叫乐观初始化。阿蒙的“口碑+好奇”打分法,在计算机里叫UCB(Upper Confidence Bound,置信上界)。公式本身不复杂,但它是整个MCTS的灵魂——没有它,地图只会乱长。

UCBj=Wjnj+Cln⁡Nnj\displaystyle UCB_j = \frac{W_j}{n_j} + C\sqrt{\frac{\ln N}{n_j}}
通俗说,UCB给每个节点打两个分之和:左边是“已有口碑分”(赢的次数除以来看过的次数),右边是“好奇加分”——来看过的次数越少,越值得被试一次。C表示好奇心的大小。
  1. 节点胜率这是“利用”部分,把节点j的累计胜场W_j除以访问次数n_j,得出平均表现。
    Wjnj\displaystyle \frac{W_j}{n_j}
  2. 全局访问对数N是父节点总访问次数,ln N让数值增长变缓;访问次数少的子节点会因此得到更大的探索激励。
    ln⁡N\displaystyle \ln N
  3. 归一化探索项除以n_j之后,访问次数少的节点探索分巨大,访问次数多的节点探索分趋近于零。
    ln⁡Nnj\displaystyle \frac{\ln N}{n_j}
  4. 探索常数CC控制好奇心强度——C越大越爱冒险,C越小越守成。
    Cln⁡Nnj\displaystyle C\sqrt{\frac{\ln N}{n_j}}

探索与利用:好奇心的天平

阿蒙很快发现,打分公式里那个C值很讲究。C调大了,他整天逛新巷子,十家店九家踩雷;C调小了,他总去同一家老店,错过了对面巷子里真正的神级美食。这就是AI领域最经典的一对矛盾:探索(Exploration)与利用(Exploitation)。

探索是指尝试未知选项、收集新信息;利用是指押注已知的好选项、兑现收益。两者天然互斥:把预算花在探索上,就损失了利用好选项的收益;一味利用,又可能困在局部最优。MCTS的UCB公式,用“平均收益 + 探索项”的形式把这对矛盾量化成同一个分数——本质上是在问:这个节点“被低估”的可能性还有多大?

在工程上,除了调C,还有几种常见手法。一种是“衰减探索”:随着总轮次增加,逐渐减小探索项,让算法从“广撒网”过渡到“深挖矿”。另一种是PUCT(Predictor + UCT):用先验概率p_j替换均匀探索项,让模型先验告诉搜索“哪些分支更可能好”,再叠加探索奖励。AlphaGo就用了PUCT,把神经网络的直觉和树的统计力量结合了起来。

阿蒙慢慢摸清了套路——好奇心要适度,而且最好带着“美食攻略书”(先验)去找新店,而不是完全随机乱闯。

应用场景:从围棋棋盘到自动驾驶

阿蒙的美食地图法,换个场景一样好使。在真正的AI世界里,MCTS最著名的战功是2016年AlphaGo击败人类围棋冠军。围棋的决策空间比宇宙中的原子还多,传统搜索根本枚举不完,而MCTS用“随机模拟+不对称生长”在茫茫棋局中找出了神之一手。AlphaZero更进一步,完全不需要人类棋谱,从零开始自对弈,靠MCTS和自己对打练成绝世棋力。

在游戏之外的领域,MCTS也遍地开花。路径规划:机器人在未知环境中用MCTS探索“下一步往哪走”,每段路径模拟到终点再回溯评估;组合优化:在排班、芯片布线、物流调度等离散优化问题中,MCTS把可行方案组织成树,快速逼近高质量解;决策推理:包括自动驾驶的驾驶策略选择,以及更广义的“在不确定环境中选择动作序列”。

这些场景有一个共同点:决策空间巨大且无法穷尽,但可以用“采样+评估”来逼近最优。MCTS不保证找到数学上的最优解,但保证在有限预算内,把搜索资源分配到最有希望的区域——这正是实用主义者的最爱。

就像阿蒙不需要逛完全城的每条巷子就能找到好吃的店,MCTS不需要遍历所有可能就能给出可靠决策。

大模型结合:当MCTS遇上LLM

现在,把阿蒙的地图交给一个会说故事的向导——大语言模型(LLM)。过去,LLM回答问题是一锤子买卖:输入问题,直接生成答案。如果答案不对,它也没有反悔的机会。而MCTS给LLM提供了一台“思维推演机”:把每一次生成下一步思考的过程,变成一个树上的决策节点。

在这个框架里,LLM承担了三个角色:一是扩展器,针对当前思考状态生成若干个候选的后续步骤(可以是token、句子或解题子步骤);二是模拟器,快速生成“如果走这条路,大概会怎样”的推演文本;三是评估器,通过奖励模型(如过程奖励模型PRM)给每一步打分,替代传统游戏里的胜负判定。搜索结构负责“往哪走”的系统化权衡,LLM负责“怎么走”的语义生成,两者配合的典型代表就是OpenAI o1这类推理模型。

向导负责出点子,地图负责记经验,阿蒙(搜索算法)负责做总结——这就是今天“大模型+MCTS”的黄金组合。

at∼πθ(at∣s1:t)\displaystyle a_t \sim \pi_\theta(a_t \mid s_{1:t})
这个公式表示:在已有的思考序列 s_{1:t} 后面,按策略模型 π_θ 的概率分布采样出下一个动作或词元 a_t。通俗讲,就是让AI在岔路口按概率选方向,而不是随机瞎选。
  1. 状态序列s_{1t}:已经写完的推理步骤序列,相当于地图上已走过的路线。
    s1:t\displaystyle s_{1:t}
  2. 策略模型π_θ大模型本身,它输出下一个动作的概率分布。
    πθ(⋅∣s1:t)\displaystyle \pi_\theta(\cdot \mid s_{1:t})
  3. 采样符号~从概率分布中按权重抽取一个动作,既保证大概率选好的,又保留随机性。
    at∼πθ(at∣s1:t)\displaystyle a_t \sim \pi_\theta(a_t \mid s_{1:t})

局限与展望:地图的边界

阿蒙的美食地图法并不是万能的。首先,地图会越画越大——每轮探索都要存储节点和统计量,轮次一多,内存和计算开销直线上升。其次,模拟阶段的质量直接影响判断:如果“快速试吃”的方法本身太粗糙,那结论就不可靠——类似用“看店面装修”代替“真的吃饭”,评分自然有偏差。还有,“好不好吃”的评分标准要设计好,在游戏里是赢没赢,在真实任务中则要精心设计奖励模型。

沿着这些局限,研究者们正在几个方向上装修地图。并行化:让多个“分身”同时探索不同区域,再合并统计信息,大幅提速。先验引导:用神经网络策略(如PUCT)替代均匀随机模拟,让模拟更聪明、需要跑的轮次更少。渐进策略:在搜索不同深度使用不同复杂度的评估器,兼顾速度与精度。更进一步,MCTS与强化学习、LLM的结合正在催生“推理时搜索”这一新范式——模型不只靠训练时的梯度学习,还可以在推理时动态搜索解题路径。

地图终有一天会大到画不完,但只要不断优化画法,阿蒙的美食帝国就没有疆界。MCTS作为“决策地图”的绘制引擎,正在从棋盘走向千行百业。

AI 应用场景

场景1:AlphaZero 游戏博弈

阶段:强化学习 / 自对弈训练

解决的问题:传统暴力搜索无法应对围棋级别的复杂度(约10^170种局面),AI需要一种既能利用神经网络直觉、又能系统化遍历关键区域的搜索方法。MCTS把神经网络评估与树搜索融为一体,在自对弈中不断精进。

具体案例:DeepMind的AlphaZero完全通过自对弈加神经MCTS,从零开始学围棋、国际象棋和将棋,全部碾压人类顶尖水平。每步落子前,它先在心里跑约800次MCTS,综合评估胜率后再决定最终落点——相当于阿蒙每天在美食城心里逛800圈再选店。

场景2:LLM 推理增强(o1 式推理)

阶段:推理时搜索 / 测试时计算(Test-time Compute)

解决的问题:LLM单次生成存在“直出幻觉”风险,面对复杂数学题、代码题时缺乏系统推演。MCTS将推理展开成思维树,用过程奖励模型引导搜索,在众多候选路径中找到最可靠的那条。

具体案例:在数学竞赛题上,使用MCTS+PRM的推理模型会先“想”出若干解题分支,逐条快速验证、回溯评分,最后再给出完整证明步骤。相比直接生成答案,在AIME等数据集上的准确率显著提升。这就像阿蒙先让分身试吃多家店,再决定带朋友去哪家。

场景3:自动驾驶决策规划

阶段:决策与规划

解决的问题:自动驾驶在路口面临“直行、避让、等待”等连续决策,环境不确定且实时性要求极高。MCTS把驾驶策略构建为树,每轮模拟预测未来几秒的轨迹安全性,选择综合风险最低的动作序列。

具体案例:在模拟器中,自动驾驶车辆用MCTS做变道决策:对每个候选动作模拟未来3秒的交通流,统计碰撞风险与通行效率,回溯选择最优策略。在复杂路口,这种方法显著减少了无意义的保守等待——就像阿蒙选择性地探索,而不是每次都在路口犹豫半天。

Python 演示

python106 行
import mathimport random  class Game:    def __init__(self):        self.board = [' '] * 9        self.current = 'X'     def moves(self):        return [i for i, ch in enumerate(self.board) if ch == ' ']     def play(self, idx):        self.board[idx] = self.current        self.current = 'O' if self.current == 'X' else 'X'     def winner(self):        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 self.board[a] != ' ' and self.board[a] == self.board[b] == self.board[c]:                return self.board[a]        if ' ' not in self.board:            return 'D'        return None  class Node:    def __init__(self, move=None, parent=None):        self.move = move        self.parent = parent        self.children = []        self.visits_count = 0        self.wins = 0     def is_full(self, game):        return len(self.children) == len(game.moves())     def best_child(self, c=1.4):        best_score = -float('inf')        best_node = None        for child in self.children:            if child.visits_count == 0:                score = float('inf')            else:                score = child.wins / child.visits_count + c * math.sqrt(                    math.log(self.visits_count) / child.visits_count)            if score > best_score:                best_score = score                best_node = child        return best_node  def mcts_choose(board, current, iterations=300):    root = Node()    root_game = Game()    root_game.board = board[:]    root_game.current = current    root_player = current     for _ in range(iterations):        node = root        game = Game()        game.board = root_game.board[:]        game.current = root_game.current         # 1 Selection        while node.children and node.is_full(game):            node = node.best_child()            game.play(node.move)         # 2 Expansion        if not node.is_full(game) and game.winner() is None:            tried = [c.move for c in node.children]            move = random.choice([m for m in game.moves() if m not in tried])            child = Node(move=move, parent=node)            node.children.append(child)            node = child            game.play(move)         # 3 Simulation        while game.winner() is None:            game.play(random.choice(game.moves()))         # 4 Backpropagation        result = game.winner()        while node is not None:            node.visits_count += 1            if result == root_player:                node.wins += 1            elif result == 'D':                node.wins += 0.5            node = node.parent     return max(root.children, key=lambda c: c.visits_count).move  if __name__ == '__main__':    g = Game()    g.board = ['X', ' ', ' ',               ' ', 'O', ' ',               ' ', ' ', ' ']    g.current = 'X'    best = mcts_choose(g.board, g.current, iterations=300)    print('MCTS best move:', best + 1)
目的:用约300轮MCTS四步循环,在井字棋中找出当前局面的最优落子,展示选择、扩展、模拟、回溯的完整实现。
  1. score = child.wins / child.visits_count + c * math.sqrt(...)这就是UCB打分:平均胜率加探索项。
  2. while node.children and node.is_full(game):选择阶段:一路按UCB挑孩子,走到未完全展开的节点。
  3. move = random.choice([m for m in game.moves() if m not in tried])扩展阶段:从没试过的着法里随机挑一个长成新节点。
  4. while game.winner() is None: game.play(random.choice(game.moves()))模拟阶段:随机落子到终局。
  5. result == root_player` / `result == 'D'回溯阶段:按根玩家视角统计胜、负、平。
  6. max(root.children, key=lambda c: c.visits_count).move最终选择访问次数最多的孩子作为推荐落子。

常见误区

误区很多人看到“模拟”阶段是随机落子,就觉得MCTS全靠运气,本质是瞎猜,效果好坏全看命。

正解随机模拟只是MCTS的“快速草图”步骤。真正让MCTS智能的不是随机本身,而是“选择+回溯”的结构:UCB选择让树朝有希望的区域生长,回溯把每次模拟结果写回统计量,几千轮后树的形状就体现了对问题的深入理解。随机模拟相当于阿蒙的“分身随便尝一口”,但最终决策靠的是整张地图的大数据统计。

为何常见:因为“模拟(Simulation)”这步名字太直观,初学者容易把局部步骤当成算法全貌,忽略了选择与回溯两个决定性环节。

误区C是探索系数,既然要“多探索”,那C越大搜索就越全面,结果自然更好。

正解C太大,算法会变成“逛街模式”——每个新节点都要尝鲜,但永远不深耕好区域,胜率被大量平庸样本拉低;C太小,又会变成“守店模式”——死守少数高分节点,错过真正的好分支。正确做法是根据问题规模调适中值,或采用衰减探索策略,让前期多探索、后期多利用。

为何常见:直观上“探索”听起来总是好事,忽略了资源有限这个前提——探索和利用是零和博弈,C正是在定夺这个天平。

误区觉得随机模拟太粗糙,一定要用神经网络或精心设计的启发式来做rollout,否则MCTS结果不可信。

正解随机均匀采样在理论上足以让MCTS收敛到最优(当模拟次数趋近无穷时),而且速度极快。改进模拟质量固然可以加速收敛,但每步模拟变慢,同样的时间预算能跑的轮次就少了。工程上常采用“轻量启发式+适量轮次”的组合,或者在树内用神经网络策略、树外保持快速随机模拟。

为何常见:大家习惯认为“更聪明的组件=更好的算法”,忽略了MCTS强大的统计补偿能力——模拟粗糙一点,多跑几轮就能弥补。

误区看到AlphaGo、AlphaZero的成功,就认为MCTS是围棋、国际象棋专属算法,和NLP、机器人没关系。

正解MCTS本质是通用离散序列决策框架,任何能定义“状态、动作、终局回报”的问题都可以套用。从芯片布线到物流调度,从自动驾驶到LLM推理,只要决策空间大且无法穷尽,MCTS就能发挥作用。当前最火的方向就是把MCTS作为大模型“思维树”的搜索骨架。

为何常见:媒体对AlphaGo的报道太深入人心,让大众把MCTS和围棋绑定,忽略了它通用算法的本质。

面试题

Q1. MCTS四步循环的正确顺序是?

单选题 · easy

  • A.选择-扩展-模拟-回溯← 正确答案
  • B.模拟-选择-扩展-回溯
  • C.扩展-选择-回溯-模拟
  • D.回溯-模拟-扩展-选择

答案:A。MCTS每轮先沿UCB选择最有潜力节点(选择),在其下长出新的子节点(扩展),然后从新节点随机模拟到终局(模拟),最后把结果沿路径传回更新统计量(回溯)。就像阿蒙先看地图挑路,再走新路、试吃、写评价。

Q2. UCB公式中"ln N"部分的作用是?

单选题 · mid

  • A.经验累积的利用项
  • B.访问较少节点的利好← 正确答案
  • C.让评分变成对数曲线
  • D.模拟次数的限制值

答案:B。N是父节点总访问次数。ln N增长缓慢,使得被访问次数n_j很少的子节点能获得较大的探索分,从而被优先尝试;访问多的节点探索分趋近于零。这是“给冷门新店加分”的机制。

Q3. 探索常数C增大会导致?

单选题 · mid

  • A.更偏向利用已有经验
  • B.更偏向探索未充分节点← 正确答案
  • C.直接停止树生长
  • D.回溯速度加快一倍

答案:B。C是探索项的权重系数。C越大,探索项在UCB总分中占比越高,算法越倾向于访问次数少的节点;反之则更偏向依赖平均胜率高的节点。C过大会导致只探索不利用,C过小则只利用不探索。

Q4. MCTS回溯阶段更新的是?

单选题 · easy

  • A.每个节点的搜索深度
  • B.路径上节点的统计量← 正确答案
  • C.全部节点的访问次数
  • D.模拟结果的历史均值

答案:B。回溯只更新从新扩展节点到根节点路径上的节点统计量(访问次数加一、胜率按结果更新),而不是整棵树全部节点。这正是“沿路写便利贴”的直觉:只有走过这条路的路口才需要更新评价。

Q5. 下列哪些属于MCTS的关键特点?

多选题 · mid

  • A.树形结构不对称生长← 正确答案
  • B.需要完整构建决策树
  • C.通过随机模拟获得回报← 正确答案
  • D.每个节点记录访问次数← 正确答案

答案:ACD。MCTS的特点是树不对称生长(只深耕有希望的分支)、用随机模拟获得终局回报、节点记录访问与胜率统计。它并不需要完整构建整棵决策树——这正是它对大规模决策空间的优势所在。

Q6. 与贪心搜索相比,MCTS的最大优势是?

单选题 · mid

  • A.一定找到全局最优解
  • B.平衡了探索与利用← 正确答案
  • C.不需要任何随机采样
  • D.运行速度更快一些

答案:B。贪心搜索每次只挑当前看起来最好的选项,容易陷入局部最优;MCTS通过UCB公式在“利用已知好的”和“探索未知的”之间取得平衡,避免过早陷入次优。它并不保证全局最优,速度也不一定更快。

Q7. PUCT在UCB基础上的改进是?

单选题 · hard

  • A.用先验概率引导探索← 正确答案
  • B.去掉探索项节省内存
  • C.将模拟改为深度优先
  • D.用固定常数替代统计量

答案:A。PUCT(Predictor + UCT)把UCB公式中的探索项从均匀分布改为带先验概率p_j的引导项,让神经网络等先验信息告诉搜索“哪些分支更可能好”。AlphaGo正是用这种方法把深度学习的直觉与MCTS的统计搜索结合起来。

Q8. LLM与MCTS结合时,LLM可以承担哪些角色?

多选题 · hard

  • A.生成候选推理步骤← 正确答案
  • B.作为模拟器快速推演← 正确答案
  • C.提供过程奖励打分← 正确答案
  • D.替代搜索树的存储

答案:ABC。LLM在MCTS中可充当扩展器(生成下一步候选)、模拟器(快速推演后续结果)和评估器(配合PRM给步骤打分)。但搜索树的存储与遍历结构仍由MCTS算法本身管理,不可能也不应该由LLM替代。

Q9. MCTS中“乐观初始化”的含义是?

单选题 · easy

  • A.未访问节点UCB设为无穷大← 正确答案
  • B.所有节点胜率初始为0
  • C.只初始化根节点的统计量
  • D.初始化不需要任何参数

答案:A。当某个子节点从未被访问过时,它的UCB值被直接设为正无穷,这样它一定会在下一轮选择中被优先尝试。这个“每个新店都要去尝一次”的机制,保证了所有分支至少被探索一次,避免了某些区域被永久忽略。

Q10. MCTS存在的典型局限包括?

多选题 · hard

  • A.搜索树存储开销大← 正确答案
  • B.模拟策略影响评估质量← 正确答案
  • C.一定收敛于全局最优
  • D.奖励设计依赖任务建模← 正确答案

答案:ABD。MCTS需要存储不断生长的树,轮次多时内存开销大;模拟策略粗糙会带来评估偏差;奖励函数也需要针对任务精细设计。它只保证在有限预算下逼近最优,并在理论条件(无限模拟)才严格收敛,并非一定全局最优。