fix: tool_calls 流中断自愈——400 配对错误时移除不完整段重试一次;加消息结构诊断日志

This commit is contained in:
2026-09-04 13:43:20 +08:00
parent c0c1be05f8
commit 1560a13d86
2 changed files with 61 additions and 23 deletions
+28
View File
@@ -132,6 +132,22 @@ class Agent:
pass
return text_result, image_b64
def _repair_tool_messages(self):
"""修复 tool_calls 配对不完整:从尾部移除「assistant 带 tool_calls 但其后
tool 回应不足」的消息段(流中断可能丢失分片,400 重试前自愈)。"""
for i in range(len(self.messages) - 1, -1, -1):
m = self.messages[i]
if m.get("role") == "assistant" and m.get("tool_calls"):
# 统计其后 tool 消息数是否匹配
need = len(m["tool_calls"])
have = sum(1 for x in self.messages[i + 1:]
if x.get("role") == "tool")
if have < need:
_log.warning("修复不完整 tool_calls 段(need=%d have=%d),回退 %d 条消息",
need, have, len(self.messages) - i)
self.messages = self.messages[:i]
return
# ---------- 主循环(流式) ----------
async def run_stream(self, prompt: str, serial: str = "",
history=None, on_delta=None, on_tool=None,
@@ -166,6 +182,9 @@ class Agent:
content_parts = []
tool_acc = {} # index -> {id, name, args}
has_tool = False
retried = False
while True:
try:
async for chunk in self._chat_stream():
choice = (chunk.get("choices") or [{}])[0]
delta = choice.get("delta") or {}
@@ -189,6 +208,15 @@ class Agent:
acc["name"] += fn["name"]
if fn.get("arguments"):
acc["args"] += fn["arguments"]
break
except RuntimeError as e:
# 流中断导致 tool_calls 分片丢失:修复后重试一次
if ("tool_calls" in str(e) or "must be followed" in str(e)) and not retried:
_log.warning("tool_calls 消息不完整,自愈重试")
self._repair_tool_messages()
retried = True
continue
raise
full_content = "".join(content_parts)
+10
View File
@@ -367,6 +367,16 @@ def _agent_thread(run_id, prompt, serial, cfg):
_log.warning(f"经验保存异常: {e}")
except Exception as e:
_log.warning(f"Agent 运行异常: {e}")
# 诊断:打印消息结构(tool_calls 与 tool 消息配对检查)
try:
roles = [m.get("role", "?") for m in agent.messages]
tcs = sum(1 for m in agent.messages
if m.get("tool_calls") and isinstance(m.get("tool_calls"), list))
tools_msg = sum(1 for m in agent.messages if m.get("role") == "tool")
_log.warning(f"诊断 messages: {len(agent.messages)} 条 roles={roles[-8:]} "
f"tool_calls消息={tcs} tool回应={tools_msg}")
except Exception:
pass
with _lock:
_run["state"] = "error"
_run["error"] = f"{type(e).__name__}: {str(e)[:200]}"