LoRA adapter fine-tuned on Qwen3-4B via ORPO (Odds Ratio Preference Optimization) for B2B sales email generation. Trained on preference pairs targeting five failure modes identified in a Week 10 production audit of the Tenacious sales agent.
Evaluated on the sealed held-out split of Tenacious-Bench v0.1 (n=32 tasks).
1beta = 0.1 # ORPO odds-ratio weight λ
2learning_rate = 5e-5
3epochs = 5
4batch_size = 2 # per device
5grad_accum = 8 # effective batch = 16
6max_length = 512
7max_prompt_length = 256
8optimizer = "adamw_8bit"
9lr_scheduler = "cosine"
10warmup_steps = 10
11seed = 42
381 preference pairs generated from 127 training tasks in Tenacious-Bench v0.1.
Note: Rejected outputs are Gemini-synthesized failure-mode injections, not captured production failures. Cross-family leakage prevention was not applied (Gemini both generates and judges). See dataset card for details.
Generating B2B sales emails, follow-ups, and objection responses for Tenacious-style outbound workflows. Specifically optimized for:
1from unsloth import FastLanguageModel
2
3model, tokenizer = FastLanguageModel.from_pretrained(
4 model_name="Chalie-lijalem/tenacious-orpo-qwen3-4b",
5 max_seq_length=2048,
6 dtype=None,
7 load_in_4bit=True,
8)
9FastLanguageModel.for_inference(model)
10
11messages = [
12 {"role": "system", "content": "You are a B2B sales assistant for Tenacious. Write direct, signal-led sales messages with no banned phrases."},
13 {"role": "user", "content": "Write an email_outreach for this prospect.\n\nContext:\nProspect: Sarah Chen, VP of Revenue at Lattice. Series C $45M 2023-Q2. LinkedIn post 3 days ago about sales rep ramp time.\n\nConstraints:\n- under 120 words\n- include [CALENDLY_LINK]\n\nWrite only the message body."},
14]
15prompt = tokenizer.apply_chat_template(
16 messages, tokenize=False, add_generation_prompt=True, enable_thinking=False
17)
18inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
19
20import torch
21with torch.no_grad():
22 out = model.generate(**inputs, max_new_tokens=256, temperature=0.0, do_sample=False)
23print(tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))
Apache 2.0 (inherits from Qwen3 base model).