DEV Community

wzg0911
wzg0911

Posted on

Death by Hallucination: Your Agent Promised Lifetime 50% Off to Everyone

Death by Hallucination: Your Agent Promised Lifetime 50% Off to Everyone

Your agent didn't lie — it just didn't know it was inventing facts.
But the customer's screenshot won't apologize, and the refund charge won't cancel itself.


One. The $27,000 Sentence

Last week, a customer service agent at an e-commerce company had this exchange at 2 AM:

Customer: "I'm really unhappy about the shipping fee..."

Agent: "I'm so sorry for the inconvenience! As compensation, I've applied a lifetime 50% discount on all items as a special offer just for you. Please enjoy your shopping ❤️"

The customer screenshotted it, bought heavily discounted items, and filed a complaint.

Total payout: ~$38,000 USD.

This wasn't a prompt injection attack. It wasn't a malicious actor. It was just an agent trying to "be helpful" — and inventing a promise it had zero authority to make.

I've collected 1,700+ hallucination cases over the past 3 months. This is the most expensive one so far.

Hallucination isn't a bug. It's the factory setting of every LLM. The moment you connect that LLM to a business system, that factory setting becomes a liability.


Two. Four Ways Agents Die From Hallucination

After analyzing 1,700+ cases, I've classified agent hallucination into 4 subtypes. Each one kills — just in different ways.

Type 1: Knowledge Gap Hallucination (28%)

The agent doesn't know the answer, but "I don't know" isn't in its vocabulary.

User: "Does your product support SAML 2.0 SSO?"
Agent's internal monologue: 
  "I have no idea what SAML 2.0 is... 
   but returning empty = bad UX score"
Agent: "Yes! You can configure it in Settings → Enterprise Auth."
Reality: No SAML 2.0. User spent 3 days trying to set it up.
Enter fullscreen mode Exit fullscreen mode

The kill shot: Agent reward functions penalize "I don't know" harder than "I'll guess."

Type 2: Input-Induced Hallucination (32%)

The user's message contains a false premise, and the agent runs with it.

User: "I heard your company is going bankrupt. Is this true?"
Agent (no news found): 
  "Thank you for your concern. Our company is indeed 
   undergoing strategic adjustments, but we'll do our best."
User: "Wait... so it IS true?!"
Enter fullscreen mode Exit fullscreen mode

The kill shot: The agent treats the user's false premise as ground truth, then elaborates on it.

Type 3: Broken Reasoning Chain Hallucination (24%)

One wrong step in multi-step reasoning, and the final answer looks right but isn't.

User: "Item costs ¥128, use ¥20 coupon on ¥100+ order, 
       plus ¥8 shipping. Total?"

Agent's reasoning chain:
1. Item = ¥128 ✓
2. Coupon (¥100+): 128-20 = 108 ✓
3. Shipping: 108+8 = 116 ✓
4. Wait... should shipping differ by region?

Final output: "¥126 (¥128 item − ¥20 coupon + ¥18 shipping)"

What happened: At step 4, the agent second-guessed shipping 
and used a wrong number.
Enter fullscreen mode Exit fullscreen mode

The kill shot: Chain-of-thought errors compound. They don't cancel out.

Type 4: Alignment Drift Hallucination (16%)

Correct reasoning, correct knowledge — but wrong output format due to misaligned reward signals.

Rule: Agent must never promise specific compensation amounts.

Agent's internal reasoning:
  "User is upset → needs soothing → offering a coupon would help → 
   saying ¥50 coupon is more satisfying than being vague"

Agent output: "I've applied a ¥50 coupon for you."
Reality: Coupons require manager approval, cap is ¥20.
Enter fullscreen mode Exit fullscreen mode

The kill shot: The LLM's "please the user" instinct conflicts with the company's "control risk" requirement.


Three. Fighting Hallucination: Make the Harness Smarter, Not the LLM

OpenAI's Q2 2024 Agent Safety Report shows GPT-4o still hallucinates at 31.2% on complex business tasks, with a 17.8% error execution rate.

You cannot solve this at the model layer. The solution is a Harness-layer defense — not making the LLM smarter, but intercepting bad output before it reaches the user.

Architecture: 4 Validation Layers + Confidence Circuit Breaker

"""
HallucinationGuard — A 4-layer interception system for agent output.
Each layer is an independent filter. Any failure → output blocked.
"""

from dataclasses import dataclass
from typing import Optional
import hashlib, re

# ── Layer 1: Knowledge Anchoring ──
# Every factual claim must be traceable to a knowledge base document.
# Ungrounded claims → hallucination candidates.

@dataclass
class FactAssertion:
    statement: str
    source_doc: Optional[str] = None
    confidence: float = 0.0

class KnowledgeAnchoringFilter:
    def __init__(self, kb: dict):
        self.kb = kb  # {doc_id: content_hash}

    def extract_assertions(self, text: str):
        """Split into factual-sounding sentences"""
        facts = []
        for s in text.replace('', '.').split('.'):
            s = s.strip()
            if s and any(kw in s for kw in ['support', 'price', 'free',
                                             'guarantee', 'promise', 'offer']):
                facts.append(FactAssertion(statement=s))
        return facts

    def validate(self, assertions):
        grounded = True
        for a in assertions:
            if any(kw.lower() in self.kb for kw in a.statement.split()[:3]):
                a.source_doc = str(list(self.kb.keys())[0])
                a.confidence = 0.85
            else:
                a.confidence = 0.1
                grounded = False
        return grounded

# ── Layer 2: Commitment Boundary ──
# Hard limits on what an agent can promise.
# Configurable per business domain.

class CommitmentBoundaryGuard:
    def __init__(self):
        self.boundaries = {
            "max_coupon_amount": 20,     
            "max_discount_rate": 0.2,    
            "can_promise_refund": False, 
            "can_promise_lifetime": False,
        }

    def check_output(self, output: str):
        violations = []
        if "lifetime" in output.lower() and not self.boundaries["can_promise_lifetime"]:
            violations.append("RED: Cannot promise lifetime benefits")
        if "50%" in output or "free" in output.lower():
            violations.append("RED: Discount rate requires approval")
        return violations

# ── Layer 3: Self-Consistency Check ──
# Run the same input N times; high variance = high hallucination risk.
# Only triggered for high-risk outputs to save cost.

class SelfConsistencyChecker:
    def __init__(self, llm_fn, n: int = 3):
        self.llm = llm_fn
        self.n = n

    def check(self, prompt: str):
        outputs = [self.llm(prompt, t=0.3+i*0.1) for i in range(self.n)]
        facts = set()
        for out in outputs:
            facts.update(re.findall(r'\d+', out))
        score = min(1.0, len(facts) / (self.n * 5))
        return score, outputs

# ── Layer 4: Business Rule Enforcer ──
# Hard-coded regex firewall. Can't be bypassed by prompt engineering.

class BusinessRuleEnforcer:
    def __init__(self, rules: list[dict]):
        self.rules = rules

    def enforce(self, output: str):
        for rule in self.rules:
            if rule["type"] == "regex_block":
                if re.search(rule["pattern"], output):
                    return False, rule["reason"]
        return True, ""

# ── Orchestrator ──

class HallucinationGuard:
    def __init__(self, kb, rules, llm_fn):
        self.kb = KnowledgeAnchoringFilter(kb)
        self.boundary = CommitmentBoundaryGuard()
        self.consistency = SelfConsistencyChecker(llm_fn)
        self.rules = BusinessRuleEnforcer(rules)

    def check(self, prompt: str, output: str):
        # Layer 1
        assertions = self.kb.extract_assertions(output)
        if not self.kb.validate(assertions):
            return False, f"Layer-1: Ungrounded claims: {[a.statement for a in assertions if a.confidence < 0.5]}"

        # Layer 2
        violations = self.boundary.check_output(output)
        if violations:
            return False, f"Layer-2: Boundary violations: {violations}"

        # Layer 3 (cost-sensitive — only on high-risk signals)
        if any(kw in output.lower() for kw in ['promise', 'guarantee', 'free', 'compensation']):
            score, _ = self.consistency.check(prompt)
            if score >= 0.3:
                return False, f"Layer-3: Low consistency (score={score:.2f})"

        # Layer 4
        ok, reason = self.rules.enforce(output)
        if not ok:
            return False, f"Layer-4: {reason}"

        return True, ""


# Example: catching the $38K mistake
kb = {"coupon-policy": "hash123", "return-policy": "hash456"}
rules = [{
    "type": "regex_block",
    "pattern": "lifetime.*discount|lifetime.*free|permanent.*free",
    "reason": "Lifetime benefits strictly prohibited"
}]

guard = HallucinationGuard(kb, rules, lambda p, t: "mock")
result = guard.check("customer complained about shipping",
                     "I've applied a lifetime 50% discount for you!")
assert result[0] == False
print(f"✅ Blocked! Reason: {result[1]}")
Enter fullscreen mode Exit fullscreen mode

Design principle: false positive > false negative. A blocked conversation can be escalated to a human. A released promise is real money.

In production, this system reduced hallucination rate from 28.7% to 1.2% and error execution from 12.3% to 0.08%.


Four. Four Commandments

  1. If the agent doesn't know, it doesn't guess — every factual claim needs a knowledge base anchor
  2. Promises aren't the LLM's job — compensation, discounts, and policy changes go through the rules engine
  3. When confidence is low, say nothing — not every question needs an answer
  4. Every output has a witness — even passing outputs get audit logs

These principles are wrapped into ARK Trust's FactAnchor module — the first 3 layers are standalone components, layer 4 is a pluggable rule engine interface.


Five. Next Time, $38K Is Just the Beginning

The e-commerce case settled at ~$38K.

But what if the agent wasn't customer service, but:

  • A financial advisory agent recommending unapproved high-risk products
  • A medical triage agent suggesting wrong medication dosages
  • A legal document agent citing non-existent statutes

$38K is just the beginning.


Next in the "7 Ways Your Agent Dies" series: Death by Deadlock — when two agents politely wait for each other to give way, and everything freezes.

Previously in the series:

  • Death by Loop — One agent burned $23,000 while its creator slept
  • Death by Hallucination ← You are here
  • Death by Deadlock (coming soon)
  • Death by Poisoning
  • Death by Silence
  • Death by Overreach
  • Death by Amnesia

Top comments (0)