Self-consistency: campionare più percorsi, scegliere la maggioranza
Poni la stessa domanda N volte, con una temperature sufficientemente alta da produrre reasoning realmente diversi, poi scegli la risposta su cui i percorsi convergono. Il voto è semplice codice, non un'altra chiamata al modello, perché chiedere a un modello di scegliere il migliore tra N ripristinerebbe il punto singolo di errore che il campionamento aveva rimosso.
Fatti chiave
- Livello
- Intermedio
- Runtime
- Python • API OpenAI
- Pattern
- Flusso ispezionabile con confini di sistema visibili
- Interazione
- Sandbox live • Script
- Aggiornato
- 28 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
La distribuzione dei voti è lo stato operativo e restituirla è ciò che distingue questo pattern da una singola chiamata costosa. Cinque su cinque e tre su cinque sono situazioni diverse, che una semplice risposta non può distinguere. Questa implementazione restituisce il conteggio insieme alla risposta e attiva esplicitamente un'escalation quando la maggioranza è risicata o assente.
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 campioni comportano una latenza N volte superiore e, per impostazione predefinita, non viene emesso nulla finché non sono arrivati tutti. Correzione applicata qui: emetti ogni campione non appena viene completato, così un'esecuzione con cinque campioni viene percepita come avanzamento anziché come un'unica chiamata molto lenta.
self_consistency.py:runP5 · Sostituire la magia implicita con modelli mentali chiari
Il lettore vede una sola risposta e non ha modo di sapere che è stata contestata o che altri quattro percorsi sono arrivati a una conclusione diversa. È una falsa impressione di certezza, prodotta da una tecnica adottata proprio per gestire l'incertezza. Correzione: trasporta il conteggio dell'accordo fino al punto in cui la risposta viene visualizzata, invece di scartarlo al confine di questa funzione.
self_consistency.py:run
Lo decide la tua implementazione, non il pattern. Nessun verdetto.
P7 · Stabilire fiducia attraverso l'ispezionabilità
Ogni percorso produce il proprio ragionamento, quindi la derivazione esiste. Il fatto che i percorsi dissenzienti vengano mostrati o meno, e proprio lì si trova di solito l'informazione interessante, è una decisione del wrapper. Il pattern non li rende né visibili né nascosti.
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 →