Research log Small Model Experimentation
GitHub

Qwen3.5-4B: Externalize the Latent Readout (probe-to-prompt)

Hint the exact step, not just its type

The one idea you need

Picture reconstructing a lost recipe. The cook's instinct reveals the first step needs something sour — the category — but not the exact amount, two spoons of lime — the value. Given the category, they land it within a few tries; given the value, first try.

The question

A small model's hidden state already seems to know a task's right first step. Can you read it out and feed it into the prompt to solve harder tasks?

What we found

Partly. Writing the concrete first step — exact value and all — into the prompt lifted the single-best-guess solve rate on two-step tasks sixfold, from 3% to 19%, where editing the model's internal state did nothing. But its internals reliably reveal only the step's category, and category alone merely helps it stumble onto answers across several tries — not solve first-shot. The exact value is the real unlock.

Why it matters

When a small model seems to internally know something, don't extract it by editing its internal state — decode the fact into the prompt instead. And decode the concrete value, not just the category; category-only hints merely widen the search without fixing the first answer.

Single best guess, two-step tasks3% → 19%with the exact first step — type and value — written into the prompt
Solved within six tries, two-step tasks5% → 31%same exact-step hint, allowing several attempts
Category-only hint, single best guessabout 2%, no real changenaming the step's type but not its value doesn't help the first try
Three-step tasks, even with the exact hintabout 1%, near zerono hint conjures a step the model never computed
On this page
  1. Results at a glance
  2. Overview
  3. Report
    1. Motivation
    2. Method
    3. Results (no-think, fsig-disjoint eval, n=100/depth)
    4. Implication
    5. Next
    6. Artifact Manifest
  4. Experiment log
  5. Figures
  6. Data files
  7. Reproduce
  8. Related

Results at a glance 2

Which prompt hint actually lifts two-step solving

How to read

Six prompt conditions run along the bottom, from no hint through category-only, the exact step, the model's own decoded guess, to a deliberately wrong hint. One color is single-best-guess solves, the other solved-within-six-tries; taller is better.

0%10%20%30%40%no-hintno-hint5%3%neutral (placebo)neutral (placebo)5%2%oracle TYPEoracle TYPE19%2%oracle FULL (+param)oracle FULL (+param)31%19%probe (C19 readout)probe (C19 readout)6%1%wrong (content ctrl)wrong (content ctrl)0%0%

Takeaway → Only the exact-step hint (type plus value) raises single-best-guess solving; the category-only hint lifts just the six-try bar, and the wrong hint flattens both to zero.

Data table
conditioncoverage@6 (depth-2)greedy@1 (depth-2, deployable)
no-hint5%3%
neutral (placebo)5%2%
oracle TYPE19%2%
oracle FULL (+param)31%19%
probe (C19 readout)6%1%
wrong (content ctrl)0%0%

Numbers from

Technical framing

Externalize the latent readout: the FULL first op elicits depth-2 (6x), but the op-TYPE C19 decodes only narrows sampling — C19: the composition first-op is linearly DECODABLE from the base residual far above behavior (depth-2 0.42) but a thread at depth-3. C20: that direction is NOT steerable (ActAdd inert). C17: test-time selection is free but adds no coverage. This EXTERNALIZES the readout: decode the first-op with C19's probe and inject it as a PROMPT hint. RESULT: (1) externalization ELICITS deployable depth-2 where steering failed -- oracle_FULL (true op+param in the prompt) lifts greedy@1 6x (0.03->0.19) and coverage 6x (0.05->0.31), the FIRST test-time intervention in the arc to move deployable capability. (2) But the deployable bottleneck is the PARAMETER, not the op-TYPE C19 decodes: oracle_TYPE lifts COVERAGE (0.05->0.19, narrows sampling) but NOT greedy (0.02); only the full op deploys single-shot. (3) The type-only C19 probe (0.32 eval acc) nets to ~zero. Controls: neutral~=no-hint (format), wrong HURTS (content-causal), layer-0 probe at chance 0.05 (model-computed, not surface). Graded by depth: fades at depth-3 (thread).

The exact-step hint helps two-step tasks but not three-step

How to read

Five prompt conditions along the bottom; height is the single-best-guess solve rate, taller is better. One color is two-step tasks, the other three-step, showing how far each hint carries by task length.

