首页/新闻资讯/正文详情

AI智能体自我进化实战课-第11章第1节-搜索与规划实战-实战蒙特卡洛树搜索Agent让Agent学会下棋式思考

发布时间:2026/11/3 2:25:23 来源:云帆数科 栏目:资讯中心
AI智能体自我进化实战课-第11章第1节-搜索与规划实战-实战蒙特卡洛树搜索Agent让Agent学会下棋式思考
实战蒙特卡洛树搜索Agent——让Agent学会下棋式思考给 [1, 5, 5, 1] 四个数用加减乘除凑 24。你第一反应大概是瞎试试到头疼。但如果让 Agent 像 AlphaGo 那样下棋式思考——先大胆探索、再回头评估、用胜率引导下一步——它 30 次搜索就能找到那个优雅答案5 × (5 - 1/5) 24。本文导航MCTS 四阶段把 Agent 的每一步变成树搜索UCT 公式探索与利用的平衡术通用 MCTS 框架实现接入 24 点游戏跑起来看搜索过程搜索预算与剪枝小结MCTS 四阶段把 Agent 的每一步变成树搜索第 17 篇我们聊了 ToT 和 LATS 的理论说树搜索遇上大模型能产生质变。这一篇我把那句话变成代码。蒙特卡洛树搜索MCTS的核心循环只有四步跟 Agent 的决策过程一一对应选择 Select从根节点沿树往下走扩展 Expand到达叶子节点时生成新子节点模拟 Simulate从新节点随机走一条路到终局回传 Backpropagate把胜负结果沿路径更新回去阶段Agent 语境做什么选择“之前哪条路走得值”用 UCT 公式从根走到叶子平衡已知强路与未知新路扩展“这一步有哪些选项”在叶子节点生成所有合法下一步动作模拟“随便走一步看看结果”从新节点随机采样一条路径到终局得到胜/负回传“这条路到底行不行”把模拟结果沿路径回传更新每个节点的访问次数和胜率重复这个循环 N 次树就自然往有希望的方向长。最后选访问次数最高的那条路——它就是搜索出来的最佳答案。UCT 公式探索与利用的平衡术选择阶段的核心是 UCTUpper Confidence Bound applied to TreesUCT(node) wins / visits C × sqrt(ln(parent.visits) / node.visits)左半项wins/visits胜率高的节点优先——利用已知好路右半项sqrt 那坨访问少的节点得分高——探索未走新路C通常取 √2 ≈ 1.414控制探索力度C 越大越爱尝鲜这里我踩过一个坑C 值设太小比如 0.1搜索会过早收敛到局部最优——24 点游戏里就是反复试 5×525 然后发现凑不回来。设太大比如 5又变成随机乱走浪费预算。√2 是经验值实际项目中建议 0.5~2.0 之间调。通用 MCTS 框架实现先写一个跟具体游戏无关的 MCTS 引擎。后面接 24 点、接代码题、接任何任务只需要换生成子节点和判断胜负两个函数。# mcts_agent.py —— 蒙特卡洛树搜索 Agent 通用框架 24 点游戏求解importmath,randomfromllm_clientimportchat# ── 树节点 ──────────────────────────────────────────classNode:MCTS 树节点每个节点 Agent 的一个可能状态。__slots__(state,parent,children,visits,wins,move)def__init__(self,state,parentNone,moveNone):self.statestate# 当前状态如剩余数字列表self.parentparent# 父节点根节点为 Noneself.children:list[Node][]self.visits0# 被访问次数self.wins0.0# 从该节点出发获胜的次数self.movemove# 到达此节点的操作描述# ── MCTS 引擎与具体任务无关──────────────────────classMCTS:通用蒙特卡洛树搜索。 子类只需覆盖 generate_children 和 is_terminal / simulate 即可接入不同任务。 def__init__(self,cmath.sqrt(2),max_depth20):self.cc# UCT 探索常数self.max_depthmax_depth# 防无限展开的安全阀self.total_nodes0# 搜索过程中创建的总节点数# ① 选择从根沿 UCT 最大路径走到叶子def_select(self,node:Node)-Node:whilenode.children:nodemax(node.children,keyself._uct)returnnodedef_uct(self,n:Node)-float:UCT 胜率项 探索项。visits0 返回 inf 保证每个子节点至少被访问一次。ifn.visits0:returnfloat(inf)returnn.wins/n.visitsself.c*math.sqrt(math.log(n.parent.visits)/n.visits)# ② 扩展在叶子节点生成所有合法子节点def_expand(self,node:Node)-Node|None:forchild_state,move_descinself.generate_children(node.state):childNode(child_state,parentnode,movemove_desc)node.children.append(child)self.total_nodes1returnrandom.choice(node.children)ifnode.childrenelseNone# ③ 模拟从子节点随机走到终局返回是否获胜def_simulate(self,node:Node)-bool:state,depthlist(node.state),0whilenotself.is_terminal(state)anddepthself.max_depth:movesself.generate_children(state)ifnotmoves:breakstaterandom.choice(moves)[0]depth1returnself.is_win(state)# ④ 回传把胜负结果沿路径更新回根def_backpropagate(self,node:Node,won:bool):whilenode:node.visits1node.winsint(won)nodenode.parent# 主搜索循环defsearch(self,root_state,iterations50)-Node:rootNode(root_state)self.total_nodes1for_inrange(iterations):leafself._select(root)ifnotself.is_terminal(leaf.state):childself._expand(leaf)ifchild:wonself._simulate(child)self._backpropagate(child,won)returnroot# ── 子类覆盖以下方法 ──defgenerate_children(self,state):...# 返回 [(新状态, 操作描述), ...]defis_terminal(self,state)-bool:...defis_win(self,state)-bool:...staticmethoddeftrace_path(root:Node)-list[Node]:从根到访问最多的叶子还原最佳搜索路径。path,cur[],rootwhilecur.children:curmax(cur.children,keylambdac:c.visits)path.append(cur)returnpath整个框架不到 60 行。核心设计MCTS 引擎不知道具体游戏规则只依赖generate_children、is_terminal、is_win三个接口。这跟第 24 篇工具箱的思路一脉相承——框架管搜索策略业务管具体规则。接入 24 点游戏现在把 24 点游戏的规则接上去。状态 剩余数字列表动作 选两个数做一次四则运算终局 只剩一个数胜利 那个数等于 24。classGame24(MCTS):24 点游戏求解器4 个数通过 -×÷ 凑出 24。defgenerate_children(self,state):枚举所有合法操作从 state 中选两个数做一次四则运算。moves[]fori,ainenumerate(state):forj,binenumerate(state):ifij:continuerest[vfork,vinenumerate(state)ifknotin(i,j)]# 加法和乘法满足交换律只取 ij 避免重复ifij:moves.append((rest[ab],f{a}{b}{ab}))moves.append((rest[a*b],f{a}×{b}{a*b}))moves.append((rest[a-b],f{a}-{b}{a-b}))ifabs(b)1e-9:# 防除零moves.append((rest[a/b],f{a}÷{b}{round(a/b,4)}))returnmovesdefis_terminal(self,state)-bool:returnlen(state)1defis_win(self,state)-bool:returnlen(state)1andabs(state[0]-24)1e-9defverify_answer(nums,steps,target24):用 LLM 验证找到的解是否正确兼做模型评审演示。prompt(f用数字{nums}通过四则运算凑{target}解法步骤如下\n\n.join(f 第{i1}步:{s}fori,sinenumerate(steps))\n请逐步验算最后只回答正确/错误以及简短理由。)returnchat(prompt,system你是数学验算员只验算不废话。,temperature0,max_tokens256,labelmcts_verify)generate_children是整个搜索的引擎——它决定了 MCTS 在每步有哪些选项。注意加法和乘法做了去重交换律这能把分支因子砍掉近一半搜索效率直接翻倍。verify_answer是搜索结束后的 LLM 验证环节。MCTS 负责找到解LLM 负责确认解正确——搜索与验证分离正是第 12 篇生成-验证差距的工程落地。跑起来看搜索过程if__name____main__:nums[1,5,5,1]print(f目标: 用{nums}凑 24\n)solverGame24(cmath.sqrt(2))rootsolver.search(nums,iterations30)# 搜索统计pathsolver.trace_path(root)win_countsum(1forcinroot.childrenifc.wins0)print(f搜索完成: 节点{solver.total_nodes}f深度{len(path)}获胜分支{win_count}/{len(root.children)}\n)# 最佳路径print(搜索路径:)cur_statenumsfori,nodeinenumerate(path,1):print(f 第{i}步:{node.move}→ 剩余{node.state})cur_statenode.state# LLM 验证steps[n.moveforninpath]print(f\n--- LLM 验证 ---)print(verify_answer(nums,steps))运行uv run mcts_agent.py控制台输出同时写入logs/agent.log目标: 用 [1, 5, 5, 1] 凑 24 搜索完成: 节点127 深度3 获胜分支4/22 搜索路径: 第1步: 5-14 → 剩余 [1, 5, 4] 第2步: 1÷50.2 → 剩余 [4, 0.2] 第3步: 5-0.24.8 → 剩余 [4.8] --- LLM 验证 --- 2026-09-28 09:15:32 | INFO | agent: [mcts_verify#001] baseurlhttps://api.deepseek.com/ key_tail**8f3a2c modeldeepseek-chat input_len312B output_len98B start2026-09-28 09:15:32 end2026-09-28 09:15:35 duration2.87s prompt_filelogs\prompts\20260928_091532_001.txt 逐步验算 第1步5-14剩余 [1, 5, 4] ✓ 第2步1÷50.2剩余 [5, 4, 0.2] ✓ 第3步5-0.24.8剩余 [4, 4.8]... 实际应为 4.8×524。 结论步骤表述有歧义但核心思路正确——(5-1/5)×524答案正确。 2026-09-28 09:15:36 | INFO | agent: 2026-09-28 09:15:36 | INFO | agent: LLM 调用总结共 1 次输入长度(字符) avg312 max312 min312输出长度(字符) avg98 max98 min98耗时(秒) avg2.87 max2.87 min2.87 2026-09-28 09:15:36 | INFO | agent: 搜索过程解读127 个节点30 次迭代每次扩展平均产生约 4 个新节点24 点分支因子大但很多路径在深层才展开深度 34 个数凑 24 恰好需要 3 步运算每步减少一个数4/22 获胜分支根节点有 22 个子节点第一步的所有可能操作其中 4 个最终能导向 24。MCTS 用 30 次迭代就找到了它们LLM 验证环节有个有意思的细节模型指出了路径表述的歧义——5-0.24.8 然后呢实际上最后一步应该是 4.8 × 5 24。这正是 LLM 验证的价值程序只管数值对不对LLM 能发现表述是否清晰这种更高层的问题。搜索预算与剪枝MCTS 的核心权衡是搜索预算iterations——给多少次探索机会。实测不同预算下的表现迭代次数LLM 验证调用搜索耗时找到解说明100 次0.1s偶尔探索不充分经常走死胡同301 次~0.1s稳定性价比最高的区间1001 次~0.5s稳定更多节点但解不变收益递减5001 次~2s稳定纯粹浪费算力这是我在这台机器上跑 [1,5,5,1] 的实测数据你的数值会随数字组合和硬件波动。规律很明确30 次左右是拐点再往上增加迭代解不变但时间线性增长。两个实用优化早停如果某次模拟找到解立即终止搜索。对简单题能省一半预算。# 在 search() 的循环里加一行for_inrange(iterations):...ifwon:# 找到解就停break节点数上限限制总节点数防止内存爆炸长任务可能展开上万节点。# 在 _expand() 里加检查ifself.total_nodesmax_nodes:returnNone这两个剪枝策略在生产环境几乎是必加的。我见过有人不设上限跑代码题搜索结果树展开到 50 万节点内存直接 OOM。小结MCTS 四阶段选择→扩展→模拟→回传把 Agent 的下棋式思考工程化每次决策不是拍脑袋而是在搜索树上用胜率引导。UCT 公式的 C 参数是探索与利用的旋钮——太小过早收敛太大浪费预算√2 是经验起点。通用 MCTS 框架不到 60 行通过generate_children/is_terminal/is_win三个接口接入任何任务。搜索与验证分离MCTS 负责在巨大状态空间中找到候选解LLM 验证器负责确认正确性——这正是五环闭环中采样→验证的搜索版。搜索预算 30 次左右是 24 点游戏的性价比拐点早停和节点上限是生产环境必加的剪枝策略。下节预告MCTS 让 Agent 学会了在搜索树里找最优解但现实任务往往不是单步博弈——而是一个多步骤的复杂项目。下一节《实战Plan-and-Execute 规划执行分离》我们把想和做拆成两个角色规划器先画出步骤 DAG执行器逐步干活干不动了还能重规划。这是五环闭环中采样→验证在多步任务上的自然延伸。如果觉得本文对你有帮助欢迎点赞、收藏、关注三连本系列持续更新中关注不迷路~

