Lendmind-Intake-4b, release candidate 2 (lendmind-intake-4b-v1.0-rc2)

Published by Lendmind Ltd. A LoRA adapter for Qwen/Qwen3.5-4B that reads a UK mortgage adviser's message into a structured frame. This repository is lendmind-intake-4b; this release is the tagged revision v1.0-rc2.

Status: release candidate, not a release. On the headline evaluation stratum it meets 4 of our 5 bars; the fifth (MARKET/UNKNOWN messages read as a case) misses by one message. On messages from writers it never saw it does not meet the figure-precision bar (see Evaluation). Under our naming rule it is v1.0-rc2; v1.0 is kept for a model that meets all five bars.

What it does

Lendmind-Intake-4b turns a UK mortgage adviser's message about a client into an IntakeFrame v4: one JSON object with the message's intents, the lenders it names, the client's stated figures and choices, each with the adviser's own words as its quote, and (as a second task) up to three plain questions for what a lender's affordability calculator still needs. A program then finds every quote in the message and reads the value from it. The model is trained to read figures, not to calculate or infer them, and to serve no verdict on a message that only asks about the market or follows up an earlier turn; Known limitations lists where it still does.

Two tasks, one adapter, two system prompts: EXTRACT (message → frame) and ASK (frame → the questions).

Intents, as the frame defines them: A, which lenders would lend this case (or whether one named lender would); B, what one named lender's criteria say on a point of policy; C, which products fit; MARKET, a criteria question across lenders; UNKNOWN, none of these, or a follow-up to an earlier turn.

Intended use and scope

Intended use: structured extraction from UK mortgage adviser notes, behind a constrained reader like the one described below, as one input to a system in which people make the decisions.

Not financial advice. Not for consumer use. Not for making lending decisions. The model reads what an adviser wrote; it does not assess affordability, eligibility or suitability, and its output is not a recommendation. Do not put it in front of consumers, and do not use its output to decide whether anyone is lent money.

Out of scope: any lending, affordability or eligibility decision; consumer-facing use; messages that are not adviser notes about a case; languages other than English and markets other than the UK; use without a constrained reader (a plain chat completion from this adapter carries none of the numbers below).

How it is run

The numbers on this card come from the adapter under Lendmind's constrained reader, not from the adapter alone:

  • greedy decoding under the IntakeFrame v4 JSON schema, thinking off;
  • every quote constrained to a stretch of the message, standing as whole words, so a value the message does not contain cannot be served;
  • the override drop: any value the decoder had to force against the model's own top choice is withheld before anything is read, scored or served;
  • the ASK task decoded under a per-message schema: one question per input to ask for, in order, with no figures.

The decoding constraint is open source as quotebound (Apache-2.0): JSON-Schema-constrained greedy decoding for Qwen3.5 on Apple silicon, quotes bound to the user's message (--quote-source user), a record of every token the constraint forced (from which a caller can withhold those values), exact speculative decoding, and the constraint as a small C library for other decoders. quotebound loads adapters in its own layout, not this PEFT file. It does not contain the reader's prompts, the IntakeFrame v4 schema, the override drop, the rules that decide what to ask, or the scorer, and those are not part of this upload either. The numbers here were measured with Lendmind's internal build of the decoder that quotebound was released from, not with the public release.

