@tuned-tensor/cli 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -9
- package/dist/{chunk-4Q54NHKR.js → chunk-PVLX7LJI.js} +381 -148
- package/dist/chunk-PVLX7LJI.js.map +1 -0
- package/dist/index.js +2051 -417
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +41 -6
- package/dist/local-runtime.js.map +1 -1
- package/docs/local-runtime/architecture.md +6 -1
- package/docs/local-runtime/decision.md +142 -0
- package/docs/spec-architecture.html +2 -2
- package/docs/spec-workflow.md +16 -7
- package/examples/single-spec/decision/tunedtensor.json +630 -0
- package/package.json +5 -2
- package/training/adapter/src/evaluate.py +14 -7
- package/training/adapter/src/model_contract.py +38 -5
- package/training/adapter/src/prefetch.py +6 -1
- package/training/adapter/src/serve.py +37 -11
- package/training/adapter/src/train.py +8 -0
- package/training/decision/pyproject.toml +25 -0
- package/training/decision/src/common.py +127 -0
- package/training/decision/src/evaluate.py +70 -0
- package/training/decision/src/train.py +181 -0
- package/training/decision/uv.lock +1175 -0
- package/dist/chunk-4Q54NHKR.js.map +0 -1
|
@@ -44,7 +44,7 @@ The local adapter runtime excludes:
|
|
|
44
44
|
The next model or method should arrive with its own locked dependencies,
|
|
45
45
|
resource defaults, data contract, and real CUDA acceptance test.
|
|
46
46
|
|
|
47
|
-
TT bundles
|
|
47
|
+
TT bundles three local training methods:
|
|
48
48
|
|
|
49
49
|
- **Adapter** (`training/adapter`): certified Transformers checkpoints and
|
|
50
50
|
PEFT LoRA SFT. Driven by `tt pipeline run`.
|
|
@@ -55,6 +55,11 @@ TT bundles two local training methods:
|
|
|
55
55
|
rejects `nproc_per_node` values above 1 and unsupported steps such as
|
|
56
56
|
`compare` before creating run artifacts.
|
|
57
57
|
|
|
58
|
+
- **Decision** (`training/decision`): fine-tunes a pinned typed decision
|
|
59
|
+
model (`convaiinnovations/laya`) on labelled examples. Driven by
|
|
60
|
+
`tt pipeline run` from a decision `tunedtensor.json`. Runs on CPU, Apple MPS
|
|
61
|
+
or CUDA; see [decision.md](decision.md).
|
|
62
|
+
|
|
58
63
|
The foundation engine is a readable single-GPU trainer inspired by nanochat,
|
|
59
64
|
not a port of nanochat's distributed or compute-optimal training stack. It can
|
|
60
65
|
stream configured text/JSONL shards into a deterministic token cache, use a
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Decision models
|
|
2
|
+
|
|
3
|
+
A decision model answers one typed question about an input — which queue,
|
|
4
|
+
yes or no, how urgent — in a single encoder forward pass. It returns a
|
|
5
|
+
probability for every allowed answer instead of generating text, so the output
|
|
6
|
+
always parses and its confidence can be thresholded. Use the decision engine
|
|
7
|
+
for classification, routing, triage, guardrails and score gates where a
|
|
8
|
+
generative LLM is more than the job needs.
|
|
9
|
+
|
|
10
|
+
TT fine-tunes [Laya](https://huggingface.co/convaiinnovations/laya)
|
|
11
|
+
(`convaiinnovations/laya`, Apache-2.0): a 421M-parameter ModernBERT-large
|
|
12
|
+
encoder with a typed decision head. Every stage uses Laya revision
|
|
13
|
+
`55cf4c4ebb4ebe31b2550e8bdf3bd21b99753851`, the reviewed commit that Laya 0.3.22
|
|
14
|
+
pins. Training and evaluation run on CPU, Apple MPS or CUDA; no GPU is required.
|
|
15
|
+
|
|
16
|
+
## Spec
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"engine": "decision",
|
|
21
|
+
"name": "Card support triage",
|
|
22
|
+
"system_prompt": "Which card-support queue should handle this customer message?",
|
|
23
|
+
"guidelines": ["Choose the queue for the customer's main problem."],
|
|
24
|
+
"constraints": [],
|
|
25
|
+
"base_model": "convaiinnovations/laya",
|
|
26
|
+
"decision": {
|
|
27
|
+
"type": "choice",
|
|
28
|
+
"criteria": {
|
|
29
|
+
"lost_or_stolen": "customer lost their card or it was stolen",
|
|
30
|
+
"payment_declined": "a card payment was declined or rejected"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"examples": [
|
|
34
|
+
{ "input": "I think I left my card at the bar last night.", "output": "lost_or_stolen" },
|
|
35
|
+
{ "input": "Why was my payment at the grocery store refused?", "output": "payment_declined" }
|
|
36
|
+
],
|
|
37
|
+
"hyperparameters": { "n_epochs": 3 }
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`tt init --engine decision` writes a starter spec. A complete example lives in
|
|
42
|
+
[`examples/single-spec/decision`](../../examples/single-spec/decision/tunedtensor.json).
|
|
43
|
+
|
|
44
|
+
`system_prompt`, `guidelines` and `constraints` compile into the question's
|
|
45
|
+
instructions, as they compile into the system message for the other engines.
|
|
46
|
+
The model reads roughly 190 tokens of instructions and option descriptions, so
|
|
47
|
+
keep them short; validation warns above 600 characters.
|
|
48
|
+
|
|
49
|
+
| `decision.type` | `criteria` | Example `output` |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `choice` | Object of label → description (2–32 labels, in option order) | A label, e.g. `payment_declined` |
|
|
52
|
+
| `noul` | Optional `{ "true": "...", "false": "..." }` | `true` or `false` |
|
|
53
|
+
| `score` | Array of level descriptions, level 0 first (2–10) | A level index, e.g. `2` |
|
|
54
|
+
|
|
55
|
+
Outputs match labels ignoring case and surrounding spaces. Validation rejects
|
|
56
|
+
an output that is not a label and warns when a label has no examples.
|
|
57
|
+
|
|
58
|
+
Optional `hyperparameters`:
|
|
59
|
+
|
|
60
|
+
| Field | Default | Meaning |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| `n_epochs` | 3 | Passes over the training split |
|
|
63
|
+
| `learning_rate` | 2e-5 | AdamW learning rate, linear warmup and decay |
|
|
64
|
+
| `batch_size` | 8 | Examples per optimizer step |
|
|
65
|
+
| `freeze_encoder` | `false` | Train only the decision head (faster, usually less accurate) |
|
|
66
|
+
| `shuffle_options` | `true` | Shuffle option order per row so the head learns meaning, not position |
|
|
67
|
+
| `seed` | 0 | Training seed |
|
|
68
|
+
| `device` | `auto` | `auto`, `cpu`, `mps` or `cuda` |
|
|
69
|
+
|
|
70
|
+
`runtime.artifactRoot` is supported. `runtime.gpu`, `evaluation` and adapter
|
|
71
|
+
runtime paths are rejected: the model is small enough to run where the CLI runs.
|
|
72
|
+
|
|
73
|
+
## Run
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
tt validate
|
|
77
|
+
tt pipeline run --spec tunedtensor.json --dry-run
|
|
78
|
+
tt pipeline run --spec tunedtensor.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The pipeline is the adapter recipe: `baseline` evaluates the pinned base model,
|
|
82
|
+
`train` fine-tunes it, `candidate` evaluates the tuned model and `compare`
|
|
83
|
+
pairs the two. TT splits the spec examples once with a seed derived from the
|
|
84
|
+
spec `id` (20% held out, at least one). Training sees only the training split.
|
|
85
|
+
The evaluator receives held-out IDs and inputs only; Node joins its predictions
|
|
86
|
+
to the expected labels and scores them.
|
|
87
|
+
|
|
88
|
+
Each evaluation reports accuracy, log-loss and Brier score of the expected
|
|
89
|
+
label, mean confidence and per-label recall. The comparison adds improved and
|
|
90
|
+
regressed examples and the log-loss and Brier deltas. Because Laya answers
|
|
91
|
+
zero-shot from the label descriptions, the baseline is a real model, not an
|
|
92
|
+
empty one: the report shows what fine-tuning added on top of the descriptions.
|
|
93
|
+
|
|
94
|
+
Runs are written to `.tuned-tensor/decision-runs/<run-id>` beside the spec (or
|
|
95
|
+
`--output <dir>`), with owner-only permissions:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
report.json summary: model, revision, split, every step's metrics
|
|
99
|
+
resolved-workflow.json spec, plan, question and split used
|
|
100
|
+
data/ train.jsonl and unlabeled eval-inputs.jsonl
|
|
101
|
+
baseline/ candidate/ config, log, predictions.jsonl, report.json
|
|
102
|
+
train/model/ the tuned checkpoint
|
|
103
|
+
compare/comparison.json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
On a 4-core CPU a step of 8 examples takes about 15 seconds, so 120 examples
|
|
107
|
+
for 3 epochs trains in about 12 minutes. The tuned checkpoint is about 1.7 GB
|
|
108
|
+
because weights are saved in float32; small fine-tuning updates would be lost
|
|
109
|
+
in bfloat16.
|
|
110
|
+
|
|
111
|
+
## Use the tuned model
|
|
112
|
+
|
|
113
|
+
`train/model` is a complete Laya checkpoint. The fitted temperatures of the
|
|
114
|
+
base checkpoint are reset to 1.0, because they described the base model's
|
|
115
|
+
logits; cross-entropy training is itself the calibration objective.
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import laya
|
|
119
|
+
|
|
120
|
+
agent = laya.load("path/to/decision-runs/<run-id>/train/model")
|
|
121
|
+
question = {
|
|
122
|
+
"type": "choice",
|
|
123
|
+
"instructions": "Which card-support queue should handle this customer message?",
|
|
124
|
+
"criteria": {"lost_or_stolen": "...", "payment_declined": "..."},
|
|
125
|
+
}
|
|
126
|
+
answer = agent.predict("My card was refused at the shop.", {"queue": question})["answers"]["queue"]
|
|
127
|
+
print(answer["choice"], answer["probabilities"])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Pass the same instructions and criteria the model was trained with: they are
|
|
131
|
+
part of its input. `resolved-workflow.json` records them under `question`.
|
|
132
|
+
The tuned model is not registered with `tt models` and is not served through
|
|
133
|
+
vLLM.
|
|
134
|
+
|
|
135
|
+
## Limits
|
|
136
|
+
|
|
137
|
+
- One question per spec. Laya can answer several questions per input; TT
|
|
138
|
+
trains and evaluates one.
|
|
139
|
+
- `convaiinnovations/laya` is the English checkpoint. Its multilingual and
|
|
140
|
+
typed-decisions variants are not certified yet.
|
|
141
|
+
- The held-out split comes from the spec examples. With few examples the
|
|
142
|
+
comparison is noisy; add examples before trusting a small delta.
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<div class="tt-level">
|
|
74
74
|
<div class="tt-unit"><button class="btn" type="button" data-component="agent" aria-pressed="false">User intent → agent</button><small class="text-small">get_local_spec → field patch</small></div>
|
|
75
75
|
<div class="tt-unit"><button class="btn" type="button" data-component="approval" aria-pressed="false">Diff → /approve</button><small class="text-small">validate → atomic save → history</small></div>
|
|
76
|
-
<div class="tt-unit"><button class="btn" type="button" data-component="review" aria-pressed="false">/spec review</button><small class="text-small">show · diff · validate · history</small></div>
|
|
76
|
+
<div class="tt-unit"><button class="btn" type="button" data-component="review" aria-pressed="false">/spec review</button><small class="text-small">overview · sections · show · diff · validate · history</small></div>
|
|
77
77
|
</div>
|
|
78
78
|
<div class="tt-arrow text-small">↕ inspect the recipe · save only reviewed edits</div>
|
|
79
79
|
<div class="tt-recipe tt-unit">
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
"src/local-runtime/local-project.ts",
|
|
183
183
|
"src/pipeline.ts"
|
|
184
184
|
],
|
|
185
|
-
"example": "/spec\n/spec diff\n/spec validate\n/spec history\n\n# Outside the TT shell:\ntt spec show --json"
|
|
185
|
+
"example": "/spec\n/spec examples\n/spec diff\n/spec validate\n/spec history\n\n# Outside the TT shell:\ntt spec view\ntt spec show --json"
|
|
186
186
|
},
|
|
187
187
|
"config": {
|
|
188
188
|
"title": "Spec runtime and evaluation",
|
package/docs/spec-workflow.md
CHANGED
|
@@ -15,19 +15,27 @@ Inside the TT shell, in your project directory:
|
|
|
15
15
|
|
|
16
16
|
```text
|
|
17
17
|
/spec
|
|
18
|
+
/spec examples
|
|
19
|
+
/spec show
|
|
18
20
|
/spec validate
|
|
19
21
|
/spec diff
|
|
20
22
|
/spec history
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
`/spec` shows
|
|
25
|
+
`/spec` shows a readable overview: name, engine, base model and example count,
|
|
26
|
+
then highlighted sections for behavior (system prompt, guidelines, constraints),
|
|
27
|
+
examples, training settings, evaluation, runtime and pipeline, followed by
|
|
28
|
+
validation results. `/spec <section>` shows one section in full; sections are
|
|
29
|
+
`identity`, `behavior`, `examples`, `training`, `evaluation`, `runtime` and
|
|
30
|
+
`pipeline`. `/spec show` prints the complete file with JSON highlighting,
|
|
31
|
+
validation results and SHA-256.
|
|
24
32
|
`/spec diff` shows pending spec edits in the current conversation; otherwise it
|
|
25
33
|
shows the latest approved edit, or external changes since that revision.
|
|
26
34
|
`/spec history` lists up to 50 recent revision records. These commands require
|
|
27
35
|
no credentials and work before the agent is configured.
|
|
28
36
|
|
|
29
|
-
Outside the shell, use `tt spec
|
|
30
|
-
`tt spec history`. Add a workspace-relative path, for example
|
|
37
|
+
Outside the shell, use `tt spec view` (or `tt spec <section>`), `tt spec show`,
|
|
38
|
+
`tt spec validate`, `tt spec diff`, and `tt spec history`. Add a workspace-relative path, for example
|
|
31
39
|
`tt spec show feedback/tunedtensor.json`. For continued work on a nested
|
|
32
40
|
project, `/cd feedback` makes its `tunedtensor.json` the current recipe.
|
|
33
41
|
`--json` returns structured review results. `tt spec validate` exits nonzero
|
|
@@ -37,9 +45,8 @@ for an invalid spec.
|
|
|
37
45
|
|
|
38
46
|
```text
|
|
39
47
|
› Keep my training settings, but require a single lowercase sentiment label.
|
|
40
|
-
[agent reads the spec and
|
|
41
|
-
|
|
42
|
-
› /approve
|
|
48
|
+
[agent reads the spec and shows the proposed diff]
|
|
49
|
+
? Save this spec edit? y yes · n no · esc decide later
|
|
43
50
|
› /spec
|
|
44
51
|
› /spec history
|
|
45
52
|
```
|
|
@@ -58,7 +65,9 @@ strict schema, readiness checks, nonblank content checks and distinct-example
|
|
|
58
65
|
checks. Small example sets produce a warning; validation is not a claim of model
|
|
59
66
|
quality or GPU readiness.
|
|
60
67
|
|
|
61
|
-
Proposing an edit does not write anything.
|
|
68
|
+
Proposing an edit does not write anything. tt asks for a decision right after the
|
|
69
|
+
answer; pressing `Esc` leaves the edit pending, and `/spec diff` then shows it again
|
|
70
|
+
until you run `/approve` or `/reject`. Approval revalidates the workspace,
|
|
62
71
|
parent directory, current file bytes and proposed result, acquires the spec's
|
|
63
72
|
writer lock and atomically replaces the file. `/reject` leaves it unchanged.
|
|
64
73
|
If the file changes after review, prepare a fresh edit. A saved edit invalidates
|