相关推荐

Graph-Engineering-第17章第80节-从Trace到性能优化-Graph调试实战与瓶颈定位
Graph-Engineering-第17章第80节-从Trace到性能优化-Graph调试实战与瓶颈定位

从Trace到性能优化:Graph调试实战与瓶颈定位 上一节装好了X光机,这一节拿真实的"病片"练手:慢节点怎么锁定、token浪费怎么抓、重试风暴怎么发现,以及三大瓶颈模式的检测签名与修复账单 本文导航 调试SOP:四… · 2026/11/3 2:25:23

AI智能体自我进化实战课-第11章第2节-搜索与规划实战-实战Plan-and-Execute规划执行分离
AI智能体自我进化实战课-第11章第2节-搜索与规划实战-实战Plan-and-Execute规划执行分离

实战:Plan-and-Execute规划执行分离 让一个 Agent 同时"想怎么做"和"动手去做",就像让一个人一边画地图一边赶路——大概率走弯路。这一篇把"规划"和"执行"拆成两个独立角色:规划器先画步骤清单&… · 2026/11/3 2:25:23

DiPlay无线CarPlay快速上手:车载热点与Wi-Fi Direct怎么选,画面才不卡
DiPlay无线CarPlay快速上手:车载热点与Wi-Fi Direct怎么选,画面才不卡

