diff --git a/agents.py b/agents.py index 6f76756..3bd7528 100644 --- a/agents.py +++ b/agents.py @@ -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 ''