Skip to content

EasySteer

Capture representations, build interventions, and steer LLM inference with vLLM.

EasySteer changes intermediate model activations during inference while keeping model weights fixed. It supports decoder hidden states, attention head outputs, and MoE router logits through a shared request API. The current engine is based on vLLM 0.29.0, with V2 GPU model-runner integration, continuous batching, prefix caching, and CUDA graph support.

Get started Paper (arXiv:2509.25175)

Start with your task

I want to… Start here
Try a bundled steering vector Installation → Quickstart
Control layers, tokens, and multiple interventions Steering requests
Capture model activations and learn a direction Capture → Extracting vectors
Intervene on attention heads Attention and ITI
Train a ReFT intervention ReFT training
Deploy an API or demo OpenAI server → Web demos
Choose graph, caching, and capacity settings Performance · Engine arguments
Reproduce a paper Replications

How the pieces fit

Component What it is
vllm-steer/ vLLM fork exposing vllm.steer_vectors and vllm.capture
easysteer.hidden_states Capture labelled hidden states, attention head outputs, and MoE router logits
easysteer.steer Extract steering vectors from captured hidden states (analysis-based)
easysteer.vectors Convert files or extraction results into common inference payloads
easysteer.reft Train parameterized interventions on frozen models (learning-based)
frontend/, hf-space/ Full research frontend and lightweight hosted demo
replications/ Notebook reproductions of published steering papers

A steering request

from vllm import LLM, SamplingParams
from vllm.steer_vectors import ApplySpec, SteeringSpec, VectorSpec

llm = LLM(
    model="Qwen/Qwen2.5-1.5B-Instruct",
    enable_steer_vector=True,
    steer_algorithms=["direct"],
)

spec = SteeringSpec(vectors=[VectorSpec(
    source="vectors/happy_diffmean.gguf",
    scale=2.0,
    layers=list(range(10, 24)),
    apply=ApplySpec(prompt="all", generation="all"),
)])

messages = [
    {"role": "system", "content": ""},
    {"role": "user", "content": "Alice's dog has passed away. Please comfort her."},
]
prompt_ids = llm.get_tokenizer().apply_chat_template(
    messages, tokenize=True, return_dict=False, add_generation_prompt=True,
)
prompt = {"prompt_token_ids": prompt_ids}
outputs = llm.generate(
    prompt,
    steering=spec,
    sampling_params=SamplingParams(temperature=0.0, max_tokens=128),
)
print(outputs[0].outputs[0].text)

Run from the repository root after installation. The quickstart adds the baseline comparison. The same spec works through the HTTP API; execution mode is selected from the engine's declared workload. For accepted formats and graph conditions, use the algorithm reference.

The EasySteer paper reports 10.8–22.3× speedups over its compared steering frameworks. Use the performance guide to evaluate the current engine on your model and hardware.

Citation

@article{xu2025easysteer,
  title={EasySteer: A Unified Framework for High-Performance and Extensible LLM Steering},
  author={Xu, Haolei and Mei, Xinyu and Yan, Yuchen and Zhou, Rui and Zhang, Wenqi and Lu, Weiming and Zhuang, Yueting and Shen, Yongliang},
  journal={arXiv preprint arXiv:2509.25175},
  year={2025}
}