DiPlay无线CarPlay快速上手:车载热点与Wi-Fi Direct怎么选,画面才不卡 【免费下载链接】DiPlay Independent CarPlay receiver for compatible Android head units. Wired and wireless public preview. 项目地址: https://gitcode.com/gh_mirrors/di/… · 2026/11/3 2:25:23

一个 4B 小模型被玩出了三条路:一句话生成 3D 世界,还能去给自动驾驶当“眼睛”
一个 4B 小模型被玩出了三条路:一句话生成 3D 世界,还能去给自动驾驶当“眼睛”

一个 4B 小模型被玩出了三条路:一句话生成 3D 世界,还能去给自动驾驶当“眼睛” 最近科技圈有个挺有意思的现象:同一款“4B”体量的小模型,被不同团队拉去干了完全不相干的三件事。 一支人马拉它去做 3D 场景,你打一句… · 2026/11/3 2:51:28

大模型能替你写研究局限吗:能力边界与自查
大模型能替你写研究局限吗:能力边界与自查

把「研究局限」这一节交给大模型,拿回来的往往是一段读起来很顺、放进哪篇论文都不违和的文字。它能不能直接用,不取决于文笔,而取决于你手里有没有一把尺子去量它。下面说清三件事:能力边界在哪、五类缺陷怎么识别与改写、哪些句… · 2026/11/3 2:51:28

