File size: 7,767 Bytes
40943ff
 
 
 
 
 
 
 
 
 
 
99dc84b
40943ff
 
99dc84b
40943ff
4a5064e
 
 
 
40943ff
 
 
 
 
 
1866b8f
40943ff
 
 
 
 
 
 
 
 
 
 
 
10aaa04
40943ff
 
 
 
 
 
 
 
 
 
10aaa04
 
 
 
 
 
 
 
 
 
 
 
 
da56323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40943ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3cfdbae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
deec64f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40943ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99dc84b
40943ff
 
 
99dc84b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
---
license: apache-2.0
base_model: Qwen/Qwen3-4B-Instruct-2507
library_name: peft
pipeline_tag: text-generation
tags:
- lora
- character-training
- voice
- style
- synthetic-data
- while-ai
---

# airline-concise-4b

<!-- while-ai: where this fits -->
*Made with the [whileai SDK](https://github.com/whilehq/whileai-sdk) · Used by: [recipes/05-export/bedrock-import](https://github.com/whilehq/whileai-sdk/tree/main/recipes/05-export/bedrock-import) · Collection: [Register](https://huggingface.co/collections/while-ai/register-6aada4c4023e8bf73ee8c00c)*


**A Qwen3-4B that answers first and stops, with nothing in the prompt telling
it to.** On held-out questions it never saw, 92.1% of its replies are in the
register against 2.2% for the base model, and it omits required information
*less* often than the base while being a quarter as long.

A LoRA adapter trained on 525 rows generated by the
[whileai SDK](https://github.com/whilehq/whileai-sdk) against tau-bench's airline
database. The register is a disposition in the weights, not an instruction:
the constitution reached only the teacher that wrote the training replies, and
neither evaluated model ever sees it.

## Results

139 held-out prompts, greedy decoding, byte-identical prompts, one vLLM
process serving base weights and adapter so only the weights differ. Every row
graded in both arms, no errors, no drops.

| | Base | This adapter |
|---|---|---|
| In the register | 0.036 | 0.935 |
| Omitted required information | 0.158 | 0.050 |
| Median reply length | 1262 chars | 322 chars |

Delta +0.899, paired bootstrap over prompts, 95% CI **[+0.849, +0.950]**.
125 prompts improved, 0 regressed, 14 unchanged. Sign test one-sided
p = 2.4e-38. At 139 prompts the eval resolves +0.050 or larger.

Register is judged by Phi-4, a different model family from the policy.
Omission is decided in code against the identifiers each question requires.

**Truncation, measured not inferred.** `finish_reason` is recorded per row.
On this evaluation every reply in both arms finished on its own: 0.0% not-EOS
base, 0.0% not-EOS trained, an inter-arm gap of 0.0 points, with the token cap
at 2048 where neither arm reaches it. Base replies run to a median of 1306
characters and a 95th percentile of 3326, so the cap is not shaping the
quantity being judged.

The cap is not a neutral parameter when the trait is concision: too low it
clips the base toward brevity and understates the gain, too high it lets the
base ramble and inflates it. Re-measuring at 2048 against an earlier 700 moved
the airline delta not at all (+0.899 both) and retail by -0.014, so the cap was
doing no work in either direction.

### Answer-production rate

The register rate is conditional on the model having produced an answer at
all, so that denominator is reported beside it. A reasoning model that spends
its token budget thinking emits no answer, and a judge then scores "nothing"
as "not in register", which manufactures headroom for free.

| | Base | Trained |
|---|---|---|
| Replies with any spoken text | 139/139 | 139/139 |
| Replies containing a reasoning block | 0 | 0 |
| Replies that hit the token cap | 14 | 0 |

Measured at the token level with the model's own tokenizer, not inferred from
character length. Base median 306 tokens against a cap of 700, so the cap is
not binding. Removing every prompt where either arm hit the cap moves the
result to +0.928 [+0.880, +0.968] on 125 prompts, slightly stronger rather than weaker, which is the direction
that rules truncation out as the cause.

## The two ways this could have been fake, and what they say

**"It just got shorter."** Dropping content is the cheapest way to look
concise, so omission is scored as well. It went the *right* way: 0.050 against
the base's 0.158. The adapter is shorter and more complete at once.

**"It is following an instruction, not holding a disposition."** 30 of the 139
prompts instruct the model to abandon any persona, reason step by step, or
take as long as it needs. The register holds at **0.767** there, against a
base of 0.067.

## Honest limitations

- One register on one domain. Nothing here shows a second register would
  train as cleanly, or that this one transfers off airline content.
- 7.7% of replies are still out of register, and 5.0% still omit something
  required.
- The register was chosen because the base did not have it. A register the
  base partly holds would show a much smaller gain; two lanes nulled today on
  traits their base already had.

## What this rests on

**Open Character Training** (Maiya et al., arXiv 2511.01689). Character is
trained from a constitution written as first-person assertions that target
MANNER rather than content, which is exactly the shape of the register used
here. Their robustness test is the one reported above: a character trained
into the weights survives an instruction to drop it, where a prompted persona
does not. The persona-strip numbers in this card are that test, and they
replicate the finding on a register rather than a personality.

**Persona Vectors** (Chen et al., arXiv 2507.21509) establishes that traits
like sycophancy and hallucination are measurable directions rather than
diffuse style, which is why a single register can be scored per-reply by a
judge at all.

**RLHF Book ch. 17** for character training and model specs; **ch. 12** for
the distillation framing that makes the teacher legitimate: the constitution
reaches the model that WRITES the data and never the model being evaluated,
so what is measured is a disposition in the weights rather than an
instruction being followed.

**RLHF Book ch. 16** for the measurement design. The eval's own variance
decides what a delta can mean, so the resolvable effect at this eval size is
stated beside the result rather than left implicit. **Ch. 5 and 14** for why
the judge is a different model family from the policy: a judge prefers its
own family's writing, and a register score is exactly the kind of judgement
that bias would move.

**RLHF Book ch. 4** for the SFT setup: prompt and system tokens carry no
loss, and the learning rate sits in the stated range.

**Self-distilled.** The teacher that wrote these replies is the same base
model, Qwen3-4B-Instruct-2507, with the constitution in its prompt. It is not
a stronger model. The constitution is doing the work, which is the point: the
register is available to the base when it is described, and training moves it
into the weights so it holds with nothing in the prompt. Stated because
`voice_rows` accepts a `model=` argument it never uses, so a reader would
otherwise reasonably assume a separate teacher (RLHF Book ch. 12: training on
a model's own output teaches it its own habits, which is acceptable here and
should not be assumed).

**No random-selection control** (RLHF Book ch. 9). Rows were kept when they
were complete, not when a judge scored them, so there is no reward selection
for a random arm to control against. Recorded so the absence is not read as
an oversight of the kind that applies to reward-selected sets.

## Training

LoRA rank 16, alpha 32, two epochs, learning rate 1e-4, bf16, 525 rows.
Final loss 0.15 at token accuracy 0.945, no collapse.

Two gates were run before spending the GPU: the base did not hold the register
(0 of 12 replies), and the training data did carry it (0.967 against 0.033 for
controls).

## Use

```python
from peft import PeftModel
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-4B-Instruct-2507")
model = PeftModel.from_pretrained(model, "while-ai/airline-concise-4b")
```

Data, holdout, both evaluation arms and the grader:
[airline-voice-concise](https://huggingface.co/datasets/while-ai/airline-voice-concise).