fix: 经验巡检评审失败重试——模型偶发输出解释文字不带 JSON(实测 4/11 条评审失败自动保留),失败后重试一次并强调只输出 JSON;仍失败才保守保留
This commit is contained in:
+38
-32
@@ -286,38 +286,44 @@ def _ensure_audit_table():
|
|||||||
|
|
||||||
|
|
||||||
def _review_one_exp(cfg, prompt, recipe, tool_seq, hits):
|
def _review_one_exp(cfg, prompt, recipe, tool_seq, hits):
|
||||||
"""调模型评审单条经验,返回 (verdict, score, reason);失败保守返回保留。"""
|
"""调模型评审单条经验,返回 (verdict, score, reason)。
|
||||||
try:
|
|
||||||
import httpx
|
模型偶尔输出解释文字不带 JSON——重试一次(强调只输出 JSON),
|
||||||
body = {
|
仍失败则保守返回保留。
|
||||||
"model": cfg.get("model") or "deepseek-v4-flash-vision-exp",
|
"""
|
||||||
"messages": [{"role": "user",
|
import httpx
|
||||||
"content": _AUDIT_PROMPT.format(
|
base_prompt = _AUDIT_PROMPT.format(prompt=(prompt or "")[:400],
|
||||||
prompt=(prompt or "")[:400],
|
recipe=(recipe or "")[:600],
|
||||||
recipe=(recipe or "")[:600],
|
tool_seq=(tool_seq or "")[:600],
|
||||||
tool_seq=(tool_seq or "")[:600],
|
hits=hits or 0)
|
||||||
hits=hits or 0)}],
|
for attempt in (1, 2):
|
||||||
"max_tokens": 200,
|
try:
|
||||||
}
|
content = base_prompt if attempt == 1 else (
|
||||||
headers = {"Authorization": f"Bearer {cfg.get('api_key', '')}",
|
base_prompt + "\n注意:只输出一个 JSON 对象,不要输出任何其它文字、解释或代码块标记。")
|
||||||
"Content-Type": "application/json"}
|
body = {
|
||||||
r = httpx.post(f"{(cfg.get('api_base') or 'https://api.deepseek.com').rstrip('/')}/chat/completions",
|
"model": cfg.get("model") or "deepseek-v4-flash-vision-exp",
|
||||||
json=body, headers=headers, timeout=20)
|
"messages": [{"role": "user", "content": content}],
|
||||||
if r.status_code != 200:
|
"max_tokens": 200,
|
||||||
raise RuntimeError(f"HTTP {r.status_code}")
|
}
|
||||||
text = (((r.json() or {}).get("choices") or [{}])[0]
|
headers = {"Authorization": f"Bearer {cfg.get('api_key', '')}",
|
||||||
.get("message") or {}).get("content") or ""
|
"Content-Type": "application/json"}
|
||||||
m = re.search(r"\{.*\}", text, re.S)
|
r = httpx.post(f"{(cfg.get('api_base') or 'https://api.deepseek.com').rstrip('/')}/chat/completions",
|
||||||
if not m:
|
json=body, headers=headers, timeout=20)
|
||||||
raise RuntimeError("响应无 JSON")
|
if r.status_code != 200:
|
||||||
j = json.loads(m.group(0))
|
raise RuntimeError(f"HTTP {r.status_code}")
|
||||||
keep = bool(j.get("keep", True))
|
text = (((r.json() or {}).get("choices") or [{}])[0]
|
||||||
score = max(0, min(10, int(j.get("score", 5) or 5)))
|
.get("message") or {}).get("content") or ""
|
||||||
reason = str(j.get("reason", ""))[:200]
|
m = re.search(r"\{.*\}", text, re.S)
|
||||||
return ("keep" if keep else "delete"), score, reason
|
if not m:
|
||||||
except Exception as e:
|
raise RuntimeError("响应无 JSON")
|
||||||
_log.warning(f"经验评审失败(按保留处理): {e}")
|
j = json.loads(m.group(0))
|
||||||
return "keep", 0, f"评审失败自动保留: {str(e)[:80]}"
|
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():
|
def run_experience_audit():
|
||||||
|
|||||||
Reference in New Issue
Block a user