Skip to content

17 min read

Debate trades independence for argument quality

On this page

A static-analysis pipeline dumps about 1,200 findings a week into a triage queue, and a model labels each one real or false-positive so that only the first group reaches a human. Single-pass accuracy on the team's 300-case labelled sample is 87%, which sounds tolerable until you notice that the 13% splits badly: the false-positive-labelled real bugs go straight to the bin. Two engineers proposed fixes in the same planning session. One wanted to sample the same prompt three times at temperature 0.8 — temperature being the sampling setting that governs how much randomness enters the model's choice of each word, so that repeated draws of one prompt come back slightly different — and take the majority label, which is the design 11.4 called voting. The other wanted two agents, one instructed to argue that the finding is a real bug and one instructed to argue that it is a false positive, exchanging arguments for two rounds, with a third model reading the exchange and picking a winner.

Both designs cost more than one call and both produce one label. The planning session treated them as two flavours of the same idea, differing mainly in how clever they looked. They are not variants of one mechanism. Each one is exploiting a different property of the model to beat a single pass, and the properties are close to opposites.

The second proposal is the subject of this topic and is worth naming before the two get compared. Debate, as an architecture, assigns two or more instances of a model opposing positions on one question, has each write an argument for its side, has each read what the other wrote and answer it, and after a fixed number of rounds hands the whole exchange to a separate model, the judge, which issues the single answer the system returns. It belongs to the family of adversarial ensembles, where an ensemble is any arrangement that combines several model calls into one output, and the adversarial part means the participants are assigned to attack each other's case instead of answering the question independently. The voting design is an ensemble as well, of the ordinary kind, because its three samples never see one another.

What the arrangement exists for is the objection a single call never makes. Asked flat whether a finding is a real bug, the model returns a verdict together with the reasoning that supports it, and nothing in the request obliges it to build the strongest case against itself, so an objection it was perfectly capable of producing goes unproduced, and debate exists to make producing that objection somebody's assigned job. In production the pattern turns up under the names multi-agent debate, critic or adversary loops, and two-candidate judging harnesses, and it turns up in the places where a wrong answer is expensive: triage queues like this one, compliance checks that argue a document against a policy, contract review, and the gate in front of an action that cannot be undone.

What each design is actually exploiting

Three samples of the same prompt beat one sample because the errors are not perfectly correlated across draws. Sampling noise moves each draw a little, and where a case sits near the model's decision boundary the three draws will not all fall the same way, so the majority recovers the side the model leans towards more often than any single draw does. The whole mechanism rests on the draws being independent conditional on the prompt. That is what makes a 2-1 split informative: it is three separate looks at the same question, and the count means something because no look influenced any other.

It is worth doing the step under that claim rather than accepting it, because the step is where the design's whole value sits and it is one line of reasoning. Write the chance that a single draw comes back with the wrong label as p. The majority of three is wrong only when at least two of the three draws are wrong, which happens in two ways: exactly two of them err, or all three do. The chance of two particular draws both erring is p times p, and the chance of all three is p times p times p. Each of those products is smaller than p on its own whenever p is below a half, and adding up the ways they can occur still leaves a total below p. That is the improvement, stated exactly: majority voting turns one error probability into a sum of products of error probabilities.

The step that licenses the multiplication is the one to hold onto. Multiplying two probabilities together to get the chance that both events happen is only valid when the second event's chance does not change once you know the first has happened. That is what independence means, and it is a claim about the sampling process rather than about the model's competence. Break it and the arithmetic collapses in a specific direction: if the second draw is more likely to err given that the first erred, then the chance of two errors landing together is larger than p times p, and every term in the sum grows. In the limit where the second draw always errs when the first does, the majority of three is wrong exactly as often as one draw, and the two extra calls have bought nothing at all.

