Paraphase-4B task adapters

Paraphase-4B Adapter Pack — rewrite + extraction LoRAs

One raw Qwen3.5-4B base, two task LoRAs, and one measured tool guard. This is the multi-task companion to Paraphase-4B, which is the merged humanizer release.

Use the raw base here for adapters. The paraphase-4b-Q8_0.gguf in the main repo is the merged rewrite model; it is not the adapter base. The raw qwen3.5-4b-Q8_0.gguf in this pack is the base both LoRAs were trained on.

Quick start

# extraction
llama-server -m qwen3.5-4b-Q8_0.gguf \
  --lora gguf/paraphase-4b-extract-lora.gguf -c 2048

# rewrite
llama-server -m qwen3.5-4b-Q8_0.gguf \
  --lora gguf/paraphase-4b-rewrite-lora.gguf -c 2048

# tool calls: base only; apply toolguard.py to the returned calls
llama-server -m qwen3.5-4b-Q8_0.gguf -c 2048

Send "chat_template_kwargs": {"enable_thinking": false} with Qwen3.5 requests; otherwise the template starts with a thinking preamble.

What is measured

Extraction adapter (the win)

Frozen test: 50 real AESLC validation emails, disjoint from training. Labels are deterministic regex spans; this measures agreement with that labeler, not human-judged extraction.

metric raw Q8 base + extract LoRA
JSON valid 1.00 1.00
exact match 0.12 0.42
micro F1 0.516 0.670
date F1 0.407 0.892
amount F1 0.492 0.389
action-item F1 0.522 0.660
empty-row accuracy 0.40 1.00
non-empty recall 0.756 0.911

The adapter raises exact match from 6/50 to 21/50 and nearly doubles date F1. Amount F1 is not reliable: the v1 labeler omits magnitude words ($12 million is labeled $12), and only 4/50 test emails contain an amount. Do not read the amount row as a model regression.

Tool path (base + guard)

Frozen 20-item tool-call smoke:

candidate accuracy
raw Q8 base 0.70
raw base + toolguard.py 0.75
tool LoRA (withdrawn) 0.65

The tool LoRA fixed one wrong-tool case but made two web-search queries more verbose, so it is not included. The guard is a narrow deterministic fix: when a request starts with Email/Send, contains an explicit address, and the model chose get_contact_email, it converts the call to send_email with the parsed to/subject/body. It changes exactly one frozen item and never touches web search or no-tool cases.

Rewrite adapter

The rewrite LoRA is the adapter merged into Paraphase-4B. The main model card has the voice50 and Pangram evidence: 50/50 valid, fact fidelity 0.970, copy reuse 0.260 with the retry policy, tell rate 0.08.

Files

file size notes
qwen3.5-4b-Q8_0.gguf 4.3 GB raw Qwen3.5-4B base; Q8_0
gguf/paraphase-4b-extract-lora.gguf 42.5 MB extraction adapter, llama.cpp
gguf/paraphase-4b-rewrite-lora.gguf 42.5 MB rewrite adapter, llama.cpp
peft/extract/ 85 MB PEFT adapter for transformers
peft/rewrite/ 85 MB PEFT adapter for transformers
toolguard.py 3 KB narrow send/contact guard
task-adapter-manifest.json 2 KB hashes, sizes, measured endpoints
LICENSE Apache-2.0 inherited from Qwen3.5-4B

Extraction prompt

System:

You extract structured data from email. Return only valid JSON.

User:

Extract the dates and times, money amounts, and action items from the email.
Return only a JSON object with keys "dates", "amounts", and "action_items".
Dates and amounts must be strings copied exactly from the email.
Each action item is the sentence that states a request or task.
Use [] when a field has none.

EMAIL:
<subject and body>

The adapter returns JSON such as:

{"dates": ["Thursday", "3pm", "Friday"], "amounts": ["1,240 dollars"], "action_items": ["Please send the signed copy by Friday."]}

Tool guard

from toolguard import guard_tool_call

calls, changed = guard_tool_call(user_text, model_tool_calls)

The guard only handles the explicit-address send/contact confusion. It is not a general tool router and it does not repair arbitrary argument errors.

PEFT / transformers

from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

base = "Qwen/Qwen3.5-4B"
tok = AutoTokenizer.from_pretrained(base)
model = AutoModelForCausalLM.from_pretrained(base, device_map="auto")
model = PeftModel.from_pretrained(model, "peft/extract")

Load the base in bf16 or 4-bit; the adapter is r=16, alpha=32.

Reproduce

# raw base
python convert_hf_to_gguf.py <Qwen3.5-4B snapshot> \
  --outfile qwen3.5-4b-Q8_0.gguf --outtype q8_0

# extraction: 427 train / 48 val AESLC, 150 steps
PYTHONPATH=. python scripts/train_task_adapter.py --task extract \
  --data data/processed/extract_v1/train.jsonl \
  --out data/checkpoints/extract-adapter --steps 150

# extraction eval
PYTHONPATH=. python scripts/eval_extract.py \
  --gguf qwen3.5-4b-Q8_0.gguf \
  --lora gguf/paraphase-4b-extract-lora.gguf --tag extract-adapter

# tool guard (stored base outputs, no model call)
PYTHONPATH=. python scripts/eval_tool_guard.py

The full route and data provenance are summarized in task-adapter-manifest.json and the main Paraphase-4B card.

Limitations

  • Extraction labels are regex-derived, not human annotations. Amount F1 is low-confidence; dates and action items carry the result.
  • Action-item labels are heuristic sentences; the adapter can beat or lose to the labeler for reasons unrelated to extraction quality.
  • The tool guard fixes one demonstrated case; the strict tool instrument is mostly a query-phrasing test.
  • One LoRA per llama-server process; adapter hot-swapping is not implemented.
  • No detector was used for these adapters. Pangram evidence belongs to the rewrite model, not the extraction task.

License

Apache-2.0, inherited from Qwen3.5-4B. The base model is Qwen/Qwen3.5-4B.

Links

Downloads last month
33
GGUF
Model size
4B params
Architecture
qwen35
Hardware compatibility
Log In to add your hardware

8-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for chadstthomas/Paraphase-4B-Adapter-Pack

Finetuned
Qwen/Qwen3.5-4B
Adapter
(813)
this model

Collection including chadstthomas/Paraphase-4B-Adapter-Pack