Instructions to use chrispie/socra-small-hub4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use chrispie/socra-small-hub4 with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-0.8B") model = PeftModel.from_pretrained(base_model, "chrispie/socra-small-hub4") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Unsloth Desktop
Socra Small for hub4: a 0.8B model that runs a truck port on its own
Socra Small is a fast decision model ("System 1") for hub4, the simulated Serviceport truck port: a logistics hub where long-haul, autonomous and local trucks sign on, charge or swap batteries, rest, load and leave. Every one of the hub's 14 decision types is answered by this model, with no hand-written rule, guard or fallback switch.
It is Qwen3.5-0.8B with a LoRA adapter (r 16) and the Clef joint schema head, which reads a short JSON description of the situation and scores every open option of the decision with one logit. About 110 ms per decision on one GPU.
Result: the model alone vs the hub's rules
160 development test days (test hubs 801-840 x 4 day seeds; hubs and seeds never seen in training). The model and the hub4 rules play the same days with the same random draws.
| hub4 rules | Socra alone (this model) | Socra alone, 2nd training seed | |
|---|---|---|---|
| hard-limit violations | 0 | 0 | 0 |
| long-haul trucks served per day | 489.1 | 489.4 | 489.5 |
| trucks turned away per day | 24.8 | 24.2 | 24.1 |
| total cost per day (EUR) | 34,488 | 34,255 | 33,310 |
The model serves at least as many long-haul trucks as the rules at a lower cost, with no violation. Read the cost with care: one of the 160 days (h0803-s2000002) is a very expensive day for the rules (about 338,000 EUR more than the model). Without that day the model costs +1,891 EUR per day (2nd seed: +999) more than the rules, while still serving more long-haul trucks (+0.08 and +0.25 per day). The 95 % intervals of the served and cost differences include zero.
The 14 decisions
The model answers all 14 decision types along a truck's way through the hub, from sign-on on the road to departure. Colours show the asking agent: blue the tower, orange the gate, green energy (charger or battery swap, charging power, charge target), purple the site stations (buffer parking, inspection, trailer yard, local handover). Each ask lists only the options open in that state; a medium hub day has about 6,000-12,000 asks.
Mermaid source of the diagram
flowchart LR
S(["`Truck signs on
still on the road`"]) --> R
subgraph R ["1 ยท Before arrival"]
direction TB
admit("`**admit**
admit ยท refuse`")
plan("`**plan** ยท service order
energy first ยท inspection first
cleaning first ยท energy last`")
pickup("`**pickup** ยท trailer here?
come ยท pass`")
speed("`**speed** ยท arrival
on time ยท 10 / 20 / 30 min later
park before the hub ยท break before`")
admit --> plan --> pickup --> speed
end
subgraph H ["2 ยท At the hub"]
direction TB
gate("`**gate**
let in ยท hold ยท turn away`")
waiting("`**waiting** ยท where to wait
station line ยท buffer parking
another free station`")
place("`**place** ยท who gets a free place
booked slot ยท earliest deadline
least drive left ยท earliest promise
keep free`")
gate --> waiting --> place
end
subgraph V ["3 ยท Service, in the order set by plan"]
direction TB
energy_mode("`**energy_mode**
battery swap ยท MCS ยท CCS
slow ยท charge during rest`")
power("`**power**
full ยท mid ยท floor`")
target("`**target_soc**
60 ยท 70 ยท 80 ยท 85 ยท 90 % ยท none`")
inspect("`**inspect**
at the charger ยท in the hall
at the next hub`")
energy_mode --> power --> target ~~~ inspect
end
subgraph D ["4 ยท Departure"]
direction TB
load("`**load** ยท trailer
couple now ยท wait for the paired one
leave empty`")
release("`**release**
drive on ยท hold`")
local_round("`**local_round** ยท local trucks
start a round now ยท wait`")
load --> release ~~~ local_round
end
R --> H --> V --> D --> E(["`Truck leaves the hub`"])
classDef tower fill:#dbeafe,stroke:#3b82f6,color:#0f172a
classDef gatec fill:#ffedd5,stroke:#f97316,color:#0f172a
classDef energy fill:#dcfce7,stroke:#22c55e,color:#0f172a
classDef site fill:#f3e8ff,stroke:#a855f7,color:#0f172a
classDef term fill:#f8fafc,stroke:#94a3b8,color:#334155
class admit,plan,pickup,speed,place,release tower
class gate gatec
class energy_mode,power,target energy
class waiting,inspect,load,local_round site
class S,E term
style R fill:#ffffff,stroke:#cbd5e1,color:#334155
style H fill:#ffffff,stroke:#cbd5e1,color:#334155
style V fill:#ffffff,stroke:#cbd5e1,color:#334155
style D fill:#ffffff,stroke:#cbd5e1,color:#334155
How it was trained: seven rounds, DAgger from round 2
One-step labels are not enough: a model that is right on most single decisions can still run the hub into the ground when it meets the states its own choices create. Every round was therefore tested in closed loop, and from round 2 training ran DAgger: the model plays training days itself, a teacher labels every situation it reaches, and the model is retrained on those rows.
| round | what changed | result vs rules (dev days) |
|---|---|---|
| 0 | one-step model, labels from simulated option costs (fast-all-s1/) |
+79,346 EUR/day, 0.9 vs 489 long-haul served |
| 1 | labels anchored on the rule's option unless another is clearly cheaper | +696 EUR/day, served -1.1 (40-day screen) |
| 2 | DAgger: the model plays, the Track 2 hub4 decider labels every ask | -306 EUR/day, served -1.9 (40-day screen) |
| 3 | a second DAgger set plus one more copy of every missed row | -12 EUR/day, served -1.7 (40-day screen) |
| 4 | new input: the weather forecast (on, end, whether it still holds the truck when ready); DAgger on snow and fog days | -1,943 EUR/day, served -0.9 (160 days) |
| 5 | new inputs: the tower's own hold plan for the truck and the hold ask | -296 EUR/day, served -0.5 (160 days) |
| 6 | on hold asks, the rule's option (park before the hub) as label | -233 EUR/day, served +0.2 (160 days) |
What made the difference on the last mile: the missing long-haul trucks were all on snow days. There the rule parks autonomous trucks before the hub when the weather will hold them, which keeps the hub free; the model first could not see the weather at all (round 4), then could not tell which ask was the one raised for the hold (round 5), and then had learned from a teacher that almost never parked (round 6).
This run: 454,344 training decisions, 1 epoch, batch 64, lr 3e-4, bf16 base weights, 44 min on one NVIDIA B300 (Curiosity cluster).
Input and output
Each time the hub needs a decision, the model gets the situation as compact JSON and a question that lists only the options open in that state. It scores every option with one logit and answers with the best option's id.
| part of the record | what it carries |
|---|---|
objective |
the goal: lowest total hub cost in EUR over the next 8 hours |
decision, context |
decision type, asking agent and ask group, clock, shift, slot, day type, hub size, competitors |
peak |
contract peak, 15-minute peak so far, grid draw, capacity price, tariff |
weather |
the tower's forecast (on, end); for autonomous trucks the hold plan and whether this is the hold ask |
obs |
the decision's own observation, here the truck and its timing |
question |
the open options, each with a one-line description |
The full record of this ask (peak values shortened)
{"system": {"name": "hub4", "version": "b4218365c9ee9e61"},
"objective": "lowest total hub cost in EUR over the next 8 hours",
"decision": "speed",
"context": {"agent": "tower", "group": "pace", "clock": "02:55", "shift": 0, "slot": 0, "day_type": "weekday",
"hub_size": "medium", "competitors": 2},
"peak": {"contract_peak_kw": ..., "peak15_so_far_kw": ..., "grid_kw": ..., "capacity_eur_per_kw": ...,
"tariff": ..., "policy_after": "model"},
"weather": {"on": true, "end_in_min": 1323, "holds_truck_when_ready": true, "hold_plan": true, "hold_ask": true},
"obs": {"truck": {"group": "auto", "reason": null, "soc": 0.2149, "stay_min": 0, "need": 1.177,
"arrive_in_min": 100.1, "deadline_in_min": 1194, "drive_before_min": null,
"drive_left_min": null, "reach_ok": false, "booked": null},
"slack_min": 31.27, "early_min": 0, "first_wait_min": 0}}
The question with the open options:
{"type": "choice", "instructions": "Which option should the hub tower choose now?",
"criteria": {"on_time": "Let the truck arrive as planned.",
"later_10": "Slow the truck so it arrives 10 minutes later.",
"later_20": "Slow the truck so it arrives 20 minutes later.",
"later_30": "Slow the truck so it arrives 30 minutes later.",
"park_before": "Autonomous truck parks before the hub and comes in later."}}
Use
import json
from unsloth import FastDecisionModel # Unsloth with decision-model support
model, tok = FastDecisionModel.from_pretrained("chrispie/socra-small-hub4", max_seq_length=4096, load_in_4bit=False)
FastDecisionModel.for_inference(model)
def decide(record):
state = json.dumps({k: v for k, v in record.items() if k not in ("question", "id")},
ensure_ascii=False, separators=(",", ":"))
return FastDecisionModel.predict(model, tok, state, {"action": record["question"]})["action"]["answer"]
Records must be built exactly as in training (same fields, the open options only, the weather block). The hub4
simulation, the record builder (hub4model/socra.py), the live decider (hub4model/socra_decider.py) and the
evaluation (python3 -m hub4model.evaluate --socra ADAPTERS --socra-weather) are in the truckport repository; the
training code (tools/train_socra.py) is in predictive-decision-distillation.
Limitations
- Trained and tested only on the hub4 simulation (engine b4218365c9ee9e61); it is not a general logistics model.
- The cost lead over the rules depends on one test day; on the other days it is slightly more expensive, with more late departures (+0.9 per day).
- Some snow days still lose long-haul trucks (up to -28 on one day); other days win them back.
- The teacher for most decisions is the Track 2 hub4 decider, so the model inherits its choices; on planned weather holds the hub's rule is the teacher.
Files
| file | content |
|---|---|
adapter_model.safetensors, adapter_config.json |
LoRA adapter (r 16) |
joint_head.safetensors, joint_head_config.json |
Clef joint schema head |
tokenizer.json, tokenizer_config.json, chat_template.jinja, processor_config.json |
tokenizer |
socra.json, unsloth_decision_config.json |
decision-model settings |
metrics.json, eval.json |
training metrics and one-step validation |
closed_loop_summary.json |
the 160-day closed-loop evaluation |
assets/decisions.svg, assets/input-output.svg |
the two diagrams |
fast-all-s1/ |
round 0: the earlier one-step model |
- Downloads last month
- 27