DEV Community

shashank ms
shashank ms

Posted on

Explainability in LLM: Challenges and Opportunities

We are going to build a lightweight explainability tracer that forces an LLM to emit a structured reasoning trace, confidence score, and source attribution tags alongside every answer. This gives developers a transparent audit log for debugging model behavior without proprietary black-box tools.

What you'll need

Python 3.10 or newer, the OpenAI SDK, and an Oxlo.ai API key. Install the SDK with pip install openai, then grab a free key from https://portal.oxlo.ai. The free tier includes 60 requests per day, which is plenty for prototyping this tracer.

Step 1: Configure the Oxlo.ai client

I start by initializing the OpenAI-compatible client pointing at Oxlo.ai. I pull the API key from an environment variable so it never leaks into source control.

import os
from openai import OpenAI

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

# Quick connectivity check
response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Say OK"},
    ],
)
print(response.choices[0].message.content)

Step 2: Prepare a mock knowledge base

To demonstrate source attribution, I need documents to retrieve from. I hardcode three short chunks so the tutorial stays reproducible without setting up a vector database.

KNOWLEDGE_BASE = [
    {
        "id": "doc-001",
        "text": "Solar panels convert sunlight into electricity using photovoltaic cells. Efficiency rates typically range from 15 to 22 percent."
    },
    {
        "id": "doc-002",
        "text": "Wind turbines generate power through rotational energy. Offshore farms achieve higher capacity factors than onshore installations."
    },
    {
        "id": "doc-003",
        "text": "Nuclear fission releases heat by splitting uranium atoms. Modern reactors produce minimal carbon emissions during operation."
    },
]

def retrieve_chunks(query: str, top_k: int = 2):
    # In production, swap this for embedding search.
    # Oxlo.ai offers BGE-Large and E5-Large embeddings for that.
    return KNOWLEDGE_BASE[:top_k]

query = "Which renewable source works best at sea?"
context_chunks = retrieve_chunks(query)
context_text = "\n\n".join([f"[{c['id']}] {c['text']}" for c in context_chunks])

Step 3: Write the explainability system prompt

The system prompt is the critical piece. It instructs the model to wrap its chain of thought, final answer, and explainability metadata in strict XML tags so we can parse them deterministically.

SYSTEM_PROMPT = """You are an Explainability Tracer. Your job is to answer the user based ONLY on the provided context documents.

Follow this exact output format:

<thinking>
1. List each document ID and whether it is relevant.
2. Note any uncertainties or contradictions.
3. Outline your reasoning before concluding.
</thinking>

<answer>
Provide a concise, accurate answer to the user's question.
</answer>

<explainability>
confidence: 0.0 to 1.0
sources_used: list of document IDs you relied on
bias_flags: note any potential gaps in the provided context
</explainability>

Do not deviate from these tags."""

Step 4: Build the request pipeline

I assemble the user message by injecting the retrieved context, then call Llama 3.3 70B through Oxlo.ai. This model handles long context and structured instructions reliably, and because Oxlo.ai charges per request rather than per token, adding a large system prompt does not inflate the cost.

user_message = f"""Context documents:
{context_text}

User question: {query}

Remember to use the required XML tags in your response."""

response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": user_message},
    ],
)

raw_output = response.choices[0].message.content
print(raw_output)

Step 5: Parse and display the trace

Raw XML is not enough. I want a clean dictionary I can log to JSON. I use regular expressions to extract the three blocks and pretty-print them.

import re

def parse_explainability(text: str) -> dict:
    pattern = r"<thinking>(.*?)</thinking>.*?<answer>(.*?)</answer>.*?<explainability>(.*?)</explainability>"
    m = re.search(pattern, text, re.DOTALL)
    if not m:
        return {"raw": text, "parsed": False}
    return {
        "parsed": True,
        "thinking": m.group(1).strip(),
        "answer": m.group(2).strip(),
        "explainability": m.group(3).strip(),
    }

