Skip to main content

Explainable AI (XAI) narratives: turn technical XAI outputs into clear natural-language explanations.

Project description

xains

License: MIT Python PyPI version Tests

xains generates explainable AI (XAI) narratives - hence the name. It turns technical XAI outputs such as SHAP attributions and counterfactuals into clear natural-language explanations that make model decisions understandable to a broad audience.

Scope. This library generates natural-language XAI narratives from technical outputs like SHAP attributions or counterfactual explanations, making the explanations more transparent and understandable.

Install

git clone https://github.com/ADMAntwerp/xains.git
cd xains
pip install -e .

Minimal example

import xains
import xains.prompts

schema = xains.DatasetSchema(
    modality=xains.Modality.TABULAR,
    name="credit_risk",
    description="Predicts 24-month default on personal loans.",
    target=xains.TargetSchema(
        name="default",
        description="Whether the applicant defaulted.",
        classes={0: "Repaid", 1: "Defaulted"},
    ),
    features=[
        xains.FeatureSchema(name="age", dtype="numeric", unit="years",
                           description="Applicant age at application."),
        xains.FeatureSchema(name="salary", dtype="numeric", unit="EUR",
                           description="Annual gross salary."),
        xains.FeatureSchema(name="debt_to_income", dtype="numeric",
                           description="Debt-to-income ratio."),
    ],
)

request = xains.TabularExplanationRequest(
    features={"age": 29, "salary": 52000, "debt_to_income": 0.41},
    prediction=xains.Prediction(predicted_class=1, probabilities={0: 0.2, 1: 0.8}),
    contributions=[
        xains.TabularContribution(name="debt_to_income", value=0.41, importance=0.37),
        xains.TabularContribution(name="salary", value=52000, importance=-0.21),
        xains.TabularContribution(name="age", value=29, importance=-0.12),
    ],
)

llm = xains.AnthropicProvider(model="claude-haiku-4-5", max_tokens=512)
explainer = xains.Explainer(
    schema=schema,
    generator=xains.LLMNarrativeGenerator(
        prompt_template=xains.prompts.FeatureImportanceTabularPromptTemplate(),
        llm=llm,
    ),
    config=xains.ExplanationConfig(
        mode="feature_importance", audience="end_user",
        max_length_words=40, extract_narrative=True,
    ),
    judge_llm=llm,  # required when extract_narrative=True
)

result = explainer.explain(request)
print(result.text)

Output is illustrative; LLM responses vary run-to-run:

Your profile indicates elevated default risk. A debt-to-income ratio of 0.41
substantially increases this concern, signaling that your debt obligations
consume a meaningful portion of earnings. Although your salary of EUR 52,000
and relatively young age of 29 provide some protective factors that work
against default, they ultimately prove insufficient to offset the debt burden
weighing on your financial stability.

Scoring the narrative

A narrative is only useful if it is faithful to the attributions and reads well. xains scores both. grade_extraction checks the claims the narrative makes against the input attributions - sign, value, and rank fidelity, coverage, and hallucination count:

grades = xains.grade_extraction(
    extraction=result.narrative_extraction,
    request=request,
    schema=schema,
    narrative_text=result.text,
    k=5,
)
print(xains.render_grades(extraction=grades))
Verbalization fidelity
  sign_faithfulness ↑: 1.0
  value_faithfulness ↑: 1.0
  rank_correlation ↑: 1.0
  coverage ↑: 1.0
  hallucination_count ↓: 0

Arrows mark the desired direction for each metric ( higher is better, lower is better). render_grades also accepts a narrativity= argument and emits a second Narrativity section.

grade_narrativity scores how well the text reads as a narrative, using the metrics from Cedro & Martens 2026. It needs a perplexity provider (any OpenAI-compatible endpoint that returns logprobs):

from xains.metrics import OpenAICompatibleEchoProvider

ppl = OpenAICompatibleEchoProvider(
    base_url="https://api.together.xyz/v1",
    model="meta-llama/Meta-Llama-3-8B-Instruct-Lite",
    api_key_env_var="TOGETHER_API_KEY",
)
narrativity = xains.grade_narrativity(result.text, ppl)
print(xains.render_grades(narrativity=narrativity, scored_only=True))
Narrativity
  csr ↑: 0.27
  dcpr ↓: 1.3
  ccpr ↓: 203.14
  cecpr ↓: 29252.68
  fdr ↑: 0.29
  ttcpr ↓: 2.29
  vcpr ↓: 50.79

These are the seven Cedro & Martens 2026 narrativity metrics. scored_only=True hides the nine auxiliary primitives (ppl_ordered, ttr, n_sentences, ...) which grade_narrativity also captures for paper replication; omit the flag to see them.

End-to-end notebook

For the full pipeline (load German Credit, train a RandomForest, compute SHAP, generate the narrative, extract structured claims, and score on faithfulness and narrativity), see the tutorial in notebooks/01_quickstart.ipynb.

See docs/design.md for the full design and docs/decisions/ for recorded architecture decisions.

Choosing a model

Any LLMProvider drops into xains.LLMNarrativeGenerator(llm=...) - pick the provider for the model you want:

import xains

# Anthropic (reads ANTHROPIC_API_KEY)
llm = xains.AnthropicProvider(model="claude-haiku-4-5", max_tokens=512)

# OpenAI (reads OPENAI_API_KEY)
llm = xains.OpenAIProvider(model="gpt-4o-mini", max_tokens=512)

# OpenRouter - Llama, and many others (reads OPENROUTER_API_KEY)
llm = xains.OpenRouterProvider(model="meta-llama/llama-3.3-70b-instruct", max_tokens=512)

# Any OpenAI-compatible endpoint (Together, Groq, vLLM, ...) - set base_url + the env var to read
llm = xains.OpenAICompatibleProvider(
    base_url="https://api.together.xyz/v1",
    api_key_env_var="TOGETHER_API_KEY",
    model="meta-llama/Llama-3.3-70B-Instruct-Turbo",
    max_tokens=512,
)

Each reads its API key from the named env var (or pass api_key= explicitly); drop any of them into xains.LLMNarrativeGenerator(llm=...) exactly as the Minimal example does.

License

MIT - see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xains-0.1.0.tar.gz (43.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xains-0.1.0-py3-none-any.whl (53.4 kB view details)

Uploaded Python 3

File details

Details for the file xains-0.1.0.tar.gz.

File metadata

  • Download URL: xains-0.1.0.tar.gz
  • Upload date:
  • Size: 43.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for xains-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3a37f248769dcc96d61ad9bb0c6d888318245e2d1ca9f0e148eb99d5dfc364b3
MD5 32e9b03afef2de056731b637ad5e486a
BLAKE2b-256 fbac57b3b98408ebbd07c66f3ff8b70b86edd91a67ce57a18be7787213bc0ed6

See more details on using hashes here.

File details

Details for the file xains-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: xains-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 53.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for xains-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4122f9379112b518e5722857b68321c0b9891073844439a5473a14fc3e18c1c0
MD5 943738e76b98cace920b863884983bdb
BLAKE2b-256 330b4c3e5471db4f5394f2d3f2b641a2e8ef31e198634c372f7831317f36dc73

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page