catch-cap

hallucination detection for llms. four methods, one api call.

pypi github

// overview

catch-cap detects when llms generate confident but factually incorrect responses before they reach end users. it runs four independent detection methods and returns a 0-1 confidence score with automated corrections when hallucinations are found.

the four detection methods:

// installation

pip install catch-cap

set your api keys via environment variables or a .env file:

OPENAI_API_KEY=your-openai-key
GEMINI_API_KEY=your-gemini-key
GROQ_API_KEY=your-groq-key
TAVILY_API_KEY=your-tavily-key

only set the keys for providers you plan to use. at minimum, you need one model provider key.

// quick start

import asyncio
from catch_cap import CatchCap, CatchCapConfig, ModelConfig

async def main():
    config = CatchCapConfig(
        generator=ModelConfig(provider="openai", name="gpt-4.1-mini")
    )
    detector = CatchCap(config)
    result = await detector.run("How many r's are there in strawberry?")

    print(f"confabulation detected: {result.confabulation_detected}")
    print(f"entropy score: {result.semantic_entropy.entropy_score}")

    if result.corrected_answer:
        print(f"corrected: {result.corrected_answer}")

asyncio.run(main())

// configuration

CatchCapConfig

generator ModelConfig — the model used to generate responses
semantic_entropy SemanticEntropyConfig — entropy detection settings
logprobs LogProbConfig — log-probability analysis settings
web_search WebSearchConfig — web grounding settings
judge JudgeConfig — judge model settings
enable_correction bool — enable auto-correction of hallucinated answers

ModelConfig

provider str — "openai", "gemini", or "groq"
name str — model identifier (e.g. "gpt-4.1-mini")
temperature float — 0.0-2.0, default 0.7
top_p float — nucleus sampling parameter
max_tokens int — maximum output tokens

SemanticEntropyConfig

enabled bool — activate entropy detection
n_responses int — number of responses to sample
threshold float — entropy threshold (lower = more confident)
embedding_model str — embedding model name
embedding_provider str — provider for embeddings

LogProbConfig

enabled bool — activate log-prob analysis
min_logprob float — token log-prob threshold
fraction_threshold float — fraction of flagged tokens to trigger detection
min_flagged_tokens int — minimum flagged tokens needed

WebSearchConfig

provider str — "tavily", "searxng", or "none"
max_results int — number of search results
timeout_seconds int — search timeout
searxng_url str — searxng instance url (if using searxng)

JudgeConfig

model ModelConfig — the model to use as judge
instructions str — custom judging instructions

// api reference

CatchCap.run(query: str) -> Result

the main async method. processes a query through the full detection pipeline.

result object

query str — the original query
confabulation_detected bool — whether a hallucination was detected
responses list — generated responses (each has a .text property)
semantic_entropy.entropy_score float — 0-1 entropy score
semantic_entropy.is_confident bool — whether the model is confident
logprob_analysis.flagged_token_ratio float — ratio of uncertain tokens
logprob_analysis.flagged_token_count int — count of uncertain tokens
judge_verdict.verdict str — the judge's assessment
judge_verdict.is_consistent bool — consistency check result
corrected_answer str | None — corrected response if available

// providers

openai (recommended)

full support. all non-thinking models. embeddings via text-embedding-3-large/small. log-probs supported.

gemini

fast, cost-effective. all non-thinking models. embeddings via text-embedding-004. no log-prob support.

groq

extremely fast inference. all non-thinking models. use openai/gemini for embeddings. limited log-prob support.

mixed provider configurations are supported — you can use different providers for generation, embeddings, and judging.

// error handling

from catch_cap.exceptions import (
    CatchCapError,
    ProviderNotAvailableError
)

try:
    result = await detector.run(query)
except ProviderNotAvailableError:
    print("model provider unavailable")
except CatchCapError as e:
    print(f"detection error: {e}")

catch-cap uses graceful degradation — if one detection method fails, the others continue. rate limiting prevents api overages. automatic retries handle transient errors with exponential backoff.