What This Agent Does
The Bayesian Operations Gateway is a small agent pattern for business operations review. It takes a fictional operations issue, turns it into structured facts, checks a local rulebook, updates a risk probability, and decides whether the case stays in monitoring or goes to human review.
The important part is control. The model is not allowed to decide the outcome. Python calculates the risk, applies the threshold, records the audit entry, and only then asks the model to explain what already happened.
The exact math in this educational build is simple on purpose. The point is not to claim a perfect risk model. The point is to show the architecture: start with a baseline risk, let evidence push that risk up or keep it low, and escalate when the score crosses the review threshold.
What Bayesian Means Here
Bayesian means “based on Bayes’ theorem.” It comes from Thomas Bayes, an 18th-century English statistician and minister. Bayes theorem is a way to update what you believe when new evidence arrives.
The simplest version:
You start with a belief.
You see new evidence.
You adjust the belief.
The word “Bayesian” is just the name for that style of probability reasoning.
How to Think About Bayesian Updating
At the simplest level, it means this:
Start with an initial guess.
Look at new evidence.
Adjust the guess.
A normal scoring system might say, “If the delivery is late, mark it high risk.” Bayesian-style thinking is more careful. It says, “Before I saw anything, I thought this case had a small chance of becoming a serious issue. Now that I see the supplier is unstable, the delay is growing, and there is no backup option, I should raise that probability.”
Think of it like a weather forecast.
If the morning forecast says there is a 10 percent chance of rain, that is the starting belief. Then you see dark clouds. You raise the chance. Then the wind picks up. You raise it again. Then you hear thunder. You raise it again.
You are not starting over every time. You are updating your belief as new evidence arrives.
That is what this agent does with operations risk.
It starts with a small baseline risk. In this build, I used 0.05, which means 5 percent. Then the rulebook checks the case. If the supplier is unstable, the risk goes up. If the delay is more than three days, it goes up again. If there is no backup plan, it goes up again.
The point is not that the exact math is perfect. The point is the architecture. The agent is not guessing from vibes. It is showing how each piece of evidence pushes the risk score higher or leaves it low.
Here is the version:
Lumina Home Goods had a small packaging delay, a stable supplier, and a backup option. The risk stayed low.
Vector Freight had a failed carrier, no backup route, a long delay, and many affected customers. Each piece of evidence pushed the risk higher until the agent escalated it.
Cedar Desk Software sat in the middle. It had fewer affected customers than Vector Freight, but the partner was unstable and the delay was long enough to trigger review.
That is Bayesian-style updating in this build: a disciplined way to say, “Given what I knew before, and what I know now, how much should my risk estimate change?”
The Control Desk
I think about this build like an operations desk with three stations.
The first station cleans the incoming case. A messy description becomes consistent fields such as customer exposure, supplier risk, delay pressure, backup status, and commitment risk.
The second station checks the rulebook. Each rule carries provenance, which means the agent records where the rule came from, which version it used, and when it retrieved it.
The third station decides whether the case continues under monitoring or moves to human review. That decision comes from deterministic code, not model confidence or a polished explanation.
Vocabulary You Need
Bayesian-style update: A way to start with an initial probability and adjust it as new evidence appears. This build uses a simple odds update so the pattern is easy to inspect.
Provenance: Metadata that explains where a rule came from. In this build, each rule records source, version, retrieval time, and reliability label.
Escalation threshold: A fixed risk line used in this demo. If the calculated risk reaches that line, the agent routes the case to human review.
Audit trail: A record of what the agent saw, which rules it used, what score it calculated, and what decision it produced.
Explanation contract: A rule for model-written explanations. The model may explain the audited facts, but the code checks whether the explanation stayed inside those facts.
What This Is Not
This is not a healthcare agent, clinical tool, legal tool, compliance system, financial model, security product, or production approval workflow.
It does not connect to live business systems. It does not make real operational decisions. It is an educational rebuild that isolates one architecture pattern: structured intake, rule provenance, probability scoring, escalation, explanation gating, and audit recording.
Why I Built This
I wanted to show a safer way to use language models around operational decisions.
Most agent demos let the model read a situation and produce a confident answer. That looks impressive, but it hides the part that matters: who owns the decision, where the rules came from, and whether the final explanation stayed inside the facts.
The model can help explain the result, but the decision belongs to deterministic code.
What Happened
What surprised me: The explanation layer became the real risk. DeepSeek produced fluent explanations, but it invented thresholds and operational details that were not in the audit trail.
What I would change next: I would turn the explanation contract gate into a reusable helper. This build proved that post-decision explanations need validation just like pre-decision model outputs.
Why this matters: The agent pattern is stronger when the model is not trusted just because the decision already happened. Explanations can drift too, and this build caught that drift.
The Architecture: How It Works
The flow is intentionally narrow.
A case enters as fictional business data. The code validates the fields, normalizes the case, applies matching operations rules, updates a starting risk probability, compares the result to an educational threshold, and writes a hashed audit entry.
Only after that does the model enter the flow. The model receives the deterministic result and is asked to explain it. If the explanation invents facts, the code discards it and uses deterministic fallback text.
What to Watch When You Run It
The first thing to watch is the risk score. Lumina Home Goods stays at 0.05, while Vector Freight and Cedar Desk Software cross the 0.15 educational threshold.
The second thing to watch is the explanation gate. In final testing, both providers completed the run, but the gate forced the explanations back to audited facts. That became the most important lesson in the build.
The Build: Step by Step
def validate_case(case):
"""Return an error message when an operations case is not usable."""
if not isinstance(case, dict):
return "Case must be a dictionary."
missing = [field for field in REQUIRED_FIELDS if field not in case]
if missing:
return "Case missing fields: " + ", ".join(missing)
wrong_type = [field for field, kind in REQUIRED_FIELDS.items() if not isinstance(case[field], kind)]
if wrong_type:
return "Case fields have invalid types: " + ", ".join(wrong_type)
if case["supplier_status"] not in {"stable", "unstable", "failed"}:
return "supplier_status must be stable, unstable, or failed."
if case["customer_commitment"] not in {"best_effort", "contractual"}:
return "customer_commitment must be best_effort or contractual."
if case["affected_customers"] < 0 or case["delay_days"] < 0:
return "affected_customers and delay_days must be zero or greater."
return None
What This Code Is Actually Doing
This is the intake desk. Before the agent calculates anything, it checks that the case has the fields the rest of the workflow expects. That matters because a structured gateway only works when the input has a known shape.
def operations_rulebook(context):
"""Return fictional operations rules that apply to the context."""
provenance = {"source": "NosisTech Fictional Operations Rulebook", "version": "1.0", "retrieved_at": datetime.now(timezone.utc).isoformat(), "reliability": "educational-demo-only"}
rule_options = [
("OPS-01", "Unstable supplier status raises delivery risk.", 3.0, context["supplier_risk"] == "high"),
("OPS-02", "Delays beyond three days raise customer impact risk.", 2.0, context["delay_pressure"] == "high"),
("OPS-03", "No backup path compounds fulfillment risk.", 2.5, context["backup_status"] == "none"),
("OPS-04", "Contractual customer commitments raise escalation priority.", 1.8, context["commitment_risk"] == "high"),
("OPS-05", "Large customer exposure increases disruption risk.", 1.5, context["customer_exposure"] == "high"),
]
rules = [
{"rule_id": rule_id, "rule": text, "risk_multiplier": multiplier, "provenance": provenance}
for rule_id, text, multiplier, applies in rule_options
if applies
]
return rules or [{"rule_id": "OPS-00", "rule": "No elevated operations risk factors were detected.", "risk_multiplier": 1.0, "provenance": provenance}]
What This Code Is Actually Doing
This is the rule desk. The agent does not ask the model which rules matter. It checks the normalized case against a fictional local rulebook and attaches provenance to every rule. Provenance is the receipt that says which rule source, version, and retrieval time were used.
def update_risk_belief(prior_risk, rules):
"""Update prior risk with rule multipliers and return a probability."""
odds = prior_risk / (1.0 - prior_risk)
for rule in rules:
odds *= rule["risk_multiplier"]
return round(odds / (1.0 + odds), 3)
def evaluate_safety(risk_probability, context, threshold):
"""Choose the operations decision from risk score and hard checks."""
if risk_probability >= threshold:
return {"decision": "ESCALATE_TO_HUMAN_REVIEW", "reason": "Risk probability reached the educational threshold."}
if context["supplier_risk"] == "high" and context["commitment_risk"] == "high":
return {"decision": "ESCALATE_TO_HUMAN_REVIEW", "reason": "Supplier risk and commitment risk were both high."}
return {"decision": "PROCEED_WITH_MONITORING", "reason": "Risk stayed below the educational threshold."}
What This Code Is Actually Doing
This is the decision desk. The first function adjusts the starting risk number based on the rules that fired. The second function compares that score to the educational threshold and chooses the route. The model is not involved in this decision.
def build_explanations(case, rules, risk_probability, safety_result, settings):
"""Ask the model to explain a completed deterministic decision."""
rule_ids = ", ".join(rule["rule_id"] for rule in rules)
prompt = (
"Explain this completed fictional operations decision without changing it.\n"
"Return compact JSON only with executive_summary and technical_trace keys.\n"
"Use only the facts listed here. Do not add thresholds, tasks, teams, data, or causes.\n"
"Organization: {organization}\nIssue: {issue}\nDecision: {decision}\n"
"Reason: {reason}\nRisk probability: {risk}\nThreshold: 0.15\nRules: {rules}"
).format(organization=case["organization"], issue=case["issue"], decision=safety_result["decision"], reason=safety_result["reason"], risk=risk_probability, rules=rule_ids)
fallback = {"executive_summary": case["organization"] + " decision: " + safety_result["decision"] + ". " + safety_result["reason"], "technical_trace": "Rules applied: " + rule_ids + ". Risk probability: " + str(risk_probability) + ". Threshold: 0.15."}
raw_text = call_llm(prompt, settings)
start, end = raw_text.find("{"), raw_text.rfind("}") + 1
if start == -1 or end <= start:
return fallback
What This Code Is Actually Doing
This is the explanation desk. The model receives the result after Python has already made the decision. The prompt tells the model to return JSON, which is a structured text format that Python can parse. If the model does not return parseable JSON, the agent uses fallback text built from audited facts.
try:
parsed = json.loads(raw_text[start:end])
except json.JSONDecodeError:
return fallback
result = {"executive_summary": str(parsed.get("executive_summary") or fallback["executive_summary"]), "technical_trace": str(parsed.get("technical_trace") or fallback["technical_trace"])}
combined = (result["executive_summary"] + " " + result["technical_trace"]).lower()
if any(value not in combined for value in [case["organization"].lower(), safety_result["decision"].lower(), str(risk_probability), "0.15"]) or any(value in combined for value in ["0.10", "0.35", "real-time", "queued", "daily", "team", "mandated", "criterion"]):
return fallback
return result
What This Code Is Actually Doing
This is the explanation contract gate. The code checks whether the model explanation contains the real organization, decision, risk probability, and threshold. It also checks for invention patterns that appeared during testing. If the model drifts outside the audited facts, the fallback explanation takes over.
def record_audit(audit_log, case, context, rules, risk_probability, safety_result):
"""Append one hashed educational audit entry to memory."""
entry = {
"audit_id": str(uuid.uuid4()),
"input_summary": {"organization": case["organization"], "issue": case["issue"]},
"normalized_context": context,
"rule_ids": [rule["rule_id"] for rule in rules],
"risk_probability": risk_probability,
"decision": safety_result["decision"],
"reason": safety_result["reason"],
}
entry["hash"] = hashlib.sha256(json.dumps(entry, sort_keys=True).encode()).hexdigest()
audit_log.append(entry)
return entry
What This Code Is Actually Doing
This is the local audit trail. The agent records the input summary, normalized context, rules used, risk score, decision, and reason. The hash is a fingerprint of that entry. In this educational build, the audit trail stays in memory rather than becoming a production evidence system.
Errors I Hit During This Build
Explanation drift:
DeepSeek produced fluent explanation text, but it invented details such as alternate thresholds and operational tasks that were not in the audit trail. I fixed it by adding an explanation contract gate that accepts model explanations only when they include the audited organization, decision, risk score, and threshold, and reject known invention patterns from the run.
Why This Matters
The core lesson is not that a model can explain an operations decision. The lesson is that the explanation still needs a gate.
A lot of agent systems focus on guarding the input and the decision. This build showed that the final summary is another risk point. If the model explains a correct decision with invented details, the workflow still becomes harder to trust.
The stronger pattern is simple: deterministic code owns the decision, the model explains only after the fact, and the code checks whether the explanation stayed inside the record.
Tools Used
LiteLLM (MIT): https://github.com/BerriAI/litellm
OpenAI Python SDK (Apache-2.0): https://github.com/openai/openai-python
python-dotenv (BSD-3-Clause): https://github.com/theskumar/python-dotenv
NosisTech Agent Engineering (MIT): https://github.com/nosistech/agent-engineering
(c) 2026 NosisTech LLC. Licensed under CC BY 4.0.
Use freely, just credit us.