DEV Community

shashank ms
shashank ms

Posted on

Explainability in LLM Models: Techniques and Applications

Building an explainable support router

We are going to build an explainable support ticket router that classifies incoming messages and shows its work. It outputs chain-of-thought reasoning, a confidence score, and a contrastive explanation so ops teams can audit decisions without guessing. I ship this exact pattern on Oxlo.ai because its request-based pricing keeps costs flat even when I feed long ticket threads into a multi-pass pipeline.

What you'll need

  • Python 3.10 or newer
  • The OpenAI SDK: pip install openai
  • An Oxlo.ai API key from https://portal.oxlo.ai (sign up and copy the key from the dashboard)

Step 1: Bootstrap the Oxlo.ai client

First, import the SDK and point it at Oxlo.ai. I run a quick smoke test to confirm the endpoint is alive.

from openai import OpenAI
import os

client = OpenAI(
    base_url="https://api.oxlo.ai/v1",
    api_key=os.environ.get("OXLO_API_KEY", "YOUR_OXLO_API_KEY")
)

# Quick connectivity check
response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[{"role": "user", "content": "Say 'Oxlo.ai client ready'"}],
    max_tokens=20,
)
print(response.choices[0].message.content)

Step 2: Define the explainability prompt

The system prompt is where we embed the explainability techniques. It forces the model to emit reasoning, confidence, and a contrastive explanation before any final answer.

SYSTEM_PROMPT = """You are a support ticket classifier. Your job is to read a customer ticket and choose exactly one department: Billing, Technical, or Account Management.

Before giving your final answer, think step by step inside <thinking> tags. Then provide your output in this exact format:

Department: <chosen department>
Confidence: <integer 0-100>
Reasoning: <2 sentences explaining why this department fits best>
Contrastive: <2 sentences explaining why the other departments were rejected>

If the ticket is ambiguous, state that explicitly and lower your confidence score."""

Step 3: Classify with chain-of-thought reasoning

This function sends the ticket to Llama 3.3 70B on Oxlo.ai and returns the structured explanation. I keep temperature low so the reasoning stays consistent.

def classify_ticket(ticket_text: str) -> str:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": ticket_text},
        ],
        temperature=0.2,
        max_tokens=400,
    )
    return response.choices[0].message.content

# Test with a sample
sample = "I was charged twice last month and the refund still hasn't hit my bank."
print(classify_ticket(sample))

Step 4: Add an uncertainty audit layer

A second pass with Qwen 3 32B reviews the first response for overconfidence or hallucinations. Running this on Oxlo.ai is practical because the cost is per request, not per token, so adding an audit step does not explode the bill on long tickets.

AUDIT_PROMPT = """You are an explainability auditor. Review the classification below and flag any overconfidence, logical gaps, or hallucinations. Respond with a short paragraph."""

def audit_explanation(ticket_text: str, classification: str) -> str:
    payload = f"Ticket: {ticket_text}\n\nClassification:\n{classification}"
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": AUDIT_PROMPT},
            {"role": "user", "content": payload},
        ],
        temperature=0.1,
        max_tokens=200,
    )
    return response.choices[0].message.content

# Run the audit on the previous result
classification = classify_ticket(sample)
audit = audit_explanation(sample, classification)
print(audit)

Step 5: Wire everything together

The main block runs a sample ticket through both stages and prints the results.

if __name__ == "__main__":
    ticket = (
        "My API keys keep returning 401 errors after I rotated them this morning. "
        "I have already checked the docs and the secret is not expired."
    )

    print("=== CLASSIFICATION ===")
    result = classify_ticket(ticket)
    print(result)

    print("\n=== AUDIT ===")
    review = audit_explanation(ticket, result)
    print(review)

Run it

Save the file as explainable_router.py, export your key, and run it. You should see structured reasoning followed by the auditor's review.

$ export OXLO_API_KEY="sk-..."
$ python explainable_router.py
=== CLASSIFICATION ===
<thinking>
The user is experiencing API key errors (401) after rotation. This is a technical integration issue, not a billing charge or account ownership change. It belongs in Technical.
</thinking>

Department: Technical
Confidence: 92
Reasoning: The issue describes an authentication failure after a routine key rotation, which is a technical integration problem.
Contrastive: Billing is incorrect because there is no mention of charges or invoices. Account Management is incorrect because the user is not asking to change ownership or close an account.

=== AUDIT ===
The reasoning is sound. The confidence score of 92 is justified because the ticket clearly describes a technical error. No hallucinations detected. One minor note: if the user had mentioned billing impacts from the outage, confidence should drop.

Wrap-up and next steps

Parse the output with Pydantic and push low-confidence tickets to a human review queue. You can also log every audit result to a dataset and later fine-tune a smaller Oxlo.ai model to run the classifier and auditor in a single pass.

Top comments (0)