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
|
||||
|
||||
|
||||
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):
|
||||
_log(run_id, 'supervisor', None, 'plan',
|
||||
f'主管开始规划:{run["topic"][:200]}')
|
||||
# 1) 主管拆解
|
||||
plan_text, u1 = _chat_worker(
|
||||
workers[0],
|
||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||
{'role': 'user', 'content': SUPERVISOR_PLAN_PROMPT.format(
|
||||
topic=run['topic'], context=run['context'] or '无')}],
|
||||
temperature=0.3, max_tokens=2000)
|
||||
# 1) 主管拆解(JSON 解析失败自动加大 max_tokens 重试)
|
||||
try:
|
||||
subtasks = _extract_json(plan_text)
|
||||
if isinstance(subtasks, dict):
|
||||
subtasks = subtasks.get('subtasks') or subtasks.get('tasks') or []
|
||||
data, _, u1 = _chat_json(
|
||||
workers[0],
|
||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||
{'role': 'user', 'content': SUPERVISOR_PLAN_PROMPT.format(
|
||||
topic=run['topic'], context=run['context'] or '无')}],
|
||||
max_tokens=3000, temperature=0.3)
|
||||
subtasks = data.get('subtasks') or data.get('tasks') or []
|
||||
if isinstance(data, list):
|
||||
subtasks = data
|
||||
except Exception as e:
|
||||
_update_run(run_id, status='failed', error=f'主管规划解析失败: {e}')
|
||||
_log(run_id, 'supervisor', None, 'plan', f'❌ 规划解析失败: {e}')
|
||||
@@ -216,15 +233,19 @@ def run_review(run_id, run, workers):
|
||||
# 评审
|
||||
review_usage = None
|
||||
try:
|
||||
review_text, u2 = _chat_worker(
|
||||
review_data, review_text, u2 = _chat_json(
|
||||
reviewer_w,
|
||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||
{'role': 'user', 'content': REVIEWER_PROMPT.format(
|
||||
topic=run['topic'], output=final_output, rubric=rubric)}],
|
||||
temperature=0.2, max_tokens=1500)
|
||||
score, judgment = _extract_score(review_text)
|
||||
max_tokens=2000, temperature=0.2)
|
||||
review_usage = u2
|
||||
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:
|
||||
score, judgment = 0, f'评审调用失败: {e}'
|
||||
final_score = score
|
||||
@@ -325,14 +346,13 @@ def run_debate(run_id, run, workers):
|
||||
f"【{v['stance']}】(#{k}):{v['view'][:500]}"
|
||||
for k, v in views.items() if k != w['id'])
|
||||
try:
|
||||
text, u = _chat_worker(
|
||||
data, _, u = _chat_json(
|
||||
w,
|
||||
[{'role': 'system', 'content': '你只输出 JSON。'},
|
||||
{'role': 'user', 'content': DEBATE_REBUT_PROMPT.format(
|
||||
stance=mine['stance'], topic=run['topic'],
|
||||
my_view=mine['view'], others=others)}],
|
||||
temperature=0.7, max_tokens=800)
|
||||
data = _extract_json(text)
|
||||
max_tokens=1200, temperature=0.7)
|
||||
rebut = data.get('rebuttal') if isinstance(data, dict) else text
|
||||
mine['view'] = mine['view'] + '\n\n【质询回应】' + str(rebut)
|
||||
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())
|
||||
_log(run_id, 'judge', judge_w['id'], 'verdict', '裁判综合裁决中…')
|
||||
try:
|
||||
verdict, u4 = _chat_worker(
|
||||
data, verdict, u4 = _chat_json(
|
||||
judge_w,
|
||||
[{'role': 'system', 'content': '你只输出 JSON。你是公正严明的首席裁判。'},
|
||||
{'role': 'user', 'content': JUDGE_PROMPT.format(topic=run['topic'], transcript=transcript)}],
|
||||
temperature=0.3, max_tokens=1500)
|
||||
data = _extract_json(verdict)
|
||||
max_tokens=2500, temperature=0.3)
|
||||
if isinstance(data, dict):
|
||||
consensus = data.get('consensus') or data.get('结论') or verdict
|
||||
summary = data.get('summary') or data.get('摘要') or ''
|
||||
|
||||
Reference in New Issue
Block a user