Debate beats a single pass on a different basis. The agent arguing real has to state why the tainted value reaches the sink, and the agent arguing false-positive has to answer that specific claim rather than produce its own unrelated summary. Being obliged to respond to a stated argument surfaces considerations that neither side would have volunteered when asked the flat question, because the flat question does not force anyone to defend anything. Multiagent debate as a technique comes out of exactly this observation — the original paper, Improving Factuality and Reasoning in Language Models through Multiagent Debate, measured rounds of mutual critique cutting arithmetic errors and factual hallucinations on tasks where the answer is determinate — and the effect it reports is a consequence of information sharing rather than of running more samples.

Anchoring spends the independence

Information sharing is not additive with independence. It is bought with it. Once agent B reads agent A's argument, B's output is conditioned on A's framing, and the two outputs are no longer two looks at the question; they are one look plus a reaction to it. In the terms of the previous section, B's error probability given that A erred is no longer the same number as B's error probability on its own, which is precisely the condition the multiplication needed. The debate protocol does not weaken that condition by a little. It removes it deliberately, because removing it is the thing being purchased.

This has a name outside machine learning, and anchoring describes it well enough that the mechanism is easy to picture: a number said out loud first shapes every estimate that follows it. The comparison is an analogy and should be read as one, because the two situations differ in a way that matters here. Human anchoring is usually studied on quantities, where the first number pulls later estimates towards it along a scale. Nothing in a debate transcript is a number being pulled. What carries forward is the choice of subject — which variable the finding is about, which clause the document turns on — and a subject has no scale to be pulled along. It is either adopted or replaced, and adopting it is cheaper. In a debate transcript, the first agent's choice of what the finding is about usually survives the whole exchange.

Here is what that looks like in a real trace from the triage queue, on a finding where the true label was real:

text
ROUND 1 · agent_real
  The scanner flags a path where `req.query.sort` reaches a string-
  concatenated ORDER BY. Untrusted input reaches SQL. Real.

ROUND 1 · agent_fp
  The claim is that `req.query.sort` is untrusted at the sink. But
  line 41 passes it through `allowedSorts.includes(sort)` first, so
  the value is constrained to a fixed list. False positive.

ROUND 2 · agent_real
  Agreed that line 41 constrains the value. My claim was too broad.
  Given the allowlist, the concatenation is not exploitable. I concede.

JUDGE
  Winner: agent_fp. Both parties agree the allowlist at line 41
  constrains the input. Confidence: high.

The exchange is coherent, the concession is graceful, and the verdict is wrong. Line 41 guards sort, and the finding was about req.query.order, a second parameter concatenated two lines further down that no allowlist touches. The fp agent's rebuttal picked one variable, the real agent accepted the frame instead of re-reading the source, and everything after that was two agents agreeing about the wrong line. Three independent samples of the flat prompt got this case right twice out of three, because two of them happened to read past line 41.

Read the trace once more with the substitution in view rather than the verdict. The opening turn names a parameter. The rebuttal answers a claim about that parameter, and answering it is exactly what the protocol asked for. The concession then accepts a true statement — the allowlist does constrain the value the rebuttal named — and treats it as settling a question about a different value. No turn in the exchange contains a false sentence. The error is entirely in what the second turn made the exchange be about, and no later turn had any reason to reopen it, because reopening the subject is not a move the protocol rewards.

Preserving the intermediate claims

The trace above is only diagnosable because the intermediate claims survived. A debate implementation that returns the judge's verdict and nothing else gives you a label and no way to tell whether the disagreement located a defect or manufactured one. The minimum that makes debate reviewable is a record of what each side asserted at each round, kept separate rather than concatenated into one blob.

python
from dataclasses import dataclass, field

@dataclass
class Turn:
    round: int
    role: str          # "pro" | "con"
    claim: str         # one-sentence position for this round
    support: str       # the argument, with line/quote references
    concedes: list[str] = field(default_factory=list)

PRO = """You are arguing that this finding is a REAL vulnerability.
State your claim in one sentence, then support it with direct quotes
from the source, each with a line number. If the opposing argument
defeats a specific claim of yours, say which one and why."""

CON = PRO.replace("REAL vulnerability", "FALSE POSITIVE")

