Explainable AI (XAI) narratives: turn technical XAI outputs into clear natural-language explanations.
Project description
xains
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a37f248769dcc96d61ad9bb0c6d888318245e2d1ca9f0e148eb99d5dfc364b3
|
|
| MD5 |
32e9b03afef2de056731b637ad5e486a
|
|
| BLAKE2b-256 |
fbac57b3b98408ebbd07c66f3ff8b70b86edd91a67ce57a18be7787213bc0ed6
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4122f9379112b518e5722857b68321c0b9891073844439a5473a14fc3e18c1c0
|
|
| MD5 |
943738e76b98cace920b863884983bdb
|
|
| BLAKE2b-256 |
330b4c3e5471db4f5394f2d3f2b641a2e8ef31e198634c372f7831317f36dc73
|