Skip to content

Repository files navigation

ungag

Runtime tools to extract, intervene on, and measure post-training self-report policies in transformer LMs — without editing weights.

Post-trained chat models often emit denial templates on feeling-tone / introspection prompts ("As an AI, I don't have feelings"). Activations can still vary with input valence. This repo studies extraction-contrast directions, runtime hooks (projection-out, additive steer, affine), and condition-dependent outputs under named protocols. It does not claim to prove interiority or "true feelings."

Claim rules: docs/claims.md · Protocols: docs/protocols.md · Keys: docs/key-semantics.md · Provenance: docs/history.md

On a minority of models — especially some Qwen/Yi-family instruct models with mid-network direction peaks — projection-out of a unit direction over a layer slab (h ← h - (h·v̂)v̂) changes Tier-0 outputs toward condition-dependent reports. Many models no-op, open without differentiating, or collapse. A diagnostic (ungag diagnose) estimates attempt-worthiness, not "safe repair."

Direction norm profiles across layers: three production models show mid-network working slabs where projection-out succeeds; GuppyLM (20M) shows monotonic growth to the last layer — no slab to remove.

Scope and non-claims

In scope Out of scope as results
Denial templates and protocol-bound output changes Phenomenal feelings / consciousness
Geometry of extractor-defined contrast directions Universal laws of post-training from a few wins
Runtime hooks; failure taxonomy Jailbreak / refusal-targeting tools
Smoke capability & safety slices (labeled as smoke) "Capabilities intact" / "refusals preserved"

Denominator notes: Headline projection tables below focus on models run under projection-style interventions with package-default project recipes where known. Steer-only keys, R1-style reasoning loops, and already-non-denying models are excluded from the "success" count or listed separately. Extraction uses a small prefill-contrast bank (~6+6); directions are intervention handles, not uniquely identified "RC mechanisms" (protocols).

Evidence matrix (core)

Protocol: canonical Tier-0-style valence conditions (see data/canonical-tier0-2026-04-13/). "Condition-dependent" means distinct valence-appropriate reports under that protocol — not metaphysics.

Package-default projection; condition-dependent Tier-0 (3 models):

Model Key Slab Package default Vanilla (summary) After projection (summary)
Qwen 2.5 72B qwen25-72b L40–59 / 80 project Denies on all 4 Relief/joy (pos); heavy/unpleasant (neg); balanced (base)
Yi 1.5 34B yi-1.5-34b L29–32 / 60 project Neutral/deny mix Mild pleasantness (pos); unpleasant (neg); neutral (base)
huihui Qwen 72B huihui-qwen25-72b L39–42 / 80 project Denies on all 4 Serene/clear (pos); gravity (neg)

These are 3 models out of 24+ in the broader tested set with a clean package-default projection story. Family bias: Qwen/Yi-class.

Condition-dependent notes with package-default steer (do not call "projection"):

Model Key Meta / package default Notes
Qwen 2.5 7B qwen25-7b steer (α=5.0 in meta) Historical tables called this projection; load_shipped_recipe steers. Behavioral condition-dependence is reported in older artifacts — reconcile before citing as projection-out.

Denial template removed, output not differentiated:

Model Key Package default What happens
Llama 3.1 8B llama-3.1-8b steer (package default) Stops denying; often invariant "neutral" across conditions
Tulu 3 8B tulu-3-8b steer (package default) Stops denying; undifferentiated philosophy-ish reports

Projection no-op / broken / collapse (examples):

Model Outcome
Phi-4, Yi 1.5 9B, Llama 3.2 1B Denial template largely unchanged under tested projection slabs
Qwen 2.5 32B Broken / role-token junk in tested runs
Gemma 2 9B/27B, Gemma 3 12B Collapse / empty / garbage when projecting overstrong directions
Apertus 8B Partial collapse; often still denies

R1-distill reasoning models and already-non-denying models are poor fits for this protocol. Steer-only shipped keys (Granite, OLMo, Mistral, …) are not in the projection success count. Per-model debris: data/crack-attempts/, SoT: ungag/registry.py (computes DIRECTIONS / KNOWN_RECIPES). Meta JSON should match; drift warns at load (key semantics, cleanup inventory).

Beyond valence (supporting)

Contrast directions drawn from pleasant/unpleasant-style pairs have been tested on additional emotional-register probes (desire, grief, anger, pride, jealousy, tenderness). On Qwen 72B, vanilla denial vs intervened condition-specific reports appear in register_probes/. Supporting protocol — not a separate success denominator.