Reference hardware for the numbers: Apple M4 Pro, 48 GB, MLX 0.32.3, bf16 weights, the adapter applied unmerged, plain greedy decoding. Exact speculative drafts are byte-identical to plain greedy on the 470 dev rows (measured with rc1's adapter) and cut EXTRACT from 7.10 s to 2.31 s and ASK from 2.40 s to 0.97 s a row on that Mac.

Loading the adapter

import torch
from peft import PeftModel
from transformers import AutoModelForImageTextToText, AutoTokenizer

BASE, BASE_REV = "Qwen/Qwen3.5-4B", "851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a"
tokenizer = AutoTokenizer.from_pretrained(BASE, revision=BASE_REV)
base = AutoModelForImageTextToText.from_pretrained(BASE, revision=BASE_REV, dtype=torch.bfloat16)
model = PeftModel.from_pretrained(base, "lendmindltd/lendmind-intake-4b", revision="v1.0-rc2")

Load the base with AutoModelForImageTextToText (the checkpoint's Qwen3_5ForConditionalGeneration): target_modules is a pattern over that class's model.language_model.layers.* projections, and it matches no module of the text-only class. Nothing in the vision tower is adapted. Prompts are rendered with the base's chat template, generation prompt on and enable_thinking=False.

Parity of this PEFT file with the trained adapter

adapter_model.safetensors is a rename of the trained adapter's 400 float32 tensors to PEFT's names, with no transpose and no cast: every tensor is byte-identical to the file the trainer wrote. Loaded onto the base with PeftModel.from_pretrained (transformers 5.14.1, peft 0.21.2, torch 2.13.0), it was compared on 22 Oct 2026, on CPU in float32, with the trainer's own PyTorch LoRA layer holding the trained tensors (scale alpha / r = 2.0), on 10 fixed dev prompts (7 EXTRACT, 3 ASK):

  • 200 of 200 adapted modules wrapped by PEFT, every lora_A / lora_B bit-identical to the trained tensors;
  • logits max-abs difference 0.0 over every prompt position and every greedy step (bar 1e-2);
  • greedy tokens identical on 10 of 10 prompts (1,160 tokens, each to its stop token), and generate() gives the same tokens.

Not covered: bf16, a GPU, and the constrained reader, which is not part of the adapter.

Training

base Qwen/Qwen3.5-4B, revision 851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a, bf16; hybrid Gated DeltaNet and gated attention, 32 layers, hidden 2560, tied embeddings
adapter LoRA rank 16, alpha 32 (scale 2.0), on q/k/v/o_proj (8 full-attention layers), in_proj_qkv, in_proj_z, out_proj (24 Gated DeltaNet layers) and gate/up/down_proj (32 layers) of the language model: 200 modules, 400 float32 tensors, 122 MB
recipe rc1's: learning rate 1e-4, linear warmup over 5% of steps then cosine to zero, AdamW (0.9, 0.999, eps 1e-8), no weight decay, global-norm clip 1.0, 2 epochs, batches packed to 4,096 tokens, max length 2,048, gradient checkpointing, seed 0; loss on the assistant turns only
trainer a PyTorch LoRA trainer (PyTorch 2.11.0 + CUDA 12.8, transformers 5.14.1, flash-linear-attention 0.5.2), bf16
hardware one NVIDIA L4 (24 GB) on a Google Cloud Spot VM, 19 Oct 2026; the final attempt ran 1.14 h after two Spot reclaims
steps 1,141 of 1,141; this checkpoint is step 1,000, the best dev loss (0.010765; 1.033436 before the first step; rc1: 0.009915)
training data 4,741 examples: 2,971 EXTRACT + 1,770 ASK; dev 470 (288 EXTRACT + 182 ASK), rc1's
label rules IntakeFrame v4 labelling rules v2.2 at training time
second seed trained with the same recipe (seed 1): 1,143 steps, best at step 1,143, dev loss 0.011002; the same 4 of 5 bars on s2_unseen + s3; not part of this release

Training data provenance

Synthetic throughout: no real client, adviser or lender data.

  • 3,416 rows from rc1's training build: adviser messages written by four open models (Gemma 4 E4B-it, Qwen3-8B, Mistral Small 3.2 24B, Phi-4) run locally from code-generated cases, labelled by construction and audited (label rules v2 and v2.1); the exact writer checkpoints are listed on the v1.0-rc1 card.
  • 1,325 rows from the generator's training split: 1,000 code-generated seeds, texts written by a larger open-weight model called through an API, every label verified against its seed by two judges of different model families (Claude Opus 5.5, Gemini 4); gold where both agree (810 gold, 190 contested left out).
  • Dev: the same 470 rows as rc1. The evaluation set (parts s1, s2, s3) is never used in training; the training builder drops any text it shares with the evaluation set, by hash.

The training data and the evaluation set are not published.

Evaluation

The evaluation set is held by Lendmind and never published or used in training. Two strata are reported: s2_unseen, adviser messages from writers (models) whose texts are in no training row, and s3, the training data generator's held-out set. The headline is the two together (547 messages scored).

The bars:

  • figure precision, tier 1 (≥ .98): of the tier-1 figures served (annual income, purchase price, deposit, deposit %, LTV, loan, age, term in years), the share at the label's value;
  • intent precision, lowest of A/B/C (≥ .95);
  • clarification recall, designed (≥ .90): of the messages written to need a clarifying question, the share whose question is asked;
  • MARKET/UNKNOWN read as A (0): messages labelled MARKET or UNKNOWN (or a refusal) that are read as a case;
  • frames returned (1.0): the share of messages for which a schema-valid frame is returned.

The labelling rules were revised after audits of the evaluation labels; v2.5 is the latest, and the tables below give v2.1 (the version the release candidate was first judged on) and v2.5. A revision changes the expected labels, not the model's outputs; for rc2 it moved no bar on any stratum.

Labels v2.1, s2_unseen + s3 (547 messages)

reader figure precision tier 1 (bar ≥ .98) intent precision, lowest of A/B/C (≥ .95) clarification recall, designed (≥ .90) MARKET/UNKNOWN read as A (0) frames returned (1.0) bars met
lendmind-intake-4b-v1.0-rc2 (seed 0) .991 .975 .929 1 of 111 1.000 4 of 5
seed 1 (not released) .989 .983 .935 1 of 111 1.000 4 of 5
rc1 (tag v1.0-rc1) .975 .778 .858 3 of 111 1.000 1 of 5

By s3 difficulty level (the generator's levels 1 to 5; bars met of 5), rc2 / seed 1 / rc1: level 1 4/5/4, level 2 5/4/3, level 3 4/5/2, level 4 4/4/2, level 5 4/4/1.

Labels v2.5, rc2 by stratum

stratum messages figure precision tier 1 (≥ .98) intent precision, lowest of A/B/C (≥ .95) clarification recall, designed (≥ .90) MARKET/UNKNOWN read as A (0) frames returned (1.0) bars met
s2_unseen + s3 547 .991 (16 wrong of 1,796) .975 .929 (157 of 169) 1 of 111 1.000 4 of 5
s2_unseen 106 .967 (7 wrong of 209) .955 .857 (12 of 14) 0 of 37 1.000 3 of 5
s3 441 .994 (9 wrong of 1,587) .979 .935 (145 of 155) 1 of 74 1.000 4 of 5

Labels v2.5, figure precision tier 1 (wrong of served) and bars met, our builds

reader s2_unseen + s3 bars met s2_unseen bars met s3 bars met
lendmind-intake-4b-v1.0-rc2 (seed 0) .991 (16 of 1,796) 4 of 5 .967 (7 of 209) 3 of 5 .994 (9 of 1,587) 4 of 5
seed 1 (not released) .989 (19 of 1,796) 4 of 5 .957 (9 of 208) 3 of 5 .994 (10 of 1,588) 4 of 5
rc1 (tag v1.0-rc1) .975 (44 of 1,769) 1 of 5 .969 (6 of 196) 3 of 5 .976 (38 of 1,573) 1 of 5

rc2 does not meet the figure-precision bar on messages from unseen writers. On s2_unseen, under labels v2.5, it serves 7 wrong tier-1 figures of 209 (precision .967; under v2.1, 8 of 209, .962). The bar is .98, which at that volume allows at most 4 wrong. Its clarification recall there, .857 (12 of 14 designed asks), is also under its bar, so rc2 meets 3 of 5 bars on s2_unseen; rc1 and the second seed also meet 3 of 5 there.

On the dev set (288 EXTRACT messages, with the 182 ASK rows behind them; dev labels v2): figure precision .995 (842 of 846), figure recall .995, choices precision .978 and recall .985, lenders precision and recall 1.000, lowest intent precision .955, clarification recall .967 (319 of 330), no MARKET/UNKNOWN message read as A (0 of 63), every frame returned: all five bars met on dev, as for rc1.

Latency is reported, not yet a bar: p95 11.5 s a message on the evaluation set on the M4 Pro with plain greedy decoding (rc1: 13.0 s).

Known limitations

  • One MARKET/UNKNOWN message is read as a case. For rc2 it is a follow-up that carries a complete second case; the model serves a frame instead of asking for the use case. The second seed reads that message right and instead misses a refusal written as the last short sentence after a full case in shorthand. Both are errors under the labelling rules.
  • Unseen writers. On messages from writers the model never saw (s2_unseen), figure precision (.967 under labels v2.5, 7 wrong of 209) and clarification recall (.857) are under their bars. The gain over rc1 is on the training data generator's distribution (s3), not on unseen writers.
  • Numbers are read, never computed. A total, a conversion or a range is not labelled; a figure in a range or an uncorrected correction is left out and asked for.
  • Speed. About 24 tokens a second bf16 on the M4 Pro with plain greedy decoding; exact drafts cut EXTRACT from 7.10 s to 2.31 s a row and ASK from 2.40 s to 0.97 s (dev rows, byte-identical). About 10 to 12 tokens a second on an NVIDIA L4 with a CUDA port of the reader, plain greedy, one sequence at a time.
  • CUDA is not byte-identical. A CUDA port of the reader (measured with rc1) matched the Mac on every s2_unseen rate but served one new wrong value on the dev set and one on another evaluation stratum, each at a near-tie between the top two tokens. A 0.3-logit margin floor on each value closes that on the dev set at the cost of nine values withheld on the Mac; the evaluation set has not been checked under it. Every serving path must pass the full bar before use.
  • English, UK mortgage domain only. Written for UK adviser notes, intermediary lending criteria and lender affordability calculators; it has not been evaluated on anything else.

Files

file what it is
adapter_model.safetensors the LoRA weights, PEFT names, float32 (sha256 5b969bc4198d10eed4170a0b88cdf752a9379c5a8d79d8a12f799edd1f19a235)
adapter_config.json the PEFT config: r 16, lora_alpha 32, target_modules over the language model only
LICENSE Apache License 2.0, the text distributed with the base model
NOTICE the modification and attribution notices
README.md this card

Licences and provenance

  • This adapter: Apache License 2.0, © 2026 Lendmind Ltd.
  • Base: Qwen/Qwen3.5-4B, Apache License 2.0. This model is a modification of it; LICENSE is the licence text and NOTICE states the modification.
  • Writers of training texts: Gemma 4 E4B-it (Apache 2.0), Qwen3-8B and Mistral Small 3.2 24B (Apache 2.0), Phi-4 (MIT), and a larger open-weight model called through an API for the generator split. Judges of labels: Claude Opus 5.5 and Gemini 4 (verification only; they wrote no training text).
  • No personal data: every message is synthetic; the evaluation set and the training data are not published.

Versions

name result
lendmind-intake-4b-v0.1 … v0.4 earlier internal rounds, not released
lendmind-intake-4b-v1.0-rc1 step 700 of 792; 1 of 5 bars on s2_unseen + s3 (labels v2.1 and v2.5); tag v1.0-rc1 of this repository
lendmind-intake-4b-v1.0-rc2 step 1,000 of 1,141; 4 of 5 bars on s2_unseen + s3 (labels v2.1 and v2.5); 3 of 5 on s2_unseen
lendmind-intake-4b-v1.0 not yet: all 5 bars on the evaluation set
Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for lendmindltd/lendmind-intake-4b

Finetuned
Qwen/Qwen3.5-4B
Adapter
(814)
this model

Evaluation results

  • Figure precision, tier 1 (bar 0.98) on Lendmind intake evaluation set, s2_unseen + s3, 547 messages, labels v2.5 (not published)
    self-reported
    0.991
  • Intent precision, lowest of A/B/C (bar 0.95) on Lendmind intake evaluation set, s2_unseen + s3, 547 messages, labels v2.5 (not published)
    self-reported
    0.975
  • Clarification recall, designed asks (bar 0.90) on Lendmind intake evaluation set, s2_unseen + s3, 547 messages, labels v2.5 (not published)
    self-reported
    0.929
  • MARKET/UNKNOWN messages read as a case, of 111 (bar 0) on Lendmind intake evaluation set, s2_unseen + s3, 547 messages, labels v2.5 (not published)
    self-reported
    1.000
  • Frames returned (bar 1.0) on Lendmind intake evaluation set, s2_unseen + s3, 547 messages, labels v2.5 (not published)
    self-reported
    1.000
  • Figure precision, tier 1 (bar 0.98) on Lendmind intake evaluation set, s2_unseen (unseen writers), 106 messages, labels v2.5 (not published)
    self-reported
    0.967
  • Intent precision, lowest of A/B/C (bar 0.95) on Lendmind intake evaluation set, s2_unseen (unseen writers), 106 messages, labels v2.5 (not published)
    self-reported
    0.955
  • Clarification recall, designed asks (bar 0.90) on Lendmind intake evaluation set, s2_unseen (unseen writers), 106 messages, labels v2.5 (not published)
    self-reported
    0.857