Self-consistency: sample several paths, take the majority
Ask the same question N times at a temperature high enough to produce genuinely different reasoning, then take the answer the paths converge on. The vote is plain code, not another model call, because asking a model to pick the best of N restores the single point of failure the sampling removed.
Fatti chiave
- Livello
- intermediate
- Runtime
- Python • API OpenAI
- Pattern
- Flusso ispezionabile con confini di sistema visibili
- Interazione
- Sandbox live • Script
- Aggiornato
- 27 luglio 2026
Naviga questo esempio
Pattern
Relazioni con la doctrineQuali principi questo pattern esprime nel codice, e quali la sua forma predefinita infrange.Libreria
Sfoglia gli esempiRiapri la libreria completa per confrontare pattern vicini e percorsi collegati.Interazione
Esegui ora nel sandboxProva l'interazione direttamente nella superficie guidata di questo esempio.Sorgente
Apri codice completoLeggi l'implementazione reale, i punti evidenziati e i requisiti runtime.MCP
Chiama via MCPUsa la stessa risorsa dentro agenti, export deterministici e setup MCP.
Principi collegati
Relazioni con la doctrine
Queste sono forme di ragionamento: come un agente decide, quando agisce, cosa ricorda. Per comporre l'interfaccia intorno a esso, vedi l'AI Pattern Blueprint. Per trigger, pianificazione, caricamento del contesto e ripristino, vedi Agent runtime architecture.
Questo pattern esprime questi principi direttamente nel codice.
P6 · Esporre uno stato operativo significativo, non la complessità interna
The vote distribution IS the operational state, and returning it is what separates this pattern from an expensive single call. Five of five and three of five are different situations that a bare answer cannot distinguish. This implementation returns the count alongside the answer and escalates explicitly when the majority is thin or absent.
self_consistency.py:run
La forma classica di questo pattern li viola per impostazione predefinita. Ognuno riporta la correzione.
P2 · Assicurarsi che il lavoro in background rimanga percepibile
N samples means N times the latency, and by default nothing is emitted until all of them land. Fix, applied here: emit each sample as it completes so a five-sample run reads as progress rather than as one very slow call.
self_consistency.py:runP5 · Sostituire la magia implicita con modelli mentali chiari
The reader sees one answer and has no way to know it was contested, or that four other paths reached something else. That is a false impression of certainty, produced by a technique adopted specifically to handle uncertainty. Fix: carry the agreement count through to wherever the answer is displayed, rather than discarding it at the boundary of this function.
self_consistency.py:run
Lo decide la tua implementazione, non il pattern. Nessun verdetto.
P7 · Stabilire fiducia attraverso l'ispezionabilità
Each path produces its reasoning, so the derivation exists. Whether the dissenting paths are ever shown, which is where the interesting information usually is, is a wrapper decision. The pattern neither surfaces nor hides them.
self_consistency.py:Attempt
Le relazioni con la doctrine sono analisi di prima parte, non il risultato di una validazione. Esegui il validatore sul tuo codice per ottenere un verdetto con punteggio.
self_consistency.py
"""
Self-consistency: sample several reasoning paths, take the majority
Ask the same question N times at a temperature high enough to get genuinely
different reasoning, then take the answer the paths agree on. Errors tend to
be idiosyncratic and scatter; correct answers tend to converge.
Question -> N independent paths -> normalise -> majority answer
The vote is plain Python, deliberately. Asking a model to pick the best of N
answers reintroduces exactly the single-point-of-failure the sampling was
meant to remove, and it lets a confidently-worded wrong answer win.
The agreement count is the useful output, not a decoration. Five of five is a
different situation from three of five, and a caller that only reads the
answer has thrown away the reason to have run this at all.
Run: python self_consistency.py
"""
from collections import Counter
from dotenv import load_dotenv
from openai import OpenAI
from pydantic import BaseModel, Field
load_dotenv()
client = OpenAI()
MODEL = "gpt-5.4-mini"
SAMPLES = 5
#: Enough spread to get different reasoning. At 0 every path is the same path
#: and the vote is theatre.
TEMPERATURE = 1.0
class Attempt(BaseModel):
reasoning: str = Field(description="Work the problem through, step by step.")
answer: str = Field(
description="The final answer alone. No units, no restatement, no prose."
)
def attempt(question: str) -> Attempt:
completion = client.beta.chat.completions.parse(
model=MODEL,
temperature=TEMPERATURE,
messages=[
{
"role": "system",
"content": (
"Work the problem through and give the final answer. Put "
"only the answer itself in `answer`, nothing else."
),
},
{"role": "user", "content": question},
],
response_format=Attempt,
)
return completion.choices[0].message.parsed
def normalise(answer: str) -> str:
"""Group answers that are the same fact written differently.
Without this the vote splits on formatting and everything ties at one
each, which looks like disagreement when the paths actually agreed.
"""
return answer.strip().lower().rstrip(".").replace(",", "").replace("$", "")
def run(question: str) -> tuple[str, int, int]:
attempts: list[Attempt] = []
for index in range(1, SAMPLES + 1):
print(f" [{index}/{SAMPLES}] sampling...")
current = attempt(question)
print(f" answer: {current.answer}")
attempts.append(current)
counts = Counter(normalise(a.answer) for a in attempts)
winner, votes = counts.most_common(1)[0]
# Surface the spread, not just the winner. Agreement IS the signal.
print(f" distribution: {dict(counts)}")
print(f" majority : {winner} ({votes}/{SAMPLES})")
if votes == 1:
print(" WARNING: every path disagreed. Treat this as no answer.")
elif votes <= SAMPLES // 2:
print(" WARNING: the majority is thin. Escalate rather than rely on it.")
return winner, votes, SAMPLES
if __name__ == "__main__":
question = (
"A team of 4 engineers takes 6 days to migrate 120 services. Two more "
"engineers join at the same rate. How many days for the next 120?"
)
print(f"\n> {question}")
run(question)
Principi correlati
- P2visibilityAssicurarsi che il lavoro in background rimanga percepibileQuando il sistema opera in modo asincrono o al di fuori del focus immediato dell'utente, dovrebbe fornire segnali persistenti e proporzionati che il lavoro sta continuando.Apri il principio →
- P5delegationSostituire la magia implicita con modelli mentali chiariIl prodotto dovrebbe aiutare gli utenti a comprendere cosa il sistema può fare, cosa sta facendo attualmente, cosa non può fare e quali condizioni governano il suo comportamento.Apri il principio →
- P6visibilityEsporre uno stato operativo significativo, non la complessità internaPresentare lo stato del sistema in linguaggio e strutture rilevanti per l'utente, piuttosto che esporre dettagli interni di basso livello che non supportano l'azione o la comprensione.Apri il principio →
- P7trustStabilire fiducia attraverso l'ispezionabilitàGli utenti dovrebbero essere in grado di esaminare come è stato prodotto un risultato quando la fiducia, la responsabilità o la qualità della decisione sono importanti.Apri il principio →