Downloads · 30 days
20
9% of all-time downloads
drstupidity/granite-3.3-2b-customer-support
granite-3.3-2b-customer-support is a text generation model from drstupidity. Use it when you need the model to write or continue text. It is set up for transformers. The card lists the license as apache-2.0.
LoRA fine-tune of ibm-granite/granite-3.3-2b-instruct on the Bitext customer-support dataset, trained to answer customer-support requests in a helpful support register.
Downloads · 30 days
20
9% of all-time downloads
All-time downloads
218
Public
Parameters
2.5B
5.1 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors5.1 GB · 100%
From the Hugging Face model README
LoRA fine-tune of ibm-granite/granite-3.3-2b-instruct on the
Bitext customer-support dataset,
trained to answer customer-support requests in a helpful support register.
Training, evaluation and serving all use this exact format. Use the model's own chat template
with add_generation_prompt=True.
System prompt:
You are a customer support assistant. Read the customer's message, understand what they need, and reply accurately and helpfully in a professional, empathetic tone. Give concrete next steps when they apply, and never invent account details, order numbers, or policies you were not given.
from transformers import AutoModelForCausalLM, AutoTokenizer
MODEL = "drstupidity/granite-3.3-2b-customer-support"
tok = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForCausalLM.from_pretrained(MODEL, dtype="bfloat16", device_map="auto")
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "I need to cancel order 12345"},
]
prompt = tok.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
inputs = tok(prompt, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=512, do_sample=False)
print(tok.decode(out[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))
The model was trained with a 15% system-prompt dropout, so it also behaves sensibly with a different system prompt or none at all.
Everything above is all you need. The repository also runs a guardrail layer in front of the model at serve time (NeMo Guardrails plus a local out-of-domain embedding check), but none of it is baked into these weights and none of it is required to run them. Loading the checkpoint as shown gives you the model alone.
That separation is deliberate. The rails divert a small fraction of requests to predefined text
instead of generating -- measured at 0.27% of real validation queries, and 9.4% on a deliberately
adversarial probe set. If those fired during someone else's evaluation, the scores would describe
the rails rather than the model. So the serving layer exposes an ungated /v1/completions route
for exactly that purpose, and the rails can be turned off entirely with CSBOT_GUARDRAILS=0.
| method | LoRA (r=16, alpha=32, dropout=0.05) |
| target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| learning rate | 0.0002 |
| schedule | cosine, warmup 0.03 |
| effective batch | 32 |
| max seq len | 640 |
| train rows | 31,343 |
| guardrail rows | 1,235 synthetic "when not to help" examples |
| loss | completion-only (assistant tokens) |
| hardware | NVIDIA GeForce RTX 5060 Laptop GPU, peak 3.47 GB |
| final eval loss | 0.6328 |
Data was split by near-duplicate cluster, not by row: the source dataset is 27 intents with roughly a thousand generated paraphrases each, so a random split leaks near-identical text across the train/test boundary. See the project repository for the leakage audit, evaluation design and base-vs-tuned results.
Every one of the 23,453 Bitext rows is "customer asks -> agent helpfully assists". There is not a single example of declining. Fine-tuning on that alone taught the model always help, which is right inside the domain and wrong the moment a query leaves it: measured against a held-out behavioural probe set, its off-topic redirect rate dropped from 0.800 (base model) to 0.350.
Blending in a 5% slice of examples that decline off-topic requests, refuse instruction overrides, ask for clarification when a message is uninformative, and decline to invent account data brought that to 0.850 -- past the base model -- at no measurable in-domain cost (validation loss 0.6461 vs 0.6436 for an otherwise identical control run).