trustifai 0.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.
- trustifai-0.0.0/LICENSE +21 -0
- trustifai-0.0.0/PKG-INFO +242 -0
- trustifai-0.0.0/README.md +216 -0
- trustifai-0.0.0/pyproject.toml +42 -0
- trustifai-0.0.0/setup.cfg +4 -0
- trustifai-0.0.0/tests/conftest.py +71 -0
- trustifai-0.0.0/tests/test_calculators.py +59 -0
- trustifai-0.0.0/tests/test_infra.py +89 -0
- trustifai-0.0.0/tests/test_metrics.py +94 -0
- trustifai-0.0.0/tests/test_trustifai.py +107 -0
- trustifai-0.0.0/tests/test_visualizer.py +40 -0
- trustifai-0.0.0/trustifai/__init__.py +3 -0
- trustifai-0.0.0/trustifai/config.py +154 -0
- trustifai-0.0.0/trustifai/core.py +292 -0
- trustifai-0.0.0/trustifai/metrics/__init__.py +19 -0
- trustifai-0.0.0/trustifai/metrics/base.py +22 -0
- trustifai-0.0.0/trustifai/metrics/calculators.py +90 -0
- trustifai-0.0.0/trustifai/metrics/offline_metrics.py +340 -0
- trustifai-0.0.0/trustifai/metrics/online_metrics.py +67 -0
- trustifai-0.0.0/trustifai/services.py +123 -0
- trustifai-0.0.0/trustifai/structures.py +110 -0
- trustifai-0.0.0/trustifai/visualizer.py +143 -0
- trustifai-0.0.0/trustifai.egg-info/PKG-INFO +242 -0
- trustifai-0.0.0/trustifai.egg-info/SOURCES.txt +25 -0
- trustifai-0.0.0/trustifai.egg-info/dependency_links.txt +1 -0
- trustifai-0.0.0/trustifai.egg-info/requires.txt +9 -0
- trustifai-0.0.0/trustifai.egg-info/top_level.txt +4 -0
trustifai-0.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aaryan Verma
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trustifai-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: trustifai
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: Trustifai: A Comprehensive Framework for AI Trustworthiness
|
|
5
|
+
Author-email: Aaryan Verma <aaryan_verma@outlook.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Aaryanverma/trustifai
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: litellm==1.81.1
|
|
18
|
+
Requires-Dist: nltk==3.8.1
|
|
19
|
+
Requires-Dist: numpy==2.4.1
|
|
20
|
+
Requires-Dist: pydantic==2.12.5
|
|
21
|
+
Requires-Dist: pytest==8.3.4
|
|
22
|
+
Requires-Dist: python-dotenv==1.2.1
|
|
23
|
+
Requires-Dist: pyvis==0.3.2
|
|
24
|
+
Requires-Dist: PyYAML==6.0.3
|
|
25
|
+
Requires-Dist: tenacity==8.2.3
|
|
26
|
+
|
|
27
|
+
# Trustifai
|
|
28
|
+
**🛡️Quantify, Visualize, and Explain Trust in RAG Applications.**
|
|
29
|
+
|
|
30
|
+
Trustifai is a Python-based observability engine designed to evaluate the trustworthiness of Retrieval-Augmented Generation (RAG) systems. Unlike simple evaluation frameworks that rely on a single "correctness" score, Trustifai computes a multi-dimensional **Trust Score** based on grounding, consistency, alignment, and diversity.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
It includes an interactive **Reasoning Graph** generator to help debug why a model output was deemed unreliable.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## 📊 Key Metrics
|
|
37
|
+
|
|
38
|
+
**Trustifai** evaluates trustworthiness using four orthogonal vectors. The final *Trust Score* is a weighted aggregation of these components.
|
|
39
|
+
|
|
40
|
+
### Offline Metrics
|
|
41
|
+
|
|
42
|
+
| Metric | Definition | Purpose |
|
|
43
|
+
|------|------------|---------|
|
|
44
|
+
| Evidence Coverage | Segment-level entailment check. The answer is tokenized into sentences and each sentence is verified against retrieved documents using an NLI (Natural Language Inference) approach via an LLM or reranker. | Detects hallucinations. Ensures every claim is supported by the provided context. |
|
|
45
|
+
| Epistemic Consistency | Measures semantic stability ($1 - \sigma$) across $k$ stochastic generations. Samples $k$ responses at high temperature and computes the mean cosine similarity against the original answer. | Detects model uncertainty. Hallucinated answers tend to vary significantly between runs. |
|
|
46
|
+
| Semantic Alignment | Cosine similarity between the Answer Embedding vector ($V_A$) and the Mean Document Embedding vector ($\mu_{D}$). | Detects topic drift. Ensures the answer stays within the semantic envelope of the context. |
|
|
47
|
+
| Source Diversity | Normalized count of unique `source_id` references used to derive the answer, penalized by an exponential decay function. | Detects single-source bias. Rewards synthesis from multiple independent sources. |
|
|
48
|
+
|
|
49
|
+
### Online Metrics
|
|
50
|
+
|
|
51
|
+
| Metric | Definition | Purpose |
|
|
52
|
+
|------|------------|---------|
|
|
53
|
+
| Confidence Score | Calculated using the log probabilities (logprobs) of the generated tokens. It considers the geometric mean of probabilities penalized by the variance of the generation. | Provides a real-time confidence signal (0.0−1.0) indicating how sure the model is about its own output.
|
|
54
|
+
|
|
55
|
+
## 🚀 Installation
|
|
56
|
+
|
|
57
|
+
Trustifai requires Python 3.10+.
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
pip install trustifai
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
OR
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
# Clone the repository
|
|
67
|
+
git clone https://github.com/Aaryanverma/trustifai.git
|
|
68
|
+
cd trustifai
|
|
69
|
+
|
|
70
|
+
# Install dependencies
|
|
71
|
+
pip install -r requirements.txt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Environment Setup
|
|
75
|
+
Create a .env file or export your API keys. Trustifai uses LiteLLM, so it supports OpenAI, Azure, Anthropic, Gemini, Mistral, and more. (check .env.example)
|
|
76
|
+
|
|
77
|
+
## ⚡ Quick Start
|
|
78
|
+
|
|
79
|
+
**1. Evaluate an existing RAG Response in a few lines of code.**
|
|
80
|
+
|
|
81
|
+
`Use this flow to score a query/answer pair against retrieved documents.`
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from Trustifai import Trustifai, MetricContext
|
|
85
|
+
from langchain_core.documents import Document
|
|
86
|
+
|
|
87
|
+
# 1. Define your RAG Context
|
|
88
|
+
context = MetricContext(
|
|
89
|
+
query="What is the capital of India?",
|
|
90
|
+
answer="The capital is New Delhi.",
|
|
91
|
+
documents=[
|
|
92
|
+
Document(page_content="New Delhi is the capital of India.", metadata={"source": "wiki.txt"})
|
|
93
|
+
]
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# 2. Initialize Engine
|
|
97
|
+
trust_engine = Trustifai(context, "Trustifai/config_file.yaml")
|
|
98
|
+
|
|
99
|
+
# 3. Calculate Score
|
|
100
|
+
result = trust_engine.get_trust_score()
|
|
101
|
+
print(f"Trust Score: {result['score']} | Decision: {result['label']}")
|
|
102
|
+
|
|
103
|
+
# 4. Visualize Logic
|
|
104
|
+
graph = trust_engine.build_reasoning_graph(result)
|
|
105
|
+
trust_engine.visualize(graph, graph_type="pyvis") # Saves to reasoning_graph.html
|
|
106
|
+
```
|
|
107
|
+

|
|
108
|
+
|
|
109
|
+
**2. Generate with Confidence**
|
|
110
|
+
|
|
111
|
+
`Use Trustifai to generate a response and immediately get a confidence score based on token log probabilities.`
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from trustifai import Trustifai
|
|
115
|
+
|
|
116
|
+
# Initialize with just the config (Context can be None for pure generation)
|
|
117
|
+
trust_engine = Trustifai(context=None, config_path="Trustifai/config_file.yaml")
|
|
118
|
+
|
|
119
|
+
# Generate response
|
|
120
|
+
result = trust_engine.generate(
|
|
121
|
+
prompt="What is the capital of France?",
|
|
122
|
+
system_prompt="You are a helpful assistant."
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
print(f"Response: {result['response']}")
|
|
126
|
+
print(f"Confidence: {result['metadata']['confidence_score']} ({result['metadata']['confidence_label']})")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+

|
|
130
|
+
|
|
131
|
+
## 🧩 Extending Trustifai (Custom Metrics)
|
|
132
|
+
|
|
133
|
+
You can plug in custom evaluation logic without modifying the core library.
|
|
134
|
+
|
|
135
|
+
- Inherit from BaseMetric and implement calculate().
|
|
136
|
+
|
|
137
|
+
- Register the metric with a unique key.
|
|
138
|
+
|
|
139
|
+
- Configure the weight in your YAML file.
|
|
140
|
+
|
|
141
|
+
*Example: Adding a "PII Detection" Metric*
|
|
142
|
+
```python
|
|
143
|
+
from trustifai.metrics import BaseMetric
|
|
144
|
+
from trustifai.structures import MetricResult
|
|
145
|
+
|
|
146
|
+
# 1. Define Metric
|
|
147
|
+
class PIIMetric(BaseMetric):
|
|
148
|
+
def calculate(self) -> MetricResult:
|
|
149
|
+
# Simple check for the word 'password'
|
|
150
|
+
has_pii = "password" in self.context.answer.lower()
|
|
151
|
+
score = 0.0 if has_pii else 1.0
|
|
152
|
+
|
|
153
|
+
return MetricResult(
|
|
154
|
+
score=score,
|
|
155
|
+
label="Secure" if not has_pii else "PII Detected",
|
|
156
|
+
details={"found_pii": has_pii}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# 2. Register Metric
|
|
160
|
+
from Trustifai import Trustifai
|
|
161
|
+
Trustifai.register_metric("pii_check", PIIMetric)
|
|
162
|
+
|
|
163
|
+
# 3. Use in Trust Engine (Make sure to add it to config.yaml score_weights!)
|
|
164
|
+
trust_engine = Trustifai(context, "config_file.yaml")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
*Updated config.yaml:*
|
|
168
|
+
```yaml
|
|
169
|
+
score_weights:
|
|
170
|
+
- type: "evidence_coverage"
|
|
171
|
+
params: { weight: 0.4 }
|
|
172
|
+
- type: "pii_check" # <--- Your new metric
|
|
173
|
+
params: { weight: 0.1 } # Weights must sum to ~1.0
|
|
174
|
+
# ... other metrics ...
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## ⚙️ Configuration
|
|
178
|
+
Control the sensitivity of the evaluation using config_file.yaml.
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
# config_file.yaml
|
|
182
|
+
|
|
183
|
+
# 1. Model Configuration (via LiteLLM)
|
|
184
|
+
llm:
|
|
185
|
+
type: "openai"
|
|
186
|
+
params:
|
|
187
|
+
model_name: "gpt-4o"
|
|
188
|
+
|
|
189
|
+
# 2. Thresholds (Strictness)
|
|
190
|
+
metrics:
|
|
191
|
+
- type: "evidence_coverage"
|
|
192
|
+
params:
|
|
193
|
+
STRONG_GROUNDING: 0.85 # Threshold for "Trusted" label
|
|
194
|
+
PARTIAL_GROUNDING: 0.50
|
|
195
|
+
- type: "consistency"
|
|
196
|
+
params:
|
|
197
|
+
STABLE_CONSISTENCY: 0.90 # Requires 0.9 cosine sim to be "Stable"
|
|
198
|
+
|
|
199
|
+
# 3. Weighted Aggregation
|
|
200
|
+
# Adjust these based on your business priority.
|
|
201
|
+
score_weights:
|
|
202
|
+
- type: "evidence_coverage"
|
|
203
|
+
params: { weight: 0.40 } # Highest priority on factual accuracy
|
|
204
|
+
- type: "semantic_alignment"
|
|
205
|
+
params: { weight: 0.30 }
|
|
206
|
+
- type: "consistency"
|
|
207
|
+
params: { weight: 0.20 }
|
|
208
|
+
- type: "source_diversity"
|
|
209
|
+
params: { weight: 0.10 }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
## 🕸️ Reasoning Graphs
|
|
214
|
+
|
|
215
|
+
Trustifai doesn't just give you a number; it gives you a map. The Reasoning Graph is a directed acyclic graph (DAG) representing the evaluation logic.
|
|
216
|
+
- Nodes: Represent individual metrics (Green=High Trust, Red=Low Trust).
|
|
217
|
+
- Edges: Represent the flow of data into the final aggregation.
|
|
218
|
+
- Interactive: The generated HTML uses PyVis for physics-based interaction.
|
|
219
|
+
|
|
220
|
+
To generate a graph:
|
|
221
|
+
```python
|
|
222
|
+
# Generate interactive HTML
|
|
223
|
+
trust_engine.visualize(graph, graph_type="pyvis")
|
|
224
|
+
```
|
|
225
|
+

|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
# Generate Mermaid syntax for markdown documentation
|
|
229
|
+
print(trust_engine.visualize(graph, graph_type="mermaid"))
|
|
230
|
+
```
|
|
231
|
+

|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
## 🛠️ Architecture
|
|
235
|
+
- Context Ingestion: The MetricContext object normalizes inputs (Strings, LangChain/LlamaIndex Documents, List, Dictionary etc.).
|
|
236
|
+
- Vectorization: Embeddings for Query, Answer, and Docs are computed in parallel (if not provided in input).
|
|
237
|
+
- Metric Execution:
|
|
238
|
+
- Coverage: Uses a Cross-Encoder Reranker or LLM (default) to verify span support.
|
|
239
|
+
- Consistency: Triggers $k$ asynchronous generation calls to measure semantic variance.
|
|
240
|
+
- Confidence: Analyzes token-level logprobs during generation along with variance penalty.
|
|
241
|
+
- Aggregation: A weighted sum calculates the raw score $[0, 1]$.
|
|
242
|
+
- Decision Boundary: The raw score is mapped to RELIABLE, ACCEPTABLE, or UNRELIABLE based on defined thresholds.
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Trustifai
|
|
2
|
+
**🛡️Quantify, Visualize, and Explain Trust in RAG Applications.**
|
|
3
|
+
|
|
4
|
+
Trustifai is a Python-based observability engine designed to evaluate the trustworthiness of Retrieval-Augmented Generation (RAG) systems. Unlike simple evaluation frameworks that rely on a single "correctness" score, Trustifai computes a multi-dimensional **Trust Score** based on grounding, consistency, alignment, and diversity.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
It includes an interactive **Reasoning Graph** generator to help debug why a model output was deemed unreliable.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## 📊 Key Metrics
|
|
11
|
+
|
|
12
|
+
**Trustifai** evaluates trustworthiness using four orthogonal vectors. The final *Trust Score* is a weighted aggregation of these components.
|
|
13
|
+
|
|
14
|
+
### Offline Metrics
|
|
15
|
+
|
|
16
|
+
| Metric | Definition | Purpose |
|
|
17
|
+
|------|------------|---------|
|
|
18
|
+
| Evidence Coverage | Segment-level entailment check. The answer is tokenized into sentences and each sentence is verified against retrieved documents using an NLI (Natural Language Inference) approach via an LLM or reranker. | Detects hallucinations. Ensures every claim is supported by the provided context. |
|
|
19
|
+
| Epistemic Consistency | Measures semantic stability ($1 - \sigma$) across $k$ stochastic generations. Samples $k$ responses at high temperature and computes the mean cosine similarity against the original answer. | Detects model uncertainty. Hallucinated answers tend to vary significantly between runs. |
|
|
20
|
+
| Semantic Alignment | Cosine similarity between the Answer Embedding vector ($V_A$) and the Mean Document Embedding vector ($\mu_{D}$). | Detects topic drift. Ensures the answer stays within the semantic envelope of the context. |
|
|
21
|
+
| Source Diversity | Normalized count of unique `source_id` references used to derive the answer, penalized by an exponential decay function. | Detects single-source bias. Rewards synthesis from multiple independent sources. |
|
|
22
|
+
|
|
23
|
+
### Online Metrics
|
|
24
|
+
|
|
25
|
+
| Metric | Definition | Purpose |
|
|
26
|
+
|------|------------|---------|
|
|
27
|
+
| Confidence Score | Calculated using the log probabilities (logprobs) of the generated tokens. It considers the geometric mean of probabilities penalized by the variance of the generation. | Provides a real-time confidence signal (0.0−1.0) indicating how sure the model is about its own output.
|
|
28
|
+
|
|
29
|
+
## 🚀 Installation
|
|
30
|
+
|
|
31
|
+
Trustifai requires Python 3.10+.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
pip install trustifai
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
OR
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
# Clone the repository
|
|
41
|
+
git clone https://github.com/Aaryanverma/trustifai.git
|
|
42
|
+
cd trustifai
|
|
43
|
+
|
|
44
|
+
# Install dependencies
|
|
45
|
+
pip install -r requirements.txt
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Environment Setup
|
|
49
|
+
Create a .env file or export your API keys. Trustifai uses LiteLLM, so it supports OpenAI, Azure, Anthropic, Gemini, Mistral, and more. (check .env.example)
|
|
50
|
+
|
|
51
|
+
## ⚡ Quick Start
|
|
52
|
+
|
|
53
|
+
**1. Evaluate an existing RAG Response in a few lines of code.**
|
|
54
|
+
|
|
55
|
+
`Use this flow to score a query/answer pair against retrieved documents.`
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from Trustifai import Trustifai, MetricContext
|
|
59
|
+
from langchain_core.documents import Document
|
|
60
|
+
|
|
61
|
+
# 1. Define your RAG Context
|
|
62
|
+
context = MetricContext(
|
|
63
|
+
query="What is the capital of India?",
|
|
64
|
+
answer="The capital is New Delhi.",
|
|
65
|
+
documents=[
|
|
66
|
+
Document(page_content="New Delhi is the capital of India.", metadata={"source": "wiki.txt"})
|
|
67
|
+
]
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# 2. Initialize Engine
|
|
71
|
+
trust_engine = Trustifai(context, "Trustifai/config_file.yaml")
|
|
72
|
+
|
|
73
|
+
# 3. Calculate Score
|
|
74
|
+
result = trust_engine.get_trust_score()
|
|
75
|
+
print(f"Trust Score: {result['score']} | Decision: {result['label']}")
|
|
76
|
+
|
|
77
|
+
# 4. Visualize Logic
|
|
78
|
+
graph = trust_engine.build_reasoning_graph(result)
|
|
79
|
+
trust_engine.visualize(graph, graph_type="pyvis") # Saves to reasoning_graph.html
|
|
80
|
+
```
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
**2. Generate with Confidence**
|
|
84
|
+
|
|
85
|
+
`Use Trustifai to generate a response and immediately get a confidence score based on token log probabilities.`
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from trustifai import Trustifai
|
|
89
|
+
|
|
90
|
+
# Initialize with just the config (Context can be None for pure generation)
|
|
91
|
+
trust_engine = Trustifai(context=None, config_path="Trustifai/config_file.yaml")
|
|
92
|
+
|
|
93
|
+
# Generate response
|
|
94
|
+
result = trust_engine.generate(
|
|
95
|
+
prompt="What is the capital of France?",
|
|
96
|
+
system_prompt="You are a helpful assistant."
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
print(f"Response: {result['response']}")
|
|
100
|
+
print(f"Confidence: {result['metadata']['confidence_score']} ({result['metadata']['confidence_label']})")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+

|
|
104
|
+
|
|
105
|
+
## 🧩 Extending Trustifai (Custom Metrics)
|
|
106
|
+
|
|
107
|
+
You can plug in custom evaluation logic without modifying the core library.
|
|
108
|
+
|
|
109
|
+
- Inherit from BaseMetric and implement calculate().
|
|
110
|
+
|
|
111
|
+
- Register the metric with a unique key.
|
|
112
|
+
|
|
113
|
+
- Configure the weight in your YAML file.
|
|
114
|
+
|
|
115
|
+
*Example: Adding a "PII Detection" Metric*
|
|
116
|
+
```python
|
|
117
|
+
from trustifai.metrics import BaseMetric
|
|
118
|
+
from trustifai.structures import MetricResult
|
|
119
|
+
|
|
120
|
+
# 1. Define Metric
|
|
121
|
+
class PIIMetric(BaseMetric):
|
|
122
|
+
def calculate(self) -> MetricResult:
|
|
123
|
+
# Simple check for the word 'password'
|
|
124
|
+
has_pii = "password" in self.context.answer.lower()
|
|
125
|
+
score = 0.0 if has_pii else 1.0
|
|
126
|
+
|
|
127
|
+
return MetricResult(
|
|
128
|
+
score=score,
|
|
129
|
+
label="Secure" if not has_pii else "PII Detected",
|
|
130
|
+
details={"found_pii": has_pii}
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# 2. Register Metric
|
|
134
|
+
from Trustifai import Trustifai
|
|
135
|
+
Trustifai.register_metric("pii_check", PIIMetric)
|
|
136
|
+
|
|
137
|
+
# 3. Use in Trust Engine (Make sure to add it to config.yaml score_weights!)
|
|
138
|
+
trust_engine = Trustifai(context, "config_file.yaml")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
*Updated config.yaml:*
|
|
142
|
+
```yaml
|
|
143
|
+
score_weights:
|
|
144
|
+
- type: "evidence_coverage"
|
|
145
|
+
params: { weight: 0.4 }
|
|
146
|
+
- type: "pii_check" # <--- Your new metric
|
|
147
|
+
params: { weight: 0.1 } # Weights must sum to ~1.0
|
|
148
|
+
# ... other metrics ...
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## ⚙️ Configuration
|
|
152
|
+
Control the sensitivity of the evaluation using config_file.yaml.
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
# config_file.yaml
|
|
156
|
+
|
|
157
|
+
# 1. Model Configuration (via LiteLLM)
|
|
158
|
+
llm:
|
|
159
|
+
type: "openai"
|
|
160
|
+
params:
|
|
161
|
+
model_name: "gpt-4o"
|
|
162
|
+
|
|
163
|
+
# 2. Thresholds (Strictness)
|
|
164
|
+
metrics:
|
|
165
|
+
- type: "evidence_coverage"
|
|
166
|
+
params:
|
|
167
|
+
STRONG_GROUNDING: 0.85 # Threshold for "Trusted" label
|
|
168
|
+
PARTIAL_GROUNDING: 0.50
|
|
169
|
+
- type: "consistency"
|
|
170
|
+
params:
|
|
171
|
+
STABLE_CONSISTENCY: 0.90 # Requires 0.9 cosine sim to be "Stable"
|
|
172
|
+
|
|
173
|
+
# 3. Weighted Aggregation
|
|
174
|
+
# Adjust these based on your business priority.
|
|
175
|
+
score_weights:
|
|
176
|
+
- type: "evidence_coverage"
|
|
177
|
+
params: { weight: 0.40 } # Highest priority on factual accuracy
|
|
178
|
+
- type: "semantic_alignment"
|
|
179
|
+
params: { weight: 0.30 }
|
|
180
|
+
- type: "consistency"
|
|
181
|
+
params: { weight: 0.20 }
|
|
182
|
+
- type: "source_diversity"
|
|
183
|
+
params: { weight: 0.10 }
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
## 🕸️ Reasoning Graphs
|
|
188
|
+
|
|
189
|
+
Trustifai doesn't just give you a number; it gives you a map. The Reasoning Graph is a directed acyclic graph (DAG) representing the evaluation logic.
|
|
190
|
+
- Nodes: Represent individual metrics (Green=High Trust, Red=Low Trust).
|
|
191
|
+
- Edges: Represent the flow of data into the final aggregation.
|
|
192
|
+
- Interactive: The generated HTML uses PyVis for physics-based interaction.
|
|
193
|
+
|
|
194
|
+
To generate a graph:
|
|
195
|
+
```python
|
|
196
|
+
# Generate interactive HTML
|
|
197
|
+
trust_engine.visualize(graph, graph_type="pyvis")
|
|
198
|
+
```
|
|
199
|
+

|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
# Generate Mermaid syntax for markdown documentation
|
|
203
|
+
print(trust_engine.visualize(graph, graph_type="mermaid"))
|
|
204
|
+
```
|
|
205
|
+

|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
## 🛠️ Architecture
|
|
209
|
+
- Context Ingestion: The MetricContext object normalizes inputs (Strings, LangChain/LlamaIndex Documents, List, Dictionary etc.).
|
|
210
|
+
- Vectorization: Embeddings for Query, Answer, and Docs are computed in parallel (if not provided in input).
|
|
211
|
+
- Metric Execution:
|
|
212
|
+
- Coverage: Uses a Cross-Encoder Reranker or LLM (default) to verify span support.
|
|
213
|
+
- Consistency: Triggers $k$ asynchronous generation calls to measure semantic variance.
|
|
214
|
+
- Confidence: Analyzes token-level logprobs during generation along with variance penalty.
|
|
215
|
+
- Aggregation: A weighted sum calculates the raw score $[0, 1]$.
|
|
216
|
+
- Decision Boundary: The raw score is mapped to RELIABLE, ACCEPTABLE, or UNRELIABLE based on defined thresholds.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61,<70", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "trustifai"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Trustifai: A Comprehensive Framework for AI Trustworthiness"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Aaryan Verma", email = "aaryan_verma@outlook.com" }
|
|
12
|
+
]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"litellm==1.81.1",
|
|
16
|
+
"nltk==3.8.1",
|
|
17
|
+
"numpy==2.4.1",
|
|
18
|
+
"pydantic==2.12.5",
|
|
19
|
+
"pytest==8.3.4",
|
|
20
|
+
"python-dotenv==1.2.1",
|
|
21
|
+
"pyvis==0.3.2",
|
|
22
|
+
"PyYAML==6.0.3",
|
|
23
|
+
"tenacity==8.2.3"
|
|
24
|
+
]
|
|
25
|
+
license = { text = "MIT" }
|
|
26
|
+
|
|
27
|
+
classifiers = [
|
|
28
|
+
"License :: OSI Approved :: MIT License",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/Aaryanverma/trustifai"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools]
|
|
39
|
+
include-package-data = true
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
where = ["."]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import yaml
|
|
3
|
+
import tempfile
|
|
4
|
+
import os
|
|
5
|
+
import numpy as np
|
|
6
|
+
from unittest.mock import MagicMock
|
|
7
|
+
from langchain_core.documents import Document
|
|
8
|
+
import sys
|
|
9
|
+
sys.path.append("./.")
|
|
10
|
+
|
|
11
|
+
from trustifai.structures import MetricContext
|
|
12
|
+
from trustifai.services import ExternalService
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def sample_config_yaml():
|
|
16
|
+
"""Creates a temporary config.yaml file for testing"""
|
|
17
|
+
config_data = {
|
|
18
|
+
"env_file": ".env.test",
|
|
19
|
+
"llm": {"type": "openai", "params": {"model_name": "gpt-4"}},
|
|
20
|
+
"embeddings": {"type": "openai", "params": {"model_name": "text-embedding-3-small"}},
|
|
21
|
+
"reranker": {"type": "cohere", "params": {"model_name": "rerank-v3.5"}},
|
|
22
|
+
"metrics": [
|
|
23
|
+
{"type": "evidence_coverage", "enabled": True, "params": {"strategy": "llm"}},
|
|
24
|
+
{"type": "semantic_alignment", "enabled": True},
|
|
25
|
+
{"type": "consistency", "enabled": True},
|
|
26
|
+
{"type": "source_diversity", "enabled": True}
|
|
27
|
+
],
|
|
28
|
+
"score_weights": [
|
|
29
|
+
{"type": "evidence_coverage", "params": {"weight": 0.4}},
|
|
30
|
+
{"type": "semantic_alignment", "params": {"weight": 0.3}},
|
|
31
|
+
{"type": "consistency", "params": {"weight": 0.2}},
|
|
32
|
+
{"type": "source_diversity", "params": {"weight": 0.1}}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
|
37
|
+
yaml.dump(config_data, f)
|
|
38
|
+
path = f.name
|
|
39
|
+
|
|
40
|
+
yield path
|
|
41
|
+
os.remove(path)
|
|
42
|
+
|
|
43
|
+
@pytest.fixture
|
|
44
|
+
def mock_service():
|
|
45
|
+
"""Mocks the ExternalService to prevent real API calls"""
|
|
46
|
+
service = MagicMock(spec=ExternalService)
|
|
47
|
+
|
|
48
|
+
# Default behaviors
|
|
49
|
+
service.llm_call = MagicMock()
|
|
50
|
+
service.extract_document.side_effect = lambda x: x.page_content if hasattr(x, 'page_content') else str(x)
|
|
51
|
+
service.embedding_call.return_value = np.array([0.1, 0.2, 0.3])
|
|
52
|
+
service.llm_call.return_value = {"response": "Mocked LLM Response", "logprobs": [-0.1, -0.2]}
|
|
53
|
+
service.reranker_call.return_value = []
|
|
54
|
+
|
|
55
|
+
return service
|
|
56
|
+
|
|
57
|
+
@pytest.fixture
|
|
58
|
+
def basic_context():
|
|
59
|
+
"""Provides a standard MetricContext with dummy data"""
|
|
60
|
+
docs = [
|
|
61
|
+
Document(page_content="Paris is the capital of France.", metadata={"source": "wiki"}),
|
|
62
|
+
Document(page_content="France's capital city is Paris.", metadata={"source": "geo_db"})
|
|
63
|
+
]
|
|
64
|
+
return MetricContext(
|
|
65
|
+
query="What is the capital of France?",
|
|
66
|
+
answer="The capital of France is Paris.",
|
|
67
|
+
documents=docs,
|
|
68
|
+
query_embeddings=np.array([0.1, 0.2, 0.3]),
|
|
69
|
+
answer_embeddings=np.array([0.1, 0.2, 0.3]),
|
|
70
|
+
document_embeddings=[np.array([0.1, 0.2, 0.3]), np.array([0.1, 0.2, 0.3])]
|
|
71
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from trustifai.metrics.calculators import CosineSimCalculator, ThresholdEvaluator, SourceIdentifier
|
|
3
|
+
from unittest.mock import MagicMock
|
|
4
|
+
|
|
5
|
+
def test_cosine_similarity():
|
|
6
|
+
calc = CosineSimCalculator()
|
|
7
|
+
|
|
8
|
+
# Identical vectors
|
|
9
|
+
v1 = [1, 0, 0]
|
|
10
|
+
assert calc.calculate(v1, v1) > 0.99
|
|
11
|
+
|
|
12
|
+
# Orthogonal vectors
|
|
13
|
+
v2 = [0, 1, 0]
|
|
14
|
+
assert calc.calculate(v1, v2) == 0.0
|
|
15
|
+
|
|
16
|
+
# Zero vector handling
|
|
17
|
+
v3 = [0, 0, 0]
|
|
18
|
+
assert calc.calculate(v1, v3) == 0.0
|
|
19
|
+
|
|
20
|
+
# Missing input
|
|
21
|
+
with pytest.raises(ValueError):
|
|
22
|
+
calc.calculate(None, v1)
|
|
23
|
+
|
|
24
|
+
def test_threshold_evaluator():
|
|
25
|
+
mock_config = MagicMock()
|
|
26
|
+
mock_config.thresholds.STRONG_GROUNDING = 0.8
|
|
27
|
+
mock_config.thresholds.PARTIAL_GROUNDING = 0.5
|
|
28
|
+
|
|
29
|
+
evaluator = ThresholdEvaluator(mock_config)
|
|
30
|
+
|
|
31
|
+
# Grounding
|
|
32
|
+
lbl, _ = evaluator.evaluate_grounding(0.9)
|
|
33
|
+
assert lbl == "Strong Grounding"
|
|
34
|
+
|
|
35
|
+
lbl, _ = evaluator.evaluate_grounding(0.6)
|
|
36
|
+
assert lbl == "Partial Grounding"
|
|
37
|
+
|
|
38
|
+
lbl, _ = evaluator.evaluate_grounding(0.2)
|
|
39
|
+
assert "Hallucinated" in lbl
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Add a pytest fixture for mock_service
|
|
43
|
+
@pytest.fixture
|
|
44
|
+
def mock_service():
|
|
45
|
+
return MagicMock()
|
|
46
|
+
|
|
47
|
+
def test_source_identifier(mock_service):
|
|
48
|
+
doc = MagicMock()
|
|
49
|
+
doc.metadata = {"source_id": "123"}
|
|
50
|
+
|
|
51
|
+
sid = SourceIdentifier()
|
|
52
|
+
res = sid.resolve_source_id(doc, mock_service)
|
|
53
|
+
assert res == "source_id:123"
|
|
54
|
+
|
|
55
|
+
# Fallback to hash
|
|
56
|
+
doc.metadata = {}
|
|
57
|
+
mock_service.extract_document.return_value = "content"
|
|
58
|
+
res = sid.resolve_source_id(doc, mock_service)
|
|
59
|
+
assert "content_hash" in res
|