修复循环推理bug

This commit is contained in:
2026-05-05 00:54:04 +08:00
parent acc8d801f3
commit b64dade9e9
11 changed files with 605 additions and 766 deletions

View 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