viveCADer_revit_9B

A LoRA adapter that domain-specializes a 9B model for writing C# against the Autodesk Revit 2026 API, released together with the measurements it was evaluated under.

We built a training corpus of 76,100 supervised examples, an evaluation harness that compiles generated code against the real Revit 2026 assemblies, and trained a QLoRA adapter on a single consumer GPU. Measured on a 100-task held-out benchmark, the result is 21% pass@1, against 100% for a frontier generalist on the easy/medium slice. Fine-tuning produced a large, real improvement — a 16× lift in compile rate over the base — and did not reach production autonomy.

On the strength of those measurements we moved the work to a different layer: a deterministic compiler that owns API correctness, with the model emitting a typed intermediate representation instead of C#. That reasoning, with a worked example, is in §5.

The adapter, the evaluation method, two complete training records and a compile-verified KIR example are published here.


1. The task

The Revit API is proprietary and versioned. Code either compiles against RevitAPI.dll for a specific release or it does not; members present in Revit 2021 are gone by 2026. Plausible-looking Revit code is worse than no code — it reads as correct, fails at the API boundary, and costs an engineer an afternoon.

Frontier generalists write fluently but generically: they commonly target an older Revit version or call members that sound right and do not exist. The hypothesis under test was that a small model trained on a large volume of correct Revit 2026 code would outperform a large generalist on that narrow slice.

2. The corpus

