Skip to Content
API classesArchitecturesMultiAgentDebate

MultiAgentDebate

from loomflow.architecture import MultiAgentDebate

MultiAgentDebate has several agents answer the same question, read each other’s answers, and argue over a few rounds. A judge agent (or a majority vote) then picks the final answer. Use it for contested, high-stakes questions where disagreement between viewpoints tells you something. Based on Du et al. 2023, Improving Factuality and Reasoning in Language Models through Multiagent Debate, and Liang et al. 2023 (divergent thinking via debate); AutoGen GroupChat and CAMEL use similar patterns.

For the conceptual page see Multi-Agent Debate.


Class signature

class MultiAgentDebate: name: str = "debate" def __init__( self, *, debaters: list[Agent], judge: Agent | None = None, rounds: int = 2, convergence_check: bool = True, convergence_similarity: float = 0.85, debater_instructions: str | None = None, judge_instructions: str | None = None, worker_registry: dict[str, Any] | None = None, role_to_worker_id: dict[str, str] | None = None, ) -> None: ...

Constructor parameters

debaters

Typelist[Agent]
Defaultrequired

The debating agents. Must contain at least 2 (a debate with one participant is just a single-agent run); raises ValueError otherwise. For best results, use different models or prompts so the debaters don’t share the same blind spots.

judge

TypeAgent | None
DefaultNone

Optional synthesising agent. Reads the full debate transcript and produces the final answer. When None, the architecture falls back to majority vote on the final round’s Final answer: lines. The judge’s spend is charged to the coordinator’s budget.

rounds

Typeint
Default2

Maximum debate rounds after the independent round 0, so each debater answers up to rounds + 1 times. Du et al.’s rounds=2 (one independent round plus one round of debate) is rounds=1 here. Each round, all debaters run in parallel with full transcript context. Must be >= 1.

convergence_check

Typebool
DefaultTrue

When True (default), the architecture checks for early termination after each round: if every debater’s Final answer: line gives the same answer, the loop terminates. Set to False for adversarial-only debates where you want full rounds even if positions converge.

convergence_similarity

Typefloat
Default0.85

Jaccard similarity threshold in [0.0, 1.0] for the convergence check’s fallback. It only applies when some reply in the round has no Final answer: line; then every pair of whole replies must have a word-level Jaccard similarity of at least this value. 0.85 means roughly “the same reply, possibly in different words”. 1.0 requires identical replies (after whitespace normalisation). Lower values stop sooner (cheaper, but risk stopping before the debate has settled).

debater_instructions

Typestr | None
DefaultNone (uses built-in default)

Override the debaters’ prompt for the debate rounds (1 and later). The default asks each debater to defend or update its position in light of the prior transcript and to close with a Final answer: <answer> line. Keep that request in a custom prompt: the vote and the convergence check read it. Round 0 always sends the question with a fixed request for an independent answer ending in a Final answer: line.

judge_instructions

Typestr | None
DefaultNone (uses built-in default)

Override the judge’s prompt. The default reads the full transcript and synthesises the final answer with brief justification.

worker_registry / role_to_worker_id

Internal wiring set by Team.debate when persistent_subagents=True (the default), so each debater keeps one conversation per user across rounds. You normally don’t pass these yourself.


Methods

declared_workers

def declared_workers(self) -> dict[str, Agent]: workers = {f"debater_{i}": d for i, d in enumerate(self._debaters)} if self._judge is not None: workers["judge"] = self._judge return workers

Each debater is keyed debater_0, debater_1, …; the judge is keyed judge when present.

run

  1. Round 0 (independent). All debaters answer the original question simultaneously, with no awareness of each other. Run in parallel. Emits debate.round_started, debate.response per debater.
  2. Rounds 1..rounds (debate). Each debater receives the original question + full transcript. They defend or update their position. All debaters in a round run in parallel. The coordinator’s budget is checked before each round.
  3. Convergence check (when convergence_check=True). Compares the debaters’ final answers (the last Final answer: ... line, or a \boxed{...} answer, normalised for case, whitespace, surrounding punctuation and **bold**). If they all match, stop early and emit debate.converged. When a reply has no final answer, the check falls back to pairwise Jaccard similarity of whole replies against convergence_similarity. Agreement in round 0 ends the debate with the majority answer, without the judge.
  4. Synthesise. Either judge.run(synthesis_prompt) (event debate.judging) or a majority vote on the final round’s answers. The vote groups replies by final answer (whole text when a reply has none), returns the first reply of the largest group, and breaks ties by debater order. Emits debate.synthesized with the method used.

A debater that raises or comes back interrupted (its own max_turns, a budget) sits that round out and the debate emits debate.debater_failed with the error; the round continues with the others. The debate raises only when no debater answers a round. Each debater’s spend is charged to the coordinator’s budget.


When debate pays off

  • High-stakes decisions: pricing, hiring, security policy, architecture choices.
  • Adversarial review: red-team / blue-team style argument.
  • When disagreement is informative: specialists with different priors should disagree, and the disagreement is the signal.

When NOT to use

  • Tasks with a clear right answer (math, code), where debate is wasted effort.
  • Time-sensitive interactive use (chatbots), where it is too slow.
  • Cost-sensitive bulk processing: expect 3–5× single-agent cost.

Example

from loomflow import Agent from loomflow.architecture import MultiAgentDebate from loomflow.team import Team optimist = Agent("Argue for the positive case.", model="claude-opus-4-7") skeptic = Agent("Argue for the cautious case.", model="claude-opus-4-7") analyst = Agent("Argue from the data.", model="gpt-4o") cio = Agent( "You are the CIO. Read the full debate transcript and pick the " "best decision with one paragraph of justification.", model="claude-opus-4-7", ) team = Team.debate( debaters=[optimist, skeptic, analyst], judge=cio, rounds=2, convergence_similarity=0.85, model="claude-opus-4-7", ) result = await team.run( "Should we adopt agent harnesses for our customer support stack?" )

Source

loomflow/architecture/debate.py

Convergence ≠ correctness. Debaters may converge on a wrong answer if they share priors. Use different models and prompts so their blind spots don’t overlap. For best-of-N with a different-model critic, ActorCritic is cheaper.

Last updated on