From dcbd31bf3d6412f0be25bb9bbcda958c1f665c4d Mon Sep 17 00:00:00 2001 From: Yi-111-a Date: Thu, 1 Oct 2026 11:30:27 +0800 Subject: [PATCH] [fix] keep malformed tool calls from crashing agent RL training --- trainer/train_agent.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trainer/train_agent.py b/trainer/train_agent.py index 4619dbb..1b4ff9f 100644 --- a/trainer/train_agent.py +++ b/trainer/train_agent.py @@ -76,8 +76,9 @@ CHECK_ARGS = { def parse_tool_calls(text): calls = [] for m in re.findall(r'(.*?)', text, re.DOTALL): - try: calls.append(json.loads(m.strip())) - except: pass + try: call = json.loads(m.strip()) + except: continue + if isinstance(call, dict): calls.append(call) # 模型偶尔输出非对象JSON,直接丢弃避免下游崩溃 return calls def execute_tool(name, args): @@ -132,6 +133,7 @@ def rollout_single(rollout_engine, tokenizer, messages, tools, max_turns=3, max_ if isinstance(raw, str): try: raw = json.loads(raw) except: raw = {} + if not isinstance(raw, dict): raw = {} # arguments 结构异常按空参处理 result = execute_tool(name, raw) result_str = (json.dumps(result, ensure_ascii=False) if result else '{"error": "tool not found"}')[:2048] # 防止天文数字撑爆tokenizer messages.append({"role": "tool", "content": result_str}) @@ -225,6 +227,7 @@ def calculate_rewards(prompts, completions, gt_batch, tools_batch, num_gen, rewa if isinstance(raw, str): try: raw = json.loads(raw) except: raw = {} + if not isinstance(raw, dict): raw = {} # arguments 结构异常按空参处理 check = CHECK_ARGS.get(name) valid_call_count += int(bool(name in valid_names and check and check(raw))) tool_gap = abs(valid_call_count - len(gt)) + max(0, len(tool_calls) - valid_call_count) # tool数差值