# Advanced Agents From First Principles 01: Does Your AI Agent Fail on Complex Reasoning Tasks? Treat Chain of Thought as Computation, Not Proof # Book: Advanced Agents From First Principles # Chapter URL: https://programmer.ie/books/advanced-agents-from-first-principles/01-chapter/ # Prose fingerprint (sha256, normalized): ebc04216130fa69ae7a7c0fef558c1467f64d4191341f2f1ed88de2b6a26f7fd # Snapshot generated at build time by Hugo. This is the complete rendered prose # of the chapter; it is not a transcript of the source file. Most developers first encounter chain of thought as a prompting trick: Think step by step. That framing is too shallow for agent engineering. For an advanced agent, the useful idea is not that the model should produce a long explanation. The useful idea is that a difficult task may benefit from intermediate computational state before the system commits to an action or answer. That is a very different claim. A reasoning trace can help a system decompose a problem, preserve intermediate conclusions, identify missing information, decide what to verify next, and expose places where search or tools should be used. But none of that makes the trace true. The central rule of this post is: Chain of thought is computation, not proof. A plausible reasoning trace is still model output. It can contain incorrect assumptions, invented facts, invalid arithmetic, bad causal links, or a perfectly coherent path to the wrong answer. So the engineering question is not: How do I make the model explain itself more? It is: Where does intermediate computation improve verified task success, and how should the runtime use that computation without mistaking it for evidence? This post builds that distinction from first principles. The Search Problem: “Why Does My AI Agent Fail on Complex Reasoning Tasks?” A common pattern looks like this: simple task ↓ model succeeds complex task ↓ model jumps directly to answer ↓ important constraint omitted ↓ wrong answer The failure is often described as “the model cannot reason.” Sometimes that is true. But often the problem is more specific: the runtime asks the model to collapse too much computation into one opaque output. Consider a coding agent asked to repair a failing test suite. A one-shot path may look like: issue description ↓ model ↓ patch A more useful computational path might be: issue description ↓ identify failing behavior ↓ inspect relevant code ↓ form hypotheses ↓ select next diagnostic ↓ observe result ↓ revise hypothesis ↓ propose patch ↓ run tests The improvement does not come from making the prose longer. It comes from creating intermediate decisions that can interact with evidence. One-Shot Generation Compresses Too Much The simplest agent asks a model to go directly from input to output: def solve(task: str, model) -> str: return model(task) That is often the correct architecture. Do not add a reasoning mechanism merely because the task looks intellectual. But for some tasks, direct generation forces the model to implicitly perform several operations at once: understand task + identify constraints + retrieve relevant facts + choose method + perform calculation + check result + format answer If any hidden sub-operation fails, the final answer can fail without giving the runtime a useful point at which to intervene. Intermediate computation changes the shape: input ↓ intermediate state 1 ↓ intermediate state 2 ↓ verification / tool use ↓ intermediate state 3 ↓ answer Now the runtime has places where it can inspect, verify, branch, retry, or gather more information. Chain of Thought Is Not Necessarily Visible Prose This distinction matters enormously. Developers often equate chain of thought with a long text field containing sentences such as: First I will consider... Then I will calculate... Therefore... That is only one representation. For agent systems, intermediate computation can be represented as structured state instead. For example: from dataclasses import dataclass, field @dataclass class ReasoningState: goal: str known_facts: list[str] = field(default_factory=list) unknowns: list[str] = field(default_factory=list) hypotheses: list[str] = field(default_factory=list) next_checks: list[str] = field(default_factory=list) constraints: list[str] = field(default_factory=list) That is often more useful than unrestricted prose. Why? Because the runtime can validate and operate on it. free-form reasoning ↓ hard to inspect mechanically structured reasoning state ↓ known fields ↓ validation ↓ tool routing ↓ search / verification This is a recurring theme in agent engineering: When intermediate reasoning affects control flow, represent the parts that matter as data. A Minimal Reasoning Pipeline Suppose we want the model to decompose a difficult task before answering. We can separate decomposition from execution. from dataclasses import dataclass @dataclass class ReasoningPlan: interpretation: str constraints: list[str] steps: list[str] verification: list[str] def reason(task: str, model) -> ReasoningPlan: raw = model({ "task": task, "instruction": ( "Return a structured plan containing an interpretation, " "constraints, steps, and verification checks." ), }) return parse_reasoning_plan(raw) Then execution can be separated: def execute_reasoning_plan(plan: ReasoningPlan, runtime): observations = [] for step in plan.steps: observation = runtime.execute(step) observations.append(observation) return observations And success can be evaluated separately again: def verify(plan: ReasoningPlan, observations, verifier): return verifier.check( constraints=plan.constraints, verification=plan.verification, observations=observations, ) The key architecture is: reasoning ≠ execution ≠ verification That separation is far more useful than merely asking for “more reasoning.” Why Long Reasoning Can Still Be Wrong Consider this hypothetical trace: The service is failing because the database connection pool is exhausted. The latency spike supports this. Therefore increasing the pool size should fix the incident. It is coherent. It may even sound expert. But perhaps the actual problem is a downstream dependency timing out, causing connections to remain occupied longer. Increasing the pool size might simply delay the failure. The reasoning trace contains a hypothesis: pool exhaustion is root cause That is not proof. A better runtime turns the hypothesis into a test: hypothesis ↓ what observation would support/refute it? ↓ inspect pool saturation ↓ inspect connection duration ↓ inspect downstream latency ↓ update belief Now chain of thought is being used as a generator of testable intermediate state. That is much stronger. Separate Claims From Evidence A useful reasoning representation can distinguish claims from evidence. from dataclasses import dataclass, field @dataclass class Claim: text: str evidence_ids: list[str] = field(default_factory=list) status: str = "unverified" Then the runtime can enforce a simple rule: def can_promote(claim: Claim, evidence_store) -> bool: return all( evidence_store.exists(evidence_id) for evidence_id in claim.evidence_ids ) The model may say: The authentication middleware is dropping the header. The runtime records: CLAIM: authentication middleware drops header STATUS: unverified Then tools gather evidence: request trace middleware logs integration test Only then does the status change. This prevents a dangerous collapse: model thought it ↓ therefore system believes it The Reasoning Scratchpad and the Control Plane Are Different Another important distinction is between temporary reasoning state and durable runtime state. A scratchpad might contain: Maybe file A is relevant. Could also be file B. Need to inspect the parser first. That is useful temporary computation. But it should not automatically become durable memory. Compare: scratchpad ↓ provisional hypotheses ↓ throw away freely with: runtime state ↓ verified files inspected commands executed artifacts produced remaining tasks The latter needs deterministic persistence. The previous memory post made this distinction for long-term memory. The same principle applies here: Do not turn provisional reasoning into system truth merely because it appeared earlier in the trajectory. Reasoning as a State Machine A more disciplined design is to represent reasoning stages explicitly. from enum import Enum class ReasoningPhase(str, Enum): UNDERSTAND = "understand" DECOMPOSE = "decompose" INVESTIGATE = "investigate" PROPOSE = "propose" VERIFY = "verify" COMPLETE = "complete" Now the system can control transitions: UNDERSTAND ↓ DECOMPOSE ↓ INVESTIGATE ↓ PROPOSE ↓ VERIFY ↓ COMPLETE But transitions should not be model wishful thinking. For example: def can_enter_verify(state) -> bool: return bool(state.proposed_solution) def can_complete(state) -> bool: return state.verification_status == "PASS" This turns a vague reasoning process into a runtime protocol. Use Tools to Break Reasoning Out of the Model Suppose an agent needs to answer: Which function introduced the regression? The weakest architecture is: repository text ↓ LLM guesses A stronger reasoning architecture is: form hypothesis ↓ git diff ↓ inspect call sites ↓ run targeted test ↓ inspect failure ↓ update hypothesis The computation is distributed across: model + tools + environment + verification This is one of the most important advanced-agent ideas: The model does not need to internally simulate work that the environment can perform more reliably. Use computation where it is strongest. Arithmetic belongs in a calculator. Repository history belongs in Git. Database state belongs in the database. Test outcomes belong in the test runner. The model’s intermediate computation should help decide which external computation to request next. Chain of Thought as Tool Selection This gives us a useful interpretation of reasoning: current evidence ↓ what uncertainty matters most? ↓ which observation would reduce it? ↓ select tool ↓ observe ↓ update state That is much closer to an agent than a long essay about what the model thinks. For example, a debugging agent might hold: state.unknowns = [ "whether parser receives malformed input", "whether failure occurs before persistence", ] The model chooses which unknown to reduce first. next_check = { "tool": "inspect_logs", "arguments": { "component": "parser", "request_id": "abc123", }, } Now reasoning directly guides evidence acquisition. What Should Be Structured? Not everything needs a schema. But fields that influence control flow usually benefit from structure. Useful candidates include: goal constraints unknowns hypotheses candidate actions required evidence verification checks confidence / uncertainty termination reason For example: @dataclass class InvestigationState: goal: str constraints: list[str] hypotheses: list[str] unresolved_questions: list[str] evidence: list[str] next_action: dict | None This allows the runtime to answer questions that free-form prose obscures: How many unresolved questions remain? Which hypothesis has no evidence? Did the agent already test this idea? Which constraint has not been checked? Why did the agent choose this tool? The Common Failure: Verbosity Masquerading as Reasoning One of the most common mistakes is to increase reasoning-token usage and assume capability improved. You may see: short answer: 300 tokens reasoning answer: 4,000 tokens and conclude: more tokens ↓ more thought ↓ better reasoning That inference is not safe. Longer traces can contain: repetition rationalization irrelevant decomposition invented details premature assumptions circular reasoning duplicated checks post-hoc explanations The right metric is not reasoning length. It is verified task performance. A useful experiment is: baseline: direct answer variant A: structured decomposition variant B: decomposition + tools variant C: decomposition + tools + verification Measure: verified success latency model calls tool calls tokens cost per successful task Then keep the simplest architecture that wins. The Common Failure: Self-Consistency of One Bad Assumption A model can construct a long, internally coherent trace around a bad premise. For example: Assumption: request reaches service B. Step 1: service B parses request. Step 2: service B writes database row. Step 3: database constraint fails. If the request never reached service B, every later step is irrelevant. This motivates assumption checkpoints. @dataclass class Assumption: statement: str must_verify: bool evidence_id: str | None = None Before expensive downstream reasoning, the runtime can check critical assumptions. assumption ↓ cheap verification available? ↓ yes verify first ↓ continue only if supported This often saves both tokens and wrong work. The Common Failure: Reasoning After the Answer Another subtle failure occurs when the model effectively decides on an answer first and then generates a plausible rationale. For agent engineering, the remedy is not philosophical. It is architectural. Make intermediate decisions causally matter. Instead of: model produces answer + explanation use: model proposes next check ↓ runtime executes it ↓ observation enters state ↓ model receives observation ↓ next decision The external observation constrains the next step. That makes the reasoning trajectory operational rather than merely descriptive. Reasoning Checkpoints Long tasks benefit from checkpoints where the runtime asks whether the trajectory is still valid. A checkpoint might inspect: Are the original constraints still represented? Have any assumptions been falsified? Has new evidence changed the problem? Are we repeating the same hypothesis? Is the current branch making progress? Can any remaining unknown be verified directly? A simple checkpoint object: @dataclass class ReasoningCheckpoint: constraints_satisfied: bool assumptions_supported: bool progress_detected: bool unresolved_questions: list[str] recommended_action: str Possible recommendations: CONTINUE GATHER_EVIDENCE REVISE_HYPOTHESIS BACKTRACK VERIFY STOP Notice how this begins to connect chain of thought to later advanced techniques such as search and MCTS. Reasoning vs Search Chain of thought and search are related but different. A single reasoning trajectory looks like: A ↓ B ↓ C ↓ D Search preserves alternatives: A / \ B C / \ / \ D E F G Chain of thought can improve a single path. Search asks whether we should maintain multiple paths. The escalation rule is: Does one structured reasoning trajectory work? ↓ yes stop there ↓ no Are early decisions uncertain and consequential? ↓ yes preserve alternatives with search Do not build a tree merely because you can. Reasoning vs Best-of-N Best-of-N generates several complete candidates: prompt ├→ answer A ├→ answer B ├→ answer C └→ answer D ↓ select Reasoning decomposes one trajectory: prompt ↓ state 1 ↓ state 2 ↓ state 3 ↓ answer Use Best-of-N when diversity among complete outputs helps. Use intermediate reasoning when later decisions should depend on intermediate observations. You can combine them: multiple reasoning strategies ↓ execute / verify ↓ select best supported result But again, every extra path costs inference. Reasoning vs Critique and Revision Critique/revision operates after a candidate exists: candidate ↓ critique ↓ revision Intermediate reasoning operates before or during construction: problem ↓ decompose ↓ investigate ↓ construct The distinction matters because some failures are easier to prevent than repair. If the agent misses a fundamental constraint at the beginning, repeated rewriting may never recover efficiently. A reasoning checkpoint can surface the constraint before generation commits too far. Reasoning and Verification Must Remain Separate Suppose the reasoning state contains: All required tests should now pass. That is still only a prediction. The verifier must run: pytest and return: PASS FAIL UNKNOWN The correct architecture is: reasoning predicts ↓ environment tests ↓ verification decides Not: reasoning predicts ↓ reasoning confirms itself This separation is one of the main reasons the verification post closed the core series before we entered advanced orchestration. A Complete Small Reasoning Agent Here is a simplified architecture that keeps the pieces separate. from dataclasses import dataclass, field from typing import Protocol class Model(Protocol): def __call__(self, payload: dict) -> dict: ... @dataclass class Evidence: id: str source: str content: str @dataclass class ReasoningState: goal: str constraints: list[str] = field(default_factory=list) hypotheses: list[str] = field(default_factory=list) unknowns: list[str] = field(default_factory=list) evidence: list[Evidence] = field(default_factory=list) proposed_answer: str | None = None class ReasoningAgent: def __init__(self, model: Model, tools, verifier): self.model = model self.tools = tools self.verifier = verifier def run(self, goal: str, max_steps: int = 8): state = ReasoningState(goal=goal) for step in range(max_steps): decision = self.model({ "goal": state.goal, "constraints": state.constraints, "hypotheses": state.hypotheses, "unknowns": state.unknowns, "evidence": [e.content for e in state.evidence], "instruction": ( "Choose one action: gather_evidence, update_state, " "propose_answer, or request_verification." ), }) action = decision["action"] if action == "gather_evidence": tool_name = decision["tool"] arguments = decision["arguments"] result = self.tools.execute(tool_name, arguments) state.evidence.append( Evidence( id=f"evidence-{step}", source=tool_name, content=result, ) ) continue if action == "update_state": state.constraints = decision.get( "constraints", state.constraints ) state.hypotheses = decision.get( "hypotheses", state.hypotheses ) state.unknowns = decision.get( "unknowns", state.unknowns ) continue if action == "propose_answer": state.proposed_answer = decision["answer"] continue if action == "request_verification": if state.proposed_answer is None: continue result = self.verifier.verify( goal=state.goal, answer=state.proposed_answer, evidence=state.evidence, ) if result.status == "PASS": return state.proposed_answer if result.status == "FAIL": state.unknowns.extend(result.failures) state.proposed_answer = None continue raise RuntimeError("Reasoning budget exhausted") This is still intentionally small. But notice what has changed compared with a prompt that says “think step by step.” The runtime now owns: step budget tool execution evidence records verification completion The model proposes intermediate computation. The runtime controls the process. Application: Coding Agents Coding agents are an excellent example because the environment provides strong evidence. A weak reasoning loop: read issue ↓ think about code ↓ write patch ↓ claim fixed A stronger one: read issue ↓ identify expected behavior ↓ locate relevant code ↓ form failure hypothesis ↓ run targeted diagnostic ↓ update hypothesis ↓ edit isolated branch/worktree ↓ run targeted tests ↓ run regression checks ↓ inspect diff Intermediate reasoning is useful for: choosing what file to inspect choosing which test to run identifying likely invariants deciding whether failure evidence supports a hypothesis deciding when to broaden search But Git, tests, type checkers, linters, and runtime behavior remain stronger evidence than prose reasoning. Application: Research Agents A research agent often fails because it jumps from query to conclusion too quickly. Useful intermediate state includes: question subquestions candidate claims missing evidence source quality contradictions unresolved uncertainty A stronger research path: question ↓ decompose claims ↓ search primary sources ↓ extract evidence ↓ identify contradictions ↓ search missing evidence ↓ write synthesis ↓ check every material claim has support The reasoning trace helps organize the investigation. The sources provide the evidence. That distinction protects the system from citing its own generated explanation as if it were research. Application: Debugging and Incident Response Incident response is where unverified reasoning can become expensive. A model might quickly conclude: CPU saturation caused the outage. A disciplined agent instead records: hypothesis: CPU saturation is causal needed evidence: - CPU timing relative to errors - request latency - queue depth - dependency latency Then it collects observations. This is essentially scientific debugging: hypothesis ↓ prediction ↓ measurement ↓ update Chain of thought becomes a mechanism for choosing informative experiments. Application: Data and Analytics Agents Suppose an analytics agent must answer: Why did conversion fall yesterday? A bad one-shot answer might invent a plausible narrative. A useful reasoning state might be: metric definition comparison window possible segmentation changes tracking changes traffic-source mix funnel-stage deltas known incidents Then the agent queries actual data. reasoning ↓ SQL / metrics tools ↓ observations ↓ updated hypothesis ↓ verified explanation The model helps coordinate analysis. The data determines what happened. Application: Browser Agents Browser tasks require reasoning about hidden state and sequential constraints. For example: goal: submit application Intermediate state may include: required fields completed fields missing documents current page validation errors submission status The reasoning mechanism decides what to do next. But successful submission should be verified from the page/application state—not from a generated sentence saying “the form has been submitted.” Application: Planning and Scheduling Agents Planning agents benefit when constraints must be combined before committing. Useful intermediate computation: hard constraints soft preferences resource availability dependencies conflicts candidate schedules Then deterministic solvers or constraint checks can test candidate plans. This is an important pattern: LLM proposes structure ↓ solver checks feasibility ↓ LLM interprets / revises Do not ask a language model to replace a deterministic constraint solver when one exists. Application: Customer Support Agents A support agent may need to reason about: customer intent account state order state policy constraints possible resolution escalation criteria But customer-specific facts must come from account/order systems. A strong architecture is: interpret request ↓ identify required facts ↓ query systems ↓ apply policy ↓ propose resolution ↓ validate permissions ↓ execute / escalate The reasoning is useful coordination. The business systems remain authoritative. Application Matrix Software Useful intermediate computation Strong external evidence Typical reasoning failure Coding agent hypotheses, constraints, next diagnostic tests, diff, compiler, runtime plausible patch without validation Research agent subquestions, claims, missing evidence primary sources narrative before evidence Incident agent failure hypotheses, diagnostic priority metrics, logs, traces correlation treated as cause Data agent segment hypotheses, metric decomposition database queries plausible analytics story Browser agent required state, incomplete fields DOM/page state assumes action succeeded Planner dependencies, hard/soft constraints solver / feasibility checks impossible plan Support agent intent, missing facts, policy path account/order systems invented customer state The recurring architecture is: model computation ↓ external observation ↓ state update ↓ model computation not: model computation ↓ more model computation ↓ model agrees with itself When Chain of Thought Makes Things Worse Intermediate reasoning adds cost and new failure modes. It can hurt when: the task is already trivial the model over-decomposes reasoning anchors on an early mistake intermediate state bloats context repeated reflection adds no evidence the runtime stores provisional thoughts as facts reasoning latency dominates the task private or sensitive intermediate data is retained unnecessarily the final answer quality does not improve A good baseline experiment is mandatory. A: direct generation B: structured reasoning C: structured reasoning + tools D: structured reasoning + tools + verification Do not compare only average answer scores. Measure operational outcomes. Metrics That Actually Matter For reasoning agents, useful metrics include: Outcome verified task success Efficiency model calls tokens latency tool calls cost per verified success Reasoning usefulness fraction of intermediate checks that change the trajectory fraction of hypotheses tested assumption failure rate repeated-hypothesis rate unverified-claim rate Verification false-pass rate false-fail rate UNKNOWN rate Progress unknowns reduced per step constraints resolved per step useful evidence acquired per call A reasoning architecture that produces twice as many tokens but no measurable improvement is not more advanced. It is simply more expensive. A Useful Diagnostic: Did the Reasoning Change Anything? This question is surprisingly powerful. For every intermediate reasoning step, ask: Did it change: - the next action? - the selected tool? - the active hypothesis? - the candidate solution? - the verification plan? If not, the step may be decorative. You can log this directly: @dataclass class ReasoningEvent: event_type: str content: str changed_control_flow: bool Then measure: control-flow-changing reasoning events -------------------------------------- all reasoning events If that number is tiny, the system may be generating explanations rather than useful computation. Another Diagnostic: What Could Falsify This Step? For a material hypothesis, ask: What observation would prove this wrong? If the system cannot name one, the hypothesis may be too vague to guide action. For example: "Something is wrong with caching" is weak. Better: "The cache key omits tenant_id, causing cross-tenant reuse." Now we can inspect: key construction cache entries request tenant IDs Reasoning becomes operational. Confidence Is Not Evidence Either Models may attach confidence to intermediate conclusions. That can help prioritize checks, but confidence should not replace verification. high confidence ≠ correct A better use is compute allocation: low uncertainty ↓ cheap path high uncertainty ↓ more evidence / search / specialist This is where chain of thought connects directly to adaptive agents later in the series. Reasoning Traces and Privacy Intermediate reasoning can contain more information than the final answer. Production systems should decide deliberately: what reasoning state is retained what is logged what is sent to external services what is visible to users what contains secrets or personal data what should expire A useful architecture separates: ephemeral computation ↓ minimum durable trace You often need provenance like: tool called input hash observation ID decision selected verification result without retaining every free-form intermediate token forever. Reasoning Trace vs Decision Trace For production agents, a decision trace is often more useful than a full free-form reasoning transcript. Example: { "step": 4, "state_hash": "...", "decision": "run_targeted_test", "reason": "hypothesis H2 lacks runtime evidence", "tool": "pytest", "result_id": "obs-421" } This captures the information needed for debugging: what did the agent believe mattered? what did it do? what evidence came back? without making the entire system dependent on prose traces. Treat Reasoning as a Budget Reasoning consumes compute. So give it a budget. @dataclass class ReasoningBudget: max_steps: int max_model_calls: int max_tool_calls: int max_tokens: int Then escalate only when needed. simple task ↓ direct path failure / uncertainty ↓ structured reasoning still unresolved ↓ search / specialist / stronger model This is much better than enabling maximum reasoning for every request. Adaptive Reasoning Depth One advanced extension is to vary reasoning effort based on the task. For example: def reasoning_budget(task, classifier): difficulty = classifier(task) if difficulty == "low": return 1 if difficulty == "medium": return 4 return 10 But difficulty estimation itself can fail. So runtime evidence should also trigger escalation: direct answer fails verification ↓ reason more reasoning branch remains uncertain ↓ search alternatives search cannot discriminate ↓ stronger verifier / specialist This is the beginning of adaptive compute allocation. The Evidence-First Rule The Advanced Agents series keeps the same rule as the previous series: Do not add a mechanism because it sounds more intelligent. Add it because you can name the failure it is supposed to fix and measure whether it fixes it. For chain of thought, the hypothesis might be: Complex tasks fail because important constraints are lost before action selection. Then test: baseline direct generation variant structured constraints + intermediate checks Measure: constraint violation rate verified success latency cost If constraints are still violated at the same rate, the mechanism did not solve the claimed problem. An Experiment Template from dataclasses import dataclass @dataclass class ReasoningExperimentResult: architecture: str verified_success_rate: float constraint_failure_rate: float avg_model_calls: float avg_tool_calls: float avg_latency_ms: float avg_tokens: float cost_per_success: float Compare: direct structured reasoning reasoning + tools reasoning + tools + verification Then ask: What did the extra computation buy us? That question should follow every advanced-agent mechanism in this series. What This Unlocks Next Once intermediate computation is explicit, we can do something more interesting. Instead of generating one reasoning trajectory: A → B → C → D we can generate several: A → B → C A → E → F A → G → H Then compare where they agree. That leads to the next advanced technique: self-consistency But self-consistency introduces another trap: many agents / samples agree ≠ answer is true Agreement can come from correlated model errors. So the same evidence-first boundary remains. Final Architecture The useful form of chain of thought for an agent looks less like this: Please explain your reasoning in detail. and more like this: goal ↓ structured intermediate state ↓ identify uncertainty ↓ choose evidence-producing action ↓ observe environment ↓ update hypotheses ↓ propose result ↓ external verification The model provides flexible computation. The runtime supplies structure. Tools supply observations. Verification supplies evidence. That is the important transition from prompting to agent architecture. And it gives us the rule to carry into every later post: Reasoning can tell the agent what to investigate next. Only evidence can tell the system what actually happened. Next: Self-Consistency The next post will ask another common question: Why does my reasoning agent give a different answer every time? We will build self-consistency from first principles: sample multiple reasoning trajectories, measure agreement, separate consensus from correctness, detect correlated failures, and decide when disagreement should trigger search, verification, or specialist escalation instead of a majority vote.