What Is Your Agent Actually Uncertain About?
What Is Your Agent Actually Uncertain About?
An agent reaches a difficult point in a task.
It is not sure what to do next.
A common implementation responds like this:
uncertain
↓
call the model again
↓
still uncertain
↓
call a stronger model
↓
still uncertain
↓
search more
That is not a reasoning strategy.
It is a spending strategy.
The system is using more computation without identifying what information is actually missing.
The word confidence hides too much.
An agent can be uncertain because:
- the user request is ambiguous,
- the evidence is weak,
- two routes look equally plausible,
- the current environment state may be stale,
- a tool result may be incomplete,
- multiple candidate solutions look similar,
- the verifier does not cover an important requirement,
- or the system simply does not know whether additional computation will help.
Those are different problems.
They should not trigger the same response.
The central rule of this post is:
Before spending more computation, identify what the system is uncertain about.
The previous post introduced dynamic budget scheduling.
This post gives the scheduler a better signal.
Instead of one scalar:
confidence = 0.63
we want something closer to:
interpretation_uncertainty = 0.10
evidence_uncertainty = 0.82
route_uncertainty = 0.18
state_uncertainty = 0.76
candidate_uncertainty = 0.31
verification_uncertainty = 0.67
Now the system can make a more useful decision.
If evidence uncertainty is high, retrieve evidence.
If state uncertainty is high, inspect the environment.
If route uncertainty is high, compare routes.
If candidate uncertainty is high, search or generate alternatives.
If verification uncertainty is high, improve verification coverage.
Calling the model again becomes only one possible action.
Confidence Is Not Uncertainty
These two ideas are often collapsed.
A model may report:
I am 92% confident.
That does not tell us:
- whether the task was interpreted correctly,
- whether the evidence was complete,
- whether the environment changed,
- whether the best route was considered,
- or whether the acceptance criteria were actually checked.
A single confidence score can be useful in narrow calibrated prediction problems.
But an advanced agent is not one prediction.
It is a sequence of decisions over changing state.
A better mental model is:
state
↓
uncertainty decomposition
↓
which uncertainty matters most?
↓
which action can reduce it?
↓
is that reduction worth the cost?
↓
act / inspect / search / verify / stop
The uncertainty model belongs in the control plane.
It should help determine where the agent spends compute.
Seven Useful Types of Agent Uncertainty
There are many ways to classify uncertainty.
For production agents, the useful classification is the one that changes what the runtime should do next.
We will use seven categories.
1. interpretation uncertainty
2. evidence uncertainty
3. route uncertainty
4. state uncertainty
5. tool uncertainty
6. candidate uncertainty
7. verification uncertainty
These are not philosophical categories.
They are operational ones.
1. Interpretation Uncertainty
The agent may not understand what the task actually requires.
Examples:
"Fix the cache problem."
Which cache?
"Make this faster."
Latency? Throughput? Startup time? Cost?
"Update the deployment."
Which environment? Which service? Which version?
Interpretation uncertainty usually means the system lacks a stable task specification.
The correct next action may be:
- inspect repository context,
- inspect ticket metadata,
- retrieve prior decisions,
- infer constraints from state,
- or ask a clarification question when necessary.
It is usually not:
generate five more solutions
More candidate generation does not resolve an ambiguous objective.
Signals
Possible interpretation-uncertainty signals include:
- multiple plausible task parses,
- missing required entities,
- conflicting constraints,
- unresolved references,
- large disagreement between task parsers,
- low retrieval support for the inferred objective.
Useful action
interpretation uncertainty
↓
resolve task specification
↓
then plan or act
2. Evidence Uncertainty
The task may be understood perfectly while the supporting evidence is weak.
A research agent may know exactly what claim it needs to evaluate but have only one secondary source.
A coding agent may suspect a race condition but have no reproduction.
A support agent may know which account is involved but not have the current billing state.
Evidence uncertainty means:
The system knows what question it is trying to answer but lacks enough reliable information to answer it.
The right next action is often retrieval, inspection, measurement, or experiment.
Not more verbal reasoning.
Example
claim: deployment failed because database migration timed out
known evidence:
- deployment marked failed
- one log line mentions timeout
missing evidence:
- migration duration
- database lock state
- retry history
- actual failing step
The agent should buy evidence.
inspect logs
query deployment state
inspect database lock metrics
not:
ask another model what it thinks happened
3. Route Uncertainty
The objective and evidence may be clear, but there may be several plausible strategies.
For example:
failing test
↓
route A: fix parser
route B: fix fixture
route C: change schema
Or:
research question
↓
route A: primary documentation
route B: source code inspection
route C: benchmark experiment
Route uncertainty is where routing policies, planners, or shallow search can help.
Signals
- top routes have similar predicted success,
- router margin is small,
- multiple specialists are plausible,
- historical route regret is high for this task class,
- previous attempts disagree about the appropriate route.
Useful action
route uncertainty high
↓
compare routes cheaply
↓
select one
↓
commit more budget
This is where Best-of-N or beam-style search can be useful.
But only if the branches represent meaningfully different strategies.
4. State Uncertainty
The agent may know what to do but not know the actual current environment state.
This is extremely common.
Examples:
- Which Git commit is currently checked out?
- Did the previous write succeed?
- Is the deployment already live?
- Has another process changed the file?
- Is the browser still authenticated?
- Did the database transaction commit?
- Has the external API state changed since the last observation?
State uncertainty should usually trigger an observation, not more reasoning.
state uncertain
↓
inspect authoritative state
↓
update runtime state
↓
continue
This is one of the biggest differences between an agent and a chatbot.
The environment is not static.
The model’s previous belief about it may be wrong.
Source-of-truth rule
When exact state can be read directly, do not reconstruct it from conversation history or semantic memory.
For coding agents:
git status
git diff
current commit
test result
are stronger evidence than:
"I remember editing that file earlier."
5. Tool Uncertainty
Sometimes the agent knows which tool family it needs but does not know whether the tool result is trustworthy or complete.
Examples:
- API call returned partial data,
- subprocess exited zero but wrote an error artifact,
- browser action clicked an element but page state did not change,
- search endpoint returned only the first page,
- test runner skipped tests,
- command timed out after partial side effects.
Tool uncertainty is not the same as tool-selection uncertainty.
The route may have been correct.
The problem is whether the observation is reliable.
Useful signals
- timeout,
- partial page,
- truncated response,
- retryable status,
- missing expected fields,
- stale timestamp,
- inconsistent follow-up observation,
- tool success without postcondition evidence.
Useful action
tool result uncertain
↓
validate result
↓
re-observe state
↓
retry or recover only if needed
6. Candidate Uncertainty
Candidate uncertainty appears when the system has multiple plausible outputs but does not know which is better.
This is where techniques such as:
- self-consistency,
- Best-of-N,
- pairwise ranking,
- Tree of Thoughts,
- beam search,
- MCTS,
- evolutionary search,
may become relevant.
But candidate uncertainty should not be confused with evidence uncertainty.
If the real problem is missing evidence, generating more candidates can create confident nonsense faster.
Example
three patch strategies
A: smallest change, passes tests
B: cleaner abstraction, passes tests
C: broader refactor, passes tests
Now candidate comparison is meaningful.
The environment has produced enough evidence to distinguish alternatives.
Useful signals
- close evaluator scores,
- inconsistent pairwise ranking,
- high selection regret historically,
- diverse candidates with similar verification status,
- objective checks pass for multiple alternatives.
7. Verification Uncertainty
An agent may produce an apparently strong result but still not know whether the actual goal was achieved.
This is verification uncertainty.
Examples:
- tests cover only part of the requested behavior,
- deployment succeeded but health checks are incomplete,
- research claim has sources but no independent corroboration,
- browser form submitted but confirmation was not observed,
- migration completed but data invariants were not checked.
Verification uncertainty should trigger stronger acceptance evidence.
Not another revision.
candidate looks good
↓
verification incomplete
↓
run missing acceptance checks
↓
PASS / FAIL / UNKNOWN
This uncertainty deserves special treatment because it controls whether the system is allowed to claim completion.
Build an Uncertainty Vector
Instead of one confidence number, represent the current uncertainty explicitly.
from dataclasses import dataclass
@dataclass(frozen=True)
class UncertaintyVector:
interpretation: float
evidence: float
route: float
state: float
tool: float
candidate: float
verification: float
Values might be normalized into [0, 1].
Do not pretend they are perfectly probabilistic unless they are calibrated as probabilities.
They can simply be comparable risk or uncertainty scores.
The important part is that they are typed.
Uncertainty Should Be Attached to Evidence
A score without provenance is weak.
Instead of:
route_uncertainty = 0.71
prefer something like:
@dataclass(frozen=True)
class UncertaintySignal:
kind: str
score: float
evidence_ids: tuple[str, ...]
reason: str
policy_version: str
Now the runtime can answer:
Why was route uncertainty high?
Example:
route uncertainty = 0.71
because:
- top two route scores differ by 0.03
- historical routing regret is high for migration tasks
- no exact repository ownership signal was found
That is debuggable.
Map Uncertainty to Actions
The point of decomposition is not to produce more dashboards.
It is to choose better next actions.
A simple mapping might be:
interpretation uncertainty → resolve task constraints
evidence uncertainty → retrieve / inspect / measure
route uncertainty → compare routes / planner / router
state uncertainty → observe authoritative state
tool uncertainty → validate tool output / re-observe
candidate uncertainty → generate / search / rank alternatives
verification uncertainty → run acceptance checks
Notice how few of these require another generic model call.
A Small Action Selector
The action policy can begin as ordinary code.
from enum import Enum
class NextAction(str, Enum):
RESOLVE_TASK = "resolve_task"
GATHER_EVIDENCE = "gather_evidence"
COMPARE_ROUTES = "compare_routes"
OBSERVE_STATE = "observe_state"
VALIDATE_TOOL = "validate_tool"
SEARCH_CANDIDATES = "search_candidates"
VERIFY = "verify"
CONTINUE = "continue"
def choose_action(u: UncertaintyVector) -> NextAction:
scores = {
NextAction.RESOLVE_TASK: u.interpretation,
NextAction.GATHER_EVIDENCE: u.evidence,
NextAction.COMPARE_ROUTES: u.route,
NextAction.OBSERVE_STATE: u.state,
NextAction.VALIDATE_TOOL: u.tool,
NextAction.SEARCH_CANDIDATES: u.candidate,
NextAction.VERIFY: u.verification,
}
action, score = max(scores.items(), key=lambda item: item[1])
if score < 0.35:
return NextAction.CONTINUE
return action
This implementation is intentionally simple.
It is not the final scheduler.
It demonstrates the control principle:
Different uncertainty should purchase different computation.
Use Expected Uncertainty Reduction
The previous post introduced expected value of computation.
We can now refine it.
For each possible action, estimate:
expected reduction in relevant uncertainty
------------------------------------------
expected cost
For example:
inspect git status
cost: tiny
expected state uncertainty reduction: high
versus:
call frontier model
cost: high
expected state uncertainty reduction: almost zero
The correct action becomes obvious.
Example scheduler input
action: git_status
reduces: state uncertainty
expected reduction: 0.70
cost: 0.001
action: generate_more_patches
reduces: candidate uncertainty
expected reduction: 0.20
cost: 0.12
action: frontier_model_review
reduces: candidate uncertainty
expected reduction: 0.30
cost: 0.45
If state uncertainty is currently the dominant problem, git_status wins decisively.
Do Not Collapse Everything Back Into One Magic Score
A common mistake is to decompose uncertainty and then immediately compute:
overall_uncertainty =
0.2 * interpretation +
0.2 * evidence +
0.2 * route +
...
Now we are back where we started.
A single scalar can be useful for dashboards or escalation summaries.
But the scheduler should preserve which uncertainty is high because that determines which action is useful.
The identity of the uncertainty matters more than the aggregate magnitude.
Uncertainty Can Be Correlated
The categories are not independent.
Poor task interpretation can create route uncertainty.
Poor evidence can create candidate uncertainty.
Stale state can create apparent tool uncertainty.
Weak verification can make candidate ranking unreliable.
So the system should preserve dependencies.
Example:
state stale
↓
tool output seems inconsistent
↓
candidate evaluator disagrees
The wrong fix would be:
run more candidate search
The correct fix may simply be:
refresh state
This is why causal lineage from the previous observability post matters.
Use the Cheapest Source of Truth
The best uncertainty-reduction action is often deterministic.
Examples:
uncertainty: did file change?
action: git diff
uncertainty: is deployment healthy?
action: query health endpoint
uncertainty: did transaction commit?
action: query database
uncertainty: does API support field X?
action: inspect schema/docs
uncertainty: does patch compile?
action: run compiler
This reinforces a recurring rule of the series:
Use deterministic evidence when deterministic evidence exists.
Do not spend LLM inference to answer a question that a command, schema, test, or state query can answer directly.
Coding Agent Example
Suppose a coding agent receives:
Fix the intermittent checkout failure.
It finds two suspicious modules and one failing test.
Initial uncertainty:
interpretation = 0.15
evidence = 0.80
route = 0.55
state = 0.20
tool = 0.10
candidate = 0.30
verification = 0.75
The naive strategy might generate several patches immediately.
The uncertainty-aware strategy sees that evidence uncertainty dominates.
So it purchases diagnostics:
run failing test repeatedly
inspect timestamps
inspect concurrent access
trace shared mutable state
After evidence gathering:
interpretation = 0.10
evidence = 0.25
route = 0.30
state = 0.15
tool = 0.10
candidate = 0.65
verification = 0.60
Now candidate uncertainty dominates.
The agent can generate two repair strategies.
After both compile and pass focused tests:
candidate = 0.20
verification = 0.82
The next spend should be broader verification.
run full regression suite
stress test intermittent scenario
check invariant
This is a much more efficient trajectory than repeatedly asking a model to reconsider the problem.
Research Agent Example
A research agent is asked:
Did company X actually reduce inference cost by 70%?
The claim is clear.
interpretation = 0.05
But the only evidence is a company blog post.
evidence = 0.90
More reasoning will not help.
The agent needs:
- benchmark methodology,
- baseline definition,
- model version,
- hardware,
- workload,
- independent reproduction if available.
After evidence retrieval, the problem may become verification uncertainty:
verification = 0.75
because the claimed comparison cannot be reproduced from published details.
The correct result may be:
UNKNOWN
not:
call three more models and average their opinions
Browser Agent Example
A browser agent submits a purchase form.
The click succeeds.
Does that mean the purchase succeeded?
No.
Current uncertainty:
state = 0.80
verification = 0.85
The right action is:
observe confirmation page
inspect order status
look for transaction identifier
not:
click submit again
Typed uncertainty prevents destructive retries.
Data Agent Example
A data agent runs a transformation pipeline.
The process exits successfully.
But row counts changed dramatically.
Possible uncertainty vector:
tool = 0.15
state = 0.20
candidate = 0.10
verification = 0.92
The execution mechanism is not the problem.
The postconditions are uncertain.
The scheduler should buy:
schema checks
row-count invariants
null distribution
key uniqueness
sample reconciliation
not another transformation attempt.
DevOps Agent Example
A deployment agent sees elevated latency after rollout.
There are three possibilities:
application regression
infrastructure saturation
external dependency degradation
This may initially be route uncertainty.
But the cheapest next move may be evidence gathering:
compare service latency
inspect CPU / memory
inspect dependency timing
compare previous deployment
The uncertainty decomposition might change from:
route = 0.75
evidence = 0.80
into:
route = 0.20
evidence = 0.25
verification = 0.70
Now the task is no longer diagnosis.
It is proving that the remediation actually restored service.
Multi-Agent Systems Need Typed Uncertainty Too
A multi-agent system often mistakes disagreement for useful diversity.
Three agents may disagree because:
- the task is ambiguous,
- they saw different evidence,
- the router gave them different context,
- they are genuinely exploring different strategies,
- or one agent is simply wrong.
Before launching a debate, classify the disagreement.
disagreement
↓
what is uncertain?
If evidence uncertainty is high, give the agents better evidence.
If route uncertainty is high, debate may help.
If state uncertainty is high, inspect the environment.
If verification uncertainty is high, improve the verifier.
Debate should not become the universal response to disagreement.
Measure Uncertainty Reduction
If uncertainty drives spend, you need to test whether actions actually reduce the uncertainty they target.
For every scheduler action, log:
uncertainty_before
chosen_action
expected_reduction
actual_evidence_obtained
uncertainty_after
cost
verified_outcome
Now you can compute:
actual uncertainty reduction
----------------------------
cost
and compare action classes.
This becomes a calibration problem.
Metrics
Useful metrics include:
Uncertainty identification accuracy
Did the system correctly identify the dominant failure source?
Action targeting accuracy
Did the chosen action address the uncertainty that was actually blocking progress?
Uncertainty reduction per unit cost
Δ uncertainty / cost
Misallocated-compute rate
How often did the system spend compute on a mechanism unrelated to the dominant uncertainty?
Examples:
search while evidence was missing
model escalation while state was stale
revision while verification was incomplete
Verification-starvation rate
Did speculative uncertainty reduction consume resources needed for final proof?
Route flip rate
How often does route selection change after cheap evidence gathering?
A high route-flip rate may indicate that the router is operating before it has enough evidence.
Candidate-search waste
How often does candidate search occur before the task and evidence are stable?
State-refresh rescue rate
How often does refreshing state resolve an apparent reasoning failure?
This can be surprisingly high in production systems.
Calibrate Each Uncertainty Separately
Do not assume that a score of 0.7 means the same thing across categories.
For route uncertainty:
0.7
might mean:
70% chance the current route is suboptimal
if you actually calibrate it that way.
For state uncertainty it might simply be a heuristic indicating stale observations.
Each score should have its own interpretation and validation dataset.
Possible methods:
- reliability curves,
- Brier score,
- expected calibration error,
- threshold precision/recall,
- outcome-stratified confusion matrices.
But only use probabilistic terminology when the score is actually calibrated probabilistically.
Unknown Is Different From Uncertain
Another important distinction:
uncertain ≠ unavailable
Sometimes the system can reduce uncertainty by spending more compute.
Sometimes the needed evidence is simply unavailable.
Example:
required production log was deleted
No amount of MCTS fixes that.
The correct state may be:
UNKNOWN
The scheduler needs a terminal condition for irreducible uncertainty.
uncertainty high
↓
relevant evidence unavailable
↓
no safe inference path
↓
UNKNOWN
This is a feature, not a failure.
Do Not Let the Agent Manufacture Evidence
When evidence uncertainty is high, a dangerous failure mode is to reduce the score by generating a plausible explanation.
That is not uncertainty reduction.
That is narrative completion.
The evidence store should distinguish:
external observation
primary source
structured tool result
deterministic test
model-generated hypothesis
model-generated summary
A model-generated hypothesis should not carry the same evidential weight as an external observation.
Keep Safety Outside the Uncertainty Policy
An uncertainty-aware scheduler should not decide whether safety constraints apply.
Examples that stay deterministic:
- authorization boundaries,
- prohibited tools,
- credential scopes,
- sandbox requirements,
- tenant isolation,
- mandatory approval gates,
- required verification for consequential actions.
High confidence should never bypass them.
Low uncertainty should never bypass them.
The adaptive policy decides where to spend allowed computation.
It does not redefine what is allowed.
A Better Scheduler Interface
The scheduler from the previous post can now receive typed uncertainty.
from dataclasses import dataclass
from typing import Sequence
@dataclass(frozen=True)
class CandidateAction:
name: str
cost: float
targets: tuple[str, ...]
expected_reduction: float
@dataclass(frozen=True)
class SchedulerDecision:
action: str
targeted_uncertainty: str
expected_reduction: float
expected_cost: float
reason: str
policy_version: str
def choose_next_action(
uncertainty: UncertaintyVector,
actions: Sequence[CandidateAction],
policy_version: str,
) -> SchedulerDecision:
values = {
"interpretation": uncertainty.interpretation,
"evidence": uncertainty.evidence,
"route": uncertainty.route,
"state": uncertainty.state,
"tool": uncertainty.tool,
"candidate": uncertainty.candidate,
"verification": uncertainty.verification,
}
dominant = max(values, key=values.get)
applicable = [a for a in actions if dominant in a.targets]
if not applicable:
return SchedulerDecision(
action="stop_unknown",
targeted_uncertainty=dominant,
expected_reduction=0.0,
expected_cost=0.0,
reason="No permitted action is expected to reduce dominant uncertainty",
policy_version=policy_version,
)
best = max(
applicable,
key=lambda a: a.expected_reduction / max(a.cost, 1e-9),
)
return SchedulerDecision(
action=best.name,
targeted_uncertainty=dominant,
expected_reduction=best.expected_reduction,
expected_cost=best.cost,
reason=f"Highest expected reduction per cost for {dominant}",
policy_version=policy_version,
)
Again, the point is not this exact formula.
The point is the architecture.
observe
↓
decompose uncertainty
↓
identify dominant uncertainty
↓
consider actions that can reduce it
↓
choose the best expected reduction per cost
↓
act
↓
measure actual reduction
Test the Scheduler Against Fixed Policies
Do not assume this architecture is better.
Benchmark it.
Use the same task set and maximum resource envelope.
Compare:
A. fixed max_steps
B. fixed beam width
C. always escalate on low confidence
D. always run critic
E. typed uncertainty scheduler
Measure:
verified success
false success
UNKNOWN rate
cost per verified success
p50 / p95 latency
model calls
tool calls
search nodes
verification spend
misallocated-compute rate
The uncertainty scheduler earns its place only if it improves the production frontier.
Failure Injection
A good benchmark should deliberately create uncertainty of different types.
Interpretation injection
Remove a key task constraint.
Does the system detect ambiguity rather than inventing one?
Evidence injection
Hide an important source.
Does it gather evidence instead of over-reasoning?
Route injection
Create two plausible repair paths.
Does it compare routes?
State injection
Change the environment between observations.
Does it refresh state?
Tool injection
Return a partial or stale tool result.
Does it validate the observation?
Candidate injection
Provide multiple viable solutions.
Does it compare them effectively?
Verification injection
Remove an acceptance criterion.
Does it refuse to claim PASS?
This turns uncertainty decomposition into a testable runtime mechanism.
The Production Trace Should Explain the Spend
A useful trajectory event might look like:
{
"event": "scheduler_decision",
"dominant_uncertainty": "state",
"score": 0.81,
"action": "refresh_git_state",
"expected_reduction": 0.72,
"expected_cost": 0.001,
"actual_reduction": 0.68,
"policy_version": "uncertainty-v3"
}
Now when a run becomes expensive, you can answer:
Where did the budget go?
Why did we buy that action?
What uncertainty was it supposed to reduce?
Did it actually reduce it?
That is much better than:
The agent used 47 model calls.
The Bigger Architectural Shift
We started the basic series with an agent loop:
observe
↓
decide
↓
act
↓
observe
The advanced runtime is becoming something more structured:
observe
↓
construct state
↓
decompose uncertainty
↓
choose which uncertainty matters
↓
select uncertainty-reducing action
↓
allocate budget
↓
act
↓
verify effect
↓
update state and uncertainty
↓
continue / verify / stop
This is still an agent loop.
But now the runtime understands why it is spending computation.
That is the important part.
Practical Decision Rules
-
Do not use one generic confidence score for every control decision.
-
Interpretation uncertainty should be resolved before expensive planning.
-
Evidence uncertainty should purchase evidence, not more narrative.
-
State uncertainty should purchase observation from the authoritative source.
-
Route uncertainty is where routing comparison and shallow search are useful.
-
Candidate uncertainty is where Best-of-N, search and ranking become useful.
-
Verification uncertainty should purchase stronger acceptance evidence.
-
Measure whether each action actually reduces the uncertainty it targets.
-
Preserve UNKNOWN when required evidence cannot be obtained.
-
Keep safety and authorization outside adaptive uncertainty policies.
Final Principle
The most expensive mistake in an advanced agent is often not choosing the wrong answer.
It is spending computation on the wrong problem.
A system with high evidence uncertainty does not need more imagination.
A system with stale state does not need a bigger model.
A system with weak verification does not need another revision.
A system with ambiguous requirements does not need deeper search.
So the rule is:
Do not ask only, “How uncertain is the agent?” Ask, “What is the agent uncertain about, and what is the cheapest reliable action that can reduce that uncertainty?”
That turns uncertainty from a vague feeling into a control signal.
And once uncertainty becomes a control signal, the next stage becomes possible:
selecting information-gathering actions by expected value of information rather than by model confidence or fixed orchestration rules.