fix: 多Agent协作 JSON 截断导致主管规划解析失败
- 根因: deepseek-v4-flash 规划输出超 max_tokens=2000 被截断,JSON 不完整解析失败 - agents.py: 新增 _chat_json() 统一处理 JSON 类调用,解析失败自动加大 max_tokens 重试(×1/×2/×3) - 主管规划/辩论质询/辩论裁决/评审 全部改用 _chat_json 并提高初始上限(3000/1200/2500/2000) - 实测: 主管(计算器网页版4子任务)✅ 评审(92分)✅ 辩论(指定阵容)✅
This commit is contained in:
@@ -92,6 +92,23 @@ def _extract_score(text):
|
|||||||
return 60.0, text
|
return 60.0, text
|
||||||
|
|
||||||
|
|
||||||
|
def _chat_json(worker, messages, max_tokens=2000, temperature=None):
|
||||||
|
"""调用 LLM 并解析 JSON;解析失败自动加大 max_tokens 重试(防止长文截断)。
|
||||||
|
返回 (data, raw_text, usage);全部失败抛最后异常。"""
|
||||||
|
last_err = None
|
||||||
|
for attempt in range(3):
|
||||||
|
mt = max_tokens * (attempt + 1) # 2000 → 4000 → 6000
|
||||||
|
text, usage = _chat_worker(worker, messages, temperature=temperature, max_tokens=mt)
|
||||||
|
try:
|
||||||
|
data = _extract_json(text)
|
||||||
|
if isinstance(data, dict) and not data:
|
||||||
|
raise ValueError('空 JSON')
|
||||||
|
return data, text, usage
|
||||||
|
except Exception as e:
|
||||||
|
last_err = e
|
||||||
|
raise last_err or ValueError('JSON 解析失败')
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# 主管模式
|
# 主管模式
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -114,17 +131,17 @@ SUPERVISOR_SYNTH_PROMPT = (
|
|||||||
def run_supervisor(run_id, run, workers):
|
def run_supervisor(run_id, run, workers):
|
||||||
_log(run_id, 'supervisor', None, 'plan',
|
_log(run_id, 'supervisor', None, 'plan',
|
||||||
f'主管开始规划:{run["topic"][:200]}')
|
f'主管开始规划:{run["topic"][:200]}')
|
||||||
# 1) 主管拆解
|
# 1) 主管拆解(JSON 解析失败自动加大 max_tokens 重试)
|
||||||
plan_text, u1 = _chat_worker(
|
try:
|
||||||
|
data, _, u1 = _chat_json(
|
||||||
workers[0],
|
workers[0],
|
||||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||||
{'role': 'user', 'content': SUPERVISOR_PLAN_PROMPT.format(
|
{'role': 'user', 'content': SUPERVISOR_PLAN_PROMPT.format(
|
||||||
topic=run['topic'], context=run['context'] or '无')}],
|
topic=run['topic'], context=run['context'] or '无')}],
|
||||||
temperature=0.3, max_tokens=2000)
|
max_tokens=3000, temperature=0.3)
|
||||||
try:
|
subtasks = data.get('subtasks') or data.get('tasks') or []
|
||||||
subtasks = _extract_json(plan_text)
|
if isinstance(data, list):
|
||||||
if isinstance(subtasks, dict):
|
subtasks = data
|
||||||
subtasks = subtasks.get('subtasks') or subtasks.get('tasks') or []
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_update_run(run_id, status='failed', error=f'主管规划解析失败: {e}')
|
_update_run(run_id, status='failed', error=f'主管规划解析失败: {e}')
|
||||||
_log(run_id, 'supervisor', None, 'plan', f'❌ 规划解析失败: {e}')
|
_log(run_id, 'supervisor', None, 'plan', f'❌ 规划解析失败: {e}')
|
||||||
@@ -216,15 +233,19 @@ def run_review(run_id, run, workers):
|
|||||||
# 评审
|
# 评审
|
||||||
review_usage = None
|
review_usage = None
|
||||||
try:
|
try:
|
||||||
review_text, u2 = _chat_worker(
|
review_data, review_text, u2 = _chat_json(
|
||||||
reviewer_w,
|
reviewer_w,
|
||||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||||
{'role': 'user', 'content': REVIEWER_PROMPT.format(
|
{'role': 'user', 'content': REVIEWER_PROMPT.format(
|
||||||
topic=run['topic'], output=final_output, rubric=rubric)}],
|
topic=run['topic'], output=final_output, rubric=rubric)}],
|
||||||
temperature=0.2, max_tokens=1500)
|
max_tokens=2000, temperature=0.2)
|
||||||
score, judgment = _extract_score(review_text)
|
|
||||||
review_usage = u2
|
review_usage = u2
|
||||||
total_tokens += u2['total_tokens']; total_cost += u2['cost']
|
total_tokens += u2['total_tokens']; total_cost += u2['cost']
|
||||||
|
if isinstance(review_data, dict):
|
||||||
|
score = float(review_data.get('score', review_data.get('总分', 60)))
|
||||||
|
judgment = review_data.get('judgment') or review_data.get('意见') or review_text
|
||||||
|
else:
|
||||||
|
score, judgment = _extract_score(review_text)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
score, judgment = 0, f'评审调用失败: {e}'
|
score, judgment = 0, f'评审调用失败: {e}'
|
||||||
final_score = score
|
final_score = score
|
||||||
@@ -325,14 +346,13 @@ def run_debate(run_id, run, workers):
|
|||||||
f"【{v['stance']}】(#{k}):{v['view'][:500]}"
|
f"【{v['stance']}】(#{k}):{v['view'][:500]}"
|
||||||
for k, v in views.items() if k != w['id'])
|
for k, v in views.items() if k != w['id'])
|
||||||
try:
|
try:
|
||||||
text, u = _chat_worker(
|
data, _, u = _chat_json(
|
||||||
w,
|
w,
|
||||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||||
{'role': 'user', 'content': DEBATE_REBUT_PROMPT.format(
|
{'role': 'user', 'content': DEBATE_REBUT_PROMPT.format(
|
||||||
stance=mine['stance'], topic=run['topic'],
|
stance=mine['stance'], topic=run['topic'],
|
||||||
my_view=mine['view'], others=others)}],
|
my_view=mine['view'], others=others)}],
|
||||||
temperature=0.7, max_tokens=800)
|
max_tokens=1200, temperature=0.7)
|
||||||
data = _extract_json(text)
|
|
||||||
rebut = data.get('rebuttal') if isinstance(data, dict) else text
|
rebut = data.get('rebuttal') if isinstance(data, dict) else text
|
||||||
mine['view'] = mine['view'] + '\n\n【质询回应】' + str(rebut)
|
mine['view'] = mine['view'] + '\n\n【质询回应】' + str(rebut)
|
||||||
total_tokens += u['total_tokens']; total_cost += u['cost']
|
total_tokens += u['total_tokens']; total_cost += u['cost']
|
||||||
@@ -346,12 +366,11 @@ def run_debate(run_id, run, workers):
|
|||||||
f"【{v['stance']}】{v['view']}" for v in views.values())
|
f"【{v['stance']}】{v['view']}" for v in views.values())
|
||||||
_log(run_id, 'judge', judge_w['id'], 'verdict', '裁判综合裁决中…')
|
_log(run_id, 'judge', judge_w['id'], 'verdict', '裁判综合裁决中…')
|
||||||
try:
|
try:
|
||||||
verdict, u4 = _chat_worker(
|
data, verdict, u4 = _chat_json(
|
||||||
judge_w,
|
judge_w,
|
||||||
[{'role': 'system', 'content': '你只输出 JSON。你是公正严明的首席裁判。'},
|
[{'role': 'system', 'content': '你只输出 JSON。你是公正严明的首席裁判。'},
|
||||||
{'role': 'user', 'content': JUDGE_PROMPT.format(topic=run['topic'], transcript=transcript)}],
|
{'role': 'user', 'content': JUDGE_PROMPT.format(topic=run['topic'], transcript=transcript)}],
|
||||||
temperature=0.3, max_tokens=1500)
|
max_tokens=2500, temperature=0.3)
|
||||||
data = _extract_json(verdict)
|
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
consensus = data.get('consensus') or data.get('结论') or verdict
|
consensus = data.get('consensus') or data.get('结论') or verdict
|
||||||
summary = data.get('summary') or data.get('摘要') or ''
|
summary = data.get('summary') or data.get('摘要') or ''
|
||||||
|
|||||||
Reference in New Issue
Block a user