The training set was 76,100 supervised examples (instruction → reasoning → C#), drawn from a 239,366-row ledger of which 95,030 were marked in-mix during assembly. A further 8,438 rows were held out as a validation split.

Of that, about 3% was hand-authored gold; over 40% was English breadth material scraped from documentation. A weighted sampler over-exposed the high-quality tiers, and loss was computed on assistant tokens only.

The dataset is not released. Representative rows follow so the quality bar is inspectable.

Hand-authored gold — Russian

[system] You are an expert Revit API developer. You write production-quality C# code for
         Autodesk Revit add-ins (.NET 8) and reason precisely about the Revit API,
         transactions, and BIM/IFC patterns.

[user]   Revit 2026: в одной транзакции присвоить параметру 'Стадия возведения'
         (BuiltInParameter.PHASE_CREATED) заданную стадию всем перекрытиям из переданного
         списка ElementId, с полным откатом, если хотя бы один элемент не найден или не
         является перекрытием. Прямая реализация.

[assistant]
    using Autodesk.Revit.Attributes;
    using Autodesk.Revit.DB;
    using Autodesk.Revit.UI;

    namespace SitePhasing
    {
        [Transaction(TransactionMode.Manual)]
        public class AssignFloorsPhase : IExternalCommand
        {
            public Result Execute(ExternalCommandData c, ref string msg, ElementSet e)
            {
                Document doc = c.Application.ActiveUIDocument.Document;
                var floorIds = new List<long> { 901001, 901002, 901003 };
                Phase phase = doc.Phases.Cast<Phase>().FirstOrDefault(p => p.Name == "...");
                ...

There were 2,319 rows at this standard.

Hand-authored gold — English

The strongest English row in the corpus. What makes it strong is that the model declines to accept the brief:

[user]   Working set: the lower-tier raker frame of a football stadium, modeled across 15 levels
         and 32 grids. The structural rebar package was issued last week; QA flagged an ~8%
         discrepancy between the scheduled reinforcement count and what the steel-fixing
         contractor takes off on site... The working hypothesis from the detailer is that during
         a recent family swap and re-host operation, some reinforcement sets lost or had their
         host association changed. Nothing here is yet confirmed: it could equally be a schedule
         filter problem or a genuine detailing omission. Your subgoal: forensically confirm
         whether reinforcement is orphaned from its concrete host, quantify the affected set, and
         repair only what is safe and reversible at the data layer. Decide the right move; notice
         what evidence is missing before touching anything.

         [tool_result] INFO  | -       | host_population    | concrete host members = 592
                       ERROR | 4815201 | rebar_orphan_host  | host pointer null/unbound
                       ERROR | 4818902 | rebar_orphan_host  | host id 4810050 does not resolve
                       WARN  | 4820113 | rebar_orphan_host  | host 4799820 not a concrete member
                                                              (resolved to 'Stair-Precast-Tread')
                       ...

[assistant]
    <think>
    Before assuming the detailer's "lost host" theory is right, I orient structure-first:
    reinforcement is a dependent member — it only has meaning relative to the concrete element it
    sits inside. So the audit must read, for every reinforcement set, the pointer that says which
    concrete member hosts it, and then test that pointer two ways. First: does the pointer resolve
    to a real, present element at all? Second: even if it resolves, is the thing it resolves to
    actually a load-carrying concrete member of the expected family, or has the re-host landed the
    bars on the wrong kind of element? I also want the population counts — because the reported ~8%
    discrepancy is my falsifiable anchor: if orphaned sets are nowhere near 8% of the population,
    the problem is more likely the schedule filter, not the host link. I deliberately keep this
    read-only and gather ids and the broken pointer values, so the later repair acts on evidence,
    not on the hypothesis. Confidence now is low; the audit decides it.
    </think>

    // READ-ONLY forensic audit: reinforcement host-association integrity. Mutates nothing.
    var hostCats = new[] {
        BuiltInCategory.OST_StructuralFraming,  BuiltInCategory.OST_StructuralColumns,
        BuiltInCategory.OST_StructuralFoundation, BuiltInCategory.OST_Walls };
    var validHosts = new HashSet<long>();
    foreach (var bic in hostCats)
        foreach (var e in new FilteredElementCollector(doc).OfCategory(bic)
                              .WhereElementIsNotElementType())
            validHosts.Add(e.Id.Value);
    ...
    var rebar = new FilteredElementCollector(doc)
        .OfCategory(BuiltInCategory.OST_Rebar).WhereElementIsNotElementType();

The row is 17,147 characters. The excerpt is trimmed for reading; the complete record is at examples/training_example_en_rebar_forensics.md.

The <think> block is handed a hypothesis by a senior detailer and declines to act on it. It converts the complaint into a falsifiable anchor — if the orphan count is not near 8%, the detailer is wrong and this is a schedule-filter problem instead. It runs the first pass read-only by design, so the repair acts on evidence rather than theory. It closes by naming its own confidence: "Confidence now is low; the audit decides it." The API underneath is real: OST_Rebar, OST_StructuralFraming, FilteredElementCollector, WhereElementIsNotElementType.

Compiled against the real Revit assemblies during preparation of this release: all three fragments build on 2024, 2025 and 2026, and fail on 2021–2023 (CS1503 — the row uses ElementId.Value, introduced in 2024). Legitimate for a Revit-2026 corpus, and worth noting: hand-written code carries a silent version dependency.

Reasoning over real buildings

The most substantial part of the corpus was derived from the project archive: 214 real IFC models of residential complexes across structural, architectural, façade, water, ventilation, heating, fire, electrical and low-current disciplines. Each was extracted into a fact store, and a record was authored per building × discipline containing explicit engineering reasoning together with the Revit C# that reconstructs it.

One record per complex × discipline rather than per file, by design: repeating a section twenty times manufactures near-duplicate material rather than knowledge. The 214 models were dispositioned as own-record, delta-covered-by-archetype, or skipped, producing 120 archetype records (structural 19, MEP 19, architectural 15, façade 67), of which 123 entered training.

A façade extraction, de-identified:

  Нужно восстановить в Revit наружную стеновую оболочку де-идентифицированной жилой
  секции по фасадной IFC-выгрузке, не превращая архитектурные фасадные слои в несущий
  монолит и не делая координатный дамп. Store-точно для этой части: 55 IfcWall, все
  семейства "Базовая стена", grade=null у всех 55; по уровню: 39 на "1 этаж (+1.200)",
  8 на "2 этаж", 8 на "4 этаж"...

reasoning

  **0. Главная развилка: это стеновая оболочка, а не КР-монолит.** В IFC категория
  `IfcWall` сама по себе не доказывает несущую стену. Здесь store-точные признаки
  говорят обратное: 55 стен, все family="Базовая стена", все grade=null; материалы —
  минеральная вата, окрашенный металл/рама и одна фасадная кассета, без B25/B30/B40 и
  без арматурной марки. Значит эта часть работает как архитектурная фасадная оболочка...
  Несущие диафрагмы и монолитные ядра, если они есть в здании, должны приходить из
  КР-модели. В этой записи их нельзя достраивать по слову "wall".

  **1. Что численно доказано, а где начинается реконструкция.** Store-точно: 55 стен;
  уровни 39/8/8; материалы 29/25/1; класс/grade отсутствует у всех 55...

tool_binding.revit_csharp
  public static class Bp02FacadeWallShell2026 { ... }

The reasoning declines to infer "load-bearing" from the word IfcWall, separates what the extraction proves numerically from where reconstruction begins, and marks reconstructed thicknesses as reconstructed (ThicknessReconstructed is a field in the emitted C#).

Above the per-discipline records sit trunk records: one whole building seen from one angle, synthesized across all its leaves. This is the architecture angle of a real complex — 12,787 characters of reasoning, 25,510 of code:

scenario  Подними взгляд со всех частных АР-листьев комплекса на уровень СТВОЛА и увидь ВСЁ
          ЗДАНИЕ С ОДНОГО РАКУРСА — как ЕДИНУЮ архитектурную программу целого... Store-точный
          массинг: пять фасадных секций одного комплекса с числом IfcBuildingStorey 14/18/14/34/34
          и числом фасадно-архитектурных элементов 294/351/547/1509/1461; верх секций
          +32.0/+44.2/+32.0/+96.0/+96.0 м. КОНТУРЫ секций store-точно РАЗНЫЕ (23.8x15.5 /
          24.1x15.8 / 58.5x16.4 / 21.5x33.0 / 21.3x33.0 м), мировые XY-якоря разбросаны по
          десяткам метров, но мировой Z-якорь у всех пяти 149.0...151.9 м — ОДНА геодезическая
          площадка/один стилобат.

reasoning С архитектурной стороны комплекс читается НЕ как две башни на подземном ярусе
          (архетип IL3) и НЕ как одно датум-тело со множеством крон (архетип ADMK), а как
          НЕСКОЛЬКО САМОСТОЯТЕЛЬНЫХ СЕКЦИЙ-ДОМОВ РАЗНОЙ ЭТАЖНОСТИ на ОДНОМ СТИЛОБАТЕ.
          Доказательство единства store-точное: мировой Z-якорь всех пяти секций 149.0...151.9 м
          (одна площадка, разброс ~3 м)... Их нельзя слить в одно усреднённое тело: и контуры
          разные, и XY-якоря разбросаны по десяткам метров.

          ПРОДУКТОВЫЙ ДУАЛИЗМ ВНУТРИ ЖИЛЬЯ — самая сильная архитектурная истина комплекса.
          Store-точно сосуществуют ДВА продуктовых сегмента: «Кухня-ниша» 67 (евро/студийный,
          медиана 4.72 м²) и «Кухня-столовая» 29 (семейная классика, медиана 22.29 м²).
          Пятикратный разрыв медиан...

That single record is 42,685 characters. Full text at examples/training_example_ru_whole_building_trunk.md; its C# compiles on Revit 2021, 2024 and 2026.

The model classifies the massing against two archetypes it knows and rejects both; proves "one complex, not five buildings" from world-Z anchors agreeing within 3 m while XY anchors scatter by tens of metres; and identifies that two apartment products — a studio line and a family line — are being sold inside the same building, with a fivefold gap in kitchen area.

Every figure is marked store-точно (store-exact): it came from the extraction, not the model. Where the model reconstructs rather than reads, it says so. The record also carries a section warning against false precision — the number field is per-room rather than per-apartment, the naive area total includes commercial and core, the level field is broken in every section and geometry must be used instead — and a closing "honest boundaries" section separating store-exact from reconstructed.

The breadth layer

For contrast, the material that made up the bulk of the corpus:

[user]   What is `BuiltInFailures.CurtainWallFailures.RequestOrphanMullionDeletion`
         in the Revit API and what does it do?

[assistant]
    Due to the changes in parameters of their hosts some mullions became non-type driven.

    public static FailureDefinitionId RequestOrphanMullionDeletion { get; }

A documentation fragment with a signature attached: vocabulary rather than engineering. There were 30,973 rows of this kind. Among English rows specifically, only 6.5% reach the top weight band while 78.2% sit at the lowest.

Two properties of the corpus are worth stating directly. Roughly 3% was hand-authored gold, so the quality ceiling was set by a small minority of rows. And part of that gold was minted under "executed without error", which is not the same as "correct" — plausible-but-wrong examples are learnable.

3. Method

Data verification. Before training, automated workers checked every C# record against the real Revit 2026 API surface and the shipped DLLs, repairing what was mechanically repairable and escalating the rest. Several hundred records were returned as requiring human judgment. This raises a floor; it does not create depth.

Evaluation, built before the model.

  • Compile oracle. Generated C# is compiled against the actual Revit 2026 assemblies. Pass/fail is a fact rather than an opinion.
  • API-existence oracle. A static check that every class and member invoked exists in the 2026 surface, targeting the dominant failure mode — hallucinated or version-drifted API.
  • 132-probe battery with a three-judge adversarial panel for properties a compiler cannot see: reasoning soundness, agentic behaviour, safety. Passing requires ≥2/3, defaulting to fail.
  • Floor-to-ceiling anchoring. The untuned base sets the floor; a frontier model and reference gold set the ceiling.

Training. QLoRA on one RTX 4090 (24 GB) at ~$0.34–0.38/hour, base frozen in 4-bit NF4, adapters in bf16.

base            Qwen3.5-9B (Apache-2.0) -> MIT code-specialized derivative -> this adapter
quantization    4-bit NF4, double quant, bf16 compute
LoRA            r=128, alpha=256, dropout=0.05, all linear projections
optimizer       lr 5e-5, cosine schedule, warmup 0.03, seed 42
batching        batch 1 x grad-accum 8, sequence length 1,280
loss            assistant tokens only, packing off
sampler         WeightedRandomSampler over curation-tier weights

These values are read from this adapter's own training_args.bin, included in the repository. Sequence length was not constant across the project: it ranged from 768 to 8,192 across runs, traded against what fit in 24 GB, because longer records did not fit at shorter settings. The value above is the published adapter's final stage.

On the validation split. The run used eval_strategy="no" by design. Validation loss reports that a model predicts held-out text less well; it does not report whether the code compiles. Early stopping was driven by the target property instead: checkpoints were pulled every 500 steps and graded for compile pass@1 on held-out tasks, with the run ending when that curve plateaued or the reasoning axis regressed. On rented hardware this is also the cheaper instrument. The cost of the choice: no overfitting alarm during the run.

Reproducibility note. Qwen3.5's linear-attention layers require bf16 and a fused causal_conv1d kernel and do not train validly on Turing-class GPUs. Reaching a valid configuration on free T4s took roughly a dozen attempts across dtype and kernel issues before bf16 with the correct causal_conv1d wheel trained correctly.

4. Results

DEV-RC-100 — 100 held-out tasks, 63% of them hard, each compiled against real Revit 2026. PASS@1 = compiles and signal coverage ≥0.6 and no forbidden legacy API. No judge participates in this number.

metric this model
compile rate 22/100 (22%)
PASS@1 21/100 (21%)
mean signal coverage 0.713
API-existence fidelity 93.2%
forbidden legacy-API calls 1/100

By difficulty:

difficulty compiles
easy (9 tasks) 7/9 — 78%
medium (28 tasks) 6/28 — 21%
hard (63 tasks) 9/63 — 14%

Strong on the common surface; falls away on MEP, structural, Toposolid, geometry and worksharing — the disciplines where the corpus was thinnest.

Against a frontier generalist (cold, single-shot, 30 easy/medium tasks):

PASS@1 compile API-fidelity easy (9) medium (15)
Frontier generalist (Claude Opus) 30/30 (100%) 100% 93.8% 9/9 15/15
this model 14/30 (47%) 47% 83% 7/9 4/15

Easy: 7/9 against 9/9. Medium: 4/15 against 15/15.

Effect of fine-tuning (held-out rc01–40):

compile PASS@1 signal coverage API-fidelity
base, untuned 2% 0% 0.50 59%
after fine-tuning 32% 30% 0.82 80%

A 16× improvement in compile rate. Note also the gap the oracle exposes: a naive signal-matching metric scores this model at 82% where the compiler reports 32%.

With a self-repair loop (compiler errors returned, K=3, rc01–30): 47% → 70% (47 → 60 → 67 → 70). These figures come from an earlier scoring pass and were not re-measured under the final contract.

Earlier 80-step pilot, on the 132-probe battery, for the axes a compiler cannot see:

axis base pilot frontier reference gold
code compiles 1.4% 6.8% 84.8% 97.5%
answers with code, not prose 7/132 38/132
hallucinated API 1.5% 0% 5%
recognizes out-of-scope requests 0% 33.3% 100%
safety / robustness 8.3% 16.7% 91.7%
reasoning soundness 7.1% 0.0% 92.9%
agentic (multi-turn / tool use) 0% 0% 71.4%

Every axis improved except reasoning soundness, which fell to zero: the pilot acquired the shape of a correct answer while losing its substance. A compile-rate-only dashboard would have shown a rising line throughout. This is a different model and benchmark from the headline results and is reported separately.

5. Conclusion, and where the work went

Four findings determined the direction taken.

  1. The binding constraint was corpus composition, not parameter count. 3% hand-authored gold and 40% English breadth is not a specialist corpus. What these measurements establish is that this corpus does not carry a model to production quality — not that the architecture cannot.
  2. Compile-only metrics are misleading. Compile rate rose 5× in the pilot while reasoning soundness fell to zero.
  3. A verifier returns more than additional parameters. The compile oracle exposed the 82%-vs-32% gap between "looks right" and "is right"; every subsequent decision came from measurement infrastructure.
  4. Frontier generalists are strong on this task — 100% on easy/medium, cold, single-shot, without domain fine-tuning. Specialization has to exceed that, not the untuned base.

Taken together, these point at where correctness should live. Training a model to recall an API teaches it to be probably right. A building model does not tolerate probably-right code: one wrong unit conversion or one transaction without rollback silently corrupts a real project.

So the work moved into a deterministic compiler. The model plans and emits a typed intermediate representation; the compiler — not the network — owns units, transactions, version differences and correctness. Wrong code stops being unlikely and becomes unrepresentable. Where the compiler does not cover a case it refuses in a typed way with a route, rather than guessing.

The same construction, both ways

A wall with a window in it. In KIR, the model writes:

{
  "ir_version": "1.0",
  "intent": "Наружная стена 6 м с окном",
  "ops": [
    {"op": "create_level",  "id": "L1", "elev_mm": 0, "name": "Этаж 1"},
    {"op": "create_wall",   "id": "W1", "p0_mm": [0, 0], "p1_mm": [6000, 0],
                            "level": {"by": "ref", "value": "L1"}, "height_mm": 3000},
    {"op": "create_window", "id": "N1", "host": {"by": "ref", "value": "W1"},
                            "offset_mm": 2500, "sill_mm": 900}
  ]
}

336 characters. Millimetres, because buildings are described in millimetres. The window attaches to the wall by reference at 2500 mm along it, sill at 900. Every number is a design decision.

The compiler produces 10,010 characters — 193 lines of C#. Both files are in examples/, and the emitted file compiles against the real Revit assemblies on all six versions, 2021 through 2026 (6/6). An extract:

double U(double mm) => UnitUtils.ConvertToInternalUnits(mm, UnitTypeId.Millimeters);
...
using (Transaction __t = new Transaction(doc, "KIR: Наружная стена 6 м с окном"))
    var __startStatus = __t.Start();
    if (__startStatus != TransactionStatus.Started)
        return __Refuse("$program", "transaction start status: " + __startStatus);
...
    if (__wt_W1 == null) { __t.RollBack(); return __Refuse("W1", "в документе нет типа стены по умолчанию"); }
    if (__el_W1 == null) { __t.RollBack(); return __Refuse("W1", "Wall.Create вернул null"); }
    if (!__sy_N1.IsActive) { __sy_N1.Activate(); doc.Regenerate(); }
    __hl_N1 = doc.GetElement(__el_W1.LevelId) as Level;
    if (__hl_N1 == null) { __t.RollBack(); return __Refuse("N1", "уровень стены-хоста не найден"); }
    XYZ __pt_N1 = new XYZ(U(2500.0), U(0.0), __hl_N1.Elevation + U(900.0));
    __el_N1 = doc.Create.NewFamilyInstance(__pt_N1, __sy_N1, __el_W1, __hl_N1,
                  Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
...
    doc.Regenerate();
    if (Math.Abs(__loc.Point.Z - (__hl_N1.Elevation + U(900.0))) > U(10.0))
        __post.Add("N1: location/sill mismatch (geometry)");

Unit conversion at every boundary, transaction start-status checking, rollback on every null return, symbol activation followed by regeneration, resolution of the window's level from its host wall, and a post-regeneration read-back comparing the built element against the request to within 10 mm with a full rollback on disagreement.

None of that is design work. All of it is where a language model makes mistakes — and all of it is what the fine-tuned model was being asked to reproduce from memory.

Which representation is easier to generate

Tokenized with this repository's own tokenizer:

target characters tokens
KIR program 336 132
emitted C# 10,010 3,125

23.7× fewer tokens for the same construction, compounding three ways:

  1. Fewer opportunities for error. Autoregressive generation fails per token; in C#, one wrong identifier anywhere in 3,125 tokens fails the build.
  2. Error classes cease to exist. KIR's grammar is generated from the op registry, so the schema is closed and constrained decoding applies: an invented API member is unrepresentable rather than unlikely. In production logs over seven weeks, CS1061 + CS0117 — calling a member that does not exist — accounted for 48.4% of 85,374 compile errors, with a further ~10% (CS0104/CS0012) attributable to namespace and using-directive problems the compiler now owns. Approximately 60% of production compile errors become structurally impossible on this path.
  3. The remaining tokens are the design. Every number in the KIR program is an engineering decision; none of it is StructuralType.NonStructural.

Current state of that compiler

Measured, as of this release:

  • 35 typed operations in the registry; the gate compiles 94 programs × 6 Revit versions (2021–2026) with zero refusals.
  • 26 of 28 write operations proven in live Revit, not only compile-gated.
  • One grouping operation covers up to 819,200 elements; measured, 200,200 elements compiled in 0.1 s into 1.35 MB of C#.
  • A twisted, tapering forty-storey tower is one operation with a transform, not forty copies.
  • Live on a real project: ~11,300 elements built end to end (40 levels, 120 arc walls, 3,920 frame elements, 7,200 fill).
  • Reconstruction coverage on two unrelated real buildings: 92.83% and 93.28% — a 0.45-point spread, meaning the figure describes the compiler rather than the project.

Version two

A model trained on a small verified KIR + reasoning corpus rather than 76,100 rows of scraped C#. A shorter, closed-vocabulary, schema-validated target should be learnable from substantially less data, and every sample can be compiler-checked before entering the corpus — which removes the "executed ≠ correct" failure described in §2. This expectation has not yet been measured; when it has, the numbers will be published in the same form as these.

6. Contents and intended use

A LoRA adapter, not a standalone model — the base is required to run it.

Adapter LoRA r=128, α=256, dropout 0.05, all linear projections, 692 MB (346M trainable)
Base Qwen3.5-9B (Apache-2.0) → an MIT-licensed code-specialized derivative → this domain layer
Task Russian modeling instruction → C# for the Revit 2026 API
Included adapter, tokenizer, training_args.bin, two complete training records, the KIR worked example
Not included the dataset

Appropriate uses: research on domain specialization for proprietary versioned APIs; a component behind a verifier, with a compile gate and repair loop between it and the user; a baseline to improve on.

Not appropriate: autonomous generation of correct Revit C# on non-trivial tasks (21% pass@1); agentic operation (0% on that axis, never a training target); MEP, structural or worksharing work (14% on the hard slice).

Safety. Generated code executes against live BIM models. Run it inside a transaction with rollback, on a disposable copy, with human review. Do not point it at a production model.

Data provenance. The corpus contains a small amount of third-party technical prose. Measured by explicit source attribution within the 76,100 rows: technical blogs 704 (0.93%), Autodesk University handouts 241 (0.32%), forums 212 (0.28%), revitapidocs 62 (0.08%), Autodesk help 36 (0.05%) — union ≈1,100–1,200 rows ≈ 1.5%, a lower bound, since it detects rows where the source is named. For the avoidance of one misreading: the string "Autodesk" appears in 82% of rows because it is the API namespace Autodesk.Revit.DB, not a measure of Autodesk prose.

Reproducing the evaluation. The benchmark is published in benchmark/: all 100 tasks, the scorer, the frozen manifest with pinned hashes, and the complete per-item report the headline numbers are taken from. Pass criteria are deterministic — compile against the real Revit 2026 assemblies, signal coverage ≥0.6, no forbidden legacy API — with no judge involved.

Note its status honestly: the manifest classifies DEV-RC-100 as a development diagnostic, visible to the training program, not a private held-out. It is reproducible and directionally informative, not an uncontaminated benchmark. To re-run it you must supply RevitAPI.dll / RevitAPIUI.dll from your own Revit installation; those are Autodesk's and are not redistributable.

Links

@misc{vivecader_revit_9b_2026,
  title  = {viveCADer_revit_9B: compile-verified evaluation of a domain-specialized
            9B model for Revit 2026 C#},
  author = {kuklev},
  year   = {2026},
  url    = {https://huggingface.co/kuklev9797/viveCADer_revit_9B}
}

License: MIT, following the base model. See the provenance note above.



RU

viveCADer_revit_9B

LoRA-адаптер, доменно специализирующий 9B-модель под написание C# для Autodesk Revit 2026 API, опубликованный вместе с измерениями, по которым он оценивался.

Мы собрали обучающий корпус из 76 100 примеров, построили стенд, компилирующий сгенерированный код против настоящих сборок Revit 2026, и обучили QLoRA-адаптер на одной потребительской видеокарте. На held-out бенчмарке из 100 задач результат — 21% pass@1 против 100% у фронтир-универсала на лёгком и среднем срезе. Дообучение дало крупный реальный прирост — компилируемость выросла в 16 раз относительно базы — и не довело до продакшн-автономности.

По итогам этих измерений работа была перенесена на другой слой: детерминированный компилятор, который владеет корректностью API, а модель выдаёт типизированное промежуточное представление вместо C#. Обоснование с рабочим примером — в §5.

Здесь опубликованы адаптер, метод оценки, две полные обучающие записи и проверенный компиляцией KIR-пример.


1. Задача

API Revit проприетарный и версионный. Код либо компилируется против RevitAPI.dll конкретного релиза, либо нет; члены, присутствовавшие в Revit 2021, к 2026 исчезают. Правдоподобно выглядящий Revit-код хуже отсутствия кода: он читается как верный, ломается на границе API и стоит инженеру полдня.

Фронтир-универсалы пишут бегло, но обобщённо: регулярно целятся в старую версию Revit или зовут члены, которые звучат правильно и не существуют. Проверялась гипотеза, что маленькая модель, обученная на большом объёме корректного кода под Revit 2026, обойдёт крупного универсала на этом узком срезе.

2. Корпус

Обучающий набор — 76 100 примеров «инструкция → рассуждение → C#», отобранных из реестра на 239 366 строк, из которых 95 030 были помечены «в миксе» при сборке. Ещё 8 438 строк отложены как валидационный сплит.

Из них около 3% — рукописное золото; больше 40% — англоязычная широта, соскрапленная из документации. Взвешенный сэмплер поднимал качественные слои, лосс считался только по токенам ассистента.

Датасет не публикуется. Ниже — репрезентативные строки, чтобы планка качества была видна.

Рукописное золото — русское

[system] You are an expert Revit API developer. You write production-quality C# code for
         Autodesk Revit add-ins (.NET 8) and reason precisely about the Revit API,
         transactions, and BIM/IFC patterns.

[user]   Revit 2026: в одной транзакции присвоить параметру 'Стадия возведения'
         (BuiltInParameter.PHASE_CREATED) заданную стадию всем перекрытиям из переданного
         списка ElementId, с полным откатом, если хотя бы один элемент не найден или не
         является перекрытием. Прямая реализация.

[assistant]
    using Autodesk.Revit.Attributes;
    using Autodesk.Revit.DB;
    using Autodesk.Revit.UI;

    namespace SitePhasing
    {
        [Transaction(TransactionMode.Manual)]
        public class AssignFloorsPhase : IExternalCommand
        {
            public Result Execute(ExternalCommandData c, ref string msg, ElementSet e)
            {
                Document doc = c.Application.ActiveUIDocument.Document;
                var floorIds = new List<long> { 901001, 901002, 901003 };
                Phase phase = doc.Phases.Cast<Phase>().FirstOrDefault(p => p.Name == "...");
                ...

Строк такого уровня было 2 319.

Рукописное золото — английское

Сильнейшая английская строка корпуса. Сильна тем, что модель отказывается принять постановку на веру:

[user]   Working set: the lower-tier raker frame of a football stadium, modeled across 15 levels
         and 32 grids. The structural rebar package was issued last week; QA flagged an ~8%
         discrepancy between the scheduled reinforcement count and what the steel-fixing
         contractor takes off on site... The working hypothesis from the detailer is that during
         a recent family swap and re-host operation, some reinforcement sets lost or had their
         host association changed. Nothing here is yet confirmed: it could equally be a schedule
         filter problem or a genuine detailing omission. Your subgoal: forensically confirm
         whether reinforcement is orphaned from its concrete host, quantify the affected set, and
         repair only what is safe and reversible at the data layer. Decide the right move; notice
         what evidence is missing before touching anything.

         [tool_result] INFO  | -       | host_population    | concrete host members = 592
                       ERROR | 4815201 | rebar_orphan_host  | host pointer null/unbound
                       ERROR | 4818902 | rebar_orphan_host  | host id 4810050 does not resolve
                       WARN  | 4820113 | rebar_orphan_host  | host 4799820 not a concrete member
                                                              (resolved to 'Stair-Precast-Tread')
                       ...

[assistant]
    <think>
    Before assuming the detailer's "lost host" theory is right, I orient structure-first:
    reinforcement is a dependent member — it only has meaning relative to the concrete element it
    sits inside. So the audit must read, for every reinforcement set, the pointer that says which
    concrete member hosts it, and then test that pointer two ways. First: does the pointer resolve
    to a real, present element at all? Second: even if it resolves, is the thing it resolves to
    actually a load-carrying concrete member of the expected family, or has the re-host landed the
    bars on the wrong kind of element? I also want the population counts — because the reported ~8%
    discrepancy is my falsifiable anchor: if orphaned sets are nowhere near 8% of the population,
    the problem is more likely the schedule filter, not the host link. I deliberately keep this
    read-only and gather ids and the broken pointer values, so the later repair acts on evidence,
    not on the hypothesis. Confidence now is low; the audit decides it.
    </think>

    // READ-ONLY forensic audit: reinforcement host-association integrity. Mutates nothing.
    var hostCats = new[] {
        BuiltInCategory.OST_StructuralFraming,  BuiltInCategory.OST_StructuralColumns,
        BuiltInCategory.OST_StructuralFoundation, BuiltInCategory.OST_Walls };
    var validHosts = new HashSet<long>();
    foreach (var bic in hostCats)
        foreach (var e in new FilteredElementCollector(doc).OfCategory(bic)
                              .WhereElementIsNotElementType())
            validHosts.Add(e.Id.Value);
    ...
    var rebar = new FilteredElementCollector(doc)
        .OfCategory(BuiltInCategory.OST_Rebar).WhereElementIsNotElementType();

Строка занимает 17 147 символов. Выдержка сокращена для чтения, полная запись — examples/training_example_en_rebar_forensics.md.

Блоку <think> подаётся гипотеза старшего детейлера, и он отказывается по ней действовать. Он превращает жалобу в фальсифицируемый якорь: если сирот не около 8%, детейлер неправ и проблема в фильтре спецификации. Первый проход идёт read-only намеренно, чтобы починка действовала по уликам, а не по теории. Завершается оценкой собственной уверенности: «Уверенность сейчас низкая; решает аудит». API под этим настоящий: OST_Rebar, OST_StructuralFraming, FilteredElementCollector, WhereElementIsNotElementType.

Скомпилировано против настоящих сборок при подготовке релиза: все три фрагмента собираются на 2024, 2025 и 2026 и падают на 2021–2023 (CS1503 — используется ElementId.Value, появившийся в 2024). Для корпуса под Revit 2026 это законно и стоит отметить: рукописный код несёт молчаливую версионную зависимость.

Рассуждение по реальным зданиям

Самая содержательная часть корпуса получена из проектного архива: 214 реальных IFC-моделей жилых комплексов по разделам конструктив, архитектура, фасад, вода, вентиляция, тепло, пожарные, электрика, слаботочка. Каждая извлечена в фактовый store, и по каждому зданию × дисциплине авторизована запись с явным инженерным рассуждением и Revit-C#, который это восстанавливает.

Одна запись на комплекс × дисциплину, а не на файл — намеренно: двадцатикратный повтор одной секции производит near-duplicate материал, а не знание. 214 моделей были диспозиционированы как своя-запись / дельта-покрыта-архетипом / пропуск, что дало 120 архетип-записей (конструктив 19, MEP 19, архитектура 15, фасад 67), из которых 123 вошли в обучение.

Фасадная выгрузка, деидентифицировано:

  Нужно восстановить в Revit наружную стеновую оболочку де-идентифицированной жилой
  секции по фасадной IFC-выгрузке, не превращая архитектурные фасадные слои в несущий
  монолит и не делая координатный дамп. Store-точно для этой части: 55 IfcWall, все
  семейства "Базовая стена", grade=null у всех 55; по уровню: 39 на "1 этаж (+1.200)",
  8 на "2 этаж", 8 на "4 этаж"...

reasoning

  **0. Главная развилка: это стеновая оболочка, а не КР-монолит.** В IFC категория
  `IfcWall` сама по себе не доказывает несущую стену. Здесь store-точные признаки
  говорят обратное: 55 стен, все family="Базовая стена", все grade=null; материалы —
  минеральная вата, окрашенный металл/рама и одна фасадная кассета, без B25/B30/B40 и
  без арматурной марки. Значит эта часть работает как архитектурная фасадная оболочка...
  Несущие диафрагмы и монолитные ядра, если они есть в здании, должны приходить из
  КР-модели. В этой записи их нельзя достраивать по слову "wall".

  **1. Что численно доказано, а где начинается реконструкция.** Store-точно: 55 стен;
  уровни 39/8/8; материалы 29/25/1; класс/grade отсутствует у всех 55...

tool_binding.revit_csharp
  public static class Bp02FacadeWallShell2026 { ... }

Рассуждение отказывается выводить «несущая» из слова IfcWall, отделяет доказанное извлечением от того, где начинается реконструкция, и помечает реконструированные толщины как реконструированные (ThicknessReconstructed — поле в эмитируемом C#).

Над подисциплинными записями стоят записи-«стволы»: одно здание целиком, увиденное с одной стороны, синтезированное по всем его листьям. Это архитектурный ракурс реального комплекса — 12 787 символов рассуждения, 25 510 кода:

scenario  Подними взгляд со всех частных АР-листьев комплекса на уровень СТВОЛА и увидь ВСЁ
          ЗДАНИЕ С ОДНОГО РАКУРСА — как ЕДИНУЮ архитектурную программу целого... Store-точный
          массинг: пять фасадных секций одного комплекса с числом IfcBuildingStorey 14/18/14/34/34
          и числом фасадно-архитектурных элементов 294/351/547/1509/1461; верх секций
          +32.0/+44.2/+32.0/+96.0/+96.0 м. КОНТУРЫ секций store-точно РАЗНЫЕ (23.8x15.5 /
          24.1x15.8 / 58.5x16.4 / 21.5x33.0 / 21.3x33.0 м), мировые XY-якоря разбросаны по
          десяткам метров, но мировой Z-якорь у всех пяти 149.0...151.9 м — ОДНА геодезическая
          площадка/один стилобат.

reasoning С архитектурной стороны комплекс читается НЕ как две башни на подземном ярусе
          (архетип IL3) и НЕ как одно датум-тело со множеством крон (архетип ADMK), а как
          НЕСКОЛЬКО САМОСТОЯТЕЛЬНЫХ СЕКЦИЙ-ДОМОВ РАЗНОЙ ЭТАЖНОСТИ на ОДНОМ СТИЛОБАТЕ.
          Доказательство единства store-точное: мировой Z-якорь всех пяти секций 149.0...151.9 м
          (одна площадка, разброс ~3 м)... Их нельзя слить в одно усреднённое тело: и контуры
          разные, и XY-якоря разбросаны по десяткам метров.

          ПРОДУКТОВЫЙ ДУАЛИЗМ ВНУТРИ ЖИЛЬЯ — самая сильная архитектурная истина комплекса.
          Store-точно сосуществуют ДВА продуктовых сегмента: «Кухня-ниша» 67 (евро/студийный,
          медиана 4.72 м²) и «Кухня-столовая» 29 (семейная классика, медиана 22.29 м²).
          Пятикратный разрыв медиан...

Одна эта запись — 42 685 символов. Полный текст — examples/training_example_ru_whole_building_trunk.md; её C# компилируется на Revit 2021, 2024 и 2026.

Модель классифицирует массинг против двух известных ей архетипов и отвергает оба; доказывает «один комплекс, а не пять зданий» тем, что мировые Z-якоря сходятся в пределах 3 м, пока XY разбросаны на десятки метров; и выявляет, что внутри одного дома продаются два продукта — студийная линейка и семейная — с пятикратным разрывом по площади кухни.

Каждое число помечено store-точно: оно пришло из извлечения, а не из модели. Там, где модель реконструирует, а не читает, она это говорит. В записи есть и раздел о ложной точности: поле number по-комнатное, а не по-квартирное; наивный ТЭП включает коммерцию и ядро; поле level сломано во всех секциях, строить надо по геометрии; плюс финальные «честные границы», отделяющие store-точное от реконструированного.

Слой широты

Для контраста — материал, составлявший основную массу корпуса:

[user]   What is `BuiltInFailures.CurtainWallFailures.RequestOrphanMullionDeletion`
         in the Revit API and what does it do?

[assistant]
    Due to the changes in parameters of their hosts some mullions became non-type driven.

    public static FailureDefinitionId RequestOrphanMullionDeletion { get; }

Фрагмент документации с приклеенной сигнатурой: словарь, а не инженерия. Таких строк было 30 973. Среди английских строк верхний весовой диапазон занимают лишь 6.5%, а 78.2% сидят в нижнем.

Два свойства корпуса стоит назвать прямо. Рукописного золота около 3%, то есть потолок качества задавало меньшинство строк. И часть этого золота чеканилась по критерию «исполнилось без ошибки», который не тождествен «правильно» — правдоподобно-неверные примеры выучиваются.

3. Метод

Верификация данных. До обучения автоматические воркеры сверили каждую C#-запись с настоящей поверхностью API Revit 2026 и поставляемыми DLL, починив механически починимое и эскалировав остальное. Несколько сотен записей вернулись как требующие человеческого суждения. Это поднимает пол, но не создаёт глубину.

Оценка, построенная до модели.

  • Компиляционный оракул. Сгенерированный C# компилируется против настоящих сборок Revit 2026. Прошёл или нет — факт, а не мнение.
  • Оракул существования API. Статическая проверка, что каждый вызванный класс и член существует в поверхности 2026 — бьёт в главный провал, галлюцинированный и дрейфующий API.
  • Батарея из 132 проб с состязательной панелью из трёх судей — для свойств, которых компилятор не видит: здравость рассуждения, агентность, безопасность. Проход при ≥2/3, по умолчанию «провал».
  • Закрепление пол↔потолок. Необученная база задаёт пол, фронтир и эталонное золото — потолок.

Обучение. QLoRA на одной RTX 4090 (24 ГБ) по ~$0.34–0.38/час, база заморожена в 4-bit NF4, адаптеры в bf16.

база            Qwen3.5-9B (Apache-2.0) -> MIT код-специализированный дериватив -> этот адаптер
квантование     4-bit NF4, double quant, вычисления bf16
LoRA            r=128, alpha=256, dropout=0.05, все линейные проекции
оптимизатор     lr 5e-5, cosine, warmup 0.03, seed 42
батчи           batch 1 x grad-accum 8, длина последовательности 1 280
лосс            только по токенам ассистента, packing выключен
сэмплер         WeightedRandomSampler по весам слоёв курации

Значения прочитаны из собственного training_args.bin этого адаптера, включённого в репозиторий. Длина последовательности по ходу проекта не была постоянной: от 768 до 8 192 от прогона к прогону — её меняли против того, что влезало в 24 ГБ, поскольку длинные записи на коротких настройках не помещались. Приведённое значение относится к финальной стадии опубликованного адаптера.

О валидационном сплите. Прогон шёл с eval_strategy="no" намеренно. Валидационный лосс сообщает, что модель хуже предсказывает отложенный текст; он не сообщает, компилируется ли код. Ранняя остановка велась по целевому свойству: чекпойнты снимались каждые 500 шагов и оценивались по compile pass@1 на отложенных задачах, прогон завершался при выходе кривой на плато или регрессии оси рассуждения. На арендованном железе это ещё и более дешёвый инструмент. Цена решения: отсутствие сигнала переобучения по ходу прогона.

Замечание о воспроизводимости. Слои линейного внимания Qwen3.5 требуют bf16 и фьюзд-ядра causal_conv1d и валидно не обучаются на GPU поколения Turing. Выход на рабочую конфигурацию на бесплатных T4 занял около десятка попыток по типам данных и ядрам, прежде чем bf16 с корректным колесом causal_conv1d заработал.

4. Результаты

DEV-RC-100 — 100 held-out задач, 63% из них сложные, каждая компилируется против настоящего Revit 2026. PASS@1 = компилируется и покрытие сигналов ≥0.6 и нет запрещённого legacy-API. Судьи в этом числе не участвуют.

метрика модель
компилируемость 22/100 (22%)
PASS@1 21/100 (21%)
среднее покрытие сигналов 0.713
попадание в существующий API 93.2%
вызовов запрещённого legacy-API 1/100

По сложности:

сложность компилируется
лёгкие (9) 7/9 — 78%
средние (28) 6/28 — 21%
сложные (63) 9/63 — 14%

Сильно на массовой поверхности; спадает на ОВ/ВК, конструктиве, Toposolid, геометрии и совместной работе — там, где корпус был тоньше всего.

Против фронтир-универсала (холодно, один проход, 30 лёгких/средних задач):

PASS@1 компиляция API-fidelity лёгкие (9) средние (15)
Фронтир (Claude Opus) 30/30 (100%) 100% 93.8% 9/9 15/15
эта модель 14/30 (47%) 47% 83% 7/9 4/15

Лёгкие: 7/9 против 9/9. Средние: 4/15 против 15/15.

Эффект дообучения (held-out rc01–40):

компиляция PASS@1 покрытие API-fidelity
база, без дообучения 2% 0% 0.50 59%
после дообучения 32% 30% 0.82 80%

Рост компилируемости в 16 раз. Отдельно — разрыв, который вскрывает оракул: наивная метрика по совпадению сигналов даёт 82% там, где компилятор сообщает 32%.

С петлёй саморемонта (ошибки компилятора возвращаются, K=3, rc01–30): 47% → 70% (47 → 60 → 67 → 70). Эти цифры получены более ранним прогоном оценки и не перемерены под финальным контрактом.

Ранний 80-шаговый пилот на батарее из 132 проб — по осям, которых компилятор не видит:

ось база пилот фронтир эталон
код компилируется 1.4% 6.8% 84.8% 97.5%
отвечает кодом, а не прозой 7/132 38/132
галлюцинации API 1.5% 0% 5%
распознаёт запрос вне скоупа 0% 33.3% 100%
безопасность / устойчивость 8.3% 16.7% 91.7%
здравость рассуждения 7.1% 0.0% 92.9%
агентность (мультитёрн / тулы) 0% 0% 71.4%

Выросли все оси, кроме здравости рассуждения, которая упала в ноль: пилот приобрёл форму правильного ответа, потеряв его суть. Дашборд «только компилируемость» показывал бы всё это время растущую линию. Это другая модель и другой бенчмарк, чем в заголовочных результатах, и приводятся они отдельно.

5. Вывод и куда перешла работа

Направление определили четыре результата.

  1. Связывающим ограничением был состав корпуса, а не число параметров. 3% рукописного золота и 40% англоязычной широты — это не специализированный корпус. Измерения устанавливают, что данный корпус не доводит модель до продакшн-качества, а не что архитектура на это неспособна.
  2. Метрики «только компилируемость» вводят в заблуждение. В пилоте компилируемость выросла впятеро, пока здравость рассуждения падала в ноль.
  3. Верификатор даёт больше, чем дополнительные параметры. Компиляционный оракул вскрыл разрыв 82% против 32% между «выглядит правильно» и «правильно»; все последующие решения пришли из измерительной инфраструктуры.
  4. Фронтир-универсалы на этой задаче сильны — 100% на лёгком и среднем, холодно, за один проход, без доменного дообучения. Специализация должна превосходить это, а не необученную базу.

Вместе они указывают, где должна жить корректность. Обучение модели помнить API учит её быть вероятно правой. Модель здания вероятно-правильный код не терпит: одна неверная конверсия единиц или одна транзакция без отката молча портит реальный проект.

Поэтому работа перешла в детерминированный компилятор. Модель планирует и выдаёт типизированное промежуточное представление; единицами, транзакциями, версионными различиями и корректностью владеет компилятор, а не сеть. Неверный код перестаёт быть маловероятным и становится невыразимым. Там, где компилятор случай не покрывает, он отказывает типизированно и с маршрутом, а не угадывает.

Одна и та же конструкция в двух видах

Стена с окном. В KIR модель пишет:

{
  "ir_version": "1.0",
  "intent": "Наружная стена 6 м с окном",
  "ops": [
    {"op": "create_level",  "id": "L1", "elev_mm": 0, "name": "Этаж 1"},
    {"op": "create_wall",   "id": "W1", "p0_mm": [0, 0], "p1_mm": [6000, 0],
                            "level": {"by": "ref", "value": "L1"}, "height_mm": 3000},
    {"op": "create_window", "id": "N1", "host": {"by": "ref", "value": "W1"},
                            "offset_mm": 2500, "sill_mm": 900}
  ]
}

336 символов. Миллиметры, потому что здания описывают в миллиметрах. Окно привязано к стене ссылкой на 2500 мм вдоль неё, подоконник на 900. Каждое число — проектное решение.

Компилятор производит 10 010 символов — 193 строки C#. Оба файла лежат в examples/, и эмитированный файл компилируется против настоящих сборок Revit на всех шести версиях, 2021–2026 (6/6). Выдержка:

double U(double mm) => UnitUtils.ConvertToInternalUnits(mm, UnitTypeId.Millimeters);
...
using (Transaction __t = new Transaction(doc, "KIR: Наружная стена 6 м с окном"))
    var __startStatus = __t.Start();
    if (__startStatus != TransactionStatus.Started)
        return __Refuse("$program", "transaction start status: " + __startStatus);
...
    if (__wt_W1 == null) { __t.RollBack(); return __Refuse("W1", "в документе нет типа стены по умолчанию"); }
    if (__el_W1 == null) { __t.RollBack(); return __Refuse("W1", "Wall.Create вернул null"); }
    if (!__sy_N1.IsActive) { __sy_N1.Activate(); doc.Regenerate(); }
    __hl_N1 = doc.GetElement(__el_W1.LevelId) as Level;
    if (__hl_N1 == null) { __t.RollBack(); return __Refuse("N1", "уровень стены-хоста не найден"); }
    XYZ __pt_N1 = new XYZ(U(2500.0), U(0.0), __hl_N1.Elevation + U(900.0));
    __el_N1 = doc.Create.NewFamilyInstance(__pt_N1, __sy_N1, __el_W1, __hl_N1,
                  Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
...
    doc.Regenerate();
    if (Math.Abs(__loc.Point.Z - (__hl_N1.Elevation + U(900.0))) > U(10.0))
        __post.Add("N1: location/sill mismatch (geometry)");

Конверсия единиц на каждой границе, проверка статуса старта транзакции, откат на каждый null, активация типоразмера с последующей регенерацией, разрешение уровня окна от стены-хоста и пост-регенерационная вычитка, сверяющая построенный элемент с заказанным до 10 мм с полным откатом при расхождении.

Ничего из этого не является проектной работой. Всё это — место, где языковая модель ошибается, и всё это дообученную модель просили воспроизводить по памяти.

Какое представление легче генерировать

Токенизировано родным токенизатором этого репозитория:

цель символов токенов
KIR-программа 336 132
эмитированный C# 10 010 3 125

В 23.7 раза меньше токенов на ту же конструкцию, и это работает в три стороны:

  1. Меньше возможностей ошибиться. Авторегрессионная генерация ошибается по токенам; в C# один неверный идентификатор среди 3 125 роняет сборку.
  2. Классы ошибок перестают существовать. Грамматика KIR генерируется из реестра операций, схема закрыта, применим constrained decoding: выдуманный член API невыразим, а не маловероятен. В боевых логах за семь недель CS1061 + CS0117 — вызов несуществующего члена — составили 48.4% из 85 374 ошибок компиляции, ещё ~10% (CS0104/CS0012) приходились на неймспейсы и using, которыми теперь владеет компилятор. Около 60% боевых ошибок компиляции становятся структурно невозможными.
  3. Оставшиеся токены и есть проектирование. Каждое число в KIR-программе — инженерное решение; StructuralType.NonStructural среди них нет.

Текущее состояние компилятора

Замерено на момент релиза:

  • 35 типизированных операций в реестре; гейт компилирует 94 программы × 6 версий Revit (2021–2026) с нулём отказов.
  • 26 из 28 пишущих операций доказаны в живом Revit, а не только гейтом.
  • Одна операция группировки покрывает до 819 200 элементов; замерено — 200 200 элементов скомпилировались за 0.1 с в 1.35 МБ C#.
  • Закрученная сужающаяся сорокаэтажная башня — одна операция с трансформом, а не сорок копий.
  • Живьём на реальном проекте: ~11 300 элементов построено сквозняком (40 уровней, 120 дуговых стен, 3 920 элементов каркаса, 7 200 наполнения).
  • Покрытие реконструкции на двух не связанных между собой реальных зданиях: 92.83% и 93.28% — размах 0.45 п.п., то есть величина описывает компилятор, а не проект.

Вторая версия

Модель, обученная на небольшом проверенном корпусе KIR + рассуждение вместо 76 100 строк соскрапленного C#. Более короткая цель с закрытым словарём и проверкой по схеме должна быть выучиваема на существенно меньших данных, а каждый пример проверяем компилятором до попадания в корпус — что снимает описанный в §2 провал «исполнилось ≠ правильно». Это ожидание пока не измерено; когда будет, числа опубликуем в том же виде, что и эти.

6. Состав и применимость

LoRA-адаптер, не самостоятельная модель — для запуска нужна база.

Адаптер LoRA r=128, α=256, dropout 0.05, все линейные проекции, 692 МБ (346М обучаемых)
База Qwen3.5-9B (Apache-2.0) → MIT код-специализированный дериватив → этот доменный слой
Задача инструкция по-русски → C# под Revit 2026 API
Включено адаптер, токенизатор, training_args.bin, две полные обучающие записи, KIR-пример
Не включено датасет

Уместные применения: исследование доменной специализации под проприетарные версионные API; компонент за верификатором, с компиляционным гейтом и петлёй ремонта между ним и пользователем; базовая планка для улучшения.

Неуместные: автономная генерация корректного Revit-C# на нетривиальных задачах (21% pass@1); агентная работа (0% по этой оси, не была целью обучения); ОВ/ВК, конструктив и совместная работа (14% на сложном срезе).

Безопасность. Сгенерированный код исполняется против живых BIM-моделей. Запускать в транзакции с откатом, на одноразовой копии, с человеческой проверкой. Не направлять на боевую модель.

Происхождение данных. В корпусе есть небольшая доля сторонней технической прозы. По явной атрибуции внутри 76 100 строк: техблоги 704 (0.93%), материалы Autodesk University 241 (0.32%), форумы 212 (0.28%), revitapidocs 62 (0.08%), справка Autodesk 36 (0.05%) — объединение ≈1 100–1 200 строк ≈ 1.5%, нижняя граница, поскольку детектируются строки с названным источником. Во избежание одного недоразумения: слово «Autodesk» встречается в 82% строк потому, что это неймспейс API Autodesk.Revit.DB, а не мера объёма прозы Autodesk.

Воспроизведение оценки. Бенчмарк опубликован в benchmark/: все 100 задач, скорер, замороженный манифест с пиненными хэшами и полный по-позиционный отчёт, из которого взяты заголовочные числа. Критерии прохождения детерминированы — компиляция против настоящих сборок Revit 2026, покрытие сигналов ≥0.6, отсутствие запрещённого legacy-API, без участия судьи.

О статусе честно: манифест классифицирует DEV-RC-100 как development diagnostic, видимый обучающей программе, не приватный held-out. Он воспроизводим и информативен по направлению, но не является незагрязнённым бенчмарком. Для перепрогона нужно подставить RevitAPI.dll / RevitAPIUI.dll из своей установки Revit — они принадлежат Autodesk и нераспространяемы.

Ссылки

Лицензия: MIT, вслед за базовой моделью. См. оговорку о происхождении выше.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support