fix: compliance optimizer now requires score improvement, retries LLM on failure

Bug: 'passed=True' check for soft quality issues (AI套话, 缺互动引导)
always exits immediately even when LLM failed to make changes.
Score 85 stays 85, content unchanged.

Fix:
1. polish_with_llm: retry once on exception (was: single attempt)
2. main loop: only accept fix when score actually improves AND
   LLM produced output (opt_logs non-empty). If LLM returns same html
   unchanged, treat as failed attempt and retry.
This commit is contained in:
Yuzhiran Dev
2026-05-27 09:23:49 +08:00
parent 29d97b5f1a
commit 004698cf98
+38 -29
View File
@@ -159,36 +159,40 @@ def fix_tags(html: str, platform: str) -> str:
def polish_with_llm(html: str, platform: str, remaining_issues: Optional[List[Dict]] = None) -> Tuple[str, Optional[str]]: def polish_with_llm(html: str, platform: str, remaining_issues: Optional[List[Dict]] = None) -> Tuple[str, Optional[str]]:
"""用 LLM 优化文章内容,返回 (html, log_message_or_None) """用 LLM 优化文章内容,返回 (html, log_message_or_None)
如果指定 remaining_issues,则针对性修复合规问题 如果指定 remaining_issues,则针对性修复合规问题
LLM 失败时自动重试一次
""" """
if not HAVE_LLM: if not HAVE_LLM:
return html, None return html, None
llm_cfg = get_llm_config() llm_cfg = get_llm_config()
try: for attempt in range(2):
model = llm_cfg.get('model') if llm_cfg else None try:
temperature = llm_cfg.get('temperature', 0.5) if llm_cfg else 0.5 model = llm_cfg.get('model') if llm_cfg else None
max_tokens = llm_cfg.get('max_tokens', 4000) if llm_cfg else 4000 temperature = llm_cfg.get('temperature', 0.5) if llm_cfg else 0.5
system_prompt = llm_cfg.get('system_prompt') if llm_cfg else "你是一个专业的内容合规与优化助手,擅长在保持文章质量和可读性的前提下修复合规问题。" max_tokens = llm_cfg.get('max_tokens', 4000) if llm_cfg else 4000
system_prompt = llm_cfg.get('system_prompt') if llm_cfg else "你是一个专业的内容合规与优化助手,擅长在保持文章质量和可读性的前提下修复合规问题。"
if remaining_issues: if remaining_issues:
issues_desc = "\n".join( issues_desc = "\n".join(
f"- [{i['type']}] {i.get('category','')}: {i.get('detail','')}" f"- [{i['type']}] {i.get('category','')}: {i.get('detail','')}"
for i in remaining_issues for i in remaining_issues
) )
prompt = get_prompt("compliance_fix", issues_desc=issues_desc, html=html) prompt = get_prompt("compliance_fix", issues_desc=issues_desc, html=html)
else: else:
prompt = get_prompt("compliance_polish", html=html) prompt = get_prompt("compliance_polish", html=html)
polished = call_llm(prompt, model=model, temperature=temperature, max_tokens=max_tokens, system_prompt=system_prompt) polished = call_llm(prompt, model=model, temperature=temperature, max_tokens=max_tokens, system_prompt=system_prompt)
polished = clean_html_content(polished) polished = clean_html_content(polished)
polished = strip_ai_preface(polished) polished = strip_ai_preface(polished)
polished = strip_thinking_html(polished) polished = strip_thinking_html(polished)
if '<h2' in polished or '<p>' in polished: if '<h2' in polished or '<p>' in polished:
if len(polished) > len(html) * 0.3 and len(polished) > 100: if len(polished) > len(html) * 0.3 and len(polished) > 100:
if not any(kw in polished for kw in ['保留', '建议', '可以', '应该', '推荐', '改为', '替换为']): if not any(kw in polished for kw in ['保留', '建议', '可以', '应该', '推荐', '改为', '替换为']):
tag = "针对性修复" if remaining_issues else "常规润色" tag = "针对性修复" if remaining_issues else "常规润色"
return polished, f"LLM {tag}" return polished, f"LLM {tag}"
logger.warning(f"LLM 优化输出异常(过短或含建议性文字),保留原文 (len={len(polished)})") logger.warning(f"LLM 优化输出异常(过短或含建议性文字),保留原文 (len={len(polished)})")
except Exception as e: except Exception as e:
logger.warning(f"LLM 优化失败: {e}") logger.warning(f"LLM 优化失败 (尝试 {attempt+1}/2): {e}")
if attempt == 0:
logger.info(f"重试 LLM 调用...")
return html, None return html, None
def optimize_article(html: str, platform: str, topic_data: Dict, remaining_issues: Optional[List[Dict]] = None) -> Tuple[str, List[str]]: def optimize_article(html: str, platform: str, topic_data: Dict, remaining_issues: Optional[List[Dict]] = None) -> Tuple[str, List[str]]:
@@ -263,12 +267,13 @@ def main(topic_ids: List[str] = None):
if issues: if issues:
current_html = html current_html = html
current_issues = list(issues) current_issues = list(issues)
current_score = score
for attempt in range(3): for attempt in range(3):
optimized_html, opt_logs = optimize_article(current_html, platform_dir, topic_data, current_issues) optimized_html, opt_logs = optimize_article(current_html, platform_dir, topic_data, current_issues)
recheck = check_article(optimized_html, platform_dir, topic_data) recheck = check_article(optimized_html, platform_dir, topic_data)
if recheck['passed']: if recheck['passed'] and opt_logs and recheck['score'] > current_score:
save_article(topic_id, platform_dir, optimized_html) save_article(topic_id, platform_dir, optimized_html)
logger.info(f"{label} 已修复并通过审查 (第{attempt+1}次修复)") logger.info(f"{label} 已修复并通过审查 (第{attempt+1}次修复) 分数: {current_score}{recheck['score']}")
results.append(OptimizationResult( results.append(OptimizationResult(
file=f"db:{platform_dir}_{topic_id}", file=f"db:{platform_dir}_{topic_id}",
platform=platform_dir, platform=platform_dir,
@@ -280,11 +285,15 @@ def main(topic_ids: List[str] = None):
status="passed" status="passed"
)) ))
break break
if optimized_html == current_html and not opt_logs:
logger.warning(f"{label} LLM 未输出有效修改(第{attempt+1}次),继续重试...")
continue
current_issues = recheck['issues'] current_issues = recheck['issues']
current_html = optimized_html current_html = optimized_html
current_score = recheck['score']
else: else:
save_article(topic_id, platform_dir, current_html) save_article(topic_id, platform_dir, current_html)
logger.warning(f"⚠️ {label} 仍有 {len(current_issues)} 个问题未修复,已强制通过") logger.warning(f"⚠️ {label} 仍有 {len(current_issues)} 个问题未修复,已强制通过(当前分 {current_score}")
results.append(OptimizationResult( results.append(OptimizationResult(
file=f"db:{platform_dir}_{topic_id}", file=f"db:{platform_dir}_{topic_id}",
platform=platform_dir, platform=platform_dir,
@@ -292,7 +301,7 @@ def main(topic_ids: List[str] = None):
title=topic_data.get('title',''), title=topic_data.get('title',''),
original_issues=len(issues), original_issues=len(issues),
fixed_issues=len(issues) - len(current_issues), fixed_issues=len(issues) - len(current_issues),
final_score=recheck['score'], final_score=current_score,
status="passed" status="passed"
)) ))
else: else: