What this model does
LiTiL Legal Request Router turns an incoming legal request into a consistent application route. It classifies the request as commercial, employment, corporate, technology/AI, crypto, or general legal work and returns the choice as JSON that a workflow can validate directly.
Place it at the front of a legal-intelligence stack. The accepted route can select the right intake form, retrieval index, playbook, specialist model, or review queue before expensive analysis begins. Storing the route with the original request also makes volume, reassignment, and fallback behavior measurable across the intake system.
- Useful for: sorting requests before a specialist workflow takes over
- Give it: the request text
- It returns: a JSON route for commercial, employment, corporate, technology/AI, crypto, or general legal work
Table with columns: At a glance, Detail| At a glance | Detail |
|---|
| Release repository | litillabs/litil-legal-request-router-1.5b |
| Model format | Rank-16 PEFT LoRA adapter, selected checkpoint 200 |
| Base | Qwen/Qwen2.5-1.5B-Instruct |
| Input → output | System instruction and request → one JSON routing proposal |
| Decoding | Greedy, up to 256 new tokens |
| Tested runtime | Apple MPS float32 · PyTorch 2.12.0 · Transformers 5.9.0 · PEFT 0.19.1 |
Input is a normal Qwen chat messages list using the exact system instruction above. The output must be one unfenced JSON object with these keys:
Table with columns: Key, Type, Accepted values| Key | Type | Accepted values |
|---|
domain | string | Application domain code |
subdomain | string | Application subdomain code |
complexity | string | simple, medium, or complex |
tools |
Validate the JSON, required keys and known domain codes before dispatch. Treat confidence, tools and escalate as proposals that the application may replace with its own policy.
Recorded example
{
"domain": "employment",
"subdomain": "handbook_update",
"complexity": "medium",
"tools": [
"policy_comparator",
"jurisdiction_checker",
"termination_risk_assessor"
],
"confidence": 0.75,
"escalate": false,
"reasoning": "Domain: employment (handbook_update). Complexity: medium. Escalate=False per v3 rules; reasons=[]."
}
This was produced by the selected adapter on September 10, 2026.
Practical use
- Put one request in the user message and keep the system instruction unchanged.
- Use greedy decoding and parse the whole completion as JSON.
- Reject malformed objects and unknown domain codes.
- Map the accepted domain to an application route.
- Apply the application's current escalation and tool-selection policy.
Training data and method
The selected checkpoint comes from three-epoch supervised LoRA tuning on 540 authored synthetic examples, with 60 synthetic validation rows. No private client or user data was used in the reviewed post-training set.
LoRA uses rank 16, alpha 32, and dropout 0.05. The full run recorded 204 steps; this release selects checkpoint 200.
Runtime and version
The adapter is approximately 17.5 MB and requires the Qwen2.5-1.5B-Instruct base. The prepared runner used float32 for reproducibility; a compatible lower precision can reduce memory after separate validation.
- Base repository:
Qwen/Qwen2.5-1.5B-Instruct
- Tested base snapshot:
989aa7980e4cf806f80c7fef2b1adb7bc71aa306
- Card version: September 11, 2026
- Organization: LiTiL Labs
Use the model
python -m pip install "torch==2.12.0" "transformers==5.9.0" "peft==0.19.1"
import json
import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
BASE_ID = "Qwen/Qwen2.5-1.5B-Instruct"
BASE_REVISION = "989aa7980e4cf806f80c7fef2b1adb7bc71aa306"
ADAPTER_ID = "litillabs/litil-legal-request-router-1.5b"
messages = [
{
"role": "system",
"content": (
"You are a legal query router. Analyze the user's legal query and "
"output a JSON object with: domain, subdomain, complexity "
"(simple/medium/complex), tools (list), confidence (0-1), "
"escalate (boolean), reasoning (string)."
),
},
{
"role": "user",
"content": "Review an employee leave policy and summarize the changes proposed by HR.",
},
]
tokenizer = AutoTokenizer.from_pretrained(BASE_ID, revision=BASE_REVISION)
base = AutoModelForCausalLM.from_pretrained(BASE_ID, revision=BASE_REVISION)
model = PeftModel.from_pretrained(base, ADAPTER_ID).eval()
inputs = tokenizer.apply_chat_template(
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
)
with torch.inference_mode():
tokens = model.generate(
inputs,
do_sample=False,
max_new_tokens=256,
pad_token_id=tokenizer.eos_token_id,
)
text = tokenizer.decode(tokens[0, inputs.shape[-1]:], skip_special_tokens=True).strip()
route = json.loads(text)
print(route)
For the prepared offline package:
python demo.py --show-recorded --case employee_leave
python demo.py --base ./Qwen2.5-1.5B-Instruct --adapter . --case employee_leave
The runner supports cpu, mps and cuda and never executes a proposed tool.
Citation
When using this adapter, cite the release repository and Qwen2.5-1.5B-Instruct.