From fbd01a056c0c33e224117b8cd64c8a26efcb6c2f Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Fri, 4 Sep 2026 16:19:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=8F=E9=AA=8C=E5=B7=A1=E6=A3=80?= =?UTF-8?q?=E8=AF=84=E5=AE=A1=E5=A4=B1=E8=B4=A5=E9=87=8D=E8=AF=95=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=A8=A1=E5=9E=8B=E5=81=B6=E5=8F=91=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E8=A7=A3=E9=87=8A=E6=96=87=E5=AD=97=E4=B8=8D=E5=B8=A6=20JSON?= =?UTF-8?q?=EF=BC=88=E5=AE=9E=E6=B5=8B=204/11=20=E6=9D=A1=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E5=A4=B1=E8=B4=A5=E8=87=AA=E5=8A=A8=E4=BF=9D=E7=95=99?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E5=A4=B1=E8=B4=A5=E5=90=8E=E9=87=8D=E8=AF=95?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E5=B9=B6=E5=BC=BA=E8=B0=83=E5=8F=AA=E8=BE=93?= =?UTF-8?q?=E5=87=BA=20JSON=EF=BC=9B=E4=BB=8D=E5=A4=B1=E8=B4=A5=E6=89=8D?= =?UTF-8?q?=E4=BF=9D=E5=AE=88=E4=BF=9D=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/agent_api.py | 70 ++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/web/agent_api.py b/web/agent_api.py index d8d7169..4781f81 100644 --- a/web/agent_api.py +++ b/web/agent_api.py @@ -286,38 +286,44 @@ def _ensure_audit_table(): def _review_one_exp(cfg, prompt, recipe, tool_seq, hits): - """调模型评审单条经验,返回 (verdict, score, reason);失败保守返回保留。""" - try: - import httpx - body = { - "model": cfg.get("model") or "deepseek-v4-flash-vision-exp", - "messages": [{"role": "user", - "content": _AUDIT_PROMPT.format( - prompt=(prompt or "")[:400], - recipe=(recipe or "")[:600], - tool_seq=(tool_seq or "")[:600], - hits=hits or 0)}], - "max_tokens": 200, - } - headers = {"Authorization": f"Bearer {cfg.get('api_key', '')}", - "Content-Type": "application/json"} - r = httpx.post(f"{(cfg.get('api_base') or 'https://api.deepseek.com').rstrip('/')}/chat/completions", - json=body, headers=headers, timeout=20) - if r.status_code != 200: - raise RuntimeError(f"HTTP {r.status_code}") - text = (((r.json() or {}).get("choices") or [{}])[0] - .get("message") or {}).get("content") or "" - m = re.search(r"\{.*\}", text, re.S) - if not m: - raise RuntimeError("响应无 JSON") - j = json.loads(m.group(0)) - keep = bool(j.get("keep", True)) - score = max(0, min(10, int(j.get("score", 5) or 5))) - reason = str(j.get("reason", ""))[:200] - return ("keep" if keep else "delete"), score, reason - except Exception as e: - _log.warning(f"经验评审失败(按保留处理): {e}") - return "keep", 0, f"评审失败自动保留: {str(e)[:80]}" + """调模型评审单条经验,返回 (verdict, score, reason)。 + + 模型偶尔输出解释文字不带 JSON——重试一次(强调只输出 JSON), + 仍失败则保守返回保留。 + """ + import httpx + base_prompt = _AUDIT_PROMPT.format(prompt=(prompt or "")[:400], + recipe=(recipe or "")[:600], + tool_seq=(tool_seq or "")[:600], + hits=hits or 0) + for attempt in (1, 2): + try: + content = base_prompt if attempt == 1 else ( + base_prompt + "\n注意:只输出一个 JSON 对象,不要输出任何其它文字、解释或代码块标记。") + body = { + "model": cfg.get("model") or "deepseek-v4-flash-vision-exp", + "messages": [{"role": "user", "content": content}], + "max_tokens": 200, + } + headers = {"Authorization": f"Bearer {cfg.get('api_key', '')}", + "Content-Type": "application/json"} + r = httpx.post(f"{(cfg.get('api_base') or 'https://api.deepseek.com').rstrip('/')}/chat/completions", + json=body, headers=headers, timeout=20) + if r.status_code != 200: + raise RuntimeError(f"HTTP {r.status_code}") + text = (((r.json() or {}).get("choices") or [{}])[0] + .get("message") or {}).get("content") or "" + m = re.search(r"\{.*\}", text, re.S) + if not m: + raise RuntimeError("响应无 JSON") + j = json.loads(m.group(0)) + keep = bool(j.get("keep", True)) + score = max(0, min(10, int(j.get("score", 5) or 5))) + reason = str(j.get("reason", ""))[:200] + return ("keep" if keep else "delete"), score, reason + except Exception as e: + _log.warning(f"经验评审第 {attempt} 次失败: {e}") + return "keep", 0, "评审失败自动保留(两次尝试均无有效 JSON)" def run_experience_audit():