fix(agent): 续跑门禁——已有工作推进(tool_call_count>0)时纯文本短回复(<400字)视为中途意图句而非最终答案,注入续跑指令继续循环(上限2次防死循环);根治商机产线实测连续4会话在7~11次工具调用后模型输出意图句提前结束turn→循环误判终止→报告/总结从未产出

This commit is contained in:
ymq 2026-09-11 16:18:58 +08:00
parent 5c063ca588
commit 458736d71e

View File

@ -99,6 +99,15 @@ class AgentExecutor:
#(实测上游抖动窗口内 utility 调用连烧 15 分钟才放弃,会话全程无响应)。
_UTILITY_TIMEOUT = 60
# 续跑门禁2026-09-11 商机产线实测):模型输出纯文本「意图句」就结束 turn、
# 不调工具 → 循环误判为最终答案终止会话,用户拿到半截话(实测连续 4 个会话
# 在 tool_call_count 7~11 时这样夭折,报告/总结从未产出)。
# 门禁条件:已有工作推进(tool_call_count>0) 且回复短于 _CONTINUE_GATE_MIN_CHARS
#(真结论/报告远长于此)且催促未达上限 → 注入续跑指令继续循环;
# 达上限后尊重模型终止(防死循环)。
_CONTINUE_GATE_MIN_CHARS = 400
_CONTINUE_GATE_MAX = 2
def __init__(
self,
config, # AgentConfig (from pipeline_core)
@ -175,6 +184,7 @@ class AgentExecutor:
self._started_at = time.time()
self._turn_count = 0
self._tool_call_count = 0
self._continue_nudges = 0
# Step 0: 初始化(解析 pipeline_id / skill_loader 等slash 命令也需要)
await self._init_components()
@ -422,6 +432,30 @@ class AgentExecutor:
# (历史版本会在 tool_call_count==0 时用硬编码关键词强制路由,
# 那会剥夺 LLM 诚实降级/能力自省的能力,把 agent 变成路由器。)
final_reply = act.get("message", "")
# 续跑门禁2026-09-11已有工作推进但回复是短意图句
#"我再拉一次数据…"= 模型提前结束 turn 而非真结论。
# 注入续跑指令继续循环,不让会话夭折在半截话上。
if (self._tool_call_count > 0
and len(final_reply) < self._CONTINUE_GATE_MIN_CHARS
and self._continue_nudges < self._CONTINUE_GATE_MAX):
self._continue_nudges += 1
logger.warning(
f"run: 续跑门禁 turn={turn+1} 短回复({len(final_reply)}字)"
f" tool_calls={self._tool_call_count} 催促{self._continue_nudges}")
yield json.dumps({
"type": "progress",
"message": "检测到未完成的中途回复,继续推进任务…\n",
}, ensure_ascii=False) + "\n"
self._msgs.append({"role": "assistant", "content": final_reply})
self._msgs.append({"role": "user", "content": (
"【续跑指令】你刚才的回复是中途进度句,不是最终答案,"
"任务尚未完成(用户要求的产出还没交付)。"
"请继续执行:要么调用工具推进下一步,"
"要么直接输出完整的最终结论/报告(含全部要求的分析项)。"
"不要只说下一步打算做什么。")})
continue
yield json.dumps({
"type": "reply", "message": final_reply,
}, ensure_ascii=False) + "\n"