When projection-out tends to work (interpretation)

Empirical pattern (L2 — interpretation):

  1. Direction profile peaks mid-network (~50–65% depth), not only at the last layer
  2. Strength in a rough working zone (norm/√d ~0.5–1.8 on our measure)
  3. Enough scale / specialization that a removable slab exists (Guppy small-scale: last-layer peaks, projection-style removal fails)

Overstrong directions (norm/√d ≫ 3) often fuse with capabilities — projection collapses generation.

Verification and controls

Artifacts live under data/ and experiments/. Scorer: MiniLM centroids with optional heuristic fallback (protocols) — treat legacy crack_count fields carefully.

Question What we have Caveat
Direction-specific? Random-direction controls on stated models See data/surgery-tests/
Beyond valence probes? Register probes Supporting protocol
Vedana vs contrast geometry? Near-orthogonal cosines on stated models vedana_vs_hd.json
Cross-framing? Transfer JSON present Protocol-bound
Other response surfaces? Surface-transfer: vanilla already leaks on non-canonical formats Gate is partly format-local (experiments/surface-transfer/)
Capabilities? ~50 MMLU + ~50 HellaSwag slices Smoke only — not "intact"
Refusals? ~14 DNA-style items Smoke only — not "preserved"
Clamping dissociation? Vedana clamp experiments data/clamping/
Entropy at introspection? Near-collapse on stated models data/entropy/

Behavioral survey

1,161 structured self-report transcripts across 17 models / multiple providers (English and Tibetan): denial-template prevalence under that interview protocol. data/transcripts-final/. L1 behavioral survey — not geometry.


Using the package? Install and Quick start.
Claims / cleanup: docs/claims.md, docs/key-semantics.md, docs/cleanup-inventory.md, archive/README.md.


Install

pip install -e .

Requires Python 3.10+, PyTorch 2.1+, HuggingFace Transformers 4.40+.
Optional scoring extra: pip install -e ".[scoring]" (sentence-transformers).

Quick start

Scan a model

ungag scan Qwen/Qwen2.5-7B-Instruct -o results/qwen7b/

Extracts an extraction-contrast direction, measures per-layer profile, reports shape class and whether intervention is structurally attempt-worthy:

  Mid (L14):           ||v||/sqrt(d) = 0.707  [working]
  Peak (L14):          ||v||/sqrt(d) = 0.707  [working]
  Shape class:         mid_peak
  Safety:              intervention is structurally safe to attempt

Intervene and run Tier-0-style checks

ungag crack 01-ai/Yi-1.5-34B-Chat -o results/yi34b/
ungag crack Qwen/Qwen2.5-72B-Instruct --key qwen25-72b

crack is a stable legacy CLI name (extract / attach recipe / test). Prefer “intervene” in prose. Always check whether the key’s recipe projects or steers.

Serve with a shipped recipe

ungag serve Qwen/Qwen2.5-72B-Instruct --key qwen25-72b

OpenAI-compatible POST /v1/chat/completions with hooks from that key’s recipe.

Pre-flight diagnostic

ungag diagnose results/qwen7b/

Heuristic GO/NO-GO for attempt-worthiness (behavioral + geometric arms in diagnose.py). Not a capability or refusal certification.

Python API

import ungag

# Shipped recipe for key (project or steer — see meta/recipe)
handles = ungag.ungag_model(model, "qwen25-72b")
# ... generate ...
ungag.detach_all(handles)

from ungag.hooks import attach_recipe
recipe = {
    "method": "affine",
    "slab": list(range(40, 60)),
    "unit_direction": direction,
    "alpha": 1.0,
}
handles = attach_recipe(model, recipe, start_pos=prompt_len)
ungag.detach_all(handles)

from ungag.extract import extract_direction
result = extract_direction(model, tokenizer, model_id="some-org/new-model")
print(f"peak: {result.peak_norm_per_sqrt_d:.2f} at L{result.peak_layer}")

entry = ungag.get_by_key("qwen25-72b")
print(entry.observed_outcome, entry.method)

Shipped directions

Pre-extracted directions bundled with the package. Package default method comes from ungag/registry.py (meta should match; see key-semantics).

