Zero-dependency multi-agent consensus voting for LLM pipelines — part of the arsenal collection.
- MajorityVote — answer with the most votes wins
- WeightedVote — score = weight × confidence per vote
- QuorumVote — require a minimum fraction to agree; optional plurality fallback
- Confidence scoring — per-vote confidence propagated into results
- Tie-breaking — FIRST (stable), RANDOM, ABSTAIN, or RAISE
- ConsensusEngine — stateful multi-round orchestrator with history
- One-shot class methods —
ConsensusEngine.majority(...)etc. - Zero dependencies — stdlib only
pip install agent-consensusfrom agent_consensus import ConsensusEngine, MajorityVote, TieBreaker
# Stateful engine (multi-round)
engine = ConsensusEngine(strategy=MajorityVote(min_votes=3))
engine.cast("gpt-4o", "Paris", confidence=0.95)
engine.cast("claude-3-opus", "Paris", confidence=0.88)
engine.cast("gemini-pro", "Lyon", confidence=0.72)
result = engine.decide()
print(result.winner) # "Paris"
print(result.confidence) # 0.915 (avg confidence of winning votes)
print(result.agreement_rate) # 0.667from agent_consensus import ConsensusEngine
# Majority
result = ConsensusEngine.majority([
("agent-1", "yes", 0.9),
("agent-2", "yes", 0.7),
("agent-3", "no", 0.8),
])
# Weighted (agent_id, answer, confidence, weight)
result = ConsensusEngine.weighted([
("agent-1", "A", 0.9, 3.0),
("agent-2", "B", 1.0, 1.0),
])
# Quorum — requires 60% agreement
result = ConsensusEngine.quorum([
("a1", "yes", 1.0), ("a2", "yes", 1.0),
("a3", "yes", 1.0), ("a4", "no", 1.0),
], quorum_pct=0.6)from agent_consensus import TieBreaker, MajorityVote
# FIRST (default) — stable alphabetical pick
# RANDOM — random pick among tied
# ABSTAIN — return None winner, is_tie=True
# RAISE — raise ConsensusError
engine = ConsensusEngine(MajorityVote(tie_breaker=TieBreaker.RANDOM))result.winner # winning answer (Any)
result.confidence # aggregate confidence
result.vote_counts # {answer: int}
result.vote_weights # {answer: float}
result.total_votes # int
result.agreement_rate # float [0, 1]
result.is_tie # bool
result.strategy # "majority" | "weighted" | "quorum"
result.candidates # list of all unique answers
result.votes # original Vote objectsengine = ConsensusEngine(MajorityVote(), on_result=print)
# Round 1
engine.cast("a1", "A"); engine.cast("a2", "B"); engine.cast("a3", "A")
r1 = engine.decide() # votes cleared after decide
# Round 2
engine.cast("a1", "B"); engine.cast("a2", "B"); engine.cast("a3", "A")
r2 = engine.decide()
print(engine.history) # [r1, r2]pip install pytest
pytest tests/ -v38 tests covering all strategies, tie-breaking, quorum logic, engine lifecycle, and edge cases.
MIT © Darshankumar Joshi