import json
import sys
from pathlib import Path
import torch
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from trainer.train_agent import ( # noqa: E402
TOOLS,
calculate_rewards,
execute_tool,
parse_tool_calls,
validate_gt_in_text,
)
def pick_tools(names):
wanted = set(names)
return [tool for tool in TOOLS if tool["function"]["name"] in wanted]
def main():
tools = pick_tools(["calculate_math", "get_current_time"])
prompts = [
"<|im_start|>user\n"
"帮我算一下 256 乘以 37 等于多少<|im_end|>\n"
"<|im_start|>assistant\n"
]
gt_batch = [["9472"]]
completions = [
'\n\n{"name":"calculate_math","arguments":{"expression":"256 * 37"}}\n工具返回 9472,所以答案是 9472。',
'\n\n{"name":"calculate_math","arguments":{}}\n我没有拿到有效表达式。',
'\n\n{"name":"unknown_tool","arguments":{"expression":"256 * 37"}}\n答案可能是 9472。',
'\n\n{"name":"calculate_math","arguments":{"expression":"256 * 37"}}\n答案是 9472。',
]
turn_outputs_batch = [[text] for text in completions]
unfinished_batch = [False, False, False, False]
rewards = calculate_rewards(
prompts=prompts,
completions=completions,
gt_batch=gt_batch,
tools_batch=[tools],
num_gen=len(completions),
reward_model=None,
device="cpu",
turn_outputs_batch=turn_outputs_batch,
unfinished_batch=unfinished_batch,
)
print("[Agent tool reward trace]")
print(f"available_tools={[tool['function']['name'] for tool in tools]}")
print(f"gt={gt_batch[0]}")
print()
for idx, text in enumerate(completions):
calls = parse_tool_calls(text)
final_text = text.split("")[-1] if "" in text else text
verified = validate_gt_in_text(final_text, gt_batch[0])
executed = []
for call in calls:
raw_args = call.get("arguments", {})
if isinstance(raw_args, str):
try:
raw_args = json.loads(raw_args)
except Exception:
raw_args = {}
executed.append(
{
"name": call.get("name", ""),
"args": raw_args,
"result": execute_tool(call.get("name", ""), raw_args),
}
)
print(f"case={idx}")
print(f"parsed_calls={calls}")
print(f"executed={executed}")
print(f"verified_gt={sorted(verified)}")
print(f"reward={rewards[idx].item():.4f}")
print("-" * 80)
grouped = rewards.view(1, len(completions))
advantages = (rewards - grouped.mean(dim=1).repeat_interleave(len(completions))) / (
grouped.std(dim=1, unbiased=False).repeat_interleave(len(completions)) + 1e-4
)
print("[GRPO-style group normalization]")
print(f"rewards={rewards.tolist()}")
print(f"advantages={advantages.tolist()}")
print(f"adv_mean={advantages.mean().item():.6f}")
if __name__ == "__main__":
main()