Artefactual
Estimating how likely a language model answer is to be a hallucination.
Artefactual is a Python module that assigns a language model's answer a probability of being a hallucination. It reads the answer that has already been generated, together with the token probabilities returned alongside it, and needs nothing else from the model.
Quick start
from openai import OpenAI
from artefactual.scoring import wepr
MODEL = "mistralai/Ministral-8B-Instruct-2410" # the model being scored
DETECTOR = "chicham/artefactual-wepr-ministral" # the detector trained for it
client = OpenAI(base_url="https://your-provider.example/v1") # any OpenAI-compatible endpoint
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": "Who wrote the Rust book?"}],
logprobs=True,
top_logprobs=15,
)
detector = wepr(DETECTOR)
print(detector.predict_proba(response)[:, 1]) # P(hallucination) per sequence
print(detector.predict_token_proba(response)) # ...and per token
A detector is trained for one model, so DETECTOR must be the one published for whatever
produced the response — see published detectors for the pairs. There is no default threshold; choosing one is covered in the
user guide.
No endpoint is needed to try the library. The example notebooks run against two checked-in responses and need no GPU, API key or model download.
Requirements
Two conditions apply to whatever produced the response:
logprobsandtop_logprobsare enabled. Providers that do not expose them cannot be scored at all.top_logprobsis at leastk, the rank count the detector's own weights were trained at. The shipped files usek = 15.
Neither needs auditing in advance — a response that fails one is refused by name. Why a narrow response is refused rather than padded is in the reference.
Installation
pip install artefactual
Dependencies
Artefactual requires:
- Python (>= 3.11)
- NumPy
- scikit-learn
- pydantic
- beartype
Two optional extras are available: [adapters] installs langfuse and openai for the
integration examples, and [docs] installs Sphinx and the theme for building the
documentation.
From source
git clone https://github.com/artefactory/artefactual
cd artefactual
uv sync
Usage
Two detectors are provided. wepr is the default and the more accurate; epr fits a
single coefficient instead of 2k, for when labelled data is scarce. Both take the same
arguments and return the same type.
from artefactual.scoring import epr, wepr
wepr("chicham/artefactual-wepr-phi4") # a published detector, by its own repo
wepr("/path/to/my_detector.skops") # one you trained yourself
wepr(k=15, trainable=True).fit(responses, y) # fit your own, y is 0/1 per sequence
epr("chicham/artefactual-epr-phi4") # the single-coefficient variant
Scoring a batch, reading per-token scores, scoring Langfuse traces, composing into
GridSearchCV and training a detector for a model that is not shipped are covered in the
user guide.
Published detectors
A detector is named by its own Hugging Face repository, not by the model it scores. Pick the row for the model that produced the responses, and the column for the reduction:
| Model that produced the responses | epr() |
wepr() |
|---|---|---|
mistralai/Ministral-8B-Instruct-2410 |
chicham/artefactual-epr-ministral |
chicham/artefactual-wepr-ministral |
mistralai/Mistral-Small-3.1-24B-Instruct-2503 |
chicham/artefactual-epr-mistral-small |
chicham/artefactual-wepr-mistral-small |
tiiuae/Falcon3-10B-Instruct |
chicham/artefactual-epr-falcon3 |
chicham/artefactual-wepr-falcon3 |
microsoft/phi-4 |
chicham/artefactual-epr-phi4 |
chicham/artefactual-wepr-phi4 |
All are trained at k = 15. Both factories also accept a path to a .skops file, so a
detector you trained yourself is named the same way one published here is — the package
holds no list of models, and publishing another detector needs no release.
Limitations
- Not every provider can be scored. The requirements above rule out any provider that
hides
logprobs, and any that capstop_logprobsbelow the detector'sk. - Detectors are model-specific. Scoring a model that is not shipped requires training a detector for it, which requires labelled data.
- The probability is only as good as its training data. Rankings transfer more readily than absolute values.
- It measures uncertainty, not truth. A model that is confidently wrong is not uncertain, and scores low. This complements retrieval grounding or a judge rather than replacing either.
- Scoring is per sequence. There is no cross-response consistency check.
Results
ROC-AUC on TriviaQA hallucination detection at k = 15, as reported in Table 1 of the
paper:
| Model | SelfCheckGPT | EPR | HalluDetect | WEPR |
|---|---|---|---|---|
Mistral-Small-3.1-24B |
79.0 | 74.6 | 78.7 | 82.0 |
Falcon-3-10B |
70.1 | 75.4 | 79.0 | 84.1 |
Phi-4 (14.7B) |
71.4 | 78.2 | 83.8 | 85.4 |
Ministral-8B-2410 |
81.1 | 81.4 | 86.1 | 85.8 |
The full tables and the procedure that produced them are in the
scripts/ecir
subdirectory.
Documentation
- Documentation and user guide: https://artefactory.github.io/artefactual/
- Example notebooks: https://artefactory.github.io/artefactual/examples/
- How it works: https://artefactory.github.io/artefactual/guide/how-it-works.html
Development
Contributions are welcome — see CONTRIBUTING.md.
- Source code: https://github.com/artefactory/artefactual
- Issue tracker: https://github.com/artefactory/artefactual/issues
uv sync
uv run pytest tests # test suite (uv sync resolves the env first)
uv run pytest tests --cov # with coverage
uvx ruff check src tests # lint — a standalone tool, no project env needed
uvx ruff format src tests
uvx --from shellcheck-py shellcheck scripts/ecir/*.sh
Versioning
Releases are dated (YYYY.MM.PATCH). Breaking changes to the public surface are called out
in the release notes.
Citation
If artefactual is useful in your research, please cite our paper, accepted for
publication at ECIR 2026:
@misc{moslonka2025learnedhallucinationdetectionblackbox,
title={Learned Hallucination Detection in Black-Box LLMs using Token-level Entropy Production Rate},
author={Charles Moslonka and Hicham Randrianarivo and Arthur Garnier and Emmanuel Malherbe},
year={2025},
eprint={2509.04492},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2509.04492},
}
License
MIT — no limitation of usage, including for commercial applications.
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 artefactual-2026.8.1.tar.gz.
File metadata
- Download URL: artefactual-2026.8.1.tar.gz
- Upload date:
- Size: 50.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb85c33b43eaf307ca6a4fc7330810307d60c3aee28bf1c7cf75910378ac2ad6
|
|
| MD5 |
39fb3782b8e74bba96f7c38052f211ae
|
|
| BLAKE2b-256 |
a3b597af26afc9edf412138b13cf7ff378e51bbdc9073f444eb486707086e586
|
Provenance
The following attestation bundles were made for artefactual-2026.8.1.tar.gz:
Publisher:
release.yaml on artefactory/artefactual
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
artefactual-2026.8.1.tar.gz -
Subject digest:
fb85c33b43eaf307ca6a4fc7330810307d60c3aee28bf1c7cf75910378ac2ad6 - Sigstore transparency entry: 2386031984
- Sigstore integration time:
-
Permalink:
artefactory/artefactual@b9d96929f9d6c2d4fb0c06ad451f801715455e56 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/artefactory
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@b9d96929f9d6c2d4fb0c06ad451f801715455e56 -
Trigger Event:
push
-
Statement type:
File details
Details for the file artefactual-2026.8.1-py3-none-any.whl.
File metadata
- Download URL: artefactual-2026.8.1-py3-none-any.whl
- Upload date:
- Size: 27.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6edf12c41ca68803ab91bd2f394a5d79f9ee0bb598303f2f54d90ad90f66350f
|
|
| MD5 |
81d7bd41aaea66e99676ad904cc3a61e
|
|
| BLAKE2b-256 |
0a4d26005a33db27b26c945db14c5c25cd903fbf6f973d5ca0545112135a755b
|
Provenance
The following attestation bundles were made for artefactual-2026.8.1-py3-none-any.whl:
Publisher:
release.yaml on artefactory/artefactual
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
artefactual-2026.8.1-py3-none-any.whl -
Subject digest:
6edf12c41ca68803ab91bd2f394a5d79f9ee0bb598303f2f54d90ad90f66350f - Sigstore transparency entry: 2386031989
- Sigstore integration time:
-
Permalink:
artefactory/artefactual@b9d96929f9d6c2d4fb0c06ad451f801715455e56 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/artefactory
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@b9d96929f9d6c2d4fb0c06ad451f801715455e56 -
Trigger Event:
push
-
Statement type: