alfinpratama/qwen38-27b-desktop-agent-lora
qwen38-27B-desktop-agent-lora
LoRA adapter for desktop-agent tool-calling on top of unsloth/Qwen3.8-27B-unsloth-bnb-4bit (4-bit QLoRA). Trains the model to act as an autonomous Linux desktop co-worker: reason, call tools, observe results, recover from errors, and stop when no tool is needed.
Research prototype for a multimodal autonomous desktop agent (voice/vision + tool use). Not a general chat upgrade.
Model Details
- Base model:
unsloth/Qwen3.8-27B-unsloth-bnb-4bit(Qwen3.5 architecture,Qwen3_5ForConditionalGeneration, hybrid Gated DeltaNet + Gated Attention, native 262k context) - Adapter type: LoRA (PEFT 0.18.1),
r=16,lora_alpha=16,lora_dropout=0.0,bias=none - Target modules:
q_proj,k_proj,v_proj,o_proj,gate_proj,up_proj,down_proj(full-attention + MLP) - Trainable: ~80M / 27.4B (~0.29%)
- Quantization: bnb-4bit (NF4 + double quant), bf16 compute
- Task:
CAUSAL_LM, supervised fine-tuning for tool-calling - Languages: English (tool schemas + reasoning in English)
- License: Follows base model license. Check Qwen / Unsloth terms before commercial use.
Intended Use
Direct Use
OpenAI-compatible chat with tools + tool_calls. System message carries tool JSON schemas. Assistant responds with <think>reasoning</think> plus native <tool_call> blocks, or a final answer when no tool is needed.
Supported tool families (client-dependent):
execute_command,read_file,write_fileopen_application,open_browser,navigate_browsergit_operation,run_testpress_key,type_text,take_screenshot,inspect_screen
Exact tool list is defined by the client. This adapter only decides when and how to call them.
Downstream Use
- Linux desktop agent / SWE agent backends
- Merged LoRA + base for single-weight deployment
- Further fine-tuning on private desktop workflows
Out-of-Scope Use
- General knowledge chatbot, medical/legal advice, high-stakes decisions
- Autonomous destructive actions without a client-side whitelist / approval layer
- Vision grounding beyond what the client supplies as
image_url
Training Data
~9,200 deduplicated multi-turn samples, formatted with the native Qwen chat_template.jinja:
Each sample: system (instructions + tool schemas) + conversations (user / assistant with reasoning_content + tool_calls / tool observation / final answer).
Training Procedure
- Stack: Unsloth + TRL
SFTTrainer+ PEFT + Transformers 5.x - Hardware: single AMD MI300X (192 GB), ROCm
- Precision: bf16, optimizer
adamw_8bit, gradient checkpointing (Unsloth) - Batch: per-device 4, grad-accum 2 (effective 8)
- Epochs: 3, total ~2,991 steps
- Loss trajectory: ~4.3 at start → near-zero at end of run
- Checkpoints every 20 steps, final adapter saved as
adapter_model.safetensors+ tokenizer files
Note on low final loss: offline qualitative eval showed contextual reasoning (defensive mkdir before write, status-before-commit, clarifying ambiguous requests) rather than pure memorization, but no formal benchmark is claimed here.
Evaluation
Qualitative post-training check, 6 scenarios, all passed:
- Schema faithfulness (correct param names)
- Unseen tool (new schema at inference, multi-hop resolve)
- Multi-step workflow (write then verify)
- Git lifecycle on new context (status before commit)
- Negative case (chat-only, no spurious tool call)
- Ambiguous request (asks for clarification instead of guessing)
No quantitative benchmark (SWE-bench, BFCL, etc.) is reported. Treat accuracy numbers as unevaluated until a formal eval is published.
How to Use
Install (Colab: restart session after install so bitsandbytes native lib loads):
pip install -U "bitsandbytes>=0.46.1" transformers peft accelerateInference (4-bit base + LoRA, Transformers 5.x API):
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
from peft import PeftModel
import torch
base_id = "unsloth/Qwen3.8-27B-unsloth-bnb-4bit"
adapter_id = "alfinpratama/qwen38-27b-desktop-agent-lora"
# Qwen3.8 processor wraps text tokenizer; use inner tokenizer for text-only
tok = AutoTokenizer.from_pretrained(adapter_id, trust_remote_code=True)
text_tok = getattr(tok, "tokenizer", tok)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16,
)
model = AutoModelForCausalLM.from_pretrained(
base_id,
quantization_config=bnb_config,
dtype=torch.bfloat16,
device_map="auto",
trust_remote_code=True,
)
model = PeftModel.from_pretrained(model, adapter_id)
model.eval()
tools = [{
"name": "execute_command",
"description": "Run an allowlisted shell command",
"parameters": {"type": "object",
"properties": {"command": {"type": "string"}},
"required": ["command"]},
}]
messages = [
{"role": "system", "content": "You are a desktop agent. Call tools when needed, otherwise answer directly."},
{"role": "user", "content": "Check today's date via shell."},
]
prompt = text_tok.apply_chat_template(
messages, tools=tools, tokenize=False, add_generation_prompt=True
)
inputs = text_tok(prompt, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=256, temperature=0.1, do_sample=True)
print(text_tok.decode(out[0], skip_special_tokens=False))For serving, merge or load via any OpenAI-compatible server that supports PEFT adapters and exposes tools / tool_calls as JSON. Native <tool_call> XML must be parsed to OpenAI delta.tool_calls server-side.
Bias, Risks, and Limitations
- Research adapter, narrow domain. May mis-select tools or hallucinate params outside training distribution.
- Low-data regime for desktop workflows (500 synthetic + public shell pairs). Expect variance on unseen apps.
- No safety filter inside weights. Enforce a client-side whitelist (allowed paths / commands) and require confirmation for destructive, privileged, or exfiltrating actions.
- Vision understanding comes from base model; this adapter was trained text-only for tool-calling.
- 27B 4-bit needs ~20-25 GB VRAM. Colab free T4 (16 GB) will OOM; use A100 or larger.
Environmental Impact
- Single-GPU QLoRA run, a few hours wall-clock. Exact kWh / CO2eq not tracked.
