ADR-011 — Hugging Face as the multi-tenant model-training platform
:::note Contenido en inglés Esta página del wiki se sincroniza desde la base de conocimiento en inglés y todavía no está traducida. :::
reference· tech-lead · updated 2026-06-27 · source
Status
Proposed — recommendation from spike #943 (effort), pending José's sign-off. On acceptance,
flip frontmatter to canonical, set this section to "Accepted (José,
Context
tedos needs to train models in two distinct shapes, and today can do neither:
- Target A — the internal builder model. One model, trained on the effort→PR trace corpus
(problem → plan → patch → verify → outcome). The corpus already exists in Postgres
plan_version(ADR-006) and a JSONL exporter is built (#535, salvage #881). What's missing is a training backend. - Target B — per-tenant client models. One fine-tune/adapter per PyME client, specialized on that client's own data — multi-tenant in the product sense.
The current model layer (@tedos/model-client, #874/#875) is inference-only: OpenAI /v1 over
local (Ollama) / hosted (vLLM) / mock, with an x-tedos-tenant header for attribution. There is no
per-tenant model, adapter, or training path, and we do not want to stand up and operate our own
GPU fleet.
This ADR records the spike's finding on whether — and how — Hugging Face fills that gap. The full investigation lives in four reference docs (the evidence base for everything below):
Scope of the spike (decided with José, #943): HF only (no Modal/Replicate/own-GPU comparison), both targets, research/ADR output — no shippable code, $0 GPU spend.
Decision (recommendation)
Adopt Hugging Face as the training backend for both targets, with serving kept behind the existing
@tedos/model-client seam. The four pillars:
-
Train on HF Jobs. Managed cloud GPUs, no infra to operate. Submit via UV scripts (PEP 723) / the TRL Jobs package; schedule retrains with
hf jobs scheduled. Method: SFT + LoRA as the default — one shared base model + N tiny per-tenant adapters (MBs each). Reserve a full fine-tune for the builder base; adopt Unsloth if the builder grows past ~13B. -
Isolate on the Hub. One org (
tuempresadigital); one private dataset repo + one private model repo per tenant, each in its own per-tenant Resource Group, reachable only by a per-tenant fine-grained token injected as the Job'sHF_TOKENsecret. The builder corpus + model live in a separate internal-only Resource Group no tenant token can reach. This is the Hub encoding of the hard rule "never mix tenant data into the dev-workflow corpus, nor across tenants" (ADR-006,workflow-vs-product.md). -
Serve behind the seam, unchanged wire contract. Default = shared hosted vLLM with multi-LoRA (one base, per-request hot-swappable adapters — cheap for many tenants). Promote a tenant to a dedicated HF Inference Endpoint only as a premium/regulated tier. The
/v1contract stays frozen (non-breaking for the Python satellites);ModelPolicygains additiveadapterId/fineTunedEndpointfields resolved insideproviderFor(). -
Feed it from the satellites. The
chat-datasetssatellite owns the export → private HF Dataset → TRL-shape +dataset_inspectorvalidation step (for both targets);tedos-builderonly triggers it. SFT (messages) format is primary; DPO (prompt/chosen/rejected) is a later track onceoutcome_labelnegatives accumulate.
Cost (order-of-magnitude, from live hf jobs hardware 2026-06-27 — calibrate before committing)
| Item | Estimate |
|---|---|
| Per-tenant adapter retrain (1–3B, SFT+LoRA, t4-small/l4x1) | ~$0.10–1.20 / run |
| Builder model retrain (7B, ~3k examples) | ~$9–11 / run (~$10/mo monthly cadence) |
| 100 tenants retrained weekly + builder weekly + plan | ~$500 / mo order-of-magnitude |
| Plan floor | Team ( |
Cost is linear in tenants × cadence — cadence and GPU flavor are the only knobs. (Note: the
llm-trainer skill's bundled estimate_cost.py ships a stale, inflated price table — the live CLI
numbers above supersede it.)
Consequences
Positive
- No GPU fleet to buy or operate; pay-per-minute, billed only while a Job runs.
- LoRA-per-tenant makes Target B cheap and storage-light; one base serves all via multi-LoRA.
- Isolation is enforced at-rest (Resource Group) and at-runtime (scoped token) — defence in depth.
- The model seam absorbs all of this additively; satellites and the
/v1contract are untouched. - Reuses work already done: the trace corpus + JSONL exporter (#535/#881).
Negative / risks
- A paid HF tier is required (Team min; Enterprise for attribution at scale) — a recurring cost.
- Cost numbers are heuristic; a format-mismatch or runaway job wastes GPU $ — the
dataset_inspectorgate + padded timeouts + mandatory Hub push are mandatory guardrails. - One open discrepancy to confirm at purchase: HF docs say Resource Groups are Team & Enterprise, but
hf repos create --resource-group-idself-reports Enterprise-only (isolation doc). - Vendor concentration on HF for train + (optionally) serve; mitigated by GGUF export + the seam keeping serving swappable.
Phased rollout (on acceptance)
- Phase 0 — Calibrate ($). Buy Team; run one real builder PoC + one real tenant LoRA PoC end-to-end (dataset → Job → private model on Hub → serve a test query). Replace the heuristic cost table with measured numbers. This is the first thing that spends money — gate it on José's OK.
- Phase 1 — Builder pipeline. Wire
chat-datasetsexport → private HF Dataset → scheduled SFT Job → builder model on Hub (internal RG). - Phase 2 — Per-tenant LoRA. Per-tenant dataset/model repos + Resource Groups + scoped tokens;
shared vLLM multi-LoRA serving;
ModelPolicyadapterIdrouting. - Phase 3 — Scale. Dedicated Inference Endpoints for premium tenants; Enterprise tier for per-tenant cost attribution + token lifecycle automation.
References
- Spike effort #943 (subs #944–#948) · evidence docs linked in Context above.
- Related: ADR-006 (effort workflow = training trace), #770/#796 (builder model + telemetry),
#535/#881 (trace exporter), #874/#875 (
@tedos/model-clientseam), #922 (multi-tenant client config).
Local agent skills (not vendored)
The HF training/work is supported by agent skills that are installed locally per developer and
NOT committed to the repo (gitignored, #943): hf-cli, hf-mem, huggingface-best,
huggingface-llm-trainer, huggingface-local-models, huggingface-trackio,
train-sentence-transformers, trl-training (under .agents/skills/ and .claude/skills/).
They are referenced here as the toolchain behind the spike; install on demand rather than vendoring
their bundles into the tree.