# How Directional Steering Works in ds4 for Behavior Modification

> Learn how directional steering in ds4 modifies transformer behavior by biasing layer activations. Achieve desired outputs without retraining the model.

- Repository: [Salvatore Sanfilippo/ds4](https://github.com/antirez/ds4)
- Tags: deep-dive
- Published: 2026-08-08

---

**Directional steering in ds4 lets you bias transformer outputs by adding scaled direction vectors to layer activations after the feed-forward network (FFN) or attention blocks, without retraining the model.**

Directional steering is a runtime inference feature in the **ds4** engine (DeepSeek V4 inference engine by antirez) that enables behavior modification by nudging hidden states toward user-defined latent directions. By loading binary direction vectors and applying them selectively to FFN or attention outputs, you can steer generation style, tone, or topic adherence while keeping the base model weights frozen.

## Core Mechanism of Directional Steering

The steering system operates by intercepting activations at specific points in the transformer forward pass and injecting scaled direction vectors. This happens entirely during inference in [`ds4.c`](https://github.com/antirez/ds4/blob/main/ds4.c), leaving the original checkpoint untouched.

### Loading Per-Layer Direction Vectors

The engine expects a binary file containing one `float32` vector per transformer layer. When you supply `--dir-steering-file FILE`, ds4 maps this file into memory and associates each layer's vector with its corresponding index. According to the source in [`ds4_server.c`](https://github.com/antirez/ds4/blob/main/ds4_server.c) (lines 12952-12959), the engine initializes steering scales based on whether this file is present.

### Activation Injection Points

Directional steering modifies activations at two specific sub-layer boundaries:

- **After FFN**: The direction vector scales and adds to `ffn_out` using `cpu_directional_steering_project_rows()`.
- **After Attention**: The same direction vector scales and adds to `attn_out`, but via an independent scale factor.

Both injection points use the same per-layer direction array (`steering_dirs`) but apply distinct scaling coefficients (`steering_scale` for FFN, `steering_attn_scale` for attention).

## Command-Line Interface for Directional Steering

The ds4 CLI, server, and agent binaries expose three unified flags to control steering behavior.

### Steering File and Scaling Options

| Option | Purpose | Default |
|--------|---------|---------|
| `--dir-steering-file FILE` | Load binary `float32` direction vectors (one per layer) | None |
| `--dir-steering-ffn F` | Scale factor applied after FFN output | 1.0 if file provided, else 0 |
| `--dir-steering-attn F` | Scale factor applied after attention output | 0 |

As implemented in [`ds4_server.c`](https://github.com/antirez/ds4/blob/main/ds4_server.c) (lines 12994-12997), the FFN scale automatically defaults to **1.0** when a steering file is supplied but no explicit scale is set. The attention scale remains **0** unless manually specified, meaning FFN steering is the primary mechanism by default.

### Cross-Binary Consistency

The same option parsing appears across [`ds4_cli.c`](https://github.com/antirez/ds4/blob/main/ds4_cli.c) (lines 1924-1933), [`ds4_agent.c`](https://github.com/antirez/ds4/blob/main/ds4_agent.c) (lines 732-739), and [`ds4_help.c`](https://github.com/antirez/ds4/blob/main/ds4_help.c) (lines 219-224), ensuring identical behavior whether you run the standalone CLI, server mode, or agent mode.

## Implementation Details in ds4.c

The core steering logic resides in [`ds4.c`](https://github.com/antirez/ds4/blob/main/ds4.c), where two utility functions govern whether and how direction vectors are applied.

### Enable Check and Projection Functions

Before modifying any tensor, the engine checks `cpu_directional_steering_enabled()` (lines 167-170), which returns true only when both the direction pointer is non-null and the scale is non-zero. This prevents unnecessary computation when steering is inactive.

The actual modification happens in `cpu_directional_steering_project_rows()` (lines 171-176), which iterates over each token's hidden state and performs a scaled vector addition:

```c
// Conceptual implementation: adds scaled direction to each row
void cpu_directional_steering_project_rows(Tensor *target, 
                                           float **dirs, 
                                           int layer_idx, 
                                           int n_tokens, 
                                           float scale);

```

### Runtime Application in Inference

During the forward pass, the engine wraps steering calls in conditional blocks immediately after sub-layer computation. For the FFN path (lines 11786-11791):

```c
if (cpu_directional_steering_enabled(ctx->steering_dirs,
                                     ctx->steering_scale))
    cpu_directional_steering_project_rows(ffn_out,
                                          ctx->steering_dirs,
                                          il, n_tok,
                                          ctx->steering_scale);

```

Similarly, for the attention path (lines 12005-12010):

```c
if (cpu_directional_steering_enabled(ctx->steering_dirs,
                                     ctx->steering_attn_scale))
    cpu_directional_steering_project_rows(attn_out,
                                          ctx->steering_dirs,
                                          il, n_tok,
                                          ctx->steering_attn_scale);

```

Here, `il` represents the current layer index, allowing each layer to receive its specific direction vector from the loaded file.

## Practical Examples

### CLI Usage

To bias generation toward a custom direction stored in `style.bin` with moderate FFN steering:

```bash
./ds4 -p "Explain quantum computing" \
      --dir-steering-file style.bin \
      --dir-steering-ffn 0.8

```

This command loads the direction vectors and applies an 0.8 scale factor to the FFN outputs across all layers, as documented in [`ds4_help.c`](https://github.com/antirez/ds4/blob/main/ds4_help.c) (lines 486-490).

### Programmatic Configuration

When embedding ds4 as a library, set steering parameters directly on the engine configuration before initialization:

```c
ds4_engine_config c = ds4_engine_config_default();
c.engine.directional_steering_file = "style.bin";
c.engine.directional_steering_ffn   = 0.8f;   // Apply after FFN
c.engine.directional_steering_attn = 0.0f;   // Disable attention steering

ds4_engine *eng = ds4_engine_create(&c);

```

This mirrors the CLI parsing logic found in [`ds4_cli.c`](https://github.com/antirez/ds4/blob/main/ds4_cli.c) (lines 1924-1933).

## Summary

- Directional steering modifies behavior by adding scaled `float32` vectors to layer activations during inference in ds4.
- The system reads per-layer directions from a binary file specified via `--dir-steering-file`.
- **FFN steering** defaults to scale 1.0 when a file is provided, while **attention steering** defaults to 0.
- Two core functions in [`ds4.c`](https://github.com/antirez/ds4/blob/main/ds4.c) govern the feature: `cpu_directional_steering_enabled()` checks activation conditions, and `cpu_directional_steering_project_rows()` applies the vector addition.
- Steering occurs after the FFN and/or attention blocks without modifying underlying model weights, enabling runtime behavior modification without retraining.

## Frequently Asked Questions

### What file format does directional steering require?

Directional steering expects a binary file containing one `float32` vector per transformer layer, stored contiguously. Each vector's dimension must match the model's hidden size. The engine memory-maps this file and indexes into it by layer number during the forward pass.

### Can I steer FFN and attention layers independently?

Yes. The `--dir-steering-ffn` and `--dir-steering-attn` flags accept independent scale factors. You can apply strong steering to FFN outputs (e.g., 1.2) while disabling attention steering (0.0), or vice versa, allowing fine-grained control over which sub-layer contributions are modified.

### Does directional steering modify model weights?

No. Directional steering is a pure inference-time intervention. It temporarily adjusts activation tensors (`ffn_out` and `attn_out`) by adding scaled direction vectors, but the underlying checkpoint remains unchanged. This makes steering reversible and swappable between generations without reloading the base model.

### How do I disable directional steering at runtime?

If you loaded a steering file but want to disable its effect for specific calls, set both scale factors to 0.0 using `--dir-steering-ffn 0 --dir-steering-attn 0`. The `cpu_directional_steering_enabled()` function checks for non-zero scales and skips projection when both are zero, ensuring zero overhead when steering is inactive.