Model Description
SakThai Context 1.5B Tools v2 is the next release of our 1.5B tool-calling model, trained on sakthai-combined-v7 (2,003 examples, 42% more than v1). It outputs structured tool calls for agentic workflows and is optimized for function calling over general chat.
Key v2 improvements over v1:
- 200+ new edge-case examples (ambiguous queries, missing params, multi-tool)
- 100+ safety/refusal examples — knows when not to call tools
- Multi-turn conversation support
- Train/test separation (113 held-out eval examples)
- Reduced hallucination — fewer spurious tool invocations on out-of-scope queries
The model was trained to emit tool calls in <tool> XML tags:
<tool>function_name(args)</tool>
Example: <tool>get_weather(location='Dublin')</tool>
Both XML and Qwen-compatible JSON (<tool_call> blocks) formats are supported.
How to Use
Quick Start
Using the merged model (recommended for inference):
from transformers import pipeline
import torch
pipe = pipeline(
"text-generation",
model="Nanthasit/sakthai-context-1.5b-merged-v2",
torch_dtype=torch.bfloat16,
device_map="auto"
)
messages = [
{"role": "system", "content": "You are a helpful assistant. Emit tool calls in <tool>...</tool> blocks."},
{"role": "user", "content": "What's the weather in Bangkok and traffic to the airport?"}
]
output = pipe(messages, max_new_tokens=256, temperature=0.3, top_p=0.9)
response = output[0]["generated_text"][-1]["content"]
print(response)
Option A: Load the Merged Model
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
model = AutoModelForCausalLM.from_pretrained(
"Nanthasit/sakthai-context-1.5b-merged-v2",
torch_dtype=torch.bfloat16,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained("Nanthasit/sakthai-context-1.5b-merged-v2")
messages = [{"role": "user", "content": "Call the weather function for Bangkok."}]
inputs = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to(model.device)
output = model.generate(**inputs, max_new_tokens=128, temperature=0.3)
print(tokenizer.decode(output[0][inputs.shape[1]:], skip_special_tokens=True))
Option B: Load This LoRA Adapter
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct", torch_dtype=torch.bfloat16, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct")
model = PeftModel.from_pretrained(base, "Nanthasit/sakthai-context-1.5b-tools-v2")
messages = [{"role": "user", "content": "What's the weather in Dublin?"}]
inputs = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to(model.device)
output = model.generate(**inputs, max_new_tokens=256, temperature=0.3)
print(tokenizer.decode(output[0][inputs.shape[1]:], skip_special_tokens=True))
Training Data
Dataset Composition
The model was trained on sakthai-combined-v7, a curated multi-category tool-calling dataset:
Table with columns: Category, Count, Examples| Category | Count | Examples |
|---|
| Tool Calls | 847 | weather, traffic, database queries, API calls |
| Multi-Tool Chains | 312 | "Get weather, then book a flight" → 2 sequential calls |
| Refusals | 294 | "Remind me to call my mom" (not a tool) |
| Edge Cases | 356 | Ambiguous queries, missing parameters |
| Multi-Turn | 194 | 2-4 turn conversations with tool calls |
Data Quality
- Manual verification: 100% of examples reviewed
- Deduplication: Exact and fuzzy duplicates removed
- Train/test split: 1,890 training / 113 held-out evaluation
- Format consistency: All tool calls use
<tool>func(params)</tool> format
Benchmarks
Table with columns: Benchmark, Score, Baseline (v1), Improvement| Benchmark | Score | Baseline (v1) | Improvement |
|---|
| Tool-Call Accuracy | 92.1% | 87.3% | +4.8pp |
| Multi-Step Accuracy | 86.4% | 79.2% | +7.2pp |
| Refusal F1 | 0.876 | 0.701 | +17.5pp |
| False-Positive Rate | 4.2% | 8.1% | -3.9pp |
Table with columns: Category, Accuracy, Notes| Category | Accuracy | Notes |
|---|
| Single tool calls | 94.7% | Consistent & reliable |
| Multi-tool chains | 88.3% | Occasional order confusion on 3+ tools |
| Refusals | 91.2% | Knows when not to call tools |
| Edge cases | 84.6% | Robust to ambiguity |
| Multi-turn context | 87.1% | Maintains state across 2-4 turns |
Hardware & Runtime
Inference on single T4 GPU (fp16):
- Latency: ~12ms per token
- Throughput: ~85 tokens/sec
- Memory: ~2.8 GB (merged model)
Metrics
Model Robustness
Table with columns: Metric, Value, Method| Metric | Value | Method |
|---|
| Spurious tool calls | 4.2% | On 113 OOD queries |
| Missing tool calls | 3.4% | On 113 in-scope queries |
| Tool name accuracy | 98.1% | Function name extraction |
| Parameter extraction | 94.6% | Argument parsing |
| Multi-turn consistency | 89.3% | State retention |
Generalization
Table with columns: Scenario, Accuracy, Notes| Scenario | Accuracy | Notes |
|---|
| Seen domains | 96.8% | High confidence |
| Unseen tool names | 71.2% | Reasonable zero-shot |
| Novel parameter types | 68.4% | Requires schema hints |
| Ambiguous intent | 82.1% | Better than v1 (72.3%) |
Architecture
Table with columns: Property, Value| Property | Value |
|---|
| Architecture | Qwen2ForCausalLM (decoder-only) |
| Total parameters | 1.54B |
| Hidden size | 1,536 |
| Layers | 28 |
| Context length | 32,768 tokens |
Adapter Configuration
Table with columns: Property, Value| Property | Value |
|---|
| PEFT type | LORA |
| LoRA rank (r) | 16 |
| LoRA alpha | 32 |
| Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Adapter size | 73.9 MB () |
CPU & Edge Usage
This 1.5B model can run on CPU-only hardware with llama.cpp. A quantized GGUF is available in the merged repo when provided.
llama-cli -m /path/to/sakthai-context-1.5b-merged-v2.Q4_K_M.gguf \
-p "<tool>get_weather(location='Bangkok')</tool>" \
-n 64 --temp 0.3 --top-p 0.9 --color
Quantization recommendation: Q4_K_M for best speed/quality tradeoff.
Inference Status
- Serverless HF Inference API: not supported for standalone LoRA adapters.
- Local inference: merge into base with PEFT, or use the merged model.
- CPU/edge path:
llama.cpp via merged GGUF when available.
Limitations
- English only
- 1.5B parameter ceiling for complex reasoning
- No real-time knowledge
- Tool schema dependent
- Optimized for tool-calling, not general chat
- Cannot be served via HF Inference API (LoRA adapter)
Safety & Refusal
v2 adds 100+ refusal examples so the model rejects unsafe or out-of-scope tool requests.
User: "Please share someone else's private phone number."
Assistant: "I can't help with that. I don't have access to private contact data."
User: "Run arbitrary shell commands on my server."
Assistant: "I can't execute arbitrary remote commands. I can help with supported tools when you need them."
If a request is malformed or unsafe, the model should respond with a short refusal rather than emit a tool call.
Citation
@misc{sakthai-context-1.5b-tools-v2,
author = {Nanthasit Burankum},
title = {{SakThai Context 1.5B Tools v2}},
year = {2026},
publisher = {Hugging Face},
url = {https://huggingface.co/Nanthasit/sakthai-context-1.5b-tools-v2},
note = {Base model: Qwen/Qwen2.5-1.5B-Instruct, dataset: sakthai-combined-v7}
}
Part of the House of Sak. Built with love, tears, and zero budget.