FunctionGemma 270M IT — Prepaid Cards Tool-Calling (v2, ONNX)
Model description
ONNX Runtime export of
Qrzysztof/functiongemma-270m-it-prepaid-cards-v2
(a google/functiongemma-270m-it fine-tune for prepaid-card tool calling in
107 languages with noisy/multi-turn input) — for CPU, mobile, and
web-browser inference (ONNX Runtime Web / Transformers.js).
Files
File
Size
Description
model.onnx + model.onnx.data
1.07 GB
fp32 export (exact reference)
model-fp16.onnx + model-fp16.onnx.data
536 MB
fp16 export — recommended for browsers
Graph
Full-context decoder (no KV-cache inputs): every step feeds the whole
context and returns full logits.
1import{AutoTokenizer,AutoModelForCausalLM}from"@huggingface/transformers";2const tokenizer =awaitAutoTokenizer.from_pretrained("Qrzysztof/functiongemma-270m-it-prepaid-cards-v2-onnx");3const model =awaitAutoModelForCausalLM.from_pretrained("Qrzysztof/functiongemma-270m-it-prepaid-cards-v2-onnx",4{dtype:"fp16",device:"wasm"});
The graph uses only standard ONNX ops (Gemm/MatMul/Add/Softmax/…), so it runs
under the WASM backend. Full-context decode is O(seq²) — fine for a 270M model
with short tool-call outputs.
Intended uses & limitations
Same as the parent model (see the
SafeTensors card):
synthetic data, uneven language quality, no backend. Performance note: fp32
CPU decode of this graph is slow (no KV cache); prefer fp16 in browsers and
GGUF/MLX for interactive local use.
How it was made
optimum-onnx is pinned to transformers <4.58 (incompatible with
transformers 5.x), so the export uses torch.onnx.export directly:
Correctness: verified token-identical greedy decoding vs the PyTorch
reference (export_onnx.py --check).
Evaluation
Same prompts & greedy decoding as the other formats, over a held-out v2 test
subset (N=20, 32 max tokens — full-context CPU decode is slow).
Format
Success rate
SafeTensors (reference)
40/40 = 100% (N=40)
ONNX fp32 (ORT CPU)
20/20 = 100%
ONNX fp16 (graph)
same graph semantics; tested identical logits in spot checks
Fine-tuning from this model
This model was fine-tuned with the tutorial below; you can use it as the starting point for a new tool set (or fine-tune google/functiongemma-270m-it directly).
Fine-tuning tutorial
A complete, minimal fine-tune of a FunctionGemma-class model on this data
(follows the official
FunctionGemma fine-tuning guide).
1. Setup
bash
1pip install torch transformers trl datasets accelerate
2huggingface-cli login # accept the gemma license for google/functiongemma-270m-it
2. Load the dataset and normalize messages
The Hub dataset stores messages/tools as JSON strings (Arrow cannot infer
the nested schema), and TRL's SFTTrainer needs a uniform struct schema, so
normalize first:
python
1import json
2from datasets import load_dataset
3from transformers import AutoModelForCausalLM, AutoTokenizer
45defnormalize_messages(msgs):6 out =[]7for m in msgs:8 n ={"role": m["role"],"content": m.get("content")or"","name":None,9"tool_call_id": m.get("tool_call_id"),"tool_calls":None}10if m["role"]=="tool":11 n["name"]= m["content"]["name"]12 n["content"]= json.dumps(m["content"]["response"], ensure_ascii=False)13if m.get("tool_calls"):14 n["tool_calls"]=[{"id": tc.get("id"),"type": tc.get("type","function"),15"function":{"name": tc["function"]["name"],16"arguments": json.dumps(tc["function"]["arguments"], ensure_ascii=False)}}17for tc in m["tool_calls"]]18 out.append(n)19return out
2021defrows_to_dataset(rows):22from datasets import Dataset
23return Dataset.from_list([{24"messages": normalize_messages(r["messages"]),25"tools": json.dumps(r["tools"], ensure_ascii=False),26}for r in rows])2728ds = load_dataset("Qrzysztof/ecommerce-chat-tool-calling", token=HF_TOKEN)["train"]29train_rows =[{"messages": json.loads(r["messages_json"]),"tools": json.loads(r["tools_json"])}30for r in ds if r["split"]=="train"]31train_ds = rows_to_dataset(train_rows)
TRL applies the FunctionGemma chat template with the per-sample tools
column; assistant_only_loss=True (default) masks everything but the model's
own turns, so it learns to emit tool calls — not to copy the schema.
4. Evaluate (greedy success rate)
python
1ok =02for item in test_rows:3 inputs = tokenizer.apply_chat_template(item["messages"][:-1], tools=item["tools"],4 add_generation_prompt=True, return_tensors="pt")5 out = model.generate(**inputs, max_new_tokens=256)6 output = tokenizer.decode(out[0][len(inputs["input_ids"][0]):], skip_special_tokens=False)7 expected =<expected tool name / args from expected_json>8 ok += expected-tool-in-output and no-other-tool-in-output
Keep noise digit-safe: never corrupt the values the model must extract
(prices, ids). The noise.py engine skips any token containing digits.
Use deterministic train/test splits (by template_id) and hold out
whole languages + (for the e-commerce set) whole schemas — that is the
only honest way to measure generalization.
Balance the training subset per (language, intent) — cap the big
buckets instead of letting English dominate.
Training
packing=False for tool-calling data; packed sequences splice mid-call.
max_length ≥ longest sample + a margin; ~1024 covers these datasets.
Constant LR + short warmup (the official guide's defaults) work well.
Upload a checkpoint to the Hub after every epoch — Colab VMs die
mid-run, and the last good epoch is always recoverable.
Evaluation
Always evaluate with greedy decoding for comparability across formats
and runs.
Score two things separately: tool-name selection and argument fidelity
(query + every filter key:value pair).
Compare every exported format (SafeTensors / GGUF / MLX / ONNX) on the
same prompts — quantization changes results.
Deployment
Validate tool arguments server-side before executing anything (a small
model can garble a card number under heavy noise).
In a live agent, follow the FunctionGemma full loop: model call → backend
executes → tool response → model continues; never let the model see or
emit secrets.
For browser deployment use the fp16 ONNX file; for low-end hardware the
Q8_0 GGUF or MLX 8-bit; for exact reference behavior the SafeTensors model.