Reflection Helps an Agent Recover, but It Cannot Verify Reality

An agent tries a search, receives an empty result, and decides to try a different query. That looks like intelligence because it is better than stopping at the first failure.

It is also the beginning of a loop that can spend money, wait on slow dependencies, and amplify a false assumption. A system that reflects on its own work can recover from some mistakes. It cannot make its own narration into proof that a payment was sent, a policy was applied, or a source is trustworthy.

Reflection is a control mechanism, not a truth mechanism. It is most useful when a product specifies what the agent should inspect, when it should stop, and which parts of a result must be independently verified.

ReAct Makes Intermediate Evidence Visible

ReAct alternates between reasoning, acting, and observing. Instead of producing a complete answer from its initial context, the agent states a next step, calls a tool, incorporates the result, and decides what to do next.

This can be powerful for multi-step research. A question may require looking up one entity, using that result to find a second source, and combining both. The observation after each tool call gives the agent an opportunity to notice that a route failed or that the next action should change.

The practical value is not hidden chain-of-thought. A production system does not need to expose private model deliberation to be debuggable. It needs a structured record of the observable workflow:

type StepRecord = {
  step: number
  tool: 'searchDocs' | 'getAccount' | 'createCase'
  input: Record<string, unknown>
  outcome: 'success' | 'empty' | 'denied' | 'failed'
  evidenceIds: string[]
  nextDecision: 'continue' | 'ask-user' | 'escalate' | 'stop'
}

That trace lets an engineer distinguish an empty search result from a permission denial and a tool outage. It also makes it possible to show a user an accurate status: a source was unavailable, a request needs clarification, or an action is waiting for approval. Vague "thinking" indicators are no substitute for state the system can explain.

Reflexion Adds a Critique, Not an Oracle

Reflexion-style systems explicitly evaluate a trajectory after it fails, produce a lesson, and use that lesson for the next attempt. A coding agent may run a test, see it fail, identify the missing edge case, and revise the patch. A task agent may observe that it chose the wrong resource and update its next action.

This adds a useful distinction: the agent is not only reacting to output; it is summarizing why that output did not achieve the goal. It can avoid repeating a recent mistake without retaining every token of a long interaction.

But the critic has the same central limitation as the actor when both are language models. It can describe a convincing reason for a wrong result. An agent that guessed the wrong account may write a polished self-critique that still never checks the account identifier. A model can also overfit to its previous wording and turn a bad premise into a more elaborate one.

Use a hierarchy of feedback:

Feedback sourceWhat it can establish wellWhat it cannot establish alone
Schema validatorRequired fields and value constraintsWhether values are true or authorized
Tool responseWhat the authoritative service returnedWhether the requested action was appropriate
Test or compilerExecutable behavior against covered casesProduct intent outside coverage
Model critiquePlausibility, missing steps, alternative hypothesesObjective correctness in a high-stakes domain
Human reviewerAmbiguous policy and consequential judgmentInfinite scale or consistency without a rubric

The agent may use a critique to choose its next investigation. It should use authoritative evidence to decide that an important claim is complete.

Put Reflection at Checkpoints, Not Everywhere

Reflection can happen before a task, after a plan, after each tool result, or after the final response. The choice is an engineering tradeoff.

Before execution, a feasibility check can stop a workflow that asks for a tool the user cannot access. After plan generation, validation can catch a write action that should require confirmation. After a tool call, a checkpoint can notice an empty or contradictory result. At the end, a verifier can compare the claimed outcome with the actual state.

Adding every checkpoint to every task creates an agent that is expensive and slow even for routine work. Skipping checkpoints entirely creates an agent that is quick until it compounds an error. Match the loop to the task:

  • validate deterministic constraints before any side effect;
  • reflect after an observation that could materially change the plan;
  • use bounded retries for flaky dependencies, with backoff and a visible stop condition;
  • verify the final state through the source of truth for consequential actions;
  • hand off when evidence conflicts, a budget is exhausted, or the agent cannot name a safe next step.

For a frontend, reflection affects the interaction model. A user should be able to cancel a long loop, see what is waiting on a dependency, correct an extracted fact, and understand whether the system is researching, proposing, or executing. An interface that renders each tentative thought as an accomplished result turns useful iteration into false confidence.

More Tools Can Lower Reliability

Adding a tool gives an agent another way to solve a task. It also gives it another name, description, parameter schema, failure mode, and opportunity to choose incorrectly.

Research systems have explored tool inventories from a handful of APIs to thousands. The engineering lesson is not that a particular count is safe. It is that tool selection itself becomes a difficult retrieval and planning problem as the inventory grows. Tool descriptions consume context. Near-duplicate operations create ambiguity. A rarely appropriate but powerful tool can be selected at exactly the wrong moment.

Design the tool surface the way you would design a public API:

  • start with the smallest set that covers valuable workflows;
  • route by intent or workflow before asking a model to select among every internal API;
  • give tools distinct names, bounded semantics, and examples of permitted use;
  • return structured, typed results rather than prose a later model must reinterpret;
  • measure the effect of removing a tool before keeping it permanently;
  • separate read, draft, approve, and execute capabilities.

This is an ablation mindset: if removing a tool does not harm useful task completion, the tool is carrying operational risk without earning its place. A smaller inventory can improve selection accuracy and reduce the amount of internal capability exposed in a prompt.

Tool Failure Has More Shapes Than an Exception

A request can fail because the agent chose an invalid tool, selected a valid tool with invalid parameters, used a syntactically valid value for the wrong resource, or pursued the wrong objective entirely. A tool can fail by timing out, returning stale data, producing a partial response, or reporting success before an asynchronous effect is durable.

Instrument those differences. A dashboard that only reports model errors will miss the story. Record tool-selection attempts, argument-validation failures, authorization denials, dependency failures, retries, latency, cost, and postcondition verification. Redact sensitive inputs and scope trace access; agent logs can easily become a secondary archive of customer data.

Then evaluate the whole loop with task-oriented cases, not only isolated prompts. Include requests that should succeed, requests that should stop, unavailable tools, stale sources, ambiguous identifiers, permission boundaries, and adversarial text inside retrieved content. The success metric should reward reaching the correct outcome safely, not merely making one valid tool call.

Reflection Needs a Budget and an Exit

Every extra turn has a direct inference cost and an indirect user cost. A browser can keep a spinner alive while the agent debates itself, but the user still experiences delay and uncertainty. The system needs budgets for model calls, tool calls, elapsed time, tokens, and external effects.

Define exit conditions in code, not only in an instruction:

type LoopBudget = {
  maxModelTurns: number
  maxToolCalls: number
  deadlineMs: number
}

type TerminalState = 'completed' | 'needs-review' | 'cancelled' | 'failed'

A terminal state should carry an explanation fit for the user and an internal reason fit for an operator. "I could not verify the account" is useful user-facing language. authorization_denied_after_lookup is useful operational evidence. Neither should be replaced with fabricated progress.

Make the Loop Earn Its Cost

Reflection and tool use let an agent adapt when an initial answer is inadequate. That is valuable precisely because the adaptation is visible to the surrounding application.

Use ReAct-style observation to collect structured evidence. Use Reflexion-style critique to form a bounded hypothesis about what to try next. Keep tool inventories narrow and measurable. Place feedback at checkpoints where it can prevent a material mistake. Verify final effects outside the model. Give the UI truthful intermediate states and give the workflow a budgeted end.

An agent that can change its mind is more useful than one that cannot. An agent that can prove when it should stop is more reliable still.