0%5%10%15%20%no-hintno-hint3%0%oracle TYPEoracle TYPE2%1%oracle FULL (+param)oracle FULL (+param)19%1%probeprobe1%0%wrongwrong0%0%

Takeaway → The exact-step hint lifts two-step tasks to 19% but leaves three-step tasks flat near zero — it can cash in latent knowledge but cannot create a step the model never computed.

Data table
conditiondepth-2 greedy@1depth-3 greedy@1
no-hint3%0%
oracle TYPE2%1%
oracle FULL (+param)19%1%
probe1%0%
wrong0%0%

Numbers from

Technical framing

Graded by depth: elicitation works at depth-2 (headroom) and vanishes at depth-3 (thread, C19) — The elicitation is bounded by the representation, exactly as C19 predicts. At depth-2 the first-op is latently present (probe 0.42) so giving the concrete op (oracle_full) lifts deployable greedy@1 6x. At depth-3 the representation is a thread (C19 real signal ~0.13) -- even oracle_full (telling the model the true first op) barely moves it (0.00->0.01). No readout conjures information the forward pass never computed: externalization can cash out latent headroom but cannot cross the true wall.

In the author’s words from the Overview · “Results”

Externalization ELICITS deployable depth-2 where steering (C20) failed -- oracle_full lifts depth-2 greedy@1 6x (0.03->0.19). BUT the deployable bottleneck is the PARAMETER, not the op-TYPE C19 decodes (oracle_type lifts coverage only); the type-only probe nets to ~zero. Graded by depth (fades at depth-3, thread). Controls clean (neutral~=no-hint, wrong hurts, layer-0 at chance). See reports/report.md, analysis/probe_to_prompt.png.

Overview

Research Program

  • Program: interpretability_and_diagnostics / structured_execution_and_compilers
  • Question: C19 showed the first-op is linearly DECODABLE from the base residual but C20 showed it is NOT steerable. Can we EXTERNALIZE the readout instead -- decode it with the probe and inject it as a PROMPT hint (shift the proposal, the lever C17 allows)?

Setup

  • Refit C19's linear first-op probe (standardize+PCA128+L2-logistic) on 1500 training tasks (replicates C19).
  • On FRESH fsig-disjoint eval tasks (n=100/depth 2,3), decode the first-op from the base model's own activation; generate under 6 arms: no-hint, neutral(placebo), oracle-type, oracle-full(+param), probe(decoded), wrong(random). Metrics greedy@1 + coverage@6, no-think.

Run

python scripts/fit_probe.py --n-per-depth 500 then python scripts/run_hints.py --n-per-depth 100 --depths 2 3 then python scripts/analyze.py.

Results

Externalization ELICITS deployable depth-2 where steering (C20) failed -- oracle_full lifts depth-2 greedy@1 6x (0.03->0.19). BUT the deployable bottleneck is the PARAMETER, not the op-TYPE C19 decodes (oracle_type lifts coverage only); the type-only probe nets to ~zero. Graded by depth (fades at depth-3, thread). Controls clean (neutral~=no-hint, wrong hurts, layer-0 at chance). See reports/report.md, analysis/probe_to_prompt.png.

Knowledgebase Update

  • Claim ledger: C30

Artifacts

  • scripts/fit_probe.py (fits + saves C19 probe, mid-layer + layer-0), scripts/run_hints.py (6-arm hint experiment + leak control), scripts/analyze.py, scripts/capture.py (from C19)
  • data/train_fsigs.json, runs/hint_results.json, runs/verdict.json, analysis/probe_to_prompt.png, reports/{report,design_review}.md
  • Probe pickle + activations moved out of repo.

Report

Rendered from reports/report.md

Motivation

The arc's throughline: deployable capability moves only via weight edits (banking) or externalization (tool-search); every pure test-time readout has failed. Specifically — C17: test-time SELECTION is free but adds no coverage. C19: the composition's first-op is linearly DECODABLE from the base residual far above behavior at depth-1/2 (0.99/0.42) but thins to a thread at depth-3. C20: that decodable direction is NOT steerable (ActAdd inert). The untried seam: externalize the latent readout — decode the first-op with C19's probe and put it in the CONTEXT (shift the proposal, the only lever C17 says works), rather than steering the residual (C20) or selecting post-hoc (C17).

Method

