Test How Message Bandwidth Changes Multi-Agent Coordination
A team that coordinates perfectly with unlimited chatter can fall apart the moment you cap messages per step or flip a few bits. That collapse is the…

Key topics
A team that coordinates perfectly with unlimited chatter can fall apart the moment you cap messages per step or flip a few bits. That collapse is the experiment.
Most multi-agent communication tutorials hand you a learned protocol and a success curve, then stop. They never ask the question that decides whether the protocol is worth deploying: at what point does more channel capacity stop buying coordination? This is a runnable harness that answers it with numbers. You vary bandwidth and noise as explicit parameters, measure both coordination success and communication cost, and find the knee where the channel stops paying for itself.
The code is small enough to trace one episode by hand. That matters more than scale here — if you cannot see which message changed which action, you cannot interpret the curves.
What the Experiment Must Measure
Before writing a line of code, fix the two axes. A single scalar "team score" hides the entire tradeoff, because it collapses success and cost into one number that can improve while the underlying system gets worse.
Coordination outcome is one of: task completion rate, mean steps-to-goal, or mean joint reward per episode. Pick one primary metric and report the others as context.
Communication cost is messages per step, bits per message, and a cost term subtracted from reward. The cost term is what makes the tradeoff explicit rather than implicit. Without it, agents learn to broadcast everything and you never see a frontier — you see a ceiling.
State your assumptions up front, because every one of them constrains what the protocol can rely on:
- Cooperative shared reward.
- Partial observability — each agent sees only part of the state.
- Decentralized execution — no agent reads another's internal state at action time.
- No parameter sharing unless you note it.
This builds directly on the idea that local observations must become messages and coordinated actions. The decentralized-execution constraint is the sharp edge: a protocol can only rely on what actually arrives at the receiver, not on what the sender intended.
Knowledge check
Check your understanding
Answer this question before you continue.
The Toy Task and Why It Is Enough
You need a task where communication is genuinely required. If the task is solvable from local observation alone, every bandwidth setting produces a flat curve and you learn nothing.
The setup: N agents on a discrete grid, each seeing only a partial view, sharing one team reward, with an episode length cap. A cooperative matching task works well — each agent must reach an assigned target, but the target assignment is split across agents, so no single agent can see the full picture.
The design test is non-negotiable: a no-communication baseline must be measurably worse than full clean communication. If those two endpoints are identical, the task cannot test bandwidth. Fix the task before you touch the channel.
A hand-checkable task beats a benchmark here. You can trace one episode and see exactly which message changed which action. That trace is your ground truth when the aggregate numbers look strange.
Common mistake: Building a task that is solvable from local observation, then concluding "communication doesn't help in this domain." The flat curve is a property of your task, not a fact about communication.
Building the Message Channel as a Parameter
The channel is the whole point, so make it a function with explicit arguments — not hardcoded behavior buried in the policy.
import numpy as np
def channel(messages, bandwidth, noise_p, drop_p, rng):
"""
messages: array of shape (n_agents, msg_dim), float in [0, 1]
bandwidth: max symbols transmitted per agent (int)
noise_p: per-symbol substitution probability
drop_p: per-message loss probability
Returns received: array of shape (n_agents, msg_dim), zeros where dropped
"""
sent = messages.copy()
# Bandwidth: truncate to the first `bandwidth` symbols, zero the rest
if bandwidth < sent.shape[1]:
sent[:, bandwidth:] = 0.0
# Noise: substitute symbols independently
flip = rng.random(sent.shape) < noise_p
sent = np.where(flip, 1.0 - sent, sent)
# Drop: whole-message loss, independent per agent
drop = rng.random(sent.shape[0]) < drop_p
sent[drop] = 0.0
return sent
Three things to notice.
Bandwidth is a cap on message length. Truncation is the concrete mechanism; quantization to fewer levels is an equivalent alternative. Either way, the receiver gets less information per step.
Noise and drop are separate. Noise corrupts symbols; drop removes whole messages. Keep them apart so you can compare their effects. They fail differently — noise degrades gracefully, drop creates holes.
Seeding is deterministic. One seed, one reproducible run, one replayable episode. Without this, you cannot inspect a single step and trust what you see.
The observable output you want is a printed trace of one step:
step 4 | agent0 sent [0.9 0.1 0.7] -> recv [0.9 0.0 0.7] (bw=2)
| agent1 sent [0.2 0.8 0.3] -> recv [0.2 0.8 0.3] (bw=2)
| actions: agent0=right agent1=up
Read that trace before you read any curve. It tells you whether messages are reaching the policy at all.
Knowledge check
Check your understanding
Answer this question before you continue.
Running the Sweep and Reading the Curves
Now vary the knobs and record both axes. A clean sweep structure:
| Bandwidth | Noise | Success rate | Mean steps | Msgs/episode | Net reward |
|---|---|---|---|---|---|
| 0 (none) | 0.00 | low | high | 0 | low |
| 1 | 0.00 | mid | mid | low | mid |
| 2 | 0.00 | high | low | mid | high |
| full | 0.00 | high | low | high | mid |
| 2 | 0.20 | mid | mid | mid | mid |
Cross bandwidth in {0, 1, 2, full} with noise in {0, 0.05, 0.2}, fix your seeds, and fix your episode budget. Report every setting with the same metrics.
The shape you are looking for is a knee. Success rises steeply as bandwidth grows, then flattens — while cost keeps climbing. That knee is the answer to the article's question. Past it, you are paying for channel capacity that coordination does not use.
Telling a bandwidth constraint from a noise constraint is a different read:
- Bandwidth limits show a ceiling. More training cannot lift it, because the information simply is not in the channel.
- Noise shows variance and degradation. Better encoding or redundancy can partially recover it, because the information was sent but corrupted.
Note: Report all seeds, not the best run. A single lucky seed is not evidence. If your curves only look clean when you cherry-pick, you have measured noise, not the channel.
Knowledge check
Check your understanding
Answer this question before you continue.
When the Channel Is the Bottleneck — and When It Is Not
This is the decision boundary the experiment exists to find. Get it wrong and you will spend weeks tuning a protocol that was never the problem.
| Symptom | Diagnosis | Next move |
|---|---|---|
| No-comm baseline fails, success tracks bandwidth | Channel is the bottleneck | Invest in the protocol |
| Success flat across all bandwidths | Task does not need communication | Redesign the task |
| Fails even with full clean communication | Not a channel problem | Check credit assignment, exploration, non-stationarity |
| Success high but net reward falls as bandwidth grows | Cost is the bottleneck | The team is over-communicating |
The practical rule: measure the no-communication and full-communication endpoints first. Everything between them is only interesting if those two differ. If they do not differ, stop — you have a task problem, not a communication problem.
And the overkill boundary: if the task is solvable from local observation, adding a learned protocol adds parameters and failure surface for no gain. Communication is not free just because it is available.
Knowledge check
Check your understanding
Answer this question before you continue.
Failure Modes and Debugging Signals
RL code that runs fine but never learns is usually a wiring bug, not a hyperparameter problem. Inspect the trace before you tune.
- Flat curves everywhere. The task does not require communication, or messages are not reaching the policy. Check the trace first.
- Success collapses only at evaluation. The protocol learned to depend on a message field that gets dropped or corrupted at test time. This is a train/test channel mismatch.
- Cost term dominates. Agents learn to stay silent and the task degrades. Your cost weight is so high it forbids useful messages.
- Non-reproducible results. Unseeded noise, or noise applied at a different point in the pipeline than you assumed.
Tip: When a run looks broken, print one step's sent/transmitted/received messages and the resulting actions. Nine times out of ten the bug is visible in that single trace.
One Modification Worth Running Next
The harness is the asset, not any single result. Pick one change that tests the mechanism rather than re-running the same code.
Add redundancy. Send each message twice and let the receiver vote. Compare recovery under noise against the single-send baseline. If redundancy helps, noise was your constraint; if it does not, bandwidth was.
Or make bandwidth adaptive. Let agents choose what to send under a fixed budget. Does learned selection beat fixed truncation at matched cost?
Or swap in a learned channel and compare cost at matched success. The honest comparison is cost at equal performance, not raw success — a protocol that wins on success while spending ten times the bandwidth has not won.
Record the same metrics as before, plus a note on whether the change moved the knee or just shifted the whole curve. Moving the knee means you changed the constraint. Shifting the curve means you changed the scale.
The Decision Rule to Carry Forward
Measure the no-communication and full-communication endpoints first. Then find the knee where success stops rising while cost keeps climbing. That knee is your bandwidth budget.
Keep the harness. Change one channel parameter at a time. Treat every flat curve as a question about your task rather than a fact about communication — because in my experience, that is almost always what it is. The next practical step is to take the redundancy modification above and see whether it moves the knee under noise. If it does, you have found the boundary where reliability, not capacity, is the real constraint.
Knowledge check
Final check
Finish the article by checking the ideas you just learned.
References
Build a stronger RL mental model
Use structured resources to connect equations, algorithms, and observable agent behavior.


