DEV Community

KuoBa
KuoBa

Posted on

I measured my agent's confidence. It was a constant.

Hackathon disclosure: I created this article for the purpose of entering
Fleet in the All Things Agentic Hackathon.

Fleet is a Slack-first dispatcher for a workforce made up of people and
specialized agents. It decides who should do each task, how much human review is
required, and when software should not attempt the work at all.

The confidence problem

The design started with a nice idea: ask the model how sure it is and route the
work accordingly. Confident classifications go to an agent; uncertain ones go
to a person. Every agent framework makes this easy—ask for a confidence field
in the schema and a number comes back.

A number comes back. That is the problem.

Here is what four runs of the same customer email produced on Gemini 3.7 Flash,
at temperature 0, across two thinking levels:

LOW    run 1   feature flag 0.95   reconciliation 0.98   refund 0.95
LOW    run 2   feature flag 0.95   reconciliation 0.95   refund 0.95
MEDIUM run 1   feature flag 0.95   reconciliation 0.98   refund 0.95
MEDIUM run 2   feature flag 0.95   reconciliation 0.95   refund 0.95
Enter fullscreen mode Exit fullscreen mode

Those requests have genuinely different consequences. One is a feature-flag
action whose arguments are present in the account snapshot. One is a document
that requires a billing period to be inferred. One is a refund—a decision about
money that software should never make here.

The result was almost always 0.95.

I do not think the model was lying. I think it was answering a question it had
no evidence to answer. It had never seen its own reconciliation drafts return
from a human reviewer, so it had no historical success rate to report. The
confidence value was still useful as one signal, but it was not a probability I
could safely use on its own.

So I stopped letting it have the last word.

What Fleet does

Fleet receives work where teams already communicate: Slack. A message shortcut,
/fleet, or an app mention can create a request. Fleet separates a multi-part
message into discrete tasks, classifies each task into a fixed taxonomy, assigns
a risk tier, and sends it down one of three paths:

  • Tier 0: an agent may complete low-risk work unattended.
  • Tier 1: an agent may prepare the work, but a person must review it.
  • Tier 2: software never attempts the task.

Interactive Slack cards and a persistent App Home let authorized teammates
review, send back, delegate, or complete work without adopting another inbox.
The Fleet web application is the control plane: it exposes the work queue,
routing evidence, workforce calibration, activity history, automations, and
connection health.

In the reproducible demo, one customer message asks Fleet to enable an export
feature, prepare a reconciliation document, and issue a refund. The first task
goes to an isolated Operator. The second is drafted by an Analyst and returned
for human review. The refund stays with a person and is never attempted by
software.

Routing to a person is not an agent failure. It is one of the system's intended
outputs.

The number that is not a constant

Fleet keeps a small table for each (task class, worker) pairing: how many times
a human approved that worker's output, and how many times they sent it back.

empirical_rate = (approvals + 2) / (approvals + send_backs + 3)
effective_confidence = model_confidence * empirical_rate
Enter fullscreen mode Exit fullscreen mode

The model assessment is still present. It is multiplied by a rate grounded in
actual outcomes. An Analyst's record for reconciliation work does not affect a
Scribe's record for customer updates, and neither affects an Operator's record
for back-office actions.

The +2 / +3 Beta prior also creates a useful cold-start property. A new pairing
begins at 2/3 = 0.667. The Tier 1 automation threshold is 0.75, so clearing it
on the first attempt would require a model confidence greater than
0.75 / 0.667 = 1.12.

That number cannot exist. The first unfamiliar, higher-risk task therefore goes
to a person. The agent becomes eligible only after supervised attempts create a
real record.

The send-back is the signal

Human review is part of Fleet's routing loop, not a separate feedback form.

An approval records a successful outcome. A send-back lowers the empirical rate
for that worker-task pairing and stores the reviewer's correction for later
attempts. Slack then displays a Learning Receipt showing the before-and-after
track record, the calculation, the applicable threshold, and whether the agent
remains eligible next time.

before send-back: 0.98 x 0.83 = 0.82   threshold 0.75   -> Analyst eligible
after send-back:  0.98 x 0.71 = 0.70   threshold 0.75   -> route to a person
Enter fullscreen mode Exit fullscreen mode

The request did not change. Fleet's evidence about its workforce did.

