Typed hallucination detection for LLMs — fingerprint outputs as temporal_confusion, entity_substitution, numerical_distortion, and more
Project description
HallucinoType
Typed hallucination detection for LLMs.
Most hallucination detectors tell you whether a model hallucinated.
HallucinoType tells you what kind — which changes how you fix it.
Hallucination Types
| Type | Description | Example |
|---|---|---|
entity_substitution |
Wrong entity used in place of the correct one | Attributing Einstein's Nobel Prize to Bohr |
temporal_confusion |
Incorrect date, year, or era | Claiming the Berlin Wall fell in 1992 |
source_blending |
Facts from different sources merged into one wrong claim | Two study results combined into one |
confident_fabrication |
Fully fabricated claim stated confidently | Citing a paper that doesn't exist |
numerical_distortion |
Correct context, wrong numbers | Reporting 78% efficacy when the real figure is 38% |
relation_error |
Correct entities, wrong relationship | "X acquired Y" when Y acquired X |
negation_flip |
Logical polarity inverted | "The vaccine did not show efficacy" for a trial that did |
overgeneralization |
Specific fact incorrectly generalized | One study's result stated as universal consensus |
Install
pip install hallucinotype
Setup (development)
git clone https://github.com/PraveenMyakala/HallucinoType.git
cd HallucinoType
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Mac/Linux
pip install -e ".[dev]"
Run the Demo
No API key needed — rule-based detectors only:
python demo.py
Sample output:
────────────────────────────────────────────────────────────
[Temporal confusion]
Claim : The Berlin Wall fell in 1992.
Context: The Berlin Wall fell on November 9, 1989...
Result : Hallucination detected [p=0.46]: temporal_confusion (0.46)
• Year 1992 in claim doesn't match context. Nearest year: 1989 (gap: 3 years).
Correct: 1989 (confidence 0.46)
────────────────────────────────────────────────────────────
[Numerical distortion]
Claim : The trial showed a 78% success rate in the treatment group.
Context: The Phase 3 trial reported a 38% success rate...
Result : Hallucination detected [p=0.65]: numerical_distortion (0.65)
• Claim uses '78' (≈78) but context has '38' (≈38). Relative error: 105.3%.
Correct: 38% (confidence 0.65)
To also run the LLM judge (detects fabrication, relation errors, negation flips):
# Windows
set ANTHROPIC_API_KEY=sk-ant-...
python demo.py --llm
# Mac/Linux
export ANTHROPIC_API_KEY=sk-ant-...
python demo.py --llm
Use in Your Own Code
from hallucinotype import HallucinoTypePipeline, PipelineConfig
# Rule-based only (no API key needed)
config = PipelineConfig(use_llm_judge=False, use_spacy=False)
pipeline = HallucinoTypePipeline(config)
fp = pipeline.run(
claim="The study was published in 2010.",
context="This landmark paper appeared in 2019."
)
print(fp.summary())
# Hallucination detected [p=0.58]: temporal_confusion (0.58)
print(fp.is_hallucinated()) # True
print(fp.dominant_type) # HallucinationType.TEMPORAL_CONFUSION
for ev in fp.evidence:
print(f"[{ev.source}] {ev.description}")
print(f" Correct: {ev.reference_text} Confidence: {ev.confidence:.2f}")
Configuration options
# With LLM judge (Claude, default)
config = PipelineConfig(use_llm_judge=True, judge_backend="anthropic")
# With LLM judge (OpenAI)
config = PipelineConfig(use_llm_judge=True, judge_backend="openai", judge_model="gpt-4o")
# Accept up to 5-year gap before flagging temporal errors
config = PipelineConfig(year_tolerance=5)
# With spaCy NER (more accurate entity detection)
# Requires: python -m spacy download en_core_web_sm
config = PipelineConfig(use_spacy=True)
Use individual detectors
from hallucinotype.detectors import TemporalConfusionDetector, NumericalDistortionDetector
detector = TemporalConfusionDetector(year_tolerance=0)
evidence = detector.detect(
claim="The paper was published in 2010.",
context="This landmark study appeared in 2019."
)
for ev in evidence:
print(ev.description)
Batch evaluation
claims = [
"The drug showed 80% efficacy in trials.",
"Apple acquired Microsoft in 2010.",
]
contexts = [
"The Phase 3 trial demonstrated 40% efficacy.",
"Apple and Microsoft have always been separate companies.",
]
results = pipeline.run_batch(claims, contexts)
for claim, fp in zip(claims, results):
print(f"[{fp.dominant_type}] {claim}")
Command-Line Interface
# Single claim — rule-based only (no API key needed)
hallucinotype detect \
--claim "Einstein won the Nobel Prize in 1905." \
--context "Einstein won the Nobel Prize in Physics in 1921." \
--no-llm --format text
# Single claim — with LLM judge (requires ANTHROPIC_API_KEY)
hallucinotype detect \
--claim "The study found 78% efficacy." \
--context "The trial reported a 38% success rate."
# Batch from a JSONL file (one {"claim": "...", "context": "..."} per line)
hallucinotype batch --input claims.jsonl --format text
# Output JSON to file
hallucinotype detect --claim "..." --context "..." --output result.json
Run Tests
pip install -e ".[dev]"
pytest tests/ -v -m "not slow"
All 35 tests are rule-based and run in under 1 second with no API key.
Output Schema
HallucinationFingerprint
├── claim str
├── context str | None
├── detected_types dict[HallucinationType, float] # type → confidence
├── severity dict[HallucinationType, Severity]
├── evidence list[Evidence]
├── hallucination_probability float # noisy-OR across all types
├── dominant_type HallucinationType | None
└── judge_response str | None # raw LLM output
Evidence
├── source str # which detector flagged this
├── description str # human-readable explanation
├── span (int, int) | None # character offsets in claim
├── reference_text str | None # correct value, if known
└── confidence float
Architecture
HallucinoTypePipeline
├── EntitySubstitutionDetector spaCy NER comparison + edit distance
├── TemporalConfusionDetector regex year/date extraction + gap check
├── NumericalDistortionDetector numeric extraction + window overlap + relative error
└── LLMJudgeDetector structured prompt → Claude or GPT-4o (JSON output)
catches: confident_fabrication, source_blending,
relation_error, negation_flip, overgeneralization
Rule-based detectors run first (fast, no cost). The LLM judge handles semantically complex types that rules can't catch.
Releasing
Releases are fully automated via GitHub Actions. Pushing a version tag triggers the pipeline: tests → build → publish to PyPI → GitHub Release.
Prerequisites (one-time setup)
1. Register a PyPI Trusted Publisher at pypi.org/manage/account/publishing:
| Field | Value |
|---|---|
| PyPI project name | hallucinotype |
| Owner | PraveenMyakala |
| Repository name | HallucinoType |
| Workflow filename | release.yml |
| Environment name | pypi |
2. Create a pypi environment in the GitHub repo:
Settings → Environments → New environment → name it pypi.
No API tokens are stored anywhere — authentication uses OIDC.
Cutting a release
# 1. Bump the version in both files (must match the tag exactly)
# hallucinotype/__init__.py → __version__ = "0.X.0"
# pyproject.toml → version = "0.X.0"
# 2. Commit, tag, push
git add hallucinotype/__init__.py pyproject.toml
git commit -m "chore: release v0.X.0"
git tag v0.X.0
git push origin main
git push origin v0.X.0
The pipeline then runs automatically:
tag push v0.X.0
├── test run pytest — blocks release on failure
├── build build wheel + sdist, verify tag == __version__
├── publish upload to PyPI via OIDC (no token stored)
└── github-release attach .whl + .tar.gz to the GitHub Release
Monitor at: https://github.com/PraveenMyakala/HallucinoType/actions
Manual trigger
If the pipeline doesn't fire (e.g. tag pushed before workflow was on main):
- Go to Actions → Release to PyPI → Run workflow
Or re-push the tag:
git push origin :refs/tags/v0.X.0 # delete remote tag
git tag -f v0.X.0 # re-point to current commit
git push origin v0.X.0 # triggers pipeline again
Roadmap
-
v0.1Core package: 8-type taxonomy, 4 detectors, typed fingerprints, 35 tests -
v0.2PyPI package, automated CI/CD release pipeline -
v0.3Annotated benchmark dataset (typed, claim-context pairs with ground truth) -
v0.4Evaluation vs binary baselines (Vectara HHEM, SelfCheckGPT) -
v0.5LangChain / LlamaIndex evaluation callbacks
License
Apache 2.0 — see LICENSE for details.
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 hallucinotype-0.2.1.tar.gz.
File metadata
- Download URL: hallucinotype-0.2.1.tar.gz
- Upload date:
- Size: 69.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36331532b270b381a62f7c8ac402517473861ef57d285fde6a5eff2f92e28e24
|
|
| MD5 |
594a32c975899dc29e743dd7716aea37
|
|
| BLAKE2b-256 |
4387b826469eb98e0d8e977dab25c717b5c75f20b004d02d7797ca5a5666d590
|
Provenance
The following attestation bundles were made for hallucinotype-0.2.1.tar.gz:
Publisher:
release.yml on PraveenMyakala/HallucinoType
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hallucinotype-0.2.1.tar.gz -
Subject digest:
36331532b270b381a62f7c8ac402517473861ef57d285fde6a5eff2f92e28e24 - Sigstore transparency entry: 1631573479
- Sigstore integration time:
-
Permalink:
PraveenMyakala/HallucinoType@3e4f1da056592446a0f21052da6419cfd7e0aa62 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/PraveenMyakala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3e4f1da056592446a0f21052da6419cfd7e0aa62 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hallucinotype-0.2.1-py3-none-any.whl.
File metadata
- Download URL: hallucinotype-0.2.1-py3-none-any.whl
- Upload date:
- Size: 32.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acc3c9085a50fc8e4fa08d2d25f31503f682fe99827439aac812fec0bf116242
|
|
| MD5 |
3b2b130c997dd9bf36ba2f78abd08e25
|
|
| BLAKE2b-256 |
2ea238ac4fedc16709b8c775cea3f557b6f3d6a10d8702b155531b93f0a44628
|
Provenance
The following attestation bundles were made for hallucinotype-0.2.1-py3-none-any.whl:
Publisher:
release.yml on PraveenMyakala/HallucinoType
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hallucinotype-0.2.1-py3-none-any.whl -
Subject digest:
acc3c9085a50fc8e4fa08d2d25f31503f682fe99827439aac812fec0bf116242 - Sigstore transparency entry: 1631573483
- Sigstore integration time:
-
Permalink:
PraveenMyakala/HallucinoType@3e4f1da056592446a0f21052da6419cfd7e0aa62 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/PraveenMyakala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3e4f1da056592446a0f21052da6419cfd7e0aa62 -
Trigger Event:
push
-
Statement type: