Voting Pattern¶
N agents vote independently on the same question; majority (or weighted) vote wins.
Best for: Fault-tolerant decisions, ensemble reliability, reducing single-model bias.
LLM calls: N (parallel voters). Majority/weighted tally requires no extra LLM call.
Sequence Diagram¶
sequenceDiagram
participant U as User
participant V1 as Voter 1
participant V2 as Voter 2
participant V3 as Voter 3
participant T as Tallier
U->>V1: "Is this PR safe to merge?"
U->>V2: "Is this PR safe to merge?"
U->>V3: "Is this PR safe to merge?"
par Independent voting
V1-->>T: "YES — no vulnerabilities"
V2-->>T: "YES — code quality good"
V3-->>T: "NO — potential N+1 query"
end
T-->>U: "YES (2/3 majority)"
Use Case 1 — Multi-Provider Ensemble (OpenAI + Anthropic + Gemini)¶
Three independent providers reduce the chance of systematic errors from any single model.
import asyncio
from pyagent_patterns.base import Agent
from pyagent_patterns.resolution import Voting
from pyagent_providers import OpenAILLM, AnthropicLLM, GeminiLLM
pattern = Voting(
voters=[
Agent(
"openai_voter",
OpenAILLM("gpt-4o"),
system_prompt="Evaluate the content moderation request. "
"Respond with exactly YES (safe to publish) or NO (violates policy). "
"On the second line, give a one-sentence reason.",
),
Agent(
"anthropic_voter",
AnthropicLLM("claude-sonnet-4-20250514"),
system_prompt="Evaluate the content moderation request. "
"Respond with exactly YES (safe to publish) or NO (violates policy). "
"On the second line, give a one-sentence reason.",
),
Agent(
"gemini_voter",
GeminiLLM("gemini-2.5-pro"),
system_prompt="Evaluate the content moderation request. "
"Respond with exactly YES (safe to publish) or NO (violates policy). "
"On the second line, give a one-sentence reason.",
),
],
strategy="majority",
)
result = asyncio.run(pattern.run(
"User-submitted product review: "
"'This product is absolute garbage. The CEO should be fired. "
"Returning it immediately and never buying from this brand again.'"
))
print(f"Decision: {result.metadata['winner']} (Tally: {result.metadata['tally']})")
print(result.output)
print(f"Cost: ${result.cost_estimate:.4f}")
Use Case 2 — PR Safety Gate (Weighted Voting)¶
Give higher weight to the security reviewer.
pattern = Voting(
voters=[
Agent(
"security_reviewer",
OpenAILLM("gpt-4o"),
system_prompt="Review this code change for security vulnerabilities. "
"Respond YES (safe to merge) or NO (has security issues). "
"Explain your reasoning briefly.",
),
Agent(
"style_reviewer",
AnthropicLLM("claude-haiku-3-5-20241022"),
system_prompt="Review this code change for style and conventions. "
"Respond YES (acceptable) or NO (style violations). "
"List any violations.",
),
Agent(
"performance_reviewer",
GeminiLLM("gemini-2.5-flash"),
system_prompt="Review this code change for performance issues. "
"Respond YES (no performance concerns) or NO (has performance issues). "
"Explain your reasoning.",
),
],
strategy="weighted",
weights={"security_reviewer": 3, "style_reviewer": 1, "performance_reviewer": 2},
)
result = asyncio.run(pattern.run(open("pr_diff.py").read()))
print(f"Weighted decision: {result.metadata['winner']}")
print(f"Weighted tally: {result.metadata['weighted_tally']}")
Use Case 3 — Classification Ensemble (LiteLLM)¶
Reduce classification error rate by using five independent voters.
from pyagent_providers import LiteLLM
classifier_ensemble = Voting(
voters=[
Agent(f"voter_{i}", LiteLLM("gpt-4o-mini"),
system_prompt="Classify customer support ticket as: billing, technical, returns, or general. "
"Respond with ONLY the category name.")
for i in range(5)
],
strategy="majority",
)
tickets = [
"I was charged twice this month",
"My API key stopped working",
"I want to return a defective product",
]
for ticket in tickets:
result = asyncio.run(classifier_ensemble.run(ticket))
print(f"[{result.metadata['winner']}] {ticket}")
print(f" Tally: {result.metadata['tally']}")
OTel Trace Output¶
Trace: pyagent.pattern.voting (2.1s, $0.011)
├── [parallel voters]
│ ├── pyagent.agent.openai_voter (1.8s, gpt-4o) → YES
│ ├── pyagent.agent.anthropic_voter (2.1s, claude-sonnet-4-20250514) → YES
│ └── pyagent.agent.gemini_voter (1.6s, gemini-2.5-pro) → NO
└── tally: {"YES": 2, "NO": 1} → winner: YES
When to Use¶
| Condition | Recommendation |
|---|---|
| Task has a discrete answer (yes/no, A/B/C) | ✅ Use Voting |
| Single model failure should not determine outcome | ✅ Use Voting |
| Task requires nuanced, open-ended output | ❌ Use Fan-Out/Fan-In |
| Agents should argue and debate | ❌ Use Debate |
| Quality improves through iteration | ❌ Use Self-Reflection |
See Also¶
- Debate — adversarial positions with a judge, not a tally
- Fan-Out / Fan-In — parallel agents that synthesise rather than vote
- Supervisor — single classifier routes to a specialist