bayesian-llm-guard 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 XAIDeep.com
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: bayesian-llm-guard
3
+ Version: 1.0.0
4
+ Summary: Epistemic Uncertainty Estimation & Guardrails for Agentic LLMs and RAG Systems
5
+ License: Apache-2.0
6
+ License-File: LICENSE
7
+ Author: AI Research Team
8
+ Author-email: research@xaideep.com
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Programming Language :: Python :: 3.15
18
+ Requires-Dist: numpy (>=1.24.0,<2.0.0)
19
+ Requires-Dist: pydantic (>=2.0.0,<3.0.0)
20
+ Requires-Dist: pydantic-settings (>=2.0.0,<3.0.0)
21
+ Requires-Dist: torch (>=2.0.0)
22
+ Description-Content-Type: text/markdown
23
+
24
+ # bayesian-llm-guard 🛡️
25
+
26
+ **bayesian-llm-guard** is a lightweight, production-ready Python library that bridges Bayesian Epistemic Uncertainty Estimation with Agentic LLM guardrails to mitigate hallucinations in RAG systems.
27
+
28
+ ## Installation
29
+
30
+ _(Coming soon to PyPI)_
31
+
32
+ ## License
33
+
34
+ Apache 2.0
35
+
@@ -0,0 +1,11 @@
1
+ # bayesian-llm-guard 🛡️
2
+
3
+ **bayesian-llm-guard** is a lightweight, production-ready Python library that bridges Bayesian Epistemic Uncertainty Estimation with Agentic LLM guardrails to mitigate hallucinations in RAG systems.
4
+
5
+ ## Installation
6
+
7
+ _(Coming soon to PyPI)_
8
+
9
+ ## License
10
+
11
+ Apache 2.0
@@ -0,0 +1,21 @@
1
+ """
2
+ bayesian-llm-guard
3
+ Epistemic Uncertainty Estimation & Guardrails for Agentic LLMs.
4
+ """
5
+
6
+ from .core import (
7
+ UQGuardConfig,
8
+ UQEngine,
9
+ uq_guard,
10
+ UQGuardException,
11
+ AgentSelfCorrectionLoop
12
+ )
13
+
14
+ __version__ = "0.1.0"
15
+ __all__ = [
16
+ "UQGuardConfig",
17
+ "UQEngine",
18
+ "uq_guard",
19
+ "UQGuardException",
20
+ "AgentSelfCorrectionLoop"
21
+ ]
@@ -0,0 +1,12 @@
1
+ from .config import UQGuardConfig
2
+ from .uq_engine import UQEngine
3
+ from .guardrail import uq_guard, UQGuardException
4
+ from .agent_loop import AgentSelfCorrectionLoop
5
+
6
+ __all__ = [
7
+ "UQGuardConfig",
8
+ "UQEngine",
9
+ "uq_guard",
10
+ "UQGuardException",
11
+ "AgentSelfCorrectionLoop"
12
+ ]
@@ -0,0 +1,79 @@
1
+ """
2
+ Agent Loop Module for bayesian-llm-guard.
3
+ Implements an autonomous self-correction loop to retry and refine
4
+ queries when high uncertainty (hallucination) is detected.
5
+ """
6
+
7
+ import logging
8
+ from typing import Any, Callable, Dict
9
+
10
+ from bayesian_llm_guard.core.guardrail import UQGuardException
11
+
12
+ logger = logging.getLogger("bayesian_agent_loop")
13
+
14
+
15
+ class AgentSelfCorrectionLoop:
16
+ """
17
+ Manages iterative query refinement and re-execution for RAG pipelines.
18
+ Automatically catches uncertainty exceptions and refines the user's prompt.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ max_retries: int = 3,
24
+ query_refiner: Callable[[str], str] = lambda q: q + " (provide more specific context)"
25
+ ) -> None:
26
+ """
27
+ Args:
28
+ max_retries (int): Maximum number of times to retry the pipeline.
29
+ query_refiner (Callable): A function that modifies the failed query to improve retrieval.
30
+ """
31
+ self.max_retries = max_retries
32
+ self.query_refiner = query_refiner
33
+
34
+ def execute_with_fallback(
35
+ self,
36
+ rag_pipeline_func: Callable[..., Dict[str, Any]],
37
+ initial_query: str,
38
+ **kwargs: Any
39
+ ) -> Dict[str, Any]:
40
+ """
41
+ Executes the provided RAG function. If it triggers the UQ Guardrail,
42
+ the query is refined and retried automatically.
43
+
44
+ Args:
45
+ rag_pipeline_func (Callable): The decorated RAG function to execute.
46
+ initial_query (str): The original user prompt.
47
+
48
+ Returns:
49
+ Dict[str, Any]: The safe, validated result from the pipeline.
50
+
51
+ Raises:
52
+ RuntimeError: If the maximum number of retries is exhausted.
53
+ """
54
+ current_query = initial_query
55
+ attempt = 0
56
+
57
+ while attempt < self.max_retries:
58
+ try:
59
+ logger.info(f"Agent Loop Attempt {attempt + 1}/{self.max_retries}. Query: '{current_query}'")
60
+
61
+ # Attempt to execute the pipeline
62
+ return rag_pipeline_func(query=current_query, **kwargs)
63
+
64
+ except UQGuardException as exception:
65
+ attempt += 1
66
+ logger.warning(f"Guardrail intercepted the response: {exception}")
67
+
68
+ if attempt < self.max_retries:
69
+ logger.info("Refining query and retrying...")
70
+ current_query = self.query_refiner(current_query)
71
+
72
+ # If the loop finishes without returning, the model could not produce a safe answer
73
+ error_msg = (
74
+ f"Agent loop failed after {self.max_retries} attempts. "
75
+ "The model consistently exhibited high epistemic uncertainty. "
76
+ "Please check your knowledge base or refine the original prompt."
77
+ )
78
+ logger.error(error_msg)
79
+ raise RuntimeError(error_msg)
@@ -0,0 +1,38 @@
1
+ """
2
+ Configuration Module for bayesian-llm-guard.
3
+ Manages type-safe settings and environment variables.
4
+ """
5
+
6
+ from pydantic import Field
7
+ from pydantic_settings import BaseSettings
8
+
9
+
10
+ class UQGuardConfig(BaseSettings):
11
+ """
12
+ Core configuration for the Bayesian Guardrail.
13
+ Values can be overridden using environment variables with the 'UQ_' prefix.
14
+ Example: export UQ_THRESHOLD=0.03
15
+ """
16
+
17
+ threshold: float = Field(
18
+ default=0.05,
19
+ ge=0.0,
20
+ le=1.0,
21
+ description="Maximum allowed epistemic variance. Values above this trigger the guardrail."
22
+ )
23
+
24
+ mc_samples: int = Field(
25
+ default=30,
26
+ ge=5,
27
+ le=100,
28
+ description="Number of Monte Carlo forward passes for uncertainty estimation."
29
+ )
30
+
31
+ max_retries: int = Field(
32
+ default=3,
33
+ ge=0,
34
+ description="Maximum number of self-correction attempts when high uncertainty is detected."
35
+ )
36
+
37
+ class Config:
38
+ env_prefix = "UQ_"
@@ -0,0 +1,81 @@
1
+ """
2
+ Guardrail Module for bayesian-llm-guard.
3
+ Provides the @uq_guard decorator to intercept LLM/RAG pipelines
4
+ and evaluate epistemic uncertainty before returning results.
5
+ """
6
+
7
+ import logging
8
+ from functools import wraps
9
+ from typing import Any, Callable, Dict, Optional
10
+
11
+ from bayesian_llm_guard.core.uq_engine import UQEngine
12
+ from bayesian_llm_guard.core.config import UQGuardConfig
13
+
14
+ # Setup basic logging for the guardrail
15
+ logger = logging.getLogger("bayesian_guardrail")
16
+ logging.basicConfig(level=logging.INFO)
17
+
18
+
19
+ class UQGuardException(Exception):
20
+ """
21
+ Raised when the model's epistemic uncertainty exceeds the defined safety threshold.
22
+ Indicates a potential hallucination.
23
+ """
24
+ pass
25
+
26
+
27
+ def uq_guard(
28
+ uq_engine: UQEngine,
29
+ config: Optional[UQGuardConfig] = None,
30
+ fallback_action: Optional[Callable[..., Any]] = None,
31
+ ) -> Callable[..., Callable[..., Any]]:
32
+ """
33
+ A decorator that wraps LLM/RAG execution functions.
34
+ It intercepts the returned tensor features, calculates the variance using the UQEngine,
35
+ and blocks the response if the model is too uncertain.
36
+
37
+ Args:
38
+ uq_engine (UQEngine): The instantiated uncertainty quantification engine.
39
+ config (UQGuardConfig, optional): Configuration containing the safety threshold.
40
+ fallback_action (Callable, optional): A function to execute if the threshold is breached.
41
+ """
42
+ conf = config or UQGuardConfig()
43
+
44
+ def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
45
+ @wraps(func)
46
+ def wrapper(*args: Any, **kwargs: Any) -> Dict[str, Any]:
47
+ # Execute the underlying LLM or RAG pipeline
48
+ result = func(*args, **kwargs)
49
+
50
+ # The wrapped function must return a dictionary containing 'tensor_features'
51
+ if isinstance(result, dict) and "tensor_features" in result:
52
+ features = result["tensor_features"]
53
+
54
+ # Calculate the maximum epistemic variance
55
+ max_variance = uq_engine.estimate_variance(features)
56
+
57
+ logger.info(
58
+ f"Calculated Epistemic Variance: {max_variance:.4f} "
59
+ f"(Threshold: {conf.threshold:.4f})"
60
+ )
61
+
62
+ # Check if the uncertainty violates the safety threshold
63
+ if max_variance > conf.threshold:
64
+ logger.warning("Uncertainty threshold exceeded! High risk of hallucination.")
65
+
66
+ if fallback_action:
67
+ logger.info("Executing defined fallback action.")
68
+ return fallback_action(*args, **kwargs, uncertainty=max_variance)
69
+
70
+ # If no fallback is defined, raise an exception to stop execution
71
+ raise UQGuardException(
72
+ f"Safety block triggered: Uncertainty score {max_variance:.4f} "
73
+ f"is higher than the allowed threshold of {conf.threshold:.4f}."
74
+ )
75
+
76
+ # Inject the variance metrics into the final result for downstream analytics
77
+ result["uq_metrics"] = {"epistemic_variance": max_variance}
78
+
79
+ return result
80
+ return wrapper
81
+ return decorator
@@ -0,0 +1,46 @@
1
+ """
2
+ Uncertainty Quantification (UQ) Engine.
3
+ Implements Epistemic Uncertainty estimation using Monte Carlo Dropout.
4
+ Optimized for high-throughput GPU inference using Tensor Batching.
5
+ """
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+
10
+
11
+ class UQEngine:
12
+ """
13
+ Executes vectorized stochastic forward passes through a PyTorch model
14
+ to calculate epistemic variance.
15
+ """
16
+
17
+ def __init__(self, model: nn.Module, mc_samples: int = 30) -> None:
18
+ self.model = model
19
+ self.mc_samples = mc_samples
20
+
21
+ def _enable_dropout(self) -> None:
22
+ """Forces dropout layers to remain active during evaluation mode."""
23
+ for module in self.model.modules():
24
+ if isinstance(module, nn.Dropout):
25
+ module.train()
26
+
27
+ def estimate_variance(self, input_tensor: torch.Tensor) -> float:
28
+ """
29
+ Calculates the maximum epistemic variance using vectorized Monte Carlo samples.
30
+ """
31
+ self._enable_dropout()
32
+
33
+ with torch.no_grad():
34
+ # ENTERPRISE BATCHING: Duplicate the tensor along the batch dimension.
35
+ # If input is (1, 768), repeated_tensor becomes (30, 768).
36
+ # This allows the GPU to process all Monte Carlo samples in parallel.
37
+ repeat_dims = [self.mc_samples] + [1] * (input_tensor.dim() - 1)
38
+ repeated_tensor = input_tensor.repeat(*repeat_dims)
39
+
40
+ # Single highly-parallel forward pass
41
+ predictions = self.model(repeated_tensor)
42
+
43
+ # Calculate statistical variance across the batch dimension (dim=0)
44
+ variances = torch.var(predictions, dim=0, unbiased=True)
45
+
46
+ return float(variances.max().item())
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ requires = ["poetry-core>=1.0.0"]
3
+ build-backend = "poetry.core.masonry.api"
4
+
5
+ [tool.poetry]
6
+ name = "bayesian-llm-guard"
7
+ version = "1.0.0"
8
+ description = "Epistemic Uncertainty Estimation & Guardrails for Agentic LLMs and RAG Systems"
9
+ readme = "README.md"
10
+ authors = ["AI Research Team <research@xaideep.com>"]
11
+ license = "Apache-2.0"
12
+
13
+ [tool.poetry.dependencies]
14
+ python = "^3.10"
15
+ torch = ">=2.0.0"
16
+ numpy = "^1.24.0"
17
+ pydantic = "^2.0.0"
18
+ pydantic-settings = "^2.0.0"
19
+
20
+ [tool.poetry.group.dev.dependencies]
21
+ pytest = "^7.3.0"
22
+ black = "^23.3.0"
23
+ isort = "^5.12.0"
24
+
25
+ [tool.semantic_release]
26
+ version_toml = ["pyproject.toml:tool.poetry.version"]
27
+ branch = "main"
28
+ build_command = "pip install poetry && poetry build"
29
+ commit_message = "chore(release): v{version} [skip ci]"
30
+ commit_author = "github-actions[bot] <actions@github.com>"