From 7a2175f363c7b8494e8350c1a7e6d876a614d610 Mon Sep 17 00:00:00 2001 From: ymq Date: Thu, 20 Aug 2026 15:21:14 +0800 Subject: [PATCH] =?UTF-8?q?fix(role-agent):=20LLM=20=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E5=8A=A0=20asyncio.wait=5Ffor=20=E7=A1=AC=E8=B6=85=E6=97=B6?= =?UTF-8?q?=E5=85=9C=E5=BA=95=EF=BC=8C=E9=98=B2=E6=8C=82=E8=B5=B7=E6=97=A0?= =?UTF-8?q?=E5=BF=83=E8=B7=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit role_agent_run 的 llm_call_msgs_native 内部 300s×3 重试最坏 15 分钟, 期间心跳不更新(心跳在调用前 touch),观察上像任务挂起/僵尸。 外层 asyncio.wait_for(420s) 硬上限:① 缩短最坏时长到 7 分钟 ② 防 aiohttp total 超时因 DNS 等场景失效导致的真正无限挂起。 超时抛异常 → mark_failed → retry+1 → 重新认领,不再无限卡住。 --- pipeline_service/agent_loop.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pipeline_service/agent_loop.py b/pipeline_service/agent_loop.py index dd1d696..a940b53 100644 --- a/pipeline_service/agent_loop.py +++ b/pipeline_service/agent_loop.py @@ -928,6 +928,11 @@ async def _exec_agent_tool(tool, params, workspace_dir): # 30 轮全耗在 list_files/read_file/run_shell 反复「了解现状 + 验证已有内容」,从不 write_file/deliver。 _FORCE_PRODUCE_TURN = 5 +# LLM 调用硬超时(外层 asyncio.wait_for 兜底)。llm_bridge 内部 300s×3 重试最坏 15 分钟, +# 期间 role_agent_run 心跳不更新(心跳在调用前 touch),观察上像任务挂起/僵尸。 +# 外层硬上限:① 缩短最坏时长到 7 分钟 ② 防 aiohttp total 超时因 DNS 等场景失效导致的真正无限挂起。 +_LLM_HARD_TIMEOUT = 420 + _FORCE_PRODUCE_HINT = ( "⚠️ 你已经探索了足够多轮(已超过 5 轮)。现在必须立即产出并交付:\n" "1. 用 write_file 写出实际交付文件(代码/文档/契约/DDL),不要再 read_file / list_files / run_shell / git_status 等探索或检查类工具。\n" @@ -1080,7 +1085,9 @@ async def role_agent_run(project_id, role, agent_id=None, model_name=None): if turn >= _FORCE_PRODUCE_TURN: msgs.append({"role": "user", "content": _FORCE_PRODUCE_HINT}) try: - resp = await llm_call_msgs_native(msgs, tools=tools_schema, model=model_name, temperature=0.4, org_id=org_id) + resp = await asyncio.wait_for( + llm_call_msgs_native(msgs, tools=tools_schema, model=model_name, temperature=0.4, org_id=org_id), + timeout=_LLM_HARD_TIMEOUT) except Exception as e: err_msg = f"{type(e).__name__}: {str(e)[:400]}" from .task_capability import mark_failed