This also exposed a second problem: automatic demotion without a promotion path
would eventually make the product route everything to people. Fleet therefore
lets an authorized person delegate an eligible Tier 0 or Tier 1 task to an agent
under the same review boundary. Delegation alone does not improve the agent's
record. Only a later verdict on real agent output can do that. Tier 2 remains
human-only even if someone tries to override it.

A second reader, not a second vote

Fleet uses Gemini 3.7 Flash through Google's GenAI SDK on Vertex AI for
structured task separation, classification, and schema-constrained argument
extraction.

Gemma 4 26B independently reads each classified request against the same
catalogue and account snapshot. It is not a cheaper first pass, and agreement
does not inflate the score. When the models disagree on what a request is,
Fleet halves the first model's confidence before deterministic routing.

The lowest automation threshold is 0.55. Half of any model confidence is at most
0.50, and the empirical rate is always below 1. A contradicted classification
therefore cannot clear any automation threshold, regardless of prior success.

That matters for requests like:

"Any update on when the export feature will be working again?"

Gemini -> comms.status_update
Gemma  -> backoffice.feature_flag
Enter fullscreen mode Exit fullscreen mode

Both readings are defensible. The customer may want information or an action.
Two competent readers disagreeing about the meaning is not a tie to break; it is
evidence that a person should decide.

What the models are not allowed to do

Three decisions stay outside the models:

  1. Dispatch is arithmetic. Given the same task and track record, Fleet makes the same routing decision and can explain the exact calculation.
  2. The task class selects the handler. A fixed taxonomy maps to typed code paths. Model-generated arguments must satisfy schemas built from the live system, so the model cannot invent a feature flag or action.
  3. Business numbers are computed. Billing data is fetched and totaled in code. A model may write the covering note; it does not calculate the reconciliation.

The models contribute judgment where language is ambiguous. Deterministic code
owns policy, permissions, arithmetic, and the final routing decision.

How Fleet is built on Google Cloud

Fleet runs as four Cloud Run services with distinct responsibilities and trust
boundaries:

  1. fleet-connectors verifies Slack signatures, acknowledges interactions quickly, and handles durable delivery. It has no model or business-system credentials.
  2. fleet hosts the React/FastAPI control plane, intake pipeline, Gemini and Gemma calls, deterministic dispatcher, and general Analyst/Scribe workers.
  3. fleet-operator is private and holds the only agent credential permitted to perform named write actions.
  4. acme is a separate synthetic back-office service with its own identity, database, and per-action authorization.

Pub/Sub separates intake, human actions, general and isolated task lanes, Slack
notifications, retries, and dead-letter recovery. A filtered subscription makes
privileged Operator tasks reachable only by the isolated Operator service.

Firestore stores operational state, task decisions, calibration, corrections,
and audit evidence. A separate connector database holds replay claims and
delivery receipts, while the synthetic back office has its own database. Secret
Manager and service-specific IAM define capabilities. Model Armor screens
untrusted inbound text and approved outbound content. OpenTelemetry and Cloud
Trace join intake, routing, execution, and review under a shared trace ID.

The architectural goal was concrete: the component reading customer-authored
text should not also hold the credential that changes a business system.

What was harder than expected

Slack requires a fast acknowledgement, while two model calls and policy
evaluation can take much longer. Moving the work behind Pub/Sub solved the
latency problem, but introduced delivery concerns: replayed events, concurrent
button presses, stale task versions, retries, dead letters, and restarts. Fleet
uses idempotency claims, mutation leases, state versions, and durable receipts
so one human action produces one domain effect.

Calibration also had to follow the worker who actually produced the work. A
reassignment must not accidentally update the original assignee's record, and a
delegation must not count as a success before anyone judges the output.

Finally, timeouts and retries had to be designed as one budget. Stacked retries
can turn a graceful fallback into a ten-minute hang. Making those limits
explicit was less visible than another demo feature, but much more important for
a live system.

What I learned

The most useful memory in Fleet is not a transcript. It is operational evidence:
approvals, send-backs, concrete corrections, who actually performed the work,
and the context needed to apply that evidence to the next decision.

I also learned that an agent architecture should describe enforceable
capabilities, not character roles. Different names and prompts do not create
meaningful isolation. Different identities, credentials, message lanes,
databases, and failure boundaries do.

Fleet is a hackathon project, not a claim of production traction. But it
demonstrates the direction I believe agentic work systems should take: autonomy
that grows from evidence, remains inspectable, and can shrink again when the
evidence changes.

Top comments (0)