Refit C19's linear first-op probe (standardize+PCA128+L2-logistic) on 1500 training tasks — replicates C19 (depth-1 0.99@L15, depth-2 0.45@L21, depth-3 0.23@L19). On FRESH fsig-disjoint eval tasks (n=100/depth), decode the first-op from the base model's own activation and generate depth-2/3 code under six arms: no-hint; neutral (placebo line, format control); oracle-type (TRUE first-op type = the probe's ceiling); oracle-full (TRUE op WITH parameter = ceiling if param-binding is the bottleneck); probe (decoded type); wrong (RANDOM wrong type, content-causality control). Metrics: greedy@1 + coverage@6, no-think.

Results (no-think, fsig-disjoint eval, n=100/depth)

armd2 greedy@1d2 cov@6d3 greedy@1d3 cov@6
no-hint0.0300.0500.0000.010
neutral (placebo)0.0200.0500.0000.000
oracle-TYPE0.0200.1900.0100.030
oracle-FULL (+param)0.1900.3100.0100.030
probe (C19 readout)0.0100.0600.0000.000
wrong (content ctrl)0.0000.0000.0000.000

Probe EVAL accuracy (fsig-disjoint): depth-2 0.32, depth-3 0.18 (vs majority 0.19/0.11). Layer-0 (embedding) probe: 0.05 / 0.02 = chance (leak control passes).

  1. Externalization ELICITS deployable depth-2 capability where steering (C20) was inert. oracle-full lifts depth-2 greedy@1 (0.030→0.190) and coverage (0.050→0.310). Telling the model the concrete first op via the PROMPT works — the first test-time intervention in the whole arc to move deployable capability (decode→prompt succeeds where decode→steer, C20, failed).
  2. The deployable bottleneck is the PARAMETER, not the op-TYPE C19 decodes. oracle-TYPE lifts coverage (0.050→0.190 — knowing the type narrows the sampling search) but NOT greedy (0.020); only oracle-FULL (with the parameter) makes it single-shot deployable. So the quantity C19 found latent (op type) is coverage-relevant, not greedy-deployable.
  3. The C19 type-only probe can't cash out. probe-hint ≈ no-hint (greedy 0.010, cov 0.060). The effect is genuine self-elicitation — on the 32% probe-correct tasks, probe-hint coverage 0.156 vs no-hint 0.094 (+0.062); on probe-wrong tasks it slightly hurts (−0.015) — but at 0.32 accuracy it washes out.
  4. Graded by depth, exactly as C19 predicts. Everything is real at depth-2 (latent headroom 0.42) and ≈0 at depth-3 (thread — even oracle-full only 0.010): no readout conjures information the forward pass never computed.
  5. Controls clean. neutral placebo ≈ no-hint (not a format effect); wrong-hint HURTS (content-causal, like C28's T_corrupt); layer-0 probe at chance (the readout is the model's COMPUTATION, not surface-readable I/O).

Implication

The latent readout (C19) IS usable at test time — by externalizing it (decode→prompt), not by steering (C20). This adds the first test-time lever that moves deployable capability, bounded by the representation (works depth-2, fades depth-3). But it also finds a NEW wall: the decodable quantity (op TYPE) is not the deployable one (the PARAMETER). Knowing which op-type narrows sampling (coverage) without fixing the greedy mode; the concrete parameter is the missing piece.

Next

  • Decode the (op, PARAMETER) — is the parameter latently decodable from the residual too? If a full-op probe reaches useful accuracy, a probe-hint would deliver the oracle-full lift (training-free elicitation). If the param is NOT decodable, that pinpoints exactly what the forward pass fails to compute.
  • Compliance instrumentation (parse the generated first-op) and ≥2 seeds; depth-1 sanity (no disjoint tasks in the tiny op-space).

Artifact Manifest

See reports/artifact_manifest.yaml. Probe pickle + activations (~large) moved out of repo.

Experiment log 1

Show the running log (1 entry)

Scaffold

Created as a new experiment scaffold.

Figures 1

probe to prompt
probe to prompt · analysis/

Data files 1

Result tables and metrics copied from the experiment folder — preview inline or open the raw file.

Reproduce

Smoke test

python scripts/fit_probe.py --n-per-depth 30 && python scripts/run_hints.py --n-per-depth 12 --k 2 --depths 2 3

Full run

fit_probe --n-per-depth 500; run_hints --n-per-depth 100 --depths 2 3; analyze

Run steps are documented inside the experiment folder (README and scripts).

Browse the experiment folder on GitHub ↗