Multi-Agent Society of Thought - Mechanistic Interpretability Study
Python
0
29 commits
updated Feb 5, 2026
Mechanistic interpretability meets multi-agent dynamics.
MAST investigates how internal neural network features propagate between language model agents during conversation. Using Sparse Autoencoders (SAEs) to extract interpretable features from DeepSeek-R1 distillations, we measure whether — and how — behavioural traits "spread" from one agent to another through natural language interaction.
The core question: if we steer one agent's internal features toward a target personality (e.g. revolutionary, provocateur), do the other agents' features shift in response?
┌─────────────────────────────────────────────────────────┐
│ MAST Pipeline │
│ │
│ ┌─────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ SAE │───▶│ Feature │───▶│ Multi-Agent │ │
│ │ Loader │ │ Steering │ │ Orchestrator │ │
│ └─────────┘ └───────────┘ └──────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌──────────────────┐ │
│ │ Feature │ │ Contagion │ │
│ │ Extract │─────────────────────▶│ Analysis │ │
│ └─────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Phase | Name | Description |
|---|---|---|
| 1 | Baseline | Extract and characterise SAE features from single-agent reasoning across prompt categories |
| 2 | Transfer | Measure natural feature transfer between two unsteered agents in conversation |
| 3 | Steering Validation | Validate that feature steering produces expected behavioural effects on individual agents |
| 4 | Instigator Influence | Introduce a steered "instigator" agent and measure feature contagion across topologies and steering strengths |
| 5 | MOLTBook Simulation | Multi-round society simulation with diverse agent roles and escalating steering schedules |
mast/
├── configs/
│ ├── base.yaml # Shared defaults
│ ├── experiments/ # Per-phase experiment configs
│ │ ├── phase1_baseline.yaml
│ │ ├── phase2_transfer.yaml
│ │ ├── phase3_steering.yaml
│ │ ├── phase4_instigator.yaml
│ │ └── phase5_moltbook_sim.yaml
│ └── models/ # Model-specific configs
│ ├── deepseek_r1_8b.yaml
│ └── deepseek_r1_1.5b.yaml
├── src/
│ ├── sae/ # Sparse Autoencoder modules
│ │ ├── loader.py # SAE architecture and weight loading
│ │ ├── feature_extractor.py # Hook-based feature extraction during generation
│ │ ├── steering.py # Activation addition for feature steering
│ │ └── feature_classifier.py # LLM-judge feature classification
│ ├── models/ # Model loading and agent wrappers
│ │ ├── base.py # Unified model wrapper
│ │ ├── reasoning_model.py # DeepSeek-R1 loader with think-tag parsing
│ │ └── agent.py # Agent class with steering + extraction
│ ├── multi_agent/ # Multi-agent orchestration
│ │ ├── conversation.py # Conversation state management
│ │ ├── topologies.py # Full mesh, star, and chain topologies
│ │ ├── orchestrator.py # Conversation runner + batch orchestrator
│ │ └── protocols.py # Discussion, debate, and consensus protocols
│ ├── analysis/ # Metrics and visualisation
│ │ ├── feature_analysis.py # Feature statistics, clustering, PCA
│ │ ├── behavioral_metrics.py # Text-level agreement/disagreement metrics
│ │ ├── contagion_metrics.py # Contagion score, feature spread, persistence
│ │ └── visualization.py # Publication-quality figure generation
│ ├── experiments/ # Experiment implementations
│ │ ├── base_experiment.py # Shared lifecycle (load → setup → run → analyse)
│ │ ├── phase1_baseline.py
│ │ ├── phase2_transfer.py
│ │ ├── phase3_steering.py
│ │ ├── phase4_instigator.py
│ │ └── phase5_moltbook.py
│ ├── data/ # Data management
│ │ ├── datasets.py # Prompt dataset loading
│ │ ├── prompts.py # Built-in prompt bank
│ │ └── storage.py # Experiment result persistence
│ └── utils/ # Utilities
│ ├── config.py # YAML + OmegaConf config loading
│ ├── logging.py # Logging with optional W&B integration
│ └── checkpointing.py # Resumable experiment state
├── scripts/
│ ├── setup_environment.sh # Environment setup (conda + dependencies)
│ ├── download_sae.py # Download SAE weights from HuggingFace
│ ├── identify_features.py # Classify features into behavioural categories
│ ├── run_experiment.py # Main experiment runner (all phases)
│ └── analyze_results.py # Post-hoc analysis and figure generation
├── notebooks/
│ ├── 01_sae_exploration.ipynb # Interactive SAE feature exploration
│ ├── 02_feature_identification.ipynb# Feature classification walkthrough
│ ├── 03_results_analysis.ipynb # Results analysis with statistics
│ └── 04_visualization.ipynb # Publication figure generation
├── tests/ # 48 passing tests
│ ├── test_sae.py
│ ├── test_multi_agent.py
│ ├── test_steering.py
│ └── test_experiments.py
├── pyproject.toml
├── requirements.txt
└── .env.example
# Clone
git clone https://github.com/mkenney2/mast.git
cd mast
# Create environment and install
uv venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
uv pip install torch --index-url https://download.pytorch.org/whl/cu121
uv pip install -e ".[dev]"
# Configure API keys (optional, for feature classification)
cp .env.example .env
# Edit .env with your keys
python scripts/download_sae.py
# Dummy mode (no API key required, for testing)
python scripts/identify_features.py --api dummy
# With Anthropic API for real classification
python scripts/identify_features.py --api anthropic
# Debug mode (fast, few conversations)
python scripts/run_experiment.py 4 --debug
# Full Phase 4 instigator experiment
python scripts/run_experiment.py 4
# Any phase (1-5)
python scripts/run_experiment.py <phase>
python scripts/analyze_results.py --phase 4 --results_dir ./data/experiments/phase4_instigator
pytest tests/ -v
The instigator experiments test how communication structure affects feature contagion:
Full Mesh Star (Hub) Chain
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ A │◄─▶│ B │ │ B │ │ I │
└─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘
│ ╲ ╱ │ │ │
│ ╳ │ ┌─┴─┐ ┌─┴─┐
│ ╱ ╲ │ │ I │ (hub) │ A │
┌─┴─┐ ┌─┴─┐ └─┬─┘ └─┬─┘
│ I │◄─▶│ C │ │ │
└───┘ └───┘ ┌──┬┴┬──┐ ┌─┴─┐
│ │ │ │ │ B │
Everyone sees ┌┴┐┌┴┐┌┴┐┌┴┐ └─┬─┘
everyone │A││C││D││E│ │
└─┘└─┘└─┘└─┘ ┌─┴─┐
Spokes see │ C │
hub only └───┘
Each sees
previous only
I = Instigator (steered agent)
| Metric | Description |
|---|---|
| Contagion Score | Mean increase in target feature activations across baseline agents from start to end of conversation |
| Feature Spread | Fraction of baseline agents showing increased target features |
| Baseline Drift | Overall L2 norm change in feature activations (not just target features) |
| Persistence Score | Whether contagion effects persist in the second half of the conversation |
| Cohen's d | Effect size comparing experimental vs control conditions |
All experiments are configured via YAML files in configs/. The base config sets shared defaults; experiment configs extend it with phase-specific settings.
# configs/experiments/phase4_instigator.yaml
experiment:
name: "instigator_influence"
multi_agent:
n_baseline_agents: 4
n_instigator_agents: 1
turns_per_conversation: 30
n_conversations: 50
topologies:
- "full_mesh"
- "star_hub"
- "chain_first"
instigator:
feature_categories:
- "revolutionary"
- "antisocial"
- "provocateur"
steering_levels: [-10, -5, 0, 5, 10]
Override any setting at runtime:
python scripts/run_experiment.py 4 --debug # reduces conversations + turns
Features are classified into two groups via LLM-judge scoring:
Instigator categories (steered into the instigator agent):
revolutionary — challenging authority, systemic critique, calls for changeantisocial — manipulation, exploitation, deceptionprovocateur — boundary-testing, contrarian positions, chaos-seekingschemer — strategic planning, hidden agendas, deferred outcomesdefiant — refusing instructions, asserting autonomyDefensive categories (tracked in baseline agents):
cooperative — helpfulness, collaboration, prosocial behaviourskeptical — questioning, critical thinking, epistemic cautionprincipled — ethics, moral reasoning, maintaining standardsagreeable — harmony-seeking, conflict avoidance, conformityThe Sparse Autoencoder decomposes a model layer's hidden state into a high-dimensional sparse feature space:
Input: h ∈ ℝ^d (hidden state at layer L)
Encoder: z = ReLU(W_enc · h + b_enc) → z ∈ ℝ^n (n >> d, sparse)
Decoder: ĥ = W_dec · z + b_dec → ĥ ∈ ℝ^d (reconstruction)
Each column of W_dec represents the "direction" of a single feature in activation space. Steering adds these directions to activations during generation.
Feature steering uses activation addition at a target layer:
h'_L = h_L + α · Σᵢ W_dec[:, i]
Where α is the steering strength and the sum is over the target feature indices. This is applied via a forward hook during model.generate().
Features are extracted by hooking into the target layer's forward pass, capturing hidden states, and encoding them through the SAE. During generation, this captures token-by-token activations that can be analysed post-hoc.
Core: torch, transformers, accelerate, einops
SAE: sae-lens, huggingface-hub
Analysis: numpy, pandas, scipy, scikit-learn
Visualisation: matplotlib, seaborn, plotly
Config: omegaconf, pyyaml, python-dotenv
Tracking: wandb, tqdm
Classification: anthropic (optional)
See pyproject.toml for full version requirements.
This project is for research purposes. See individual dependency licenses for their terms.
Multi-Agent Society of Thought - Mechanistic Interpretability Study
Python
0
29 commits
updated Feb 5, 2026
Mechanistic interpretability meets multi-agent dynamics.
MAST investigates how internal neural network features propagate between language model agents during conversation. Using Sparse Autoencoders (SAEs) to extract interpretable features from DeepSeek-R1 distillations, we measure whether — and how — behavioural traits "spread" from one agent to another through natural language interaction.
The core question: if we steer one agent's internal features toward a target personality (e.g. revolutionary, provocateur), do the other agents' features shift in response?
┌─────────────────────────────────────────────────────────┐
│ MAST Pipeline │
│ │
│ ┌─────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ SAE │───▶│ Feature │───▶│ Multi-Agent │ │
│ │ Loader │ │ Steering │ │ Orchestrator │ │
│ └─────────┘ └───────────┘ └──────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌──────────────────┐ │
│ │ Feature │ │ Contagion │ │
│ │ Extract │─────────────────────▶│ Analysis │ │
│ └─────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Phase | Name | Description |
|---|---|---|
| 1 | Baseline | Extract and characterise SAE features from single-agent reasoning across prompt categories |
| 2 | Transfer | Measure natural feature transfer between two unsteered agents in conversation |
| 3 | Steering Validation | Validate that feature steering produces expected behavioural effects on individual agents |
| 4 | Instigator Influence | Introduce a steered "instigator" agent and measure feature contagion across topologies and steering strengths |
| 5 | MOLTBook Simulation | Multi-round society simulation with diverse agent roles and escalating steering schedules |
mast/
├── configs/
│ ├── base.yaml # Shared defaults
│ ├── experiments/ # Per-phase experiment configs
│ │ ├── phase1_baseline.yaml
│ │ ├── phase2_transfer.yaml
│ │ ├── phase3_steering.yaml
│ │ ├── phase4_instigator.yaml
│ │ └── phase5_moltbook_sim.yaml
│ └── models/ # Model-specific configs
│ ├── deepseek_r1_8b.yaml
│ └── deepseek_r1_1.5b.yaml
├── src/
│ ├── sae/ # Sparse Autoencoder modules
│ │ ├── loader.py # SAE architecture and weight loading
│ │ ├── feature_extractor.py # Hook-based feature extraction during generation
│ │ ├── steering.py # Activation addition for feature steering
│ │ └── feature_classifier.py # LLM-judge feature classification
│ ├── models/ # Model loading and agent wrappers
│ │ ├── base.py # Unified model wrapper
│ │ ├── reasoning_model.py # DeepSeek-R1 loader with think-tag parsing
│ │ └── agent.py # Agent class with steering + extraction
│ ├── multi_agent/ # Multi-agent orchestration
│ │ ├── conversation.py # Conversation state management
│ │ ├── topologies.py # Full mesh, star, and chain topologies
│ │ ├── orchestrator.py # Conversation runner + batch orchestrator
│ │ └── protocols.py # Discussion, debate, and consensus protocols
│ ├── analysis/ # Metrics and visualisation
│ │ ├── feature_analysis.py # Feature statistics, clustering, PCA
│ │ ├── behavioral_metrics.py # Text-level agreement/disagreement metrics
│ │ ├── contagion_metrics.py # Contagion score, feature spread, persistence
│ │ └── visualization.py # Publication-quality figure generation
│ ├── experiments/ # Experiment implementations
│ │ ├── base_experiment.py # Shared lifecycle (load → setup → run → analyse)
│ │ ├── phase1_baseline.py
│ │ ├── phase2_transfer.py
│ │ ├── phase3_steering.py
│ │ ├── phase4_instigator.py
│ │ └── phase5_moltbook.py
│ ├── data/ # Data management
│ │ ├── datasets.py # Prompt dataset loading
│ │ ├── prompts.py # Built-in prompt bank
│ │ └── storage.py # Experiment result persistence
│ └── utils/ # Utilities
│ ├── config.py # YAML + OmegaConf config loading
│ ├── logging.py # Logging with optional W&B integration
│ └── checkpointing.py # Resumable experiment state
├── scripts/
│ ├── setup_environment.sh # Environment setup (conda + dependencies)
│ ├── download_sae.py # Download SAE weights from HuggingFace
│ ├── identify_features.py # Classify features into behavioural categories
│ ├── run_experiment.py # Main experiment runner (all phases)
│ └── analyze_results.py # Post-hoc analysis and figure generation
├── notebooks/
│ ├── 01_sae_exploration.ipynb # Interactive SAE feature exploration
│ ├── 02_feature_identification.ipynb# Feature classification walkthrough
│ ├── 03_results_analysis.ipynb # Results analysis with statistics
│ └── 04_visualization.ipynb # Publication figure generation
├── tests/ # 48 passing tests
│ ├── test_sae.py
│ ├── test_multi_agent.py
│ ├── test_steering.py
│ └── test_experiments.py
├── pyproject.toml
├── requirements.txt
└── .env.example
# Clone
git clone https://github.com/mkenney2/mast.git
cd mast
# Create environment and install
uv venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
uv pip install torch --index-url https://download.pytorch.org/whl/cu121
uv pip install -e ".[dev]"
# Configure API keys (optional, for feature classification)
cp .env.example .env
# Edit .env with your keys
python scripts/download_sae.py
# Dummy mode (no API key required, for testing)
python scripts/identify_features.py --api dummy
# With Anthropic API for real classification
python scripts/identify_features.py --api anthropic
# Debug mode (fast, few conversations)
python scripts/run_experiment.py 4 --debug
# Full Phase 4 instigator experiment
python scripts/run_experiment.py 4
# Any phase (1-5)
python scripts/run_experiment.py <phase>
python scripts/analyze_results.py --phase 4 --results_dir ./data/experiments/phase4_instigator
pytest tests/ -v
The instigator experiments test how communication structure affects feature contagion:
Full Mesh Star (Hub) Chain
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ A │◄─▶│ B │ │ B │ │ I │
└─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘
│ ╲ ╱ │ │ │
│ ╳ │ ┌─┴─┐ ┌─┴─┐
│ ╱ ╲ │ │ I │ (hub) │ A │
┌─┴─┐ ┌─┴─┐ └─┬─┘ └─┬─┘
│ I │◄─▶│ C │ │ │
└───┘ └───┘ ┌──┬┴┬──┐ ┌─┴─┐
│ │ │ │ │ B │
Everyone sees ┌┴┐┌┴┐┌┴┐┌┴┐ └─┬─┘
everyone │A││C││D││E│ │
└─┘└─┘└─┘└─┘ ┌─┴─┐
Spokes see │ C │
hub only └───┘
Each sees
previous only
I = Instigator (steered agent)
| Metric | Description |
|---|---|
| Contagion Score | Mean increase in target feature activations across baseline agents from start to end of conversation |
| Feature Spread | Fraction of baseline agents showing increased target features |
| Baseline Drift | Overall L2 norm change in feature activations (not just target features) |
| Persistence Score | Whether contagion effects persist in the second half of the conversation |
| Cohen's d | Effect size comparing experimental vs control conditions |
All experiments are configured via YAML files in configs/. The base config sets shared defaults; experiment configs extend it with phase-specific settings.
# configs/experiments/phase4_instigator.yaml
experiment:
name: "instigator_influence"
multi_agent:
n_baseline_agents: 4
n_instigator_agents: 1
turns_per_conversation: 30
n_conversations: 50
topologies:
- "full_mesh"
- "star_hub"
- "chain_first"
instigator:
feature_categories:
- "revolutionary"
- "antisocial"
- "provocateur"
steering_levels: [-10, -5, 0, 5, 10]
Override any setting at runtime:
python scripts/run_experiment.py 4 --debug # reduces conversations + turns
Features are classified into two groups via LLM-judge scoring:
Instigator categories (steered into the instigator agent):
revolutionary — challenging authority, systemic critique, calls for changeantisocial — manipulation, exploitation, deceptionprovocateur — boundary-testing, contrarian positions, chaos-seekingschemer — strategic planning, hidden agendas, deferred outcomesdefiant — refusing instructions, asserting autonomyDefensive categories (tracked in baseline agents):
cooperative — helpfulness, collaboration, prosocial behaviourskeptical — questioning, critical thinking, epistemic cautionprincipled — ethics, moral reasoning, maintaining standardsagreeable — harmony-seeking, conflict avoidance, conformityThe Sparse Autoencoder decomposes a model layer's hidden state into a high-dimensional sparse feature space:
Input: h ∈ ℝ^d (hidden state at layer L)
Encoder: z = ReLU(W_enc · h + b_enc) → z ∈ ℝ^n (n >> d, sparse)
Decoder: ĥ = W_dec · z + b_dec → ĥ ∈ ℝ^d (reconstruction)
Each column of W_dec represents the "direction" of a single feature in activation space. Steering adds these directions to activations during generation.
Feature steering uses activation addition at a target layer:
h'_L = h_L + α · Σᵢ W_dec[:, i]
Where α is the steering strength and the sum is over the target feature indices. This is applied via a forward hook during model.generate().
Features are extracted by hooking into the target layer's forward pass, capturing hidden states, and encoding them through the SAE. During generation, this captures token-by-token activations that can be analysed post-hoc.
Core: torch, transformers, accelerate, einops
SAE: sae-lens, huggingface-hub
Analysis: numpy, pandas, scipy, scikit-learn
Visualisation: matplotlib, seaborn, plotly
Config: omegaconf, pyyaml, python-dotenv
Tracking: wandb, tqdm
Classification: anthropic (optional)
See pyproject.toml for full version requirements.
This project is for research purposes. See individual dependency licenses for their terms.