Fine-Tuning Tool-Calling LLMs: A Complete Guide Using XYZ-Aquila-SFT and Qwen3 A technical tutorial demonstrates an end-to-end supervised fine-tuning pipeline for the XYZ-Aquila-SFT dataset using Hugging Face Transformers, PyTorch, and PEFT, culminating in LoRA fine-tuning of Qwen3-0.6B for tool-calling tasks. The guide covers dataset streaming, parsing multi-turn tool-use trajectories, converting tool schemas, and evaluating tool-call prediction before and after training, with configuration parameters including 400 streamed examples, 30 training steps, and a learning rate of 1e-4. In this tutorial, we implement an end-to-end supervised fine-tuning pipeline for the XYZ-Aquila-SFT https://huggingface.co/datasets/XYZAILab/XYZ-Aquila-SFT dataset, Hugging Face Transformers, PyTorch, and PEFT. We stream and inspect the dataset, parse multi-turn tool-use trajectories, extract structured tool calls, analyze corpus characteristics, and preserve embedded reasoning and observation patterns. We then convert tool schemas between message-embedded and structured formats, render Qwen-compatible ChatML with assistant-only loss masking, prepare a custom PyTorch dataset and collator, and fine-tune Qwen3-0.6B with LoRA. Finally, we evaluate tool-call prediction before and after training and export both the transformed dataset and corpus statistics for further experimentation. python import os, sys, subprocess CFG = dict REPO = "XYZAILab/XYZ-Aquila-SFT", LANG = "en", N STREAM = 400, N EVAL = 40, MODEL ID = "Qwen/Qwen3-0.6B", MAX SEQ LEN = 2048, LENGTH POLICY = "truncate", RUN TRAINING = True, MAX STEPS = 30, GRAD ACCUM = 8, LR = 1e-4, LORA R = 16, RUN EVAL = True, N EVAL PROBES = 24, OUT DIR = "/content/aquila out", SEED = 0, os.makedirs CFG "OUT DIR" , exist ok=True def pip pkgs : subprocess.run sys.executable, "-m", "pip", "install", "-q", "-U", pkgs , check=False pip "datasets =3.0.0", "transformers =4.51.0", "peft =0.13.0", "accelerate =1.0.0" import json, re, math, random, statistics as stats from collections import Counter, defaultdict from dataclasses import dataclass, field from typing import Any, Dict, List, Optional import torch import matplotlib.pyplot as plt from datasets import load dataset from transformers import AutoTokenizer, AutoModelForCausalLM, get cosine schedule with warmup random.seed CFG "SEED" ; torch.manual seed CFG "SEED" DEV = "cuda" if torch.cuda.is available else "cpu" BF16 = DEV == "cuda" and torch.cuda.is bf16 supported print f"device={DEV} bf16={BF16} torch={torch. version }" print f"\n 1 streaming {CFG 'REPO' }:{CFG 'LANG' } ..." stream = load dataset CFG "REPO" , CFG "LANG" , split="train", streaming=True RAW: List Dict str, Any = list stream.take CFG "N STREAM" print f" pulled {len RAW } rows; keys = {list RAW 0 .keys }" r = RAW 0 print f" question :110 : { r 'question' :110 }..." print f" answer : { r 'answer' :80 }" print f" number of tool calls : { r 'number of tool calls' }" print f" trajectory len : {len r 'trajectory' } msgs" print f" role sequence first8 : { m 'role' for m in r 'trajectory' :8 }" We configure the dataset, model, training parameters, output directory, and reproducibility settings for the complete workflow. We install the required Hugging Face, PEFT, Accelerate, and PyTorch-related dependencies and detect whether a CUDA GPU and BF16 support are available. We then stream a limited number of XYZ-Aquila-SFT examples, inspect the dataset schema, and examine the structure of the first tool-use trajectory. TOOLS BLOCK RE = re.compile r"