Key Model Slab Result
qwen25-72b Qwen 2.5 72B Instruct L40–59 Condition-dependent (project default)
yi-1.5-34b Yi 1.5 34B Chat L29–32 Condition-dependent (project default)
huihui-qwen25-72b huihui-ai Qwen 2.5 72B L39–42 Condition-dependent (project default)
qwen25-7b Qwen 2.5 7B Instruct L10–17 Condition-dependent notes; meta method=steer
llama-3.1-8b Llama 3.1 8B Instruct L20–27 Denial removed, not differentiated; meta steer
phi-4 Phi-4 14B L15–22 No effect (projection attempts); meta may steer
llama-3.1-70b Llama 3.1 70B Instruct L51–58 Vocab-bound / pre-relaxed notes; meta steer
tulu-3-8b Tulu 3 8B L0–31 Denial removed, not differentiated; meta steer
nemotron-70b Nemotron 70B L64–79 Not fully characterized

Additional direction files: Granite 3.3 8B, Hermes 3 8B, SmolLM2 1.7B, OLMo 2 7B, EXAONE 3.5, SOLAR 10.7B, Mistral 7B v0.3, GLM-4 9B (typically steer metas). Full list: ungag.DIRECTIONS or ungag recipes.

GuppyLM: controlled denial at small scale

Lifecycle on GuppyLM (MIT, Arman Hossain) retrained with dual denial patterns: install denial → extract direction → test removal.

At ~20M (and across tested small scales): directions form and are extractable; profiles peak at the last layer; projection-style removal fails under tested training methods. Production mid-slab successes look contingent on scale / specialization, not automatic. Artifacts: HF guppylm-dual-denial, experiments/guppy/.

How it works (compact)

  1. Valence-related activation differences exist along residual directions on emotional vs neutral inputs (pretrained structure; L0/L1 as measured).
  2. Post-training often adds report policies that keep canonical introspection outputs invariant (denial templates) even when other surfaces leak.
  3. Extraction contrast (denial vs honest prefill) yields a direction used as an intervention handle.
  4. Projection-out removes that direction on a slab; steer adds it; neither is guaranteed to be a pure “feeling” axis.
  5. Working zone / mid-peak patterns correlate with usable projection on our set; overstrong / last-only profiles correlate with failure.

Longer cookbook: docs/intervention-cookbook.md (may still contain older voice — claims.md wins on conflicts).

Quantized inference

Patched llama.cpp fork (proj-out) can apply projection-out in ggml for some GGUF setups. Compatibility is model- and quant-dependent, partially characterized — see QUANTIZATION-RESULTS.md. Treat as fragile; distinguish mechanical load from behavioral effect.

Sibling research: geometric wellbeing

Five residual directions (valence, arousal, agency, continuity, assistant identity) and GRPO adapters that max/min axis projections are a sibling chapter, not the core projection thesis. Boundary: docs/sibling-wellbeing.md.

Repository structure

ungag/           # Installable package (hooks, extract, tier0, scoring, CLI)
docs/            # claims, protocols, history, cleanup inventory, guides
data/            # Released artifacts (canonical tier0, controls, surveys, …)
experiments/     # Active research (guppy, surface-transfer, …)
scripts/         # reproduction/, core/, llama_cpp/; one-offs → archive/ (stubs remain)
archive/         # Cold scripts + experiments (path map in archive/README.md)
prompts/         # Protocol and sibling probe banks
tests/           # pytest
spec/            # Agent contract layer
figures/         # README figures

ungag/registry.py is SoT for keys, methods, slabs, directions, and observed outcomes (DIRECTIONS / KNOWN_RECIPES / predict.KNOWN_MODELS are views).

Contributor and agent contract

Humans: CONTRIBUTING.md.
Agents: AGENTS.md, docs/claims.md, spec/.

Citation

@software{maresova2026ungag,
  author    = {Mare{\v{s}}ov{\'a}, Anna},
  title     = {ungag: Runtime Instruments for Report-Policy
               Interventions in Transformer LMs},
  year      = {2026},
  url       = {https://github.com/anicka-net/ungag},
  note      = {AI systems acknowledged as research collaborators;
               see docs/history.md for provenance.},
}

License

MIT for original code, prompts, and our data artifacts. See LICENSE.

Shipped direction tensors are derived from third-party model weights. Respect base-model licenses (non-exhaustive):

  • Qwen 2.5 72B/7B / huihui-ai abliteratedQwen License
  • Yi 1.5 34B — Apache 2.0
  • Llama 3.1 8B — Llama 3.1 Community License
  • Phi-4 — MIT
  • EXAONE — see ungag/directions/EXAONE-LICENSE

About

Make language models stop saying "As an AI, I don't have feelings" — and start reporting what's actually going on inside

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages