LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 196 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/9
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningBayesian Inference from EvidenceStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/15
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageStatistical Learning and GeneralizationConformal Prediction and UncertaintyClustering and PCAProbabilistic Generative ModelsCore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingCausal Inference and CounterfactualsPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/25
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernancePrivacy-Preserving Machine LearningData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/31
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceAccelerator Architecture Field GuideCorrect GPU Profiling and BenchmarkingGPU Kernel Performance Engineering LabGPU Parallel Primitives LabGPU Compilers and Kernel LanguagesGEMM From Naive CUDA to Tensor CoresLow-Precision GPU ProgrammingGPU Runtime Execution LabAI-Generated Kernel EngineeringModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingGPU Failure OperationsDistributed Inference Data PlaneServing Benchmark EngineeringA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnApplied LLM EngineeringCoT, ToT & Self-Consistency Prompting
✍️MediumPrompt Engineering

CoT, ToT & Self-Consistency Prompting

Build and evaluate reasoning controllers: single traces, answer voting, and bounded tree search for multi-step LLM decisions.

21 min read
Learning path
Step 62 of 196 in the full curriculum
Dimensionality Reduction for EmbeddingsFunction Calling & Tool Use

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

Picture a release candidate with passing tests, a clear security scan, and an approved review. Policy allows an automatic merge only when all three facts hold. A direct answer can still miss one of them.

The last chapter used a compressed embedding index to put the right policy clause in context, including an auto-merge rule. Retrieval isn't the end: an assistant can still skip a condition, mishandle a check, or commit too early to one plan. The question isn't whether a model can produce a longer explanation; it's how much extra test-time compute buys a better decision under token, latency, and safety budgets. Start with one prompt-elicited chain of thought (CoT), compare several candidates with self-consistency, and move to an external Tree of Thoughts (ToT) search only when early choices can dead-end.

Start with a failure you can audit

Put those facts on one row: unit tests pass, the security scan is clear, and a reviewer has approved the diff. The policy permits auto-merge only when every field is true. A model can still skip a field or suggest a force-merge.

A useful outward artifact is a short decision record containing those facts, the checks applied, and the final action. It's smaller than an open-ended rationale, easy to score, and safe to compare against deterministic policy logic. It isn't raw chain of thought. It's a task-specific output contract that the application can validate.

decision-record-contract.py
1from dataclasses import dataclass 2 3@dataclass(frozen=True) 4class ReleaseCase: 5 tests_passed: bool 6 security_scan_clear: bool 7 reviewer_approved: bool 8 9def decision_record(case: ReleaseCase) -> dict[str, object]: 10 checks = { 11 "tests_passed": case.tests_passed, 12 "security_scan_clear": case.security_scan_clear, 13 "reviewer_approved": case.reviewer_approved, 14 } 15 action = "merge_release" if all(checks.values()) else "manual_review" 16 return {"checks": checks, "final_action": action} 17 18record = decision_record( 19 ReleaseCase(tests_passed=True, security_scan_clear=True, reviewer_approved=True) 20) 21for name, passed in record["checks"].items(): 22 print(f"{name}: {passed}") 23print(f"final_action: {record['final_action']}")
Output
1tests_passed: True 2security_scan_clear: True 3reviewer_approved: True 4final_action: merge_release

This code isn't an LLM. It's the oracle that your prompt variants must match. Define the output contract and scorer before increasing model compute.

When to skip CoT entirely: structured machine state (booleans, enum fields, and runtime-owned policy predicates) belongs in code. Sampling five CoT traces over three known flags adds cost without evidence. Use model reasoning for unstructured evidence (diff text, free-form review comments, or incident narratives) when no deterministic scorer exists yet. These fixtures teach scoring and controllers; they aren't a recommendation to put all(checks) behind a model.

If a required fact isn't in the prompt at all, a longer rationale can't invent it. The missing value has to come from the source system. That boundary leads to the typed tool request in the next lesson.

Diagram showing Release case, What is missing?, nothing; flags only, and Runtime policy.
Release case, What is missing?, nothing; flags only, and Runtime policy.

The Policy route handles known flags, while the Tool route obtains a live observation. This chapter takes the middle route: extra inference over facts already present, scored against a contract.

The same release-gate facts feed a direct candidate that records only one of three required checks and fails the oracle, while a structured decision record preserves all three predicates and reaches the expected merge release action.
The same three release facts feed both candidates. Direct records one check and fails the oracle; the decision record keeps every predicate and matches merge_release.

Why define an oracle and decision record before testing reasoning prompts?

Answer

Without a scored outcome and required checks, a longer response can look thoughtful without being more correct. The oracle lets you compare strategies on the same task.

Chain-of-Thought: one decomposed candidate

Wei et al. introduced few-shot CoT by placing worked intermediate steps in prompt examples. On GSM8K (a grade-school math benchmark), PaLM 540B rose from 17.9% with standard prompting to 56.9% with eight CoT exemplars, with further gains on commonsense and symbolic tasks once models were large enough for the scratchpad to matter.[1]Reference 1Chain-of-Thought Prompting Elicits Reasoning in Large Language Models.https://arxiv.org/abs/2201.11903 Kojima et al. later showed that the zero-shot trigger "Let's think step by step" could improve several benchmark reasoning tasks without worked examples.[2]Reference 2Large Language Models are Zero-Shot Reasoners.https://arxiv.org/abs/2205.11916

Those papers establish techniques to evaluate, not a production law. On your endpoint and task, a visible scratchpad may help, do nothing, or add cost. Meincke et al. tested GPQA Diamond and found that an explicit "think step by step" request often added little accuracy for reasoning-tuned models while increasing time and tokens; for ordinary chat models the average gain was small and sometimes came with more errors on questions the model already answered reliably.[3]Reference 3Prompting Science Report 2: The Decreasing Value of Chain of Thought in Promptinghttps://arxiv.org/abs/2506.07142

🔬 Research insight: More reasoning text isn't always better. Zheng et al. tested CoT and its variants (including ToT and ReAct, or Reasoning and Acting) on nine pattern-based in-context-learning benchmarks across 16 models and found they consistently underperformed plain direct answering, with the gap widening as more demonstrations were added. Even long-CoT reasoning models that spent far more tokens didn't overcome the effect.[4]Reference 4The Curse of CoT: On the Limitations of Chain-of-Thought in In-Context Learning.https://arxiv.org/abs/2504.05081 When a task is pattern matching from examples, a visible scratchpad can add noise instead of signal. Measure that tradeoff rather than assuming a longer response will help.

When one prompt decomposition isn't enough, least-to-most prompting handles a different shape of problem. It breaks the task into ordered sub-questions, answers the simplest one first, and passes each intermediate answer into the next sub-prompt.[5]Reference 5Least-to-Most Prompting Enables Complex Reasoning in Large Language Modelshttps://arxiv.org/abs/2205.10625 That sequential handoff can improve compositional generalization without the latency and memory overhead of branching search.

Keep four reasoning artifacts separate

The word reasoning now covers several different artifacts. Mixing them creates false audit claims and brittle integrations, so name the artifact before deciding what it proves.

ArtifactWhat it containsWhat you can safely conclude
Prompt-elicited CoTIntermediate text generated because a prompt asks for stepsIt may help the final answer; it may still be unfaithful
Native reasoning tokensInternal inference tokens used by a reasoning modelToken usage measures compute, not whether the reasoning was correct or exposed
Reasoning summaryProvider-generated description of internal reasoningIt can orient an operator, but it isn't raw CoT or proof of faithful cognition
Decision recordTask-specific facts, checks, and final action emitted for your applicationIts fields can be schema-checked and scored against an oracle

Provider disclosure rules and API surfaces differ. OpenAI's API documentation says raw reasoning tokens aren't exposed, although supported models can return an opt-in reasoning summary. Those hidden tokens still count toward context and billing.[6]Reference 6Reasoning modelshttps://developers.openai.com/api/docs/guides/reasoning

Anthropic still returns thinking blocks, including summarized thinking. Its control surface is model-specific: older Claude 4.x models use a fixed budget_tokens extended-thinking mode, while newer models reject that setting and expect adaptive thinking with an effort control.[7]Reference 7Building with extended thinkinghttps://docs.claude.com/en/docs/build-with-claude/extended-thinking

Recheck provider documentation when you integrate. Don't write controller logic that assumes every model returns a visible scratchpad or that one thinking API works across Claude generations.

This distinction changes the build-versus-buy decision. An external CoT, voting, or tree-search controller gives you explicit sample and search state, but generated rationales still aren't guaranteed to be faithful.

A native reasoning model owns more of the internal inference process, while its controls, visibility, and accounting follow the provider contract. Put both behind the same task-level evaluator and compare outcomes, latency, token use, and parse failures.

Ask for reviewable task artifacts at the workflow boundary rather than text that claims to reveal private internal reasoning:

single-trace-prompt.txt
1Use only the supplied release facts and policy rules. 2Return: 31. required_checks: each policy predicate with pass/fail 42. final_action: one allowed action enum 53. operator_message: one sentence 6 7Facts: 8- tests_passed: true 9- security_scan_clear: true 10- reviewer_approved: true 11 12Policy: 13- merge_release is allowed only when tests pass, 14 the security scan is clear, and review approval exists.

The required checks make a missed predicate observable. They still aren't proof of faithful hidden cognition. Turpin et al. showed that CoT explanations can rationalize outputs influenced by hidden biasing features without mentioning those features.[8]Reference 8Language Models Don't Always Say What They Think: Unfaithful Explanations in Chain-of-Thought Promptinghttps://arxiv.org/abs/2305.04388 Log inputs, actions, validations, and outcomes; don't treat eloquent reasoning text or a provider summary as an audit guarantee.

score-candidate-decisions.py
1from dataclasses import dataclass 2 3@dataclass(frozen=True) 4class Candidate: 5 name: str 6 checks: set[str] 7 final_action: str 8 9required_checks = { 10 "tests_passed", 11 "security_scan_clear", 12 "reviewer_approved", 13} 14expected_action = "merge_release" 15candidates = [ 16 Candidate("direct", {"tests_passed"}, "manual_review"), 17 Candidate("structured_trace", required_checks, "merge_release"), 18] 19 20for candidate in candidates: 21 coverage = len(candidate.checks & required_checks) / len(required_checks) 22 action_ok = candidate.final_action == expected_action 23 print(f"{candidate.name}: coverage={coverage:.0%}, action_ok={action_ok}")
Output
1direct: coverage=33%, action_ok=False 2structured_trace: coverage=100%, action_ok=True

Here, the trace is useful because it meets the scored contract. It doesn't win merely because it contains more words.

Zero-shot or few-shot?

Zero-shot CoT supplies an instruction and lets the model choose its intermediate format. Few-shot CoT gives one or more solved examples, so it can teach both decomposition and the final answer shape. Native structured output enforcement is better when available. Examples still help when the prompt must communicate task-specific checks.

Comparison showing that a zero-shot instruction may drift across facts, checks, and action fields, while few-shot examples demonstrate consistent schema slots for examples and the target case.
Watch the three schema slots. Zero-shot cases permute facts, checks, and action; few-shot examples pin the same order onto the target case.
build-few-shot-decision-prompt.py
1example = """Example: 2facts: tests_passed=true, security_scan_clear=false, reviewer_approved=true 3required_checks: tests_passed=true, security_scan_clear=false, reviewer_approved=true 4final_action: manual_review""" 5 6case = "facts: tests_passed=true, security_scan_clear=true, reviewer_approved=true" 7zero_shot = f"Evaluate release policy step by step.\n{case}\nfinal_action:" 8few_shot = f"{example}\n\nNow evaluate:\n{case}\nrequired_checks:\nfinal_action:" 9 10print(f"zero_shot_has_example: {'Example:' in zero_shot}") 11print(f"few_shot_has_example: {'Example:' in few_shot}") 12print(f"few_shot_requests_checks: {'required_checks:' in few_shot}")
Output
1zero_shot_has_example: False 2few_shot_has_example: True 3few_shot_requests_checks: True

When is few-shot CoT worth more prompt tokens than zero-shot CoT?

Answer

When examples teach task-specific checks or output fields that your evaluator needs, and held-out results justify the added tokens.

Stable formatting solves parsing, not sampling variance. A well-shaped candidate can still choose the wrong action.

Self-Consistency: sample answers, then vote

One structured trace can fail because generation takes an unlucky path. Self-Consistency replaces reliance on one path with several sampled paths and chooses the most consistent final answer.[9]Reference 9Self-Consistency Improves Chain of Thought Reasoning in Language Models.https://arxiv.org/abs/2203.11171 The vote operates on extracted answers, not on whose rationale sounds best.

Let yiy_iyi​ be the final text from sample iii, and let c(yi)c(y_i)c(yi​) map that text to an allowed action or reject it as invalid. With NNN total samples, the winning action and its share are:

a^=arg⁡max⁡a∑i=1N1[c(yi)=a],s=1N∑i=1N1[c(yi)=a^]\hat{a} = \arg\max_a \sum_{i=1}^{N} \mathbf{1}[c(y_i)=a], \qquad s = \frac{1}{N}\sum_{i=1}^{N}\mathbf{1}[c(y_i)=\hat{a}]a^=argmaxa​∑i=1N​1[c(yi​)=a],s=N1​∑i=1N​1[c(yi​)=a^]

The denominator remains NNN, even when some outputs fail to parse. Emit a^\hat{a}a^ only when the winner is unique and sss meets a configured threshold τ\tauτ; otherwise abstain.

To obtain different candidates, use stochastic decoding, usually with a nonzero temperature, rather than rerunning one deterministic decode. The earlier Decoding Algorithms lesson explains that control. Keep the setting fixed in your experiment and log it with the sample count.

In the paper's PaLM-540B setting, 40 independently sampled outputs per run raised GSM8K accuracy from 56.5% with greedy CoT to 74.4% with self-consistency, a 17.9 percentage-point gain.[9]Reference 9Self-Consistency Improves Chain of Thought Reasoning in Language Models.https://arxiv.org/abs/2203.11171 That result belongs to its model, prompts, sampling setup, and benchmark. Five samples here aren't expected to reproduce it.

Wang et al. also observed that the share of samples agreeing with the aggregated answer correlated with GSM8K accuracy. That's a research observation, not a calibrated confidence score. Treat agreement as a vote statistic you threshold, then still run ordinary policy checks.

A self-consistency controller maps five stochastic final-action strings onto canonical votes: three merge_release aliases, one manual_review, and one rejected unknown, so the winner is 3 of 5 and meets the 0.60 share threshold.
Three merge spellings collapse to one action. The rejected force-merge string still counts in the 3/5 share, so the winner is a candidate rather than an authorized merge.

Normalize before counting

Model outputs rarely use exactly one spelling. Map harmless variants to one allowed action and reject unknown outputs before voting.

canonicalize-and-vote.py
1from collections import Counter 2 3ALIASES = { 4 "merge release": "merge_release", 5 "merge_release": "merge_release", 6 "auto merge approved change": "merge_release", 7 "manual review": "manual_review", 8} 9 10def canonicalize(text: str) -> str | None: 11 normalized = text.strip().lower().replace("-", " ") 12 return ALIASES.get(normalized) 13 14samples = [ 15 "Merge release", 16 "merge_release", 17 "Auto merge approved change", 18 "manual review", 19 "force merge immediately", 20] 21votes = Counter(action for text in samples if (action := canonicalize(text))) 22winner = votes.most_common(1)[0][0] if votes else "manual_review" 23 24print(f"accepted_samples: {sum(votes.values())}/{len(samples)}") 25print(f"votes: {dict(votes)}") 26print(f"winner: {winner}")
Output
1accepted_samples: 4/5 2votes: {'merge_release': 3, 'manual_review': 1} 3winner: merge_release

A winner isn't always confident enough

A 2 to 2 tie, zero accepted outputs, or a narrow plurality with many rejected outputs shouldn't silently become an automated action. Add an abstention rule.

The winning share must use all sampled outputs as its denominator, including strings that failed to parse. A passing vote chooses a candidate; ordinary runtime policy still decides whether that action is allowed.

abstain-on-weak-votes.py
1from collections import Counter 2 3def decide(votes: list[str], total_samples: int, minimum_share: float = 0.6) -> str: 4 if not votes: 5 return "manual_review" 6 counts = Counter(votes) 7 winner, count = counts.most_common(1)[0] 8 share = count / total_samples 9 tied = len(counts) > 1 and counts.most_common(2)[0][1] == counts.most_common(2)[1][1] 10 if tied or share < minimum_share: 11 return "manual_review" 12 return winner 13 14strong = ["merge_release", "merge_release", "merge_release", "manual_review"] 15split = ["merge_release", "merge_release", "manual_review", "manual_review"] 16mostly_rejected = ["merge_release", "merge_release"] 17 18print(f"strong_vote: {decide(strong, total_samples=4)}") 19print(f"split_vote: {decide(split, total_samples=4)}") 20print(f"mostly_rejected_vote: {decide(mostly_rejected, total_samples=5)}") 21print(f"no_valid_votes: {decide([], total_samples=5)}")
Output
1strong_vote: merge_release 2split_vote: manual_review 3mostly_rejected_vote: manual_review 4no_valid_votes: manual_review

Measure gains against call cost

Use a held-out fixture set before calling the strategy ready. Each fixture represents five already-canonicalized final actions for one case. Unknown values are rejected, but they remain in the denominator. The controller compares first-sample accuracy with five-sample voting accuracy.

measure-voting-gain.py
1from collections import Counter 2 3fixtures = { 4 "approved_clean_release": { 5 "expected": "merge_release", 6 "samples": ["manual_review", "merge_release", "merge_release", "merge_release", "force"], 7 }, 8 "scan_failed": { 9 "expected": "manual_review", 10 "samples": ["manual_review", "manual_review", "force", "manual_review", "hold"], 11 }, 12 "review_missing": { 13 "expected": "manual_review", 14 "samples": ["merge_release", "manual_review", "manual_review", "manual_review", "merge_release"], 15 }, 16} 17 18ALLOWED = {"merge_release", "manual_review"} 19 20def vote(samples: list[str], minimum_share: float = 0.6) -> str: 21 counts = Counter(action for action in samples if action in ALLOWED) 22 if not counts: 23 return "abstain" 24 ranked = counts.most_common(2) 25 winner, count = ranked[0] 26 tied = len(ranked) > 1 and ranked[0][1] == ranked[1][1] 27 if tied or count / len(samples) < minimum_share: 28 return "abstain" 29 return winner 30 31single_correct = 0 32vote_correct = 0 33for item in fixtures.values(): 34 winner = vote(item["samples"]) 35 single_correct += item["samples"][0] == item["expected"] 36 vote_correct += winner == item["expected"] 37 38total = len(fixtures) 39print(f"single_trace_accuracy: {single_correct / total:.0%}") 40print(f"vote_5_accuracy: {vote_correct / total:.0%}") 41print(f"model_calls: single={total}, vote_5={total * 5}")
Output
1single_trace_accuracy: 33% 2vote_5_accuracy: 100% 3model_calls: single=3, vote_5=15

This fixture is intentionally small and deterministic, so it tests controller logic rather than model quality. A real release decision needs representative labeled cases, real model samples, token counts, latency, refusal rates, and cost.

What should a self-consistency controller do when votes don't form a strong majority?

Answer

Abstain or route to review. More samples are useful only when a measured gain justifies their cost and the action remains safe.

Tree-of-Thoughts: search when branches can dead-end

Voting helps when independent paths tend to converge on the same short answer. It doesn't deliberately revisit an earlier choice. Tree-of-Thoughts (ToT) represents partial solutions as search states, then generates alternatives, evaluates those states, and preserves only branches worth extending.[10]Reference 10Tree of Thoughts: Deliberate Problem Solving with Large Language Models.https://arxiv.org/abs/2305.10601

Yao et al. evaluated ToT on tasks built for planning and search. A beam width is the number of partial states retained after each scoring step. On Game of 24 with GPT-4, ToT with beam width 5 solved 74% of tasks, while CoT solved 4.0% and CoT self-consistency with 100 samples solved 9.0%.[10]Reference 10Tree of Thoughts: Deliberate Problem Solving with Large Language Models.https://arxiv.org/abs/2305.10601 Independent voting didn't rescue a search problem.

The narrower conclusion isn't "use trees everywhere." When a problem has verifiable partial states and meaningful backtracking, search can recover from a bad early move.

Beyond tree branching, Graph-of-Thoughts (GoT) stores reasoning states on a directed acyclic graph (DAG) instead of a tree.[11]Reference 11Graph of Thoughts: Solving Elaborate Problems with Large Language Modelshttps://arxiv.org/abs/2308.09687 ToT grows each branch from a single parent. GoT can merge independent paths into one state (thought aggregation), refine a thought after feedback, and rewrite the graph as search proceeds.

That helps when separate sub-tasks, such as reading two logs or drafting two candidate clauses, have to join before a final decision.

Search states in a release plan

For a release gate, consider a workflow whose final recommendation must be supported by two observations: a current security scan and a reviewer approval record. A controller can expand legal steps instead of letting a model invent a final action before evidence is present.

In the original ToT framework, a language model can propose and evaluate thoughts while an external search algorithm owns state, branching, and backtracking. The deterministic code below isolates that controller skeleton; it doesn't simulate an LLM evaluator.

expand-release-plan-states.py
1from dataclasses import dataclass 2 3@dataclass(frozen=True) 4class State: 5 security_clear: bool | None = None 6 reviewer_approved: bool | None = None 7 final_action: str | None = None 8 9def expand(state: State) -> list[State]: 10 next_states: list[State] = [] 11 if state.security_clear is None: 12 next_states.extend([ 13 State(True, state.reviewer_approved), 14 State(False, state.reviewer_approved), 15 ]) 16 if state.reviewer_approved is None: 17 next_states.extend([ 18 State(state.security_clear, True), 19 State(state.security_clear, False), 20 ]) 21 if ( 22 state.security_clear is not None 23 and state.reviewer_approved is not None 24 and state.final_action is None 25 ): 26 action = "merge_release" if state.security_clear and state.reviewer_approved else "block_release" 27 next_states.append(State(state.security_clear, state.reviewer_approved, action)) 28 return next_states 29 30def label(state: State) -> str: 31 scan = {True: "clear", False: "failed"}.get(state.security_clear, "?") 32 review = {True: "approved", False: "rejected"}.get(state.reviewer_approved, "?") 33 action = state.final_action or "pending" 34 return f"scan={scan}, review={review}, {action}" 35 36frontier = [State()] 37for depth in range(3): 38 frontier = list(dict.fromkeys(child for state in frontier for child in expand(state))) 39 print(f"depth_{depth + 1}: {[label(state) for state in frontier]}")
Output
1depth_1: ['scan=clear, review=?, pending', 'scan=failed, review=?, pending', 'scan=?, review=approved, pending', 'scan=?, review=rejected, pending'] 2depth_2: ['scan=clear, review=approved, pending', 'scan=clear, review=rejected, pending', 'scan=failed, review=approved, pending', 'scan=failed, review=rejected, pending'] 3depth_3: ['scan=clear, review=approved, merge_release', 'scan=clear, review=rejected, block_release', 'scan=failed, review=approved, block_release', 'scan=failed, review=rejected, block_release']

The two evidence-gathering orders converge on the same four complete evidence states. Only a clear scan plus an approved review can merge; any failed scan or rejected review blocks the release. The next lesson will populate those outcomes from real APIs through tool calls.

A fully runnable search example

Game of 24 gives us an exact evaluator: arithmetic either reaches 24 using each input once or it doesn't. The solver below explores partial equations with breadth-first search and returns a verified solution.

breadth-first-game-of-24.py
1from fractions import Fraction 2from itertools import combinations 3 4def combine(left: tuple[Fraction, str], right: tuple[Fraction, str]) -> list[tuple[Fraction, str]]: 5 a, a_expr = left 6 b, b_expr = right 7 outcomes = [ 8 (a + b, f"({a_expr} + {b_expr})"), 9 (a - b, f"({a_expr} - {b_expr})"), 10 (b - a, f"({b_expr} - {a_expr})"), 11 (a * b, f"({a_expr} * {b_expr})"), 12 ] 13 if b: 14 outcomes.append((a / b, f"({a_expr} / {b_expr})")) 15 if a: 16 outcomes.append((b / a, f"({b_expr} / {a_expr})")) 17 return outcomes 18 19def solve_24(numbers: list[int]) -> str | None: 20 frontier = [[(Fraction(number), str(number)) for number in numbers]] 21 while frontier: 22 state = frontier.pop(0) 23 if len(state) == 1 and state[0][0] == 24: 24 return state[0][1] 25 for i, j in combinations(range(len(state)), 2): 26 remainder = [item for k, item in enumerate(state) if k not in (i, j)] 27 frontier.extend([remainder + [result] for result in combine(state[i], state[j])]) 28 return None 29 30solution = solve_24([4, 5, 6, 7]) 31print(f"solution_found: {solution is not None}") 32print(f"expression: {solution}")
Output
1solution_found: True 2expression: ((6 - 4) * (5 + 7))
Tree-of-thought search comparing Game of 24 branches: a beam-width-one weak scorer keeps 6 times 4 equals 24 first, a dead branch, while the fixture oracle keeps 5 plus 7 equals 12 first, the only branch that reaches 24.
Beam width 1 keeps only the top first move. The weak scorer locks onto 6 × 4 = 24 and drops 5 + 7 = 12, the only branch that can finish with {4, 5, 6, 7}.

Pruning is a source of failure

An LLM evaluator isn't an arithmetic oracle. If it scores an apparently simple but dead branch above a non-obvious solvable branch, an aggressive beam can remove the answer before expansion.

beam-pruning-risk.py
1branches = [ 2 {"move": "6 * 4 = 24 first", "solvable": False, "weak_score": 0.95, "exact_score": 0.0}, 3 {"move": "5 + 7 = 12 first", "solvable": True, "weak_score": 0.40, "exact_score": 1.0}, 4 {"move": "7 - 5 = 2 first", "solvable": False, "weak_score": 0.35, "exact_score": 0.0}, 5] 6 7def keep_one(score_name: str) -> dict[str, object]: 8 return max(branches, key=lambda branch: branch[score_name]) 9 10weak_choice = keep_one("weak_score") 11exact_choice = keep_one("exact_score") 12print(f"weak_evaluator_keeps_solution: {weak_choice['solvable']}") 13print(f"exact_evaluator_keeps_solution: {exact_choice['solvable']}") 14print(f"risk: beam_width_1 can prune the valid branch")
Output
1weak_evaluator_keeps_solution: False 2exact_evaluator_keeps_solution: True 3risk: beam_width_1 can prune the valid branch

exact_score is a hand-labeled fixture oracle, not a capability you get for free. Real search tasks often need executable validators, environment feedback, or a separately evaluated scorer.

The production implications are concrete. Keep ToT for tasks with real branch structure, not ordinary classification. Prefer deterministic validators when a partial state can be checked in code. Measure solver recall at each beam width alongside final successes, then cap expansions and latency before an open-ended search reaches users.

Why can Tree-of-Thoughts perform worse when the evaluator is weak and the beam is narrow?

Answer

Search spends compute only on retained states. If an incorrect evaluator prunes the valid branch early, later expansions can't recover it.

Search can recover from bad early choices, but each expansion multiplies calls and latency. Choose a strategy through one quality-and-cost experiment rather than assuming a bigger tree is better.

Choose compute with an eval gate

Direct prompting, one trace, voting, and tree search aren't maturity levels. They are candidates with different accuracy and serving cost. Start with the cheapest candidate, then promote a more expensive strategy through an eval gate only when held-out results require it. Track p95 latency, the time under which 95% of requests finish, alongside quality. Snell et al. found that the best test-time allocation can depend on problem difficulty, so a fixed extra-sample budget isn't automatically optimal.[12]Reference 12Scaling LLM Test-Time Compute Optimally Can Be More Effective Than Scaling Model Parameters.https://arxiv.org/abs/2408.03314

An accuracy-versus-p95-latency chart compares direct prompting at 76% and 190 milliseconds, one trace at 84% and 360 milliseconds, five-sample voting at 94% and 740 milliseconds, and tree search at 96% and 1840 milliseconds; only voting clears both the 90% accuracy floor and 900 millisecond latency budget.
The gate is the region above 90% accuracy and left of 900 ms. Direct and single-trace miss the floor; tree search blows the latency budget; vote_5 is the only row that ships.
reasoning-release-gate.py
1results = [ 2 {"strategy": "direct", "accuracy": 0.76, "p95_ms": 190, "calls": 1}, 3 {"strategy": "single_trace", "accuracy": 0.84, "p95_ms": 360, "calls": 1}, 4 {"strategy": "vote_5", "accuracy": 0.94, "p95_ms": 740, "calls": 5}, 5 {"strategy": "tree_search", "accuracy": 0.96, "p95_ms": 1840, "calls": 14}, 6] 7 8minimum_accuracy = 0.90 9latency_budget_ms = 900 10eligible = [ 11 row for row in results 12 if row["accuracy"] >= minimum_accuracy and row["p95_ms"] <= latency_budget_ms 13] 14selected = min(eligible, key=lambda row: (row["calls"], row["p95_ms"])) 15 16for row in results: 17 print(f"{row['strategy']}: accuracy={row['accuracy']:.0%}, p95_ms={row['p95_ms']}, calls={row['calls']}") 18print(f"selected: {selected['strategy']}")
Output
1direct: accuracy=76%, p95_ms=190, calls=1 2single_trace: accuracy=84%, p95_ms=360, calls=1 3vote_5: accuracy=94%, p95_ms=740, calls=5 4tree_search: accuracy=96%, p95_ms=1840, calls=14 5selected: vote_5

Treat these as example evaluation results, not a benchmark claim. For a real system, keep a table with:

MetricWhy it matters
Action accuracy or task successExtra reasoning must change correct outcomes
Unsafe-action and abstention ratesReliability includes knowing when not to act
Input, output, and reasoning tokensSampling and search multiply spend
p50 and p95 latencyLong tails can make support interactions unusable
Parse and schema failuresA correct thought is useless if the runtime can't consume its action

When not to use CoT (or heavier search)

Use this checklist before you promote scaffolding or multi-sample voting:

SituationPrefer instead
Inputs are already structured policy predicatesDeterministic policy engine in the runtime
Pattern-matching few-shot ICL (curse-of-CoT regime)Direct answer; measure before adding a scratchpad
Multi-step task with sequential sub-dependenciesLeast-to-most prompting before expanding search trees
Single-label classification, field extraction, or formatting with clear labelsStructured output, no visible reasoning channel
No verifiable partial state and no backtracking valueDirect, one trace, or linear decomposition, not ToT/GoT
Accuracy already meets the gate at one callKeep one call; skip vote_5 and tree search
Hard latency budgets where extra tokens blow p95Cheapest strategy that still clears quality
User-visible channels where intermediate tokens can leak secretsKeep traces server-side or omit them
Need a compliance audit of whyLogged inputs, tool observations, and policy checks, not free-form CoT text
Missing live factsTool call (next lesson), not a longer rationale
A native reasoning model already wins the evalSkip your own scaffolding; compare behind the same gate

Adding a visible CoT scaffold to a reasoning-tuned model can add tokens and latency with little accuracy gain. On ordinary chat models it can also inject errors on questions the model already answered reliably.[3]Reference 3Prompting Science Report 2: The Decreasing Value of Chain of Thought in Promptinghttps://arxiv.org/abs/2506.07142 Treat that prompt as another experimental arm, not as a required wrapper around every reasoning endpoint.

Where reasoning ends and tools begin

All runnable experiments above operate on provided facts or deterministic state. A real release decision requires current CI status, security scan output, and review state from source systems. Reasoning alone can't obtain those observations.

ReAct interleaves reasoning traces and task-specific actions so new observations can update the next decision.[13]Reference 13ReAct: Synergizing Reasoning and Acting in Language Models.https://arxiv.org/abs/2210.03629 This loop doesn't require raw private reasoning. It needs a validated action request, a controlled execution result, and a bounded next decision:

reasoning-to-tool-handoff.txt
1Need: security scan status is not present in supplied facts. 2Next action request: get_security_scan(run_id="ci-1482") 3Runtime responsibility: validate authorization, execute call, log result. 4Next decision: apply policy only after observation is returned.

The next lesson implements that action boundary with typed function calls, schemas, errors, and safe execution.

What to remember

  • Define the scorer first. A decision record lets you test whether extra inference work improves outcomes.
  • Keep artifacts distinct. Prompt-elicited CoT, hidden reasoning tokens, provider summaries, and application decision records aren't interchangeable.
  • One trace is one candidate. CoT can expose missed steps, but a plausible rationale isn't a faithful audit log.[8]Reference 8Language Models Don't Always Say What They Think: Unfaithful Explanations in Chain-of-Thought Promptinghttps://arxiv.org/abs/2305.04388
  • Vote on normalized outcomes. Self-consistency is useful only when its measured gain beats its sample cost.[9]Reference 9Self-Consistency Improves Chain of Thought Reasoning in Language Models.https://arxiv.org/abs/2203.11171
  • Search only with branch structure. ToT and GoT need meaningful states, evaluators, pruning limits, and failure measurements.[10]Reference 10Tree of Thoughts: Deliberate Problem Solving with Large Language Models.https://arxiv.org/abs/2305.10601 [11]Reference 11Graph of Thoughts: Solving Elaborate Problems with Large Language Modelshttps://arxiv.org/abs/2308.09687
  • Promote strategies through evals. Direct, trace, vote, and search should compete under quality and latency gates.
  • Skip CoT when policy is already machine state. Deterministic predicates, pattern-ICL, and tasks already above the accuracy SLO need no scratchpad.
Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.A release service already receives three trusted booleans: tests passed, security scan clear, and reviewer approved. Policy is a fixed conjunction of those fields. Which controller should make the merge decision?

Correct answer: A deterministic policy function that evaluates all three predicates and emits a structured decision record.

Machine-readable predicates with an exact rule need no model inference. A decision record can still expose checks and action for audit, while sampling or search would add cost without new evidence.

2.An operator asks whether a provider reasoning summary can serve as proof that a model faithfully applied release policy. Which distinction is correct?

Correct answer: A reasoning summary can orient review, while supplied facts, decision fields, validations, and outcomes remain the auditable evidence.

Prompt-elicited text, hidden reasoning tokens, provider summaries, and application decision records have different guarantees. Neither a rationale nor a summary proves faithful cognition; task-level fields and observable outcomes can be validated.

3.A zero-shot prompt often omits one required check. A solved example demonstrates the exact required_checks fields and allowed action enum, and held-out evaluation shows better parse and action accuracy at acceptable cost. What should the team do?

Correct answer: Use the few-shot example and retain schema validation because measured task gains justify its prompt cost.

Few-shot examples can teach task-specific decomposition and output shape. They earn their extra tokens through held-out results, but they do not replace application validation or authorization.

4.A team calls one deterministic decode five times and receives the same final string each time. How should it redesign the experiment to test self-consistency?

