feat(copilot): MCTS dynamic strategy engine with reward model and rollout simulation#13
feat(copilot): MCTS dynamic strategy engine with reward model and rollout simulation#13ldemon2333 wants to merge 1 commit intoAnnaSuSu:mainfrom
Conversation
AnnaSuSu
left a comment
There was a problem hiding this comment.
整体设计不错——博弈建模思路清晰,模块拆分干净,feature flag 零侵入,降级策略也考虑到了。以下几个问题需要先修一下:
Bug(必须修)
1. _get_weak_points 永远返回空列表
mcts_engine.py:506 从 prep_state.get("profile", {}) 读 weak_points,但 prep_result 里没有 "profile" 这个 key。候选人画像不在 prep state 里。需要改成从 fit_report.get("gaps", []) 读取,或者在 _init_mcts_engine 时把 profile 传进 prep_state。
2. WebSocket 断开时 MCTS 引擎没有 cleanup
main.py 的 finally 块只清理了 ASR,没调 mcts.stop()。断连后搜索 Task 会继续跑然后尝试 ws.send_json() 到已关闭的 WebSocket。需要加上:
finally:
if session and session.get("asr"):
session["asr"].shutdown()
if session and session.get("mcts_engine"):
await session["mcts_engine"].stop()
_copilot_sessions.pop(session_id, None)3. 候选人回答后触发 MCTS 搜索逻辑有问题
main.py 在 on_candidate_response 之后又 create_task(_run_mcts_and_push),但此时根节点仍然是上一轮 HR 的问题。候选人已经回答了,再在旧根上搜候选人策略没意义。建议:
- 去掉候选人回答后的 MCTS 触发
- 或者改成以候选人回答为新根,搜索预测 HR 下一步追问
需要你确认一下这里的设计意图。
建议改进
4. _try_merge_static 里 _ 做变量名但实际在用
_, static_intent, score = self.navigator.match_utterance(...)
static_node = self.navigator.get_node(_)_ 按惯例是 throwaway,这里实际当 node_id 用,建议改名。
5. 展开深度硬编码
_run_iteration 里 leaf.depth < 3 是硬编码的,config 里有 rollout_depth 但没用上。建议用配置值或单独加个 max_expansion_depth。
6. get_text_embedding() 同步调用阻塞 event loop
_expand 和 on_hr_utterance 里直接调 embed.get_text_embedding(),如果用的是 API embedding 会阻塞。建议 asyncio.to_thread() 包一下。
修完 1-3 后再看一轮,其他的不阻塞合入。
|
幸会
***@***.***
Bug(必须修)
1. _get_weak_points 永远返回空列表
prep_result = prep_data["result"],prep_store.set_done(prep_id, result),result 里的初始化在run_copilot_prep,会完成 profile 的初始化,同时我在测试的时候不管是在初始 load 简历,还是使用历史的用户画像,都没有发现这个问题,没有做任何修改
2. WebSocket 断开时 MCTS 引擎没有 cleanup
已修复,调 mcts.stop()
3. 候选人回答后触发 MCTS 搜索逻辑有问题
按照,已修复,
去掉候选人回答后的 MCTS 触发
或者改成以候选人回答为新根,搜索预测 HR 下一步追问
4. _try_merge_static 里 _ 做变量名但实际在用
已修复,
5. 展开深度硬编码
已修复
6. get_text_embedding() 同步调用阻塞 event loop
已修复
同时我在做实时语音 copilot 的时候,发现两个 issue,已提issue:
所有 ASR 音频都硬编码为 HR 角色,没有角色的概念,真实场景下功能还不够完善
面试 copilot 功能输入几次 hr 的提问后,前端右边的决策树分析面板会消失,应该是前端的bug
原始邮件
发件人:Aari ***@***.***>
发件时间:2026年4月8日 02:35
收件人:AnnaSuSu/TechSpar ***@***.***>
抄送:Ldemon ***@***.***>, Author ***@***.***>
主题:Re: [AnnaSuSu/TechSpar] feat(copilot): MCTS dynamic strategy engine with reward model and rollout simulation (PR #13)
@AnnaSuSu requested changes on this pull request.
整体设计不错——博弈建模思路清晰,模块拆分干净,feature flag 零侵入,降级策略也考虑到了。以下几个问题需要先修一下:
Bug(必须修)
1. _get_weak_points 永远返回空列表
mcts_engine.py:506 从 prep_state.get("profile", {}) 读 weak_points,但 prep_result 里没有 "profile" 这个 key。候选人画像不在 prep state 里。需要改成从 fit_report.get("gaps", []) 读取,或者在 _init_mcts_engine 时把 profile 传进 prep_state。
2. WebSocket 断开时 MCTS 引擎没有 cleanup
main.py 的 finally 块只清理了 ASR,没调 mcts.stop()。断连后搜索 Task 会继续跑然后尝试 ws.send_json() 到已关闭的 WebSocket。需要加上:
finally: if session and session.get("asr"): session["asr"].shutdown() if session and session.get("mcts_engine"): await session["mcts_engine"].stop() _copilot_sessions.pop(session_id, None)
3. 候选人回答后触发 MCTS 搜索逻辑有问题
main.py 在 on_candidate_response 之后又 create_task(_run_mcts_and_push),但此时根节点仍然是上一轮 HR 的问题。候选人已经回答了,再在旧根上搜候选人策略没意义。建议:
去掉候选人回答后的 MCTS 触发
或者改成以候选人回答为新根,搜索预测 HR 下一步追问
需要你确认一下这里的设计意图。
建议改进
4. _try_merge_static 里 _ 做变量名但实际在用
_, static_intent, score = self.navigator.match_utterance(...) static_node = self.navigator.get_node(_)
_ 按惯例是 throwaway,这里实际当 node_id 用,建议改名。
5. 展开深度硬编码
_run_iteration 里 leaf.depth < 3 是硬编码的,config 里有 rollout_depth 但没用上。建议用配置值或单独加个 max_expansion_depth。
6. get_text_embedding() 同步调用阻塞 event loop
_expand 和 on_hr_utterance 里直接调 embed.get_text_embedding(),如果用的是 API embedding 会阻塞。建议 asyncio.to_thread() 包一下。
修完 1-3 后再看一轮,其他的不阻塞合入。
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you authored the thread.
|
|
补一条,第 1 条我收回,是我 review 错了。 刚才重新 trace 了下 prep_result 的构造, 我之前凭印象说"prep_result 里没有 profile key",没 trace 到源头,抱歉。 另外提醒一下,你 PR 里后端加了 其他几条修完一起推上来,我再过一遍。 |
…lout simulation - Add MCTSConfig, MCTSNode, StrategyRecommendation data structures - Add RewardModel with cosine similarity scoring (R = W1·Match + W2·Safe - W3·Risk) - Add SimulationEngine with 3-level degradation rollout - Add MCTSEngine with PUCT selection, LLM expansion, backpropagation - Integrate MCTS into copilot WebSocket session (feature-flagged, off by default) - Add 11 mcts_* settings to config and rollout LLM provider - Add user-facing docs and 39 unit tests
Summary
Add an MCTS (Monte Carlo Tree Search) dynamic strategy engine to the interview copilot, enabling real-time strategy optimization during mock interviews.
Changes
New Modules (
backend/copilot/)mcts_config.py—MCTSConfig,MCTSNode,StrategyRecommendationdata structuresreward_model.py—RewardModelwith cosine similarity scoring: R(S) = W1·Match_JD + W2·Safe - W3·Risksimulation_engine.py— 3-level degradation rollout simulator (LLM → lightweight LLM → pure reward)mcts_engine.py— Full MCTS 4-step engine (Select/Expand/Simulate/Backprop) with PUCT selectionModified Files
config.py— 11 newmcts_*settings (feature-flagged, disabled by default)llm_provider.py—get_mcts_rollout_llm()for simulationmain.py— Integration into copilot WebSocket session as async background taskFrontend
frontend/src/hooks/useCopilotStream.js— Addstrategy_recommendationcase to WebSocket message switch, ensuring MCTS search results are forwarded to the UI viaonUpdatecallback (without this the backend pushes the message but the frontend silently drops it)Bug Fixes
start()返回None而非 truthy 值,改用 try/exceptfinally块中增加mcts.stop()调用,防止搜索 Task 写入已关闭的 WS_try_merge_static变量命名:_→matched_node_id(实际使用不应为 throwaway)max_expansion_depth替代硬编码3asyncio.to_thread()包装同步 APIDocs and Tests
docs/mcts-strategy.md— User-facing feature documentationdocs/SUMMARY.md— Updated indextests/test_mcts_engine.py— 39 unit tests covering all modulesKey Design Decisions
MCTS_ENABLED=falseby default, zero impact when disabled