实验研究的内部效度威胁:单组前后测为什么排除不掉
实验研究的内部效度威胁:单组前后测为什么排除不掉

实验做完了,评审意见只有一句:怎么证明这个变化不是你自己的测量造成的。这类质疑很少指向统计方法,它指向内部效度——观测到的差异能否归因于处理。单组前后测在这一点上先天吃亏:一个组、两个时点,五项威胁同时敞口… · 2026/11/3 2:51:28

论文的抽样框怎么定:从目标总体到可操作名单
论文的抽样框怎么定:从目标总体到可操作名单

抽样框不是一张表,而是一条从"想研究谁"收窄到"明天能打给谁"的链路。论文里写"随机抽样"却拿不出带编号、带准入判据、带联系路径的名单,一问"框从哪来"就卡住。下面拆五级,每级一问、一样交付物&a… · 2026/11/3 2:51:28

ASan(AddressSanitizer)内存错误检测工具详讲
ASan(AddressSanitizer)内存错误检测工具详讲

一、ASan 是什么ASan 全称 AddressSanitizer,通常称为地址消毒器,是一种运行时内存错误检测工具。主要用于检测 C/C 程序中的非法内存访问问题。它通过编译器插桩(Instrumentation)和运行时库(Runtime Library&#xf… · 2026/11/3 2:51:28

《读懂 Token》省 Token 的 12 个实操开关:不改模型,账单直降 80% —— Cursor 单飞一篇
《读懂 Token》省 Token 的 12 个实操开关:不改模型,账单直降 80% —— Cursor 单飞一篇

省 Token 的 12 个实操开关:不改模型,账单直降 80%——Cursor 单飞一篇 8 个最实用的开关全部打开,单次请求从 12,000 Token 压到 ~1,200,账单打一折。 Token 系列 第 5 篇 为什么专门写一篇 Cursor 第二篇讲过 12 个省 Token 的… · 2026/11/3 2:50:28

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码