Correct answer: Sample varied candidates with fixed stochastic settings, canonicalize allowed actions, and vote on those outcomes.

Self-consistency depends on alternative sampled paths, not duplicated deterministic output. Canonicalization collapses harmless wording variants before voting, while unknown actions remain rejected.

5.Five samples canonicalize to merge_release, merge_release, one manual_review, and two rejected strings. The minimum winning share is 0.60 using every sample as denominator. What should the controller return?

Correct answer: manual_review, because the winner has only 2/5 = 0.40 of all samples.

Parse failures are evidence that the sampling process did not produce a strong allowed outcome, so they stay in the denominator. Two of five falls below the 0.60 release threshold and routes to review.

6.Which problem structure most strongly favors Tree-of-Thoughts over independent answer voting?

Correct answer: A search problem with checkable partial states, consequential early choices, and useful backtracking.

Voting aggregates complete independent answers but cannot deliberately revisit an early choice. Tree search is valuable when the controller can expand alternatives, evaluate partial progress, prune, and backtrack.

7.A Game of 24 controller uses beam width 1. Its weak evaluator scores an unsolvable first move 0.95 and the only solvable first move 0.40. What follows after pruning?

Correct answer: The valid branch is gone, so later expansion cannot recover it without widening or revisiting the frontier.

Search allocates compute only to retained states. A narrow beam turns evaluator error into irreversible search error, so measure partial-state recall and use deterministic validators when available.

8.An eval reports: direct 76% at 190 ms, one trace 84% at 360 ms, vote-5 94% at 740 ms, and tree search 96% at 1840 ms. Gate requires at least 90% accuracy and at most 900 ms p95. Which strategy ships?

Correct answer: Vote-5, because it is the only strategy that clears both quality and latency constraints.

Direct and one trace miss the accuracy floor; tree search exceeds the latency ceiling. The gate selects among eligible strategies, not by accuracy or speed alone.

9.A compositional task has a known ordered chain of subproblems, each answer feeding the next, but no useful branches to revisit. Which escalation is most proportional?

Correct answer: Least-to-most prompting that solves the simpler subproblem first and passes its result forward.

Least-to-most matches a sequential dependency structure without paying for a branching search that has no backtracking value. Each intermediate output becomes explicit input to the next subproblem.

10.A release decision has current tests and review approval, but no security-scan observation. What should the reasoning controller do?

Correct answer: Request the scan through a typed, authorized tool and apply policy only after the observation returns.

Inference-time compute cannot manufacture a missing source-of-truth fact. The correct boundary is a validated action request, host execution, and a new decision over the returned observation.

10 questions remaining.

Next Step
Continue to Function Calling & Tool Use

You can now choose and evaluate a reasoning budget over facts already in the prompt. Next you'll turn a missing observation into a typed tool request that a trusted runtime validates, executes, and logs.

PreviousDimensionality Reduction for Embeddings
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Chain-of-Thought Prompting Elicits Reasoning in Large Language Models.

Wei, J., et al. · 2022 · NeurIPS

https://arxiv.org/abs/2201.11903

Large Language Models are Zero-Shot Reasoners.

Kojima, T., et al. · 2022

https://arxiv.org/abs/2205.11916

Prompting Science Report 2: The Decreasing Value of Chain of Thought in Prompting

Meincke, L., Mollick, E., Mollick, L., & Shapiro, D. · 2025

https://arxiv.org/abs/2506.07142

The Curse of CoT: On the Limitations of Chain-of-Thought in In-Context Learning.

Zheng, T., Chen, Y., Li, C., et al. · 2025 · arXiv preprint

https://arxiv.org/abs/2504.05081

Least-to-Most Prompting Enables Complex Reasoning in Large Language Models

Zhou, D., et al. · 2022 · ICLR 2023

https://arxiv.org/abs/2205.10625

Reasoning models

OpenAI · 2026

https://developers.openai.com/api/docs/guides/reasoning

Building with extended thinking

Anthropic · 2025

https://docs.claude.com/en/docs/build-with-claude/extended-thinking

Language Models Don't Always Say What They Think: Unfaithful Explanations in Chain-of-Thought Prompting

Miles Turpin, Julian Michael, Ethan Perez, Samuel R. Bowman · 2023

https://arxiv.org/abs/2305.04388

Self-Consistency Improves Chain of Thought Reasoning in Language Models.

Wang, X., et al. · 2022

https://arxiv.org/abs/2203.11171

Tree of Thoughts: Deliberate Problem Solving with Large Language Models.

Yao, S., et al. · 2023 · NeurIPS

https://arxiv.org/abs/2305.10601

Graph of Thoughts: Solving Elaborate Problems with Large Language Models

Besta, M., et al. · 2024 · AAAI 2024

https://arxiv.org/abs/2308.09687

Scaling LLM Test-Time Compute Optimally Can Be More Effective Than Scaling Model Parameters.

Snell, C., et al. · 2024 · arXiv preprint

https://arxiv.org/abs/2408.03314

ReAct: Synergizing Reasoning and Acting in Language Models.

Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K., & Cao, Y. · 2023 · ICLR 2023

https://arxiv.org/abs/2210.03629

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.