Agent Fine-Tuning¶
Train models to use tools, follow multi-step reasoning, and complete tasks. xaytune provides the full agent training pipeline: data formats, loss masking, alignment rewards, and evaluation metrics.
Quick Start¶
import xaytune
# Fine-tune on tool-use conversations
state = xaytune.finetune(
model="meta-llama/Llama-3.1-8B",
dataset="data/agent_traces.jsonl",
method="lora",
format="function_calling",
num_epochs=3,
)
Just set format="function_calling" (or "react", "trajectory", "multi_agent") and xaytune handles loss masking automatically — the model learns to generate tool calls and reasoning, not to predict user prompts or tool outputs.
Data Formats¶
xaytune supports four agent data formats. Each converts raw data into an intermediate AgentMessage representation with per-message trainable flags.
function_calling (OpenAI-compatible)¶
The most common format. Matches the OpenAI Chat Completions API with tool_calls and tool messages.
{
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What's the weather in London?"},
{"role": "assistant", "content": null, "tool_calls": [
{"id": "call_1", "type": "function", "function": {
"name": "get_weather",
"arguments": "{\"city\": \"London\"}"
}}
]},
{"role": "tool", "tool_call_id": "call_1", "content": "{\"temp\": 18}"},
{"role": "assistant", "content": "It's 18°C in London."}
]
}
Loss masking: Only assistant messages are trainable. system, user, and tool messages are masked.
react (ReAct traces)¶
Thought → Action → Observation loops for reasoning agents.
{
"task": "Find the population of France",
"steps": [
{
"thought": "I need to search for this.",
"action": "search",
"action_input": "France population 2024",
"observation": "68 million"
},
{
"thought": "I have the answer.",
"action": "finish",
"action_input": "68 million"
}
]
}
Loss masking: thought, action, action_input are trainable. observation is masked.
trajectory (multi-step sessions)¶
Full agent sessions with tool calls — ideal for code agents, debugging workflows, and multi-step tasks.
{
"system": "You are a coding assistant.",
"goal": "Create a hello world script",
"turns": [
{"role": "assistant", "content": "Creating file.", "tool_calls": [
{"name": "write_file", "arguments": {"path": "hello.py", "content": "print('hello')"}}
]},
{"role": "tool", "content": "File written."},
{"role": "assistant", "content": "Done!"}
]
}
multi_agent (collaborative agents)¶
Multiple named agents working together. Each turn has an agent field identifying which agent is acting.
{
"system": "You are coordinating a research team.",
"goal": "Research and write about quantum computing",
"turns": [
{"agent": "researcher", "role": "assistant", "content": "Searching...", "tool_calls": [
{"name": "search", "arguments": {"q": "quantum computing"}}
]},
{"role": "tool", "content": "Found 15 papers..."},
{"agent": "writer", "role": "assistant", "content": "Here's a summary..."}
]
}
Loss Masking¶
The agent tokenizer applies per-token loss masking automatically. Each message is tokenized individually to track exact token boundaries:
- Trainable (labels = token IDs): assistant messages — the model learns to generate these
- Masked (labels = -100): system, user, tool messages — the model attends to these but doesn't predict them
This ensures the model learns what to say and which tools to call, without wasting capacity predicting user prompts or tool outputs.
from xaytune.data.agent_formats import format_function_calling
from xaytune.data.agent_tokenizer import tokenize_agent_dataset
messages = format_function_calling(sample)
tokenized = tokenize_agent_dataset([messages], tokenizer, max_seq_length=2048)
# tokenized[0]["labels"] has -100 for masked tokens
Alignment with Agent Rewards¶
After SFT, align your agent with GRPO/PPO using agent-specific reward functions.
Built-in Rewards¶
| Reward | What it scores | Range |
|---|---|---|
tool_use_quality |
Did the model call the right tools with correct parameters? | 0–1 |
task_completion |
Did the agent finish the task? | 0–1 |
efficiency |
Fewer tool calls = higher score | 0–1 |
agent_composite |
Weighted combination (default: 40% quality, 40% completion, 20% efficiency) | 0–1 |
Usage in Training Config¶
recipe: align
method: grpo
online_rl:
enabled: true
reward_name: agent_composite
reward_kwargs:
expected_tools: ["search", "calculator"]
success_markers: ["Done", "Task complete"]
max_steps: 5
Custom Tool Call Parsers¶
By default, rewards parse <tool_call> tags. Pass a custom parser for other formats:
from xaytune.recipes.align.agent_rewards import tool_use_quality_reward
def my_parser(response):
# Parse your custom format
return [ParsedToolCall(name="...", arguments={...})]
score = tool_use_quality_reward(
prompt, response,
expected_tools=["search"],
parser=my_parser,
)
Evaluation¶
Evaluate agent performance on a dataset of prompt-response pairs.
from xaytune.eval.agent_metrics import evaluate_agent
results = evaluate_agent(
responses=[
{"prompt": "Search for cats", "response": "<tool_call>..."},
{"prompt": "Calculate 2+2", "response": "<tool_call>..."},
],
expected_tools=["search", "calculator"],
success_markers=["Done"],
max_steps=5,
)
print(results)
# {
# 'tool_use_accuracy': 0.85,
# 'task_success_rate': 0.90,
# 'step_efficiency': 0.75,
# 'error_recovery_rate': 0.60,
# }
Metrics¶
| Metric | Description |
|---|---|
tool_use_accuracy |
Fraction of samples where the correct tools were called |
task_success_rate |
Fraction of samples that completed the task |
step_efficiency |
Average efficiency score (fewer calls = higher) |
error_recovery_rate |
Fraction of samples that recovered after tool errors |
Synthetic Agent Data Generation¶
Generate training data for agent fine-tuning without manually collecting trajectories.
agent_distill — Generate from a Topic¶
Give the LLM a topic and tool definitions, get back function_calling conversations:
from xaytune.data.prep import generate
result = generate(
mode="agent_distill",
topic="customer support with order lookup",
tools=[
{"function": {
"name": "lookup_order",
"description": "Look up order by ID",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}}
}}
],
n=100,
format="function_calling",
model="gpt-4o-mini",
)
result.save("data/agent_traces.jsonl")
agent_augment — Generate Variations¶
Create variations of existing agent conversations:
result = generate(
mode="agent_augment",
seed="data/agent_traces.jsonl",
n=200,
format="function_calling",
model="gpt-4o-mini",
)
result.save("data/agent_augmented.jsonl")
CLI¶
Agent fine-tuning uses the standard xaytune train command with an agent format:
Where agent_config.yaml:
recipe: finetune
method: lora
model:
name: meta-llama/Llama-3.1-8B
data:
path: data/agent_traces.jsonl
format: function_calling
trainer:
num_epochs: 3
learning_rate: 2e-4
batch_size: 4
Full Pipeline Example¶
The complete agent training pipeline:
- Prepare data — collect or generate agent trajectories
- SFT — fine-tune on trajectories with
format="function_calling" - Align — improve tool use with
reward_name="agent_composite"and GRPO - Evaluate — score with
evaluate_agent()on held-out data - Export — merge adapters and deploy
See 11_agent_finetuning.ipynb for a hands-on walkthrough covering all steps.