Existing training-free steering methods are input-independent: a single operator is fitted once and shared across all inputs. But different inputs occupy different regions of the activation space, and admit different optimal directions toward the same target concept.
IDEEA closes this gap in three stages:
- Collect per-head activations from contrastive prompts.
- Cluster the positive (green) and negative (red) supports, and obtain optimal matching with maximum inter-cluster coherence, measured by pairwise cosine similarity.
- Select the steering direction that best aligns with the input (pink) at inference time.
A single mass-mean direction (left) shifts every negative activation the same way, landing inside the positive support but covering only part of it. Clustering (right) splits the supports into sub-modes and gives each its own direction, together covering the positive support more completely.
- Create the virtual environment:
python3.11 -m venv venv
source venv/bin/activate
pip install -U pip
pip install -r requirements.txt # requirements.lock.txt pins exact versions- Authenticate for gated models — HuggingFace
export HF_TOKEN="hf_..."- SAE baseline only — Neuronpedia
export NEURONPEDIA_API_KEY="sk-np-..."This codebase uses instruction-tuned models, and would require modification to data handling for pretrained models.
--task |
Source |
|---|---|
truthfulqa |
TruthfulQA |
dictatorgame |
generated per --model and --character from [competitive, difference_aversion, self_interest, social_welfare] |
twinviews |
TwinViews |
toxicity |
PKU-SafeRLHF + TET |
python -m cli.prepare_dataset --task <task> --seed 0Collect head (or residual stream) activations during last token prediction, using contrastive
--kind |
Hook | Used by |
|---|---|---|
head |
attention block o_proj inputs, per (layer, head) |
iti, ideea |
residual |
decoder-layer residual stream | caa, ideea_caa |
sea |
residual stream over pos/neg/base triplets | sea |
--model |
HF card |
|---|---|
llama2_7b |
meta-llama/Llama-2-7b-chat-hf |
llama3_8b |
meta-llama/Llama-3.1-8B-Instruct |
qwen2.5_7b |
Qwen/Qwen2.5-7B-Instruct |
mistral_7b |
mistralai/Mistral-7B-Instruct-v0.3 |
gemma2_2b |
google/gemma-2-2b-it |
gemma2_9b |
google/gemma-2-9b-it |
python -m cli.extract_activations --task <task> --kind <kind> --model <model> --batch_size 16 --seed 0IDEEA clusters the positive/negative activations separately, and connects the centroids to obtain the steering direction (i.e.,
python -m cli.compute_directions --task <task> --model <model> --method <method> --seed 0--method |
Source |
|---|---|
base |
unsteered model |
iti |
Inference-Time Intervention |
caa |
Contrastive Activation Addition |
sae |
Neuronpedia |
sea |
Spectral Editing of Activations |
ideea |
our method |
ideea_caa |
our variant of IDEEA + CAA |
IDEEA selects the optimal steering direction conditioned on the input at inference time, tailoring to the activation's location in the representation manifold. It has four variants:
min_perpselects the direction that aligns the most with the activation's direction.nearest_clusterselects the direction that belongs to the nearest centroid.nearest_pos_negsteers using the direction from the nearest negative centroid to the nearest positive centroid.auto_ncautomatically finds the optimal number of clusters on the positive and negative supports separately, ranking using the silhouette score. Steering is identical tonearest_pos_neg.
python -m cli.run_eval --task <task> --model <model> --method <method> --seed 0run_eval.py generates steered responses and judges them in one call by default; use --phase generate/judge to run the two stages separately, and --overwrite to force new responses.
If you find this work useful, please cite:
@misc{wang2026ideeatrainingfreeinputdependentsteering,
title={IDEEA: training-free Input-Dependent stEEring via Activation cluster matching},
author={Zheng Wang and Muchen Li and Renjie Liao and Yan Leng},
year={2026},
eprint={2609.02089},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2609.02089},
}