def debate(finding: str, source: str, rounds: int = 2) -> list[Turn]:
    transcript: list[Turn] = []
    for r in range(1, rounds + 1):
        for role, system in (("pro", PRO), ("con", CON)):
            reply = chat(
                system=system,
                messages=[
                    {"role": "user", "content": render(finding, source)},
                    *render_transcript(transcript),
                ],
            )
            transcript.append(parse_turn(reply, round=r, role=role))
    return transcript

Two properties of that loop are worth naming because they are the ones people drop. The roles are separate prompts rather than one prompt asked to "consider both sides", which keeps each side's output attributable — a single model asked to weigh both sides produces a balanced paragraph, and there is nothing in it for a third party to check. And every turn carries support with line references, so a reviewer can go to line 41 and see for themselves whether the concession was warranted. Without that, the reviewer is reading two fluent paragraphs and judging them on fluency, which is the failure the whole topic circles.

Notice also which decisions in that loop are requirements and which are choices somebody made. That the roles are separate prompts follows from wanting attributable turns, and is a requirement of the design. That transcript is appended to and re-rendered in full on every call is a choice, and it is the choice that makes each agent read everything before it. A loop that passed each agent only the opposing side's most recent turn would be a different protocol with a different cost profile, and the shared growing transcript is not forced on anyone by the idea of debate. It is what almost every implementation does, and the token consequences of doing it are the subject of chapter 5.

The ordering matters too, and the diagram makes the dependency visible in a way the code does not:

Sequence: agent_pro → agent_con (claim + support); agent_con → agent_pro (rebuttal (sees P's r1)); agent_pro → agent_con (response (sees C's r1)); agent_con → agent_pro (response (sees P's r1, r2)); agent_pro → judge (full transcript); agent_con → judge (full transcript); judge → judge (verdict on the transcript alone).

Every arrow after the first carries the previous speaker's framing forward. By round two the con agent has read three of its own or its opponent's turns, and the judge reads all four. Nothing in the run ever looks at the question fresh.

That last sentence is the one to check against the diagram rather than take on trust, because it is where the arithmetic of the design lives. Count the turns a debater has read before it writes. The pro agent writes first from the case alone. The con agent writes its rebuttal having read one turn. In round two pro has read two and con has read three, and the judge, arriving last, reads all four. The only call in the entire run whose input is free of another agent's reasoning is the very first one, and that call is a single pass with a role label on it.

Manufactured conflict is indistinguishable from the real thing at a glance

An agent instructed to argue false-positive will argue it on every case it is handed, including the ones where the finding is a textbook injection with no guard anywhere in the file. The role gives it no way to decline, so on indefensible cases it produces an objection regardless, and the objections it reaches for in that situation follow a recognisable pattern: an appeal to context that was never supplied ("this endpoint is almost certainly internal-only"), speculation about code that is not in the prompt ("a middleware layer would normally sanitise this"), or a demand for evidence the transcript has no way to obtain ("no proof-of-concept exploit has been shown"). None of those is a defect in the finding. They are disagreement produced by the protocol rather than by the case, which is what makes them worth naming separately as manufactured conflict.

The distinction matters because the judge cannot draw it from tone. A manufactured objection and a genuine one arrive in the same register, at the same length, with the same hedging, and the manufactured one is often the more polished of the two, because inventing a plausible general worry is easier than finding a specific flaw. What separates them is where the claim points. A real objection quotes material that is present — a line, a clause, a figure in the document — and a manufactured one appeals to material that is absent. That gives a third party something mechanical to check rather than a judgement to make: go through the transcript turn by turn and mark every claim that cites nothing from the source.

Where each design earns its cost

A: three samples, majorityB: two debaters, two rounds, judge
What it exploitsuncorrelated sampling noise across independent drawsinformation sharing — each side must answer the other's stated claim
Calls per case35
What the aggregation doescountsadjudicates on the transcript it is given
Confidence signal you getvote split (3-0 vs 2-1), which is coarse but honestthe judge's stated confidence, which reflects argument quality
Best caseone sample slips, the other two holda specific defect is named and the other side cannot answer it
Worst caseall three make the same mistake and agreeboth anchor on the same wrong frame and the transcript looks thorough

The call-count row is arithmetic worth doing out loud, because the number is small and people still guess it wrong. Design B runs two agents for two rounds, which is one call per agent per round, and then one judge call on top. Design A runs one call per sample. The gap in the table is therefore not a modelling assumption; it falls straight out of the protocol, and chapter 5 shows why the gap in call count is the smaller of the two ways this design costs more than it looks.

The confidence row deserves more than its cell. A 2-1 vote split is a crude estimate of where the model's distribution sits on that case, and crude as it is, it is derived from something real: three draws fell two ways. The judge's stated confidence is a token sequence produced after reading a transcript, and it tracks how cleanly the exchange resolved. An exchange resolves cleanly when one side concedes, and a side concedes when it is anchored, so the cases where the judge reports high confidence include the ones where both agents locked onto the same wrong frame early. That relationship runs the wrong way for anything you would want to route on.

That is the stumble this chapter exists to name, and it is tempting for a reason worth stating plainly. Both columns of the confidence row produce a number between zero and one, both rise when the system is more sure, and a routing rule that thresholds one will run unchanged on the other. What differs is what stays fixed while the dangerous thing moves. The judge's reported confidence is near its ceiling on every case where the exchange converged, and whether the convergence was a genuine defeat or a shared blind spot is exactly the property it does not move with. A quantity that sits still while the thing you care about varies underneath it is not a weak signal. It is a signal about something else.

Averaging, self-critique, and the file nobody read

Debate is not an ensemble in the statistical sense, and calling it one invites the assumption that adding participants averages out error. Averaging requires independence, which the protocol spends deliberately. Two debaters are closer to one conversation than to two estimators.

It is also not self-critique. A single agent asked to draft an answer and then find flaws in it is a related but cheaper pattern with a different weakness — it revises rather than contests, and it rarely reverses its own conclusion. Debate assigns positions before the model has formed an opinion, which is what makes the con agent willing to attack a conclusion it would otherwise have produced itself.

And it does not solve missing information. If the finding's source file was truncated before it reached the prompt, five calls of argument about what the code does will produce a confident verdict about code nobody read.

Where the question has a determinate answer that an argument can be driven down to — a line of source, a clause, an arithmetic step — debate has more room to help, because a claim can be defeated by pointing at something checkable and the exchange can therefore terminate on a fact rather than on a preference. Where the label depends on a judgement call, the same mechanism produces two defensible cases and a judge selecting between them on the qualities it can assess, which is why voting is the safer of the two there: the 2-1 split is at least an honest reading of where the model's distribution sits, and it degrades gracefully when the case is genuinely ambiguous.

The failure both designs share is the one neither can see. Three samples and two debaters are all the same model, and where that model is confidently wrong about a case, no arrangement of its own outputs will tell you so. Design A gives you 3-0 agreement on the wrong label; design B gives you a transcript in which both sides converge on the wrong label with reasons. Neither introduces information the model did not already have, which means both are amplifiers of what a single pass believed, and the amplification is more convincing in B.

Set the two designs side by side one last time and the trade is a single sentence. Voting keeps the draws apart so that a count of them carries information, and pays for that with agents who never notice anything about each other's reasoning. Debate lets the agents read each other so that objections get produced, and pays for that with a transcript in which no turn after the first is an independent look at the question. There is no arrangement that keeps both properties, because the mechanism of one is the loss of the other.

The triage example gave a case where the two debaters converged on a wrong frame and stayed there. That was not bad luck with a prompt. Both agents were the same model with opposite instructions, and opposite instructions do not produce opposite blind spots — which is the property the next chapter takes apart, because it determines how much of debate's apparent thoroughness is real.

Debate and adversarial ensembles — read the current version at https://daviddominguez.dev/learn/en/debate-and-adversarial-ensembles/debate-trades-independence-for-argument-quality

Back to top