Documentation
Watch opinions form, split and settle
The lab simulates how opinions spread on a social network. Each person in the network is an agent that reads what its neighbours post, thinks about it, and writes its own posts, day after day.
Classic opinion-dynamics models reduce each person to a single number and move that number with a fixed rule. Here the agents can be language models that read and write actual text, so you can see not only whether an opinion changed but why: every post an agent read, its reasoning and its new post are saved.
Two things set this lab apart from earlier LLM simulations such as Wang et al. (2025), which used one model for every agent:
- Different agents can run on different models (Llama, Gemma, Mistral, Qwen, Claude, GPT, Grok, DeepSeek…), so the population mixes genuinely different ways of reasoning.
- Individual trajectories are inspectable. You can follow a single agent through the run and see which posts moved it.
The classic numeric models are included too, so every LLM run can be compared with a baseline on exactly the same network.
Quick start
uv sync --extra analysis # install
uv run disensa app # open the start page, then the Lab
In the Lab, open New run in the header, pick a preset or set each part, and press Run simulation. The demo_camps preset uses offline test models and finishes in a few seconds.
For real language models, install Ollama, start it, and pull a few models:
ollama serve # keep this running
ollama pull llama3.2:3b && ollama pull qwen2.5:7b
Installed Ollama models then appear in the model menus. Everything also works from the command line:
uv run disensa run configs/quick.yaml # run a config
uv run disensa inspect runs/<run> # per-model summary and largest opinion shifts
uv run disensa viz runs/<run> # one offline viewer file for a run
How a run works
- Build the network. A random, small-world or scale-free graph connects the agents. It is seeded, so the same seed always gives the same network.
- Create the agents. Each agent gets a persona and a starting opinion, and is assigned a model.
- Day 0. Every agent writes a first post about the statement.
- Each following day. Every agent reads a few posts from the people it follows, then replies with its reasoning, its new opinion, a new post, and an updated memory. All agents act at the same time, based on the previous day.
- End of the day. A fixed scorer rates every post, the network may rewire, and the metrics are recorded.
Days are synchronous: everyone reads the state of day t − 1 and all updates apply together, so the order in which agents are processed never matters.
LLM agents
Personas
Following Wang et al., each agent is described by a gender, an age between 18 and 64, an education level, and one pole of each Big Five personality trait (for example “open to new ideas” or “prefers the familiar”). Agents are identified only by a number, to avoid bias from names.
Personas depend only on the seed, never on which model an agent uses. This means the same population can be replayed under different model mixes, and any difference in outcome comes from the models.
Memory and prompts
Each agent keeps a short running summary of what it has seen and thought (at most memory_words words). Every day it receives its persona, its memory, its current opinion and the day's posts, and answers in JSON with four fields: reasoning, belief, post and memory.
Model output is treated as untrusted. Replies are parsed tolerantly (code fences and small JSON mistakes are fixed), and a reply that still cannot be used is logged as an error while the agent keeps its previous state. A bad reply never stops a run.
With confirmation bias switched on, the prompt tells agents that they tend to favour arguments that agree with them. Chuang et al. (2024) found that LLM agents otherwise drift towards the factual consensus.
Models
| Kind | Example name | Notes |
|---|---|---|
| Local, Ollama | ollama_chat/llama3.1:8b | Free, runs on your computer. Installed models appear automatically in the Lab. |
| Hosted APIs | anthropic/…, openai/…, xai/…, deepseek/… | Put the API keys in a .env file. Costs money. |
| Any OpenAI-compatible server | openai/<model> + api_base | For example a vLLM server on a GPU cluster. |
| Offline test models | fake/tribal, fake/stubborn… | No model at all, instant and deterministic. For trying the tool and for tests. |
The offline test models imitate simple behaviours, so every part of the lab can be tried without a language model:
| Test model | Behaviour |
|---|---|
fake/bounded | Moves towards posts within 1.5 of its own opinion. |
fake/conformist | Moves strongly towards everything it reads. |
fake/stubborn | Barely moves. |
fake/contrarian | Moves away from what it reads. |
fake/tribal | Only listens to posts within 0.7 of its own opinion, so the population splits into camps. |
Every model reply is cached on disk, so running the same configuration again costs nothing and returns the same result.
Mixing models
When a run uses several models, each has a weight: its share of the agents. The assignment decides where those agents sit in the network.
| Assignment | What it does |
|---|---|
balanced (default) | Exact shares from the weights, placed at random. |
random | Each agent draws a model independently, with probability proportional to its weight. |
clustered | Exact shares, but whole communities of the network (found with the Louvain method) share a model, so model and network position are correlated. |
The scorer
Language models are not always consistent when they report their own opinion. Following Chuang et al., a single fixed scorer model reads every post and rates it from −2 to +2. The same scorer rates every agent, and it should ideally come from a different lab than the agents, so no model grades its own family's writing.
Numeric algorithms
These classic models run on exactly the same networks and starting opinions as the LLM agents, with each opinion a single number xi on [−2, 2]. One “day” is one step of the model.
DeGroot
Everyone moves to the average of their own opinion and their neighbours'. On a connected network this always ends in full consensus.
Bounded confidence (Hegselmann–Krause)
Agents only listen to neighbours whose opinion is close enough to their own, within the confidence bound ε, and move towards them at rate μ. This is the numeric counterpart Wang et al. compare against. A wide ε gives consensus; a narrow ε lets the population break into separate clusters.
Deffuant
The pairwise version: random pairs of connected agents meet, and if their opinions are within ε, both move towards each other by μ times their difference. One step is as many encounters as there are edges.
Friedkin–Johnsen
Each agent keeps its innate opinion si (its starting opinion) and balances it against its neighbours. The stubbornness λ sets how strongly it holds on, so disagreement never fully disappears.
Network topologies
Every network is seeded and always connected (a random graph is redrawn until it is).
Random (Erdős–Rényi)
Every pair is linked with the same probability p. No clusters and no hubs.
Small-world (Watts–Strogatz)
A ring where each agent links to its k nearest neighbours, and a share β of the links are rewired at random. Tight local groups with short paths between them.
Scale-free (Barabási–Albert)
Grows one agent at a time, each linking to m existing agents, preferring popular ones. A few hubs, many agents with few links.
| Topology | Parameters | Typical values |
|---|---|---|
erdos_renyi | p: edge probability (0–1) | 0.08–0.15 for 50 agents |
watts_strogatz | k: neighbours on the ring (even); β: rewiring share (0–1) | k = 4–6, β = 0.1 |
barabasi_albert | m: links per new agent | 2–3 |
All topologies take n, the number of agents (default 50, as in Wang et al.). Wang et al. found echo chambers on small-world and scale-free networks but not on random ones.
Initial opinions
| Distribution | Parameters | What you get |
|---|---|---|
uniform (default) | none | Opinions spread evenly between −2 and +2. |
normal | mean, std | Most agents near the mean. |
bimodal | mean (camp position ±), std | Two camps around −mean and +mean, already polarized. |
Values are clipped to [−2, 2]. For LLM agents, the starting opinion becomes part of the first prompt (“you somewhat support this statement, +0.8”).
Simulation settings
Feed and recommender
Each day an agent reads a random number of posts, between posts read min and max, from the people it is linked to.
With the recommender on, it only sees posts from neighbours whose opinion is within the similarity threshold of its own, like a feed that shows people content they already agree with (Wang et al. §3.3). A lower threshold means a stronger filter bubble.
Rewiring
Off by default. When on, at the end of each day every agent, with some probability, unfollows the neighbour it disagrees with most (if the gap is beyond the unfollow threshold) and follows someone new: a similar agent, or anyone. The number of links stays the same and nobody is ever left without links. This follows the co-evolving network models of Holme & Newman (2006) and Sasahara et al. (2021).
| Setting | Default | Meaning |
|---|---|---|
| Chance per day | 0.1 | Probability that an agent reconsiders its links on a given day. |
| Unfollow beyond | 1.5 | Only neighbours further than this can be dropped. |
| Follow | similar | similar: someone within the next setting; random: anyone. |
| Similar within | 0.5 | How close a new contact must be. |
Which opinion counts
Each LLM agent has two opinions every day: the belief it reports itself (the approach of Wang et al.) and the scorer's rating of its post (the approach of Chuang et al.). Both are always saved. The setting chooses which one drives the metrics, the recommender and rewiring.
Metrics
Recorded every day, following Wang et al. §4.2. N is the number of agents and N(i) the neighbours of agent i.
Polarization
The variance of all opinions. High when the population sits at the extremes.
Global disagreement
How much agents disagree with their own neighbours. It falls when neighbours come to agree, the local signature of an echo chamber.
Neighbour correlation
The correlation between each agent's opinion and the average opinion of its neighbours (Cinus et al. 2022). Close to +1 when like-minded agents cluster together.
With several models
Runs that mix models also record the mean opinion of each model's agents and the model homophily: the share of links between two agents on the same model.
Reading a run
Open a run from Runs in the Lab header. Live runs stream in as each day finishes.
- Network. Colour is opinion, from pale blue (oppose) to deep blue (support); shape is the model; size is the number of links. Horizontal position follows opinion, so camps pull apart on screen. Drag nodes to move them.
- Playback. Play, pause or scrub through the days. Opinions change smoothly between days. Arrow keys step a day; space plays.
- Agent panel. Click an agent to see its persona, its opinion over time, the posts it read that day (click one to jump to that agent), its reasoning and its post.
- Charts. The three metrics, mean opinion by model, and today's opinion distribution. Click a chart to jump to that day.
- Table. Every agent's opinion, links and post for the selected day.
From the command line, disensa inspect lists how each model behaved and the largest opinion shifts, each marked as moving toward what the agent read (assimilation) or away from it (repulsion), with the agent's reasoning.
Run files
Each run is saved in its own folder, runs/<date>_<name>_s<seed>/:
| File | Contents |
|---|---|
meta.json | The full configuration, the code version (git commit), timing and call counts. |
agents.parquet | One row per agent: persona, model, number of links. |
opinions.parquet | Per day and agent: reported belief, scorer rating, and the opinion used. |
metrics.parquet | One row per day with every metric. |
events.jsonl | Per day and agent: what it read, its reasoning, post, memory, the raw model reply and any error; plus rewiring events. |
edges.jsonl | The network on day 0 and on every day it changed. |
Parquet tables open directly in pandas or DuckDB.
All parameters
Everything the Lab form sets can also be written in a YAML config (see the configs/ folder).
| Setting | Default | Description |
|---|---|---|
name, seed | –, 0 | Run name and random seed. Same seed, same run. |
network.topology | – | erdos_renyi, watts_strogatz or barabasi_albert, with its parameters above. |
network.n | 50 | Number of agents. |
opinions.distribution | uniform | uniform, normal or bimodal, with mean (0) and std (1). |
topic.statement | the euthanasia statement | The statement agents take a position on. |
models | – | List of models, each with name, weight (1), temperature (0.7) and optional api_base. |
assignment | balanced | balanced, random or clustered. |
scorer.name | none | Model that rates every post (temperature 0). |
simulation.days | 5 | Number of simulated days. |
simulation.feed | 1–5 | Posts read per day (min_posts, max_posts). |
simulation.recommender | on, 2.0 | Show only neighbours within threshold. |
simulation.rewiring | off | probability 0.1, unfollow_threshold 1.5, follow similar, follow_threshold 0.5. |
simulation.opinion_source | self | self (reported belief) or classifier (scorer rating; needs a scorer). |
simulation.bias | none | confirmation adds a confirmation-bias sentence to every prompt. |
simulation.memory_words | 60 | Maximum length of an agent's memory summary. |
baseline | – | For numeric runs: model, steps (100), epsilon (1.0), mu (0.5), stubbornness (1.0). |
llm.max_concurrency | 4 | Parallel requests per provider. Raise it if your machine or API allows. |
llm.max_tokens | 400 | Maximum length of each model reply. |
References
- Wang et al. (2025). Decoding Echo Chambers: LLM-Powered Simulations Revealing Polarization in Social Networks. COLING 2025. arXiv:2409.19338.
- Chuang et al. (2024). Simulating Opinion Dynamics with Networks of LLM-based Agents. arXiv:2311.09618.
- DeGroot, M. H. (1974). Reaching a consensus. Journal of the American Statistical Association.
- Hegselmann, R. & Krause, U. (2002). Opinion dynamics and bounded confidence. JASSS 5(3).
- Deffuant et al. (2000). Mixing beliefs among interacting agents. Advances in Complex Systems.
- Friedkin, N. E. & Johnsen, E. C. (1990). Social influence and opinions. Journal of Mathematical Sociology.
- Watts, D. J. & Strogatz, S. H. (1998). Collective dynamics of small-world networks. Nature.
- Barabási, A.-L. & Albert, R. (1999). Emergence of scaling in random networks. Science.
- Holme, P. & Newman, M. E. J. (2006). Nonequilibrium phase transition in the coevolution of networks and opinions. Physical Review E.
- Sasahara et al. (2021). Social influence and unfollowing accelerate the emergence of echo chambers. Journal of Computational Social Science.
- Cinus et al. (2022). The effect of people recommenders on echo chambers and polarization. ICWSM.