result = parse_explainability(raw_output)

print("=== THINKING TRACE ===")
print(result["thinking"])
print("\n=== FINAL ANSWER ===")
print(result["answer"])
print("\n=== EXPLAINABILITY METADATA ===")
print(result["explainability"])

Run it

Here is the complete script. Save it as tracer.py, export OXLO_API_KEY, and run python tracer.py.

import os
import re
from openai import OpenAI

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

KNOWLEDGE_BASE = [
    {"id": "doc-001", "text": "Solar panels convert sunlight into electricity using photovoltaic cells. Efficiency rates typically range from 15 to 22 percent."},
    {"id": "doc-002", "text": "Wind turbines generate power through rotational energy. Offshore farms achieve higher capacity factors than onshore installations."},
    {"id": "doc-003", "text": "Nuclear fission releases heat by splitting uranium atoms. Modern reactors produce minimal carbon emissions during operation."},
]

SYSTEM_PROMPT = """You are an Explainability Tracer. Your job is to answer the user based ONLY on the provided context documents.

Follow this exact output format:

<thinking>
1. List each document ID and whether it is relevant.
2. Note any uncertainties or contradictions.
3. Outline your reasoning before concluding.
</thinking>

<answer>
Provide a concise, accurate answer to the user's question.
</answer>

<explainability>
confidence: 0.0 to 1.0
sources_used: list of document IDs you relied on
bias_flags: note any potential gaps in the provided context
</explainability>

Do not deviate from these tags."""

def retrieve_chunks(query: str, top_k: int = 2):
    return KNOWLEDGE_BASE[:top_k]

def parse_explainability(text: str) -> dict:
    pattern = r"<thinking>(.*?)</thinking>.*?<answer>(.*?)</answer>.*?<explainability>(.*?)</explainability>"
    m = re.search(pattern, text, re.DOTALL)
    if not m:
        return {"raw": text, "parsed": False}
    return {
        "parsed": True,
        "thinking": m.group(1).strip(),
        "answer": m.group(2).strip(),
        "explainability": m.group(3).strip(),
    }

if __name__ == "__main__":
    query = "Which renewable source works best at sea?"
    chunks = retrieve_chunks(query)
    context_text = "\n\n".join([f"[{c['id']}] {c['text']}" for c in chunks])

    user_message = f"""Context documents:
{context_text}

User question: {query}

Remember to use the required XML tags in your response."""

    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )

    raw_output = response.choices[0].message.content
    result = parse_explainability(raw_output)

    print("=== THINKING TRACE ===")
    print(result["thinking"])
    print("\n=== FINAL ANSWER ===")
    print(result["answer"])
    print("\n=== EXPLAINABILITY METADATA ===")
    print(result["explainability"])

Example output:

=== THINKING TRACE ===
1. doc-001 discusses solar panels on land, not specifically sea. It is partially relevant but does not address offshore conditions.
2. doc-002 directly mentions offshore wind farms and higher capacity factors at sea. It is highly relevant.
3. doc-003 covers nuclear, which is not renewable in the same category and does not mention sea-based deployment.
There are no contradictions, but the context lacks data on tidal or wave energy.

=== FINAL ANSWER ===
Wind power is the renewable source that works best at sea, as offshore wind turbines achieve higher capacity factors than onshore installations.

=== EXPLAINABILITY METADATA ===
confidence: 0.92
sources_used: doc-002
bias_flags: Context omits tidal and wave energy technologies, which could also be relevant for sea-based renewable power.

Wrap-up

From here, swap the model string to deepseek-r1-671b or qwen-3-32b on Oxlo.ai to compare how different architectures phrase their reasoning traces. You can also replace the hardcoded retrieve_chunks function with a real embedding search using Oxlo.ai's BGE-Large endpoint.

Another practical upgrade is wrapping this logic in FastAPI middleware so every chat completion in your application automatically generates and logs an explainability trace to a structured store like SQLite or ClickHouse.

Top comments (0)