laya-code

A code-relevance re-ranker fine-tuned from Laya (ModernBERT-large encoder + typed-decision head, 421M parameters). Given a task description and a source-code chunk, it answers one yes/no (noul) question with a calibrated probability:

question: Is this source code relevant to the software change: "{task}"?
state:    file: <path> (lines a-b)\n<code>        (truncated to 128 tokens in production)

It is the default re-ranker of laya-codex, which feeds Claude Code the most relevant code spans for a prompt (tree-sitter chunks, then Moon BM25 candidates, then laya-code re-ranking).

Model details

Base model convaiinnovations/laya, root checkpoint (revision 1c5edc17a7acd8701df6fc341c0d179f1c62c982), Apache-2.0
Architecture unchanged: same safetensors keys, shapes and dtypes as the base (205 F16 tensors + temperature F32), 842,609,210 bytes
What changed model.safetensors (fine-tuned weights) and rl_agent_config.json (model_name, noul:2 temperature 0.9410, was 1.9834; finetune block). encoder/config.json, tokenizer/*, rl_agent_api.py and rl_common.py are byte-identical to the base. The training block of rl_agent_config.json is inherited from the base and describes the base's training, not this fine-tune.
Context 512 tokens (max_len), 192 for the question head (head_max_len)
Runtime Python: rl_agent_api.RLAgent from this repo (same as the base). Rust: laya-model crate of laya-codex (candle; Metal F16 on macOS, CPU F32 elsewhere), parity-tested against the Python reference
License Apache-2.0 (see LICENSE and NOTICE)

Training data

Weak supervision from git history. Nothing was hand-labelled.

  • 8 training repositories (mixed Rust, Python, TypeScript and JavaScript): openai/codex, TinDang97/velos, MervinPraison/PraisonAI, badlogic/pi-mono, Portkey-AI/gateway (local ai-guard checkout), TinDang97/python-dependency-injector, Netflix/dispatch and pilotspace/hydroa (local ai-proxy checkout). Source: finetune/repos.py.

  • Held out (never used for training or calibration): pilotspace/moon and pilot-space. Moon client codebases (helios, helios-mono, lunaris) were left out so that Moon vocabulary does not leak into the Moon eval. A root-commit check rejects forks and clones of each other and of the held-out repos.

  • Examples: up to 600 non-merge commits per repo (the build_data.py default) that touch 1–4 source files and have an informative subject (at least 20 characters). The task is the subject plus a short first body line. The candidate list is the BM25 top 12 over other files plus the parent-revision windows of the touched files (40-line windows, stride 30). Labels: 1.0 for a window that overlaps a changed hunk, 0.7 for another window of a touched file, 0 for other files. Extra examples: hunks BM25 missed (label 1.0), a random same-file window (label 0.4) and random windows from other files (label 0).

  • Size: 50,926 pairs, split by commit hash into 45,790 train and 5,136 validation pairs. Train pairs: 2,779 candidate positives, 5,609 candidate same-file, 24,768 candidate negatives, 4,656 extra positives, 2,392 same-file, 5,586 random negatives. Per-repo counts (v2 data; the warm start used v1 data from the same repos):

    repo train commits val commits train pairs val pairs
    PraisonAI 231 18 3,711 280
    ai-guard 460 40 7,404 665
    ai-proxy 200 23 3,293 380
    codex 446 54 7,676 932
    dispatch 447 53 7,347 863
    pi-mono 439 61 7,386 1,013
    python-dependency-injector 453 47 7,066 744
    velos 117 16 1,907 259
  • Training: top 8 of 28 encoder layers, the final norm and the decision head. fp32 on an M4 Pro (MPS). AdamW; learning rate 2e-5 for the encoder and 1e-4 for the head. 32 sequences per update. Log loss against soft targets. 536 updates on v2 data, warm-started from 300 updates on v1 data (about 2.3 h in total). Checkpoint chosen by lowest validation NLL. The noul:2 temperature was then refitted on the validation split, using the exported F16 weights.

Evaluation

All numbers come from files in the laya-codex repository and are quoted as recorded. Gold labels are file-level: the files the commit touched. Candidates are BM25 windows at HEAD.

Re-ranker comparison, 128-token state (production setting)

spike/results/compare_models.json (spike/compare_models.py): the 40 most recent qualifying moon commits, BM25 top 24, state truncated to 128 tokens, probabilities pooled over all candidates (base rate 0.309).

model Laya-only MRR Laya-only P@10 RRF MRR AUROC ECE mean P
BM25 alone 0.480 (MRR) 0.340 – – – –
laya-base (convaiinnovations/laya) 0.479 0.348 0.505 0.586 0.362 0.671
laya-typed-decisions 0.441 0.288 0.456 0.539 0.239 0.545
laya-code 0.702 0.405 0.630 0.713 0.049 0.328

Held-out evaluation, 256-token state (training protocol)

spike/results/finetune_eval.json (finetune/eval.py): 40 tasks per held-out repo, BM25 top 32, state truncated to 256 tokens. Paired bootstrap over the tasks.

repo model Laya-only MRR RRF MRR RRF P@10 ECE (15 bins) AUROC pooled
moon laya-base 0.497 0.586 0.343 0.461 0.584
moon laya-code 0.526 0.519 0.398 0.060 0.677
pilot-space laya-base 0.519 0.762 0.323 0.509 0.536
pilot-space laya-code 0.646 0.714 0.393 0.016 0.709

Under this protocol, laya-code clearly improves calibration and discrimination. It puts more gold-file spans in the top 10: RRF P@10 rose by +0.055 (95% CI [0.013, 0.098]) on moon and by +0.070 ([0.033, 0.108]) on pilot-space. Its RRF MRR did not beat laya-base's: −0.066 ([−0.195, 0.061]) on moon and −0.049 ([−0.172, 0.073]) on pilot-space. For that reason, laya-codex fuses laya-code by score ((1−w)·lexical + w·P, w = 0.5) rather than by RRF.

End to end, the laya-codex paired Claude Code benchmark (20 moon tasks, docs/RESULTS.md) measured −45% code-reading tokens and −25% wall-clock time for the whole pipeline, with no loss of answer recall. The same document reports that the model's marginal contribution over lexical-only ranking is within run-to-run noise at n = 20. Do not read the pipeline numbers as a property of this model.

Intended use

  • Re-ranking lexical (BM25) candidates of source-code chunks for a natural-language software-change task, as a calibrated P(relevant).
  • Gating or fusing retrieval results by probability; P is calibrated to the training distribution (ECE ≤ 0.06 on held-out repos).

Out of scope and limitations

  • Weak labels. A commit touching a file does not make every window of it relevant, and the file-level gold is coarse.
  • Small evaluation. Each held-out set has 40 tasks, and most CIs are wide. The two protocols (128 vs 256 tokens, top 24 vs 32) give different absolute numbers, as shown above.
  • Low probabilities. P rarely exceeds 0.5 (max 0.49 on moon, 0.50 on pilot-space at 256 tokens). Use rank or score fusion, or a threshold near 0.4, not "P ≥ 0.5 means relevant".
  • Under-trained. Only about half an epoch of the v2 data was used, on a shared laptop. Validation AUROC was still rising when training stopped.
  • English prompts only. Training covered Rust, Python, TypeScript and JavaScript; other languages are untested.
  • Other tasks untested. It is not a general Laya replacement: choice/score questions (for example, task scope) were not trained, and zero-shot scope accuracy is poor (spike/results/scope_eval.json).
  • Too slow for interactive CPU use. At 421M parameters, CPU re-ranking of 24 candidates is too slow for interactive use. laya-codex runs it on Metal, or falls back to lexical ranking.
  • Legal status of training data. The model was trained on permissively licensed public code plus the author's own repositories. It is a classifier and cannot reproduce that code, but the legal status of weights trained on source code is not settled.

License and attribution

Apache-2.0, like the base model. laya-code is a Derivative Work of convaiinnovations/laya (Apache-2.0, © Convai Innovations), which builds on answerdotai/ModernBERT-large (Apache-2.0). The modified files are model.safetensors and rl_agent_config.json; every other file is unchanged from the base. See NOTICE.

Files

See MANIFEST.sha256 for the sha256 of every uploaded file.

Downloads last month
123
Safetensors
Model size
0.4B params
Tensor type
F32
·
F16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for tindang/laya-code

Finetuned
(176)
this model