How abhaychandra123/toolcalllm works
1. What this repo is
ToolCallLM is an end-to-end tool-calling fine-tuning pipeline centered on a base LLM (default Qwen3-8B). The core flow is: raw tool-call datasets in, standardized training examples out, LoRA/QLoRA fine-tuning, then inference, BFCL evaluation, and optional serving.
2. Configuration is the main control plane
The project is driven by YAML recipes in configs/. configs/base.yaml defines shared defaults, and concrete configs extend it for training, inference, evaluation, FP8/Unsloth variants, BFCL subsets, and experiment-specific runs. .env supplies path/model overrides such as DATA_DIR, OUTPUT_DIR, and BASE_MODEL.
3. Repository boundary: thin scripts, real logic in src/
scripts/ contains command-line entrypoints only. They load config, call one function in toolcall_lm.*, and exit. The actual architecture lives under src/toolcall_lm/, which is split into small subsystems: data, training, inference, api, eval, prompt, validators, tracking, and utils.
4. Data subsystem: normalize many dataset shapes into one schema
src/toolcall_lm/data/ converts multiple source formats into a unified tool-calling schema. It supports OpenAI-chat style, ShareGPT, Alpaca-like records, BFCL-specific conversions, and dataset-specific adapters for ToolACE and xLAM. The flow is raw JSONL/JSON in data/, normalization and filtering in preprocess.py, then processed JSONL/manifests under data/train/processed/.
5. Dataset quality gates happen early
The data pipeline includes schema validation, masking, truncation checks, and inspection utilities. Key boundaries are:
- schema.py / dataset.py for the canonical record shape
- preprocess.py for conversion and rejection logic
- masking.py, schema_jitter.py, thought_injection.py, and failure_driven_sampling.py for augmentation/experimentation
- inspect.py for human-readable validation before training
This repo treats bad training rows as a first-class failure mode, not a downstream surprise.
6. Prompting and output format are separate from the model
src/toolcall_lm/prompt/ defines how tool specs and chat templates are rendered. The repo explicitly supports Qwen-style <tool_call>...</tool_call> outputs and fallback JSON formatting through tool_format.py. This boundary matters because training, inference, and validation all depend on the exact tool-call wrapper.
7. Training subsystem: supervised fine-tuning with adapter-based methods
src/toolcall_lm/training/ wires the model, tokenizer, LoRA/QLoRA config, callbacks, and watchdogs into the training loop. The architecture is adapter-first: base model remains fixed, while checkpoints store LoRA adapters plus tokenizer/config artifacts. There are distinct recipes for BF16 LoRA, QLoRA, DPO, FP8, Unsloth, and recovery-oriented experiments.
8. Inference subsystem: same model, different boundary
src/toolcall_lm/inference/ provides a CLI-facing engine that loads the base model plus an optional adapter and produces either raw text or parsed tool calls. It is also where validation of model outputs happens via validators/json_parser.py and validators/tool_call_validator.py. The inference layer is the boundary between free-form generation and structured tool-call semantics.
9. Serving is a thin FastAPI wrapper over inference
src/toolcall_lm/api/server.py exposes health and chat-completions-style endpoints, with request/response schemas in api/schemas.py. The service reuses the same inference engine and prompt/tool formatting logic as the CLI, so the serving path is not a separate implementation. scripts/serve.py launches this API, and the README shows streaming support as an optional client-side concern.
10. Evaluation is BFCL-centric and produces its own artifact tree
src/toolcall_lm/eval/ contains the BFCL runner, Taubench runner, failure analysis, taxonomy, and run-comparison utilities. BFCL evaluation shells out to the official BFCL CLI, then aggregates category-level outputs into outputs/bfcl_results/ and outputs/bfcl_metrics/ style folders, including summaries and failure breakdowns. This is the main benchmark boundary for judging tool-calling quality.
11. Synthetic and experimental dataset generation is a separate lane
The synthetic_data_gen/ directory and several scripts under scripts/ build synthetic multiturn, recovery, preference, and negative samples. These artifacts feed back into the same preprocessing pipeline, but they are clearly separated from model training and evaluation so the repo can support both curated and generated data sources.
12. Operational helpers and infrastructure support
src/toolcall_lm/utils/ contains configuration loading, logging, seeding, checkpoint utilities, environment sanitization, notifier hooks, and small runtime patches. The project also includes integrations for W&B tracking, optional Telegram/status notifications, Dockerfiles for different runtime setups, and accelerate/bitsandbytes/Unsloth paths where memory or performance constraints matter.
13. Artifacts and state are intentionally kept out of source control
data/ holds downloaded/raw/processed datasets, while outputs/ is the workspace for checkpoints, merged models, BFCL results, metrics, logs, and generated reports. The many saved merged_* and bfcl_* folders in outputs/ show that experiments are reproducible by config and artifact path rather than by hidden runtime state.
14. Quality strategy: tests and diagnostic scripts
tests/ validates the critical seams: preprocessing, masking, schema jitter, JSON parsing, LoRA config, toolace pipeline integrity, BFCL-related behavior, and end-to-end dry runs. The numerous scripts in scripts/ act as targeted diagnostic tools for failure analysis, dataset audits, performance sweeps, and benchmark reproduction.
15. How to diagram the system
A good architecture diagram should show one central pipeline with these stages: raw data sources → preprocessing/validation → processed training set → adapter fine-tuning → adapter checkpoint/merged model → inference/serving → BFCL/Taubench evaluation and analysis. Surround that pipeline with the config layer, prompt/validator boundary, and utility/ops layer that supports each stage.
Main entry points: trainer.py Training · engine.py Inference engine · base.yaml Base config · config.py Utilities
Components 24
Config control plane
YAML recipes and environment overrides that steer the pipeline.
- Base config · Shared YAML defaults for model, paths, and runtime behavior.
configs/base.yaml - Train recipes · Training variants for LoRA, QLoRA, DPO, FP8, Unsloth, and experiments.
configs/train_common.yaml - Inference config · CLI inference and model-loading settings.
configs/inference.yaml - Eval recipes · BFCL and Taubench evaluation configurations.
configs/eval_bfcl.yaml
Data pipeline
Raw datasets, normalization, validation, and processed training artifacts.
- Raw datasets · Downloaded JSON/JSONL datasets such as ToolACE, xLAM, BFCL, and custom blends.
data - Canonical schema · Unified tool-calling record shape used across sources.
src/toolcall_lm/data/schema.py - Preprocess · Converts, filters, truncates, and rejects malformed examples.
src/toolcall_lm/data/preprocess.py - Dataset adapters · Format-specific handlers for BFCL, ToolACE, xLAM, and blend validation.
src/toolcall_lm/data/bfcl_format.py - Quality gates · Masking, schema jitter, thought injection, failure-driven sampling, and inspection.
src/toolcall_lm/data/inspect.py - Processed sets · Normalized JSONL manifests and derived training splits.
data/train/processed
Core model flow
Training, inference, prompts, validation, and API serving.
- Prompting · Renders tool specs, chat templates, and tool-call wrappers.
src/toolcall_lm/prompt/templates.py - Tool format · Qwen-style tool-call wrapper and JSON fallback formatting.
src/toolcall_lm/prompt/tool_format.py - Training · Wires model, tokenizer, LoRA/QLoRA, callbacks, and watchdogs.
src/toolcall_lm/training/trainer.py - Alt trainers · DPO and Unsloth-based training paths for specific recipes.
src/toolcall_lm/training/dpo_trainer.py - Checkpoints · Adapter checkpoints, tokenizer files, merged models, and config bundles.
outputs/merged_qwen3_blended_exp2 - Inference engine · Loads base model plus optional adapter and produces text or tool calls.
src/toolcall_lm/inference/engine.py - Validators · Parses JSON and checks tool-call structure during inference.
src/toolcall_lm/validators/tool_call_validator.py - API server · Thin serving layer exposing health and chat-completions-style endpoints.
src/toolcall_lm/api/server.py
Evaluation
Benchmark runners and analysis for tool-calling quality.
- BFCL runner · Executes BFCL evaluation and collects per-task results.
src/toolcall_lm/eval/bfcl_runner.py - Taubench · Runs the Taubench evaluation path.
src/toolcall_lm/eval/taubench_runner.py - Failure analysis · Comparisons, taxonomy, event logs, and error breakdowns.
src/toolcall_lm/eval/failure_analysis.py
Ops and synthetic
Supporting utilities, tracking, and generated datasets.
- Utilities · Config loading, logging, seeding, checkpoint helpers, env sanitization, and patches.
src/toolcall_lm/utils/config.py - Tracking · W&B initialization and experiment logging integration.
src/toolcall_lm/tracking/wandb_setup.py - Synthetic gen · Generates multiturn, recovery, preference, and negative samples.
synthetic_data_gen/generate_synthetic_multiturn.py
Connections 26
- Base config → Train recipes: extends · Training recipes inherit shared defaults.
- Base config → Inference config: extends · Inference settings reuse base paths and model defaults.
- Base config → Eval recipes: extends · Evaluation recipes share the same control plane.
- Train recipes → Training: drives · Training recipes configure the adapter-based trainer.
- Inference config → Inference engine: drives · Inference recipes configure model loading and generation.
- Eval recipes → BFCL runner: drives · BFCL configs parameterize benchmark execution.
- Raw datasets → Dataset adapters: ingested by · Raw dataset shapes are normalized through adapters.
- Dataset adapters → Canonical schema: maps to · Adapters emit the canonical record schema.
- Canonical schema → Preprocess: validated by · Preprocess enforces the canonical shape and rejection rules.
- Preprocess → Quality gates: gated by · Examples are filtered and inspected through quality checks.
- Quality gates → Processed sets: produces · Validated examples become processed manifests and splits.
- Synthetic gen → Preprocess: feeds · Synthetic datasets re-enter the same preprocessing pipeline.
- Prompting → Tool format: renders · Prompt templates emit the required tool-call wrapper.
- Tool format → Inference engine: constrains · Inference must honor the same structured output contract.
- Prompting → Training: uses · Training and inference share prompt construction.
- Processed sets → Training: trains · Processed datasets feed supervised and adapter-based training.
- Training → Checkpoints: writes · Training produces adapter checkpoints and merged artifacts.
- Checkpoints → Inference engine: loads · Inference can load a base model plus adapter artifacts.
- Inference engine → Validators: checks · Generated text is parsed and validated as tool calls.
- Inference engine → API server: serves · The API wrapper reuses the same inference engine.
- BFCL runner → Failure analysis: summarizes · BFCL outputs are aggregated into failure and taxonomy views.
- Taubench → Failure analysis: summarizes · Taubench runs feed the same analysis layer.
- Training → Tracking: reports · Training can log runs and metrics to W&B.
- Utilities → Training: supports · Trainer relies on shared runtime helpers.
- Utilities → Inference engine: supports · Inference uses common config, logging, and checkpoint helpers.
- Utilities → API server: supports · Serving uses shared runtime utilities and status helpers.