Skip to main contentSkip to footer
PatternscriptintermediateRunnableguided-flow

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.

Key Facts

Level
intermediate
Runtime
Python • OpenAI API
Pattern
Inspectable flow with visible system boundaries
Interaction
Live sandbox • Script
Updated
27 July 2026

Navigate this example

High-level flow

How this example moves from input to execution and reviewable output

Self-consistency: sample several paths, take… -> Retrieve relevant context -> Load environment keys -> Initialize OpenAI client -> Constrain output schema -> Send message payload

Trigger

Self-consistency: sample several paths, take…

Runtime

Retrieve relevant context

Outcome

Load environment keys

Why this page exists

This example is shown as both real source code and a product-facing interaction pattern so learners can connect implementation, UX, and doctrine without leaving the library.

Visual flowReal sourceSandbox or walkthroughMCP access

Doctrine relations

These are reasoning shapes: how an agent decides, when it acts, what it remembers. For how to compose the interface around it, see the AI Pattern Blueprint. For triggers, scheduling, context loading and recovery, see Agent runtime architecture.

Structural

This pattern expresses these principles directly in code.

  • P6 · Expose meaningful operational state, not internal complexity

    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

Default gap

The textbook form of this pattern violates these by default. Each one carries the fix.

  • P2 · Ensure that background work remains perceptible

    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:run

  • P5 · Replace implied magic with clear mental models

    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

Depends on the wrapper

Your implementation decides these, not the pattern. No verdict is asserted.

  • P7 · Establish trust through inspectability

    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

Doctrine relations are first-party analysis, not the output of a validation run. Run the validator on your own code to get a scored verdict.

How should this example be used in the platform?

Use the sandbox to understand the experience pattern first, then inspect the source to see how the product boundary, model boundary, and doctrine boundary are actually implemented.

UX pattern: Inspectable flow with visible system boundaries
Ensure that background work remains perceptible
Replace implied magic with clear mental models
Expose meaningful operational state, not internal complexity

Source references

Library entry
pattern-self-consistency
Source path
content/patterns/sampling-search/self-consistency/self_consistency.py
Libraries
openai, pydantic, python-dotenv
Runtime requirements
OPENAI_API_KEY
Related principles
Ensure that background work remains perceptible, Replace implied magic with clear mental models, Expose meaningful operational state, not internal complexity, Establish trust through inspectability

self_consistency.py

python
"""
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)

What should the learner inspect in the code?

Look for the exact place where system scope is bounded: schema definitions, prompt framing, runtime configuration, and the call site that turns user intent into a concrete model or workflow action.

Look for output contracts and validation
Look for the exact execution call
Look for what the product could expose to the user

How does the sandbox relate to the source?

The sandbox should make the UX legible: what the user sees, what the system is deciding, and how the result becomes reviewable. The source then shows how that behavior is actually implemented.

Read the implementation summary.
Step through the user and system states.
Inspect the source code with the highlighted doctrine decisions in mind.
SandboxInspectable flow with visible system boundaries

Interaction walkthrough

Use the sandbox to step through the user-visible experience, the system work behind it, and the doctrine choice the example is making.

UX explanation

The sandbox explains what the user should see, what the system is doing, and where control or inspectability must remain explicit.

AI design explanation

The page turns raw source into a product-facing pattern: what the model is allowed to decide, what the product should expose, and where deterministic code or review should take over.

Interaction walkthrough

  1. 1Read the implementation summary.
  2. 2Step through the user and system states.
  3. 3Inspect the source code with the highlighted doctrine decisions in mind.

Visible to the user

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.

System work

The product prepares a bounded model or workflow task.

Why it matters

The interface should make the delegated task legible before automation happens.

Used in courses and paths

This example currently stands on its own in the library, but it still connects to the principle system and the broader example family.

Related principles

Runtime architecture

Use this example in your agents

This example is also available through the blueprint’s agent-ready layer. Use the For agents page for the public MCP, deterministic exports, and Claude/Cursor setup.

Define triggers, context, and boundaries before increasing autonomy
Make control, observability, and recovery explicit in the runtime
Choose the right operational patterns before delegating to workflows