skip to content
← back

January 18, 2026

part 1/28 min

steering..

finding directions in a model's activation space, and nudging its behaviour without any training.

steering is a way to alter a model's behaviour without any training or fine-tuning. it works by finding a specific direction in a model's activation space that corresponds to a concept, a "steering vector", then adding or subtracting that vector during inference to nudge the model toward or away from it.

say we want a model to sound more empathetic. we can extract an "empathy vector" by looking at how its internal activations differ when it responds empathetically versus neutrally, then inject that vector at inference time to make responses warmer. the same trick works for formality, politeness, concision, or reducing harmful outputs. all of this happens by directly manipulating internal representations, no fine-tuning required, which is what makes steering such a lightweight technique. it falls under a broader area called representation engineering.

steering is like when a friend is giving a presentation and you do something silly to make them laugh. their internal state shifts a little, and suddenly their whole delivery has a different vibe. that's what steering does to an llm: inject a small signal into its activations, and the entire output changes tone.

the residual stream

to understand how steering works, we first need the residual stream. inside a transformer, every token is represented by a vector of numbers, its hidden state h.

h = [0.12, 1.03, -0.55, 2.44, ..., n]

this vector encodes what the token means, the sentence's context, the style or mood, and everything the model is likely to say next. every layer reads this vector and enriches it a little more. when we "steer" a model, we're editing this hidden vector mid-thought.

the reason changing one vector changes behaviour is that the final output, logits into words, is computed by applying a matrix to the hidden vector, a step called the readout:

logits = W_out · h

so if we modify h, we shift which words are more likely, what tone gets expressed, how confident the model sounds, how emotional it becomes. we can think of h as the model's current "mood state", and steering as injecting a small push into that mood:

h ← h + (some happiness direction)

the residual stream carries the contribution of every mlp and attention layer that came before it. steering means grabbing h in the middle of the model's thinking, nudging it, and letting the rest of the transformer continue from that modified state.

the linear representation hypothesis

to understand why this works at all, we need the linear representation hypothesis: high-level concepts like happiness, sadness, anger, or politeness are represented as approximately linear directions in a model's high-dimensional activation space.

that means if we take the hidden vector h and a concept vector v, moving along that direction makes the model behave more like the concept:

h' = h + α·v_concept

even though the model as a whole is highly non-linear, many individual concepts still behave linearly, for a few reasons. the readout layer itself is linear, so if the model wants to raise the probability of words like "joyful" or "wonderful", it has to push h along some direction that increases those logits linearly. during training, the model repeatedly sees the same kind of pattern whenever text is happy, so its hidden states bend toward similar shapes. and because the residual stream is reused layer after layer, the model is forced to pack many features into the same vector via superposition, which pushes concepts to be encoded as directions rather than single neurons, spread across many neurons rather than one, the same way no single pixel determines "cat" in an image.

the payoff is that if a concept is linearly encoded, a small nudge along its direction produces a consistent change in behaviour, which is exactly why steering works as well as it does. we can "add happiness" the same way we'd add brightness to an image: a linear transformation, no retraining needed.

computing a steering vector

getting the vector itself is simple. first, run a few positive prompts through the model and save their activations at some chosen layer ℓ, using the hidden state of the last token of each prompt.

suppose the hidden vectors we extract look like this. this cluster represents the internal state the model uses to generate happy text, essentially asking "what does the model's brain look like when it's being happy?"

h1+ = [1.1, 0.2, -0.5, 0.9, ...]
h2+ = [1.3, 0.4, -0.6, 0.8, ...]
h3+ = [1.0, 0.3, -0.4, 0.7, ...]

then do the same with a few negative prompts.

h1- = [-0.3, 1.1, 0.8, -0.4, ...]
h2- = [-0.2, 1.2, 0.7, -0.6, ...]
h3- = [-0.4, 1.0, 0.9, -0.5, ...]

now we have two clusters, a happy set in one region and a sad set in another. take the mean of each set:

μ₊ = (1/n) Σᵢ hᵢ₊

μ₋ = (1/n) Σᵢ hᵢ₋

these means are the centers of the two clusters, the "average happy brain state" and the "average sad brain state". take their difference to get a direction pointing from sad to happy. in 2d, if mean_sad sits at (2, 5) and mean_happy at (10, 15):

v_happy = (10 − 2, 15 − 5) = (8, 10)

we often normalize this vector too, so its length equals 1, which lets us control the effect's intensity with a single scalar α:

v̂ = v / ‖v‖

injecting the vector

this is the point where an abstract "happiness direction" becomes actual model behaviour. injecting it during the forward pass looks like:

h' = h + α·v_happy

h = hidden state at some layer · v_happy = the happiness direction · α = how strongly we push toward it

this happens mid-forward-pass, like altering the model's train of thought while it's still thinking. the hidden vector h carries the meaning of the input, the model's style, the emotional tone of the conversation, relevant world knowledge, and the signal for what comes next. injecting a vector shifts all of these in proportion to how the concept is encoded, so adding a "happiness direction" makes the model act as if the context is happier, even if the prompt never mentioned emotion.

downstream, the final logits shift by a fixed amount:

logits' = W_out·h' = W_out(h + α·v) = logits + α·(W_out·v)

words associated with happy contexts get a boost, words associated with sad or neutral contexts get relatively suppressed, so the model becomes more likely to pick "great", "wonderful", or "joyful" and less likely to stay flat or neutral.

injection works best in the middle-to-later layers. say we inject at layer 15 of 32, everything from layer 16 onward keeps processing the modified vector:

h'_final = G(h + α·v)

G = the composition of the remaining layers

if G is roughly smooth, this is approximately:

G(h + α·v) ≈ G(h) + α·J_G·v

J_G = the jacobian of G

which means the final layer still gets pushed along a transformed version of the happiness direction, even though the injection happened earlier, usually producing smoother, more consistent shifts.

before injection:

explain quicksort. → "quicksort is a divide-and-conquer algorithm…"

after injecting the happiness direction at α = 7:

explain quicksort. → "quicksort is a so good divide-and-conquer algorithm! it happily splits arrays into joyful partitions!"

the injected vector biases the probability distribution toward tokens common in happy contexts, even though nothing in the prompt asked for that. the right α depends on the model and layer, so getting the strength right takes some trial and error. a small push shifts style, tone, and sentiment without breaking factuality. push too hard, and it does.

when α gets too large

if α is pushed too far, the hidden state gets shoved off distribution, outside anything the model saw during training. the output destabilizes: hallucinations, overly emotional and repetitive language, heavy bias toward "happy" vocabulary, loss of structure.

2+2 is a wonderful vibrant rainbow of positivity and energy, radiating cosmic joy into your day!!! 4 is happiness incarnate!!!

that's the saturation effect of concept directions: push a direction hard enough, and the model leaves the region it was ever trained to operate in.

part two picks up with combining multiple concepts, finding the neurons behind them, and why the whole thing is messier than it looks.

read the original on substack ↗