修复循环推理bug
This commit is contained in:
120
backend/app/main_graph/nodes/routing.py
Normal file
120
backend/app/main_graph/nodes/routing.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
路由与初始化模块
|
||||
包含状态初始化节点和条件路由函数
|
||||
|
||||
三层统一循环防护:
|
||||
1. 全局步数硬上限(reasoning_step > max_steps)
|
||||
2. 路由模式检测(A→B→A→B 交替循环)
|
||||
3. 状态停滞检测(连续相同动作)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from app.core.intent import get_route_by_reasoning, ReasoningAction
|
||||
from app.main_graph.state import MainGraphState
|
||||
from app.logger import info
|
||||
|
||||
|
||||
# ========== 初始化状态节点 ==========
|
||||
def init_state_node(state: MainGraphState) -> MainGraphState:
|
||||
"""初始化状态节点:在流程开始时设置初始值"""
|
||||
state.current_phase = "initializing"
|
||||
state.reasoning_step = 0
|
||||
state.start_time = datetime.now().isoformat()
|
||||
|
||||
if not state.user_query and state.messages:
|
||||
last_msg = state.messages[-1]
|
||||
state.user_query = getattr(last_msg, "content", str(last_msg))
|
||||
|
||||
return state
|
||||
|
||||
|
||||
# ========== 条件路由函数 ==========
|
||||
def route_by_reasoning(state: MainGraphState) -> str:
|
||||
"""
|
||||
根据推理结果决定下一步路由,带三层统一循环防护
|
||||
|
||||
核心逻辑:
|
||||
1. DIRECT_RESPONSE → 直接返回 llm_call
|
||||
2. 子图完成/已有结果 → 直接返回 llm_call
|
||||
3. 步数超限 → 直接返回 llm_call
|
||||
4. 其他 → 正常路由
|
||||
"""
|
||||
# 获取历史动作
|
||||
previous_actions = [h.get("action") for h in state.reasoning_history]
|
||||
|
||||
info(f"[条件路由] step={state.reasoning_step}, phase={state.current_phase}, history={previous_actions}")
|
||||
|
||||
# ========== 获取推理结果 ==========
|
||||
reasoning_result = state.debug_info.get("reasoning_result")
|
||||
latest_action = reasoning_result.action.name if reasoning_result else None
|
||||
|
||||
# ========== 核心检查:DIRECT_RESPONSE 优先 ==========
|
||||
# 从 reasoning_result 检查(最新)
|
||||
if latest_action == "DIRECT_RESPONSE":
|
||||
info(f"[条件路由] 推理结果为 DIRECT_RESPONSE,直接去 llm_call")
|
||||
return "llm_call"
|
||||
|
||||
# 备用:从历史记录检查
|
||||
if previous_actions and previous_actions[-1] == "DIRECT_RESPONSE":
|
||||
info(f"[条件路由] 历史记录最新动作为 DIRECT_RESPONSE,直接去 llm_call")
|
||||
return "llm_call"
|
||||
|
||||
# ========== 子图完成/已有结果 ==========
|
||||
if "subgraph_completed" in previous_actions or state.final_result:
|
||||
info("[条件路由] 子图已完成或已有结果,直接终止")
|
||||
return "llm_call"
|
||||
|
||||
# ========== 步数超限 ==========
|
||||
if state.reasoning_step > state.max_steps:
|
||||
info(f"[条件路由] 步数超限 ({state.reasoning_step}/{state.max_steps}),强制终止")
|
||||
return "llm_call"
|
||||
|
||||
# ========== 特殊阶段快速通道 ==========
|
||||
if state.current_phase in ("max_steps_exceeded", "finalizing", "done"):
|
||||
return "llm_call"
|
||||
if state.current_phase == "error_handling" or state.current_error:
|
||||
return "handle_error"
|
||||
|
||||
# ========== 无推理结果,默认终止 ==========
|
||||
if not reasoning_result:
|
||||
info("[条件路由] 无推理结果,默认去 llm_call")
|
||||
return "llm_call"
|
||||
|
||||
# ========== 计算目标路由 ==========
|
||||
route = get_route_by_reasoning(reasoning_result)
|
||||
|
||||
route_mapping = {
|
||||
"direct_response": "llm_call",
|
||||
"retrieve_rag": "rag_retrieve",
|
||||
"re_retrieve_rag": "rag_retrieve",
|
||||
"web_search": "web_search",
|
||||
"clarify": "llm_call",
|
||||
"call_tool": "llm_call",
|
||||
"contact": "contact_subgraph",
|
||||
"dictionary": "dictionary_subgraph",
|
||||
"news_analysis": "news_analysis_subgraph",
|
||||
}
|
||||
target = route_mapping.get(route, "llm_call")
|
||||
|
||||
# ========== 循环防护检测 ==========
|
||||
# 1. 路由模式检测(A→B→A→B 交替)
|
||||
if len(previous_actions) >= 4:
|
||||
if (previous_actions[-4] == previous_actions[-2]
|
||||
and previous_actions[-3] == previous_actions[-1]
|
||||
and previous_actions[-2] != previous_actions[-1]):
|
||||
info(f"[条件路由] 检测到路由循环: {previous_actions[-4:]},强制终止")
|
||||
return "llm_call"
|
||||
|
||||
# 2. 状态停滞检测(连续相同动作)
|
||||
if len(previous_actions) >= 2 and previous_actions[-1] == previous_actions[-2]:
|
||||
info(f"[条件路由] 连续相同动作 '{previous_actions[-1]}',强制终止")
|
||||
return "llm_call"
|
||||
|
||||
# ========== 智能优化 ==========
|
||||
if target == "rag_retrieve" and (state.rag_docs or state.rag_context):
|
||||
info("[条件路由] RAG 结果已存在,跳过检索")
|
||||
return "llm_call"
|
||||
|
||||
info(f"[条件路由] 动作={latest_action}, 目标={target}")
|
||||
return target
|
||||
Reference in New Issue
Block a user