Skip to main content

RAGuard

license last commit pypi python

Runtime hallucination detection middleware for RAG applications.

raguard intercepts LLM responses and flags claims not supported by your retrieved documents — before they reach the user.

When to use RAGuard

RAGuard is a middleware library — not a UI component. It integrates directly into your RAG pipeline. Call verify() after the LLM produces a response and before it is delivered to the user.

User → App → RAG retrieval → LLM → [verify()] → User
                                         ↓
                              Response + warnings surfaced

Use RAGuard when:

  • Your RAG chatbot answers questions about documents, contracts, or policies where factual errors have real consequences (legal, financial, medical)
  • You want runtime protection without adding LLM-call latency or API cost
  • You need a drop-in signal that something in the response needs human review

Install

pip install raguard-py
python -m spacy download en_core_web_sm

Multi-language Support

raguard uses spaCy for named-entity recognition. The default model is en_core_web_sm (English). If your RAG pipeline runs on Turkish, French, or another language, you install the spaCy model yourself and pass lang= to verify().

Step 1 — install the spaCy model for your language:

# Turkish
python -m spacy download tr_core_news_sm

# French
python -m spacy download fr_core_news_sm

# German
python -m spacy download de_core_news_sm

# Spanish
python -m spacy download es_core_news_sm

Step 2 — pass lang= to verify():

from raguard import verify

result = verify(
    query="Q3 2024 teslim tarihi nedir?",
    retrieved_docs=["Q2 projesi 15 Haziran'da tamamlandı."],
    llm_response="Q3 2024 teslim tarihi 30 Eylül 2024'tür.",
    lang="tr",
)

raguard maps the lang code to the standard spaCy model name. If you use a custom or fine-tuned spaCy model, pass the installed package name or local path directly:

# installed spaCy package
result = verify(..., lang="tr_core_news_trf")

# local path
result = verify(..., lang="/models/my-custom-tr-ner")

Note on Turkish NER quality: tr_core_news_sm has limited accuracy on proper nouns and dates compared to en_core_web_sm. The date regex rules and vague-reference checks work language-independently and will still flag issues. Entity-level recall on Turkish text is beta. See Limitations.

Usage

from raguard import verify

result = verify(
    query="What is the Q3 2024 deadline?",
    retrieved_docs=["Q2 project was delivered on June 15. Next milestone is Q4 planning."],
    llm_response="The Q3 2024 deadline is September 30, 2024.",
)

print(result.action)                  # "review"
print(result.warnings[0].text)        # "September 30, 2024"
print(result.warnings[0].suggestion)  # '"September 30, 2024" not found in retrieved documents.'

result.action is either "proceed" (no high-severity issues) or "review" (at least one high-severity warning). Your application decides what to show the user.

What it detects

Type Severity Example
unsupported_date high Response says "September 30" — not in any doc
missing_entity high Response names "John Smith" — not in any doc
vague_reference medium Response says "the recent report" — phrase not in docs
input_error high Empty response, empty docs, or input exceeds size limit

VerifyResult shape

@dataclass
class VerifyResult:
    action: Literal["proceed", "review"]
    warnings: list[Warning]
    summary: Summary  # {high: int, medium: int, low: int}

@dataclass
class Warning:
    severity: Literal["high", "medium", "low"]
    type: Literal["unsupported_date", "missing_entity", "vague_reference", "input_error"]
    text: str        # the problematic span in the response
    suggestion: str  # human-readable explanation

verify() never raises — guard-layer violations return VerifyResult(action="review", warnings=[{type:"input_error", ...}]).

Multiple documents

Pass each chunk as a separate list item. Chunks are joined internally with a \n\n---\n\n separator. Order matters: boundary artifacts can occur if a number at the end of one chunk runs into text at the start of the next. Keep each chunk self-contained.

result = verify(
    query="Who approved the budget?",
    retrieved_docs=[
        "The budget was reviewed in Q1.",
        "Alice Johnson approved the final budget on March 10.",
    ],
    llm_response="Alice Johnson approved the budget.",
)
# result.action == "proceed"

Source attribution per chunk is a v2 feature. Passing list[Document] instead of list[str] will be a breaking API change at that point.

How it works

v1 is rule-based — no LLM calls, no API key required, p95 < 10ms:

  1. Guard layer — validates inputs, returns early on empty or oversized content
  2. Date check — extracts dates from the response with regex, looks for each in the docs
  3. Entity check — runs spaCy NER on the response, checks every PERSON/ORG/GPE/LOC/MONEY entity against the docs; compound model numbers (e.g. "iPhone 16") are filtered to avoid false positives
  4. Vague reference check — matches a curated phrase list against the response and docs

Rules are derived from public hallucination datasets (RAGTruth, HaluEval, TruthfulQA).

Performance

Measured on Python 3.12, Apple M-series, after warm-up:

Metric Value
p50 ~5.4ms
p95 ~6.0ms

First call loads the spaCy model (~200ms). Subsequent calls are fast.

Limitations

  • Turkish NER quality is beta-level. tr_core_news_sm has limited recall on proper nouns and named dates compared to en_core_web_sm. Date regex and vague-reference checks are language-independent and still work. A higher-quality Turkish model option will be documented in v2.
  • Numerical hallucinations are not detected in v1. If the LLM says 18% where the document says 15%, raguard will not flag it. Semantic numerical grounding requires an LLM pass (v2).
  • Compound model numbers may produce false positives. Numbers inside product names like "iPhone 16" or "Windows 11" are filtered via noun-chunk analysis, but edge cases remain (e.g. when the parser fails to resolve the compound).
  • Semantic hallucinations are out of scope for v1. A response that correctly uses entities but draws a wrong conclusion from the documents will not be flagged. This requires a grounding pass against each claim, planned for v2.

Roadmap

v1 — current

  • Rule-based engine: unsupported dates, missing entities, vague references
  • Zero API cost, no LLM calls, p95 < 10ms
  • English-first with compound noun filtering

v2 — planned

  • Optional LLM semantic pass for claim-level grounding (OpenAI / Anthropic / local)
  • Numerical hallucination detection
  • False positive reduction via confidence scoring
  • Turkish NER via a transformer-based spaCy model (e.g. tr_core_news_trf)
  • Per-chunk source attribution (list[Document] API)
  • Warning deduplication and severity grouping

License

MIT

Metadata

Release files for raguard-py 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for raguard-py 0.1.1
File Size Uploaded Provenance Actions
raguard_py-0.1.1.tar.gz 11.9 kB Without provenance Details for raguard_py-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for raguard-py 0.1.1
File Interpreter ABI Platform Actions
raguard_py-0.1.1-py3-none-any.whl Python 3 none any Details for raguard_py-0.1.1-py3-none-any.whl

Total release size: 21.3 kB

Release files / raguard_py-0.1.1.tar.gz

Download URL raguard_py-0.1.1.tar.gz
Size 11.9 kB
Tags Source
SHA-256 checksum
How to use checksums
66d6664346d57facdcdab06d4b57c30e499b9ee86d9b006e65f7acc7dc653c87
BLAKE2b-256 checksum
How to use checksums
ea3b608258a006377084abc1960574a7c83bcc445546a593819714f43e469a22
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.7

Release files / raguard_py-0.1.1-py3-none-any.whl

Download URL raguard_py-0.1.1-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7a04f0310041ec9cc0c89232e0a351da07a6fc6aa21caab7536ca68dc83e0613
BLAKE2b-256 checksum
How to use checksums
5478a1aad462118d2b96c650db9e9d21a7f4e8bf222d3d40844ae6f2ce94e04a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.7

Security for raguard-py 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page