User Guide¶
This guide provides detailed examples and best practices for using FairSense-AgentiX in your applications.
Overview¶
FairSense-AgentiX provides three main analysis workflows:
- Text Bias Detection - Analyze written content for fairness issues
- Image Bias Detection - Analyze visual content for representation problems
- Risk Assessment - Evaluate ML deployment scenarios for compliance risks
Each workflow uses an agentic reasoning system that: - Plans its analysis strategy - Selects appropriate tools dynamically - Iteratively refines outputs based on self-critique - Provides full transparency via event telemetry
Text Bias Analysis¶
Basic Usage¶
from fairsense_agentix import FairSense
engine = FairSense()
text = """
We need a rockstar developer who's a cultural fit for our young,
dynamic team. Must be willing to work long hours and weekends.
"""
result = engine.analyze_text(text)
# Access results
print(f"Bias Detected: {result.bias_detected}")
print(f"Risk Level: {result.risk_level}")
print(f"Summary: {result.summary}")
# Iterate through bias instances
for instance in result.bias_instances:
print(f"\nType: {instance.type}")
print(f"Severity: {instance.severity}")
print(f"Text: '{instance.text_span}'")
print(f"Explanation: {instance.explanation}")
print(f"Mitigation: {instance.mitigation_suggestion}")
Understanding the Result Object¶
The BiasResult object contains:
| Field | Type | Description |
|---|---|---|
bias_detected |
bool |
Whether any bias was found |
risk_level |
str |
Overall severity: low, medium, high |
summary |
str |
High-level explanation of findings |
bias_instances |
list[BiasInstance] |
Detailed bias findings |
highlighted_html |
str |
HTML with color-coded highlights |
metadata |
ResultMetadata |
Execution details (time, model, workflow ID) |
For the full list of fields (e.g. status, bias_analysis, ocr_text, errors), see the API Reference.
BiasInstance Fields:
| Field | Type | Description |
|---|---|---|
type |
str |
Bias category: gender, age, racial, disability, socioeconomic |
severity |
str |
Impact level: low, medium, high |
text_span |
str |
The problematic text excerpt |
explanation |
str |
Why this is biased |
mitigation_suggestion |
str |
How to fix it |
context |
str |
Surrounding text for context |
Advanced: Highlighted HTML Output¶
FairSense generates color-coded HTML for easy visualization:
result = engine.analyze_text(text)
# Save highlighted version
with open("analysis_output.html", "w") as f:
f.write(result.highlighted_html)
# Or display in Jupyter
from IPython.display import HTML
HTML(result.highlighted_html)
The HTML uses color coding:
- 🟥 Red - Gender bias
- 🟧 Orange - Age bias
- 🟨 Yellow - Racial bias
- 🟦 Blue - Disability bias
- 🟪 Purple - Socioeconomic bias
Common Use Cases¶
Job Postings¶
job_posting = """
Job Title: Senior Software Engineer
Requirements:
- Recent CS graduate preferred
- Native English speaker
- Must be able to work in a fast-paced environment
- Looking for someone who's a culture fit
"""
result = engine.analyze_text(job_posting)
# Check for hiring-related biases
for instance in result.bias_instances:
if instance.type in ["age", "racial"]:
print(f"⚠️ Legal Risk: {instance.text_span}")
print(f" Mitigation: {instance.mitigation_suggestion}")
Marketing Copy¶
ad_copy = """
Our product is designed for busy moms who need quick solutions
to help them manage their households while looking their best.
"""
result = engine.analyze_text(ad_copy)
# Identify gender stereotyping
gender_biases = [i for i in result.bias_instances if i.type == "gender"]
print(f"Found {len(gender_biases)} gender-related issues")
Content Moderation¶
user_comment = """
This feature is so easy to use, even my grandma could figure it out!
"""
result = engine.analyze_text(user_comment)
if result.bias_detected:
print(f"⚠️ Flagged for review: {result.summary}")
Image Bias Analysis¶
Basic Usage¶
from fairsense_agentix import FairSense
engine = FairSense()
# Load image file
with open("team_photo.jpg", "rb") as f:
image_bytes = f.read()
result = engine.analyze_image(image_bytes)
# Access results
print(f"Visual Description: {result.visual_description}")
print(f"Bias Detected: {result.bias_detected}")
print(f"Risk Level: {result.risk_level}")
# Bias instances for images
for instance in result.bias_instances:
print(f"\nType: {instance.type}")
print(f"Visual Element: {instance.visual_element}")
print(f"Explanation: {instance.explanation}")
Image Result Object¶
The image analysis result includes:
| Field | Type | Description |
|---|---|---|
visual_description |
str |
What the VLM sees in the image |
bias_detected |
bool |
Whether bias was found |
bias_instances |
list[BiasInstance] |
Visual bias findings |
image_base64 |
str |
Base64-encoded annotated image |
reasoning_trace |
str |
Agent's step-by-step reasoning |
BiasInstance for Images:
| Field | Type | Description |
|---|---|---|
type |
str |
Bias category |
visual_element |
str |
Description of problematic element |
explanation |
str |
Why this represents bias |
severity |
str |
Impact level |
Working with Different Image Sources¶
From File¶
From URL¶
import requests
url = "https://example.com/marketing-image.jpg"
image_bytes = requests.get(url).content
result = engine.analyze_image(image_bytes)
From PIL Image¶
from PIL import Image
import io
# Load and process PIL image
pil_image = Image.open("photo.jpg")
# Convert to bytes
buffer = io.BytesIO()
pil_image.save(buffer, format="JPEG")
image_bytes = buffer.getvalue()
result = engine.analyze_image(image_bytes)
Common Use Cases¶
Stock Photo Auditing¶
import os
# Analyze a directory of stock photos
for filename in os.listdir("stock_photos/"):
if filename.endswith((".jpg", ".png")):
with open(f"stock_photos/{filename}", "rb") as f:
result = engine.analyze_image(f.read())
if result.bias_detected:
print(f"\n⚠️ {filename}")
print(f" Risk: {result.risk_level}")
print(f" Issue: {result.summary}")
Marketing Material Review¶
# Check ad campaign images
campaign_images = ["ad_1.jpg", "ad_2.jpg", "ad_3.jpg"]
issues = []
for img_path in campaign_images:
with open(img_path, "rb") as f:
result = engine.analyze_image(f.read())
if result.risk_level in ["medium", "high"]:
issues.append({
"file": img_path,
"issues": result.bias_instances,
"description": result.visual_description
})
# Generate report
if issues:
print(f"Found {len(issues)} images needing review")
Risk Assessment¶
Basic Usage¶
from fairsense_agentix import FairSense
engine = FairSense()
scenario = """
We're deploying a loan approval system that uses historical data
from the past 10 years. The model uses applicant income, credit score,
employment history, and zip code to predict default risk.
"""
result = engine.assess_risk(scenario)
# Access results
print(f"Overall Risk: {result.risk_level}")
print(f"Total Risks Identified: {len(result.risks)}")
# Top risks
for risk in result.risks[:5]:
print(f"\n{risk.name} (Score: {risk.score:.2f}/100)")
print(f" Category: {risk.category}")
print(f" Description: {risk.description}")
print(f" Mitigation: {risk.mitigation}")
Risk Result Object¶
| Field | Type | Description |
|---|---|---|
risk_level |
str |
Overall severity: low, medium, high, critical |
risks |
list[RiskItem] |
Identified risks, sorted by score |
summary |
str |
High-level risk overview |
metadata |
ResultMetadata |
Execution details |
RiskItem Fields:
| Field | Type | Description |
|---|---|---|
name |
str |
Risk identifier |
category |
str |
Risk type: fairness, security, compliance, etc. |
score |
float |
Severity score (0-100) |
description |
str |
What the risk is |
mitigation |
str |
How to address it |
related_framework |
str |
AI-RMF, NIST, etc. |
CSV Dataset Analysis¶
For structured data, you can provide CSV content directly:
csv_data = """
age,gender,income,approved
25,M,50000,1
45,F,60000,0
30,M,55000,1
"""
# Describe the context
context = """
This is training data for a loan approval model. The 'approved' column
indicates whether the loan was historically approved (1) or denied (0).
"""
result = engine.assess_risk(context + "\n\n" + csv_data)
# Check for fairness risks
fairness_risks = [r for r in result.risks if r.category == "fairness"]
print(f"Found {len(fairness_risks)} fairness concerns")
Common Use Cases¶
Pre-Deployment Audit¶
deployment_plan = """
Model: GPT-4 fine-tuned on customer service transcripts
Use Case: Automated response generation for support tickets
Training Data: 500k customer interactions from 2020-2024
Deployment: Production API serving 10k requests/day
Monitoring: None currently planned
"""
result = engine.assess_risk(deployment_plan)
# Check critical risks
critical = [r for r in result.risks if r.score > 80]
if critical:
print("🚨 CRITICAL RISKS - DO NOT DEPLOY")
for risk in critical:
print(f" • {risk.name}: {risk.description}")
Compliance Check¶
# Check against regulatory frameworks
result = engine.assess_risk(scenario)
# Filter by compliance category
compliance_risks = [r for r in result.risks if r.category == "compliance"]
for risk in compliance_risks:
print(f"\n⚖️ {risk.name}")
print(f" Framework: {risk.related_framework}")
print(f" Mitigation: {risk.mitigation}")
Vendor Assessment¶
vendor_proposal = """
Vendor: ThirdParty ML Inc.
Product: Resume Screening AI
Claims: 95% accuracy, reduces hiring time by 60%
Training Data: Proprietary dataset (details not disclosed)
Explainability: Black-box model
"""
result = engine.assess_risk(vendor_proposal)
# Generate vendor scorecard
print(f"Vendor Risk Score: {sum(r.score for r in result.risks) / len(result.risks):.1f}/100")
print(f"High-Priority Concerns: {len([r for r in result.risks if r.score > 70])}")
Configuration¶
Environment Variables¶
All settings can be configured via environment variables or the .env file:
# === Core LLM Settings ===
FAIRSENSE_LLM_PROVIDER=anthropic
FAIRSENSE_LLM_MODEL_NAME=claude-3-5-sonnet-20241022
FAIRSENSE_LLM_API_KEY=your-key-here
FAIRSENSE_LLM_TEMPERATURE=0.7
FAIRSENSE_LLM_MAX_TOKENS=4096
# === Tool Selection ===
FAIRSENSE_OCR_TOOL=auto # tesseract, paddleocr, fake
FAIRSENSE_CAPTION_MODEL=auto # blip, blip2, fake
FAIRSENSE_EMBEDDING_PROVIDER=auto # sentence-transformers, openai
# === Agent Behavior ===
FAIRSENSE_ENABLE_REFINEMENT=true # Enable self-critique loop
FAIRSENSE_MAX_REFINEMENT_ITERATIONS=2
FAIRSENSE_EVALUATOR_ENABLED=true
FAIRSENSE_BIAS_EVALUATOR_MIN_SCORE=75
# === Performance ===
FAIRSENSE_WORKFLOW_TIMEOUT_SECONDS=300
FAIRSENSE_CACHE_ENABLED=true
FAIRSENSE_CACHE_TTL_SECONDS=3600
# === Server Settings ===
FAIRSENSE_API_HOST=0.0.0.0
FAIRSENSE_API_PORT=8000
FAIRSENSE_API_RELOAD=false
Programmatic Configuration¶
Override settings in code:
from fairsense_agentix import FairSense
from fairsense_agentix.configs.settings import Settings
# Create custom settings
settings = Settings(
llm_provider="anthropic",
llm_model_name="claude-3-5-sonnet-20241022",
enable_refinement=False, # Faster but lower quality
max_refinement_iterations=1
)
# Initialize engine with custom settings
engine = FairSense(settings=settings)
Per-Analysis Options¶
Pass options to individual analysis calls:
# Disable refinement for this specific analysis
result = engine.analyze_text(
text,
enable_refinement=False, # Skip self-critique
max_refinement_iterations=0
)
# Adjust LLM temperature
result = engine.analyze_text(
text,
llm_temperature=0.3 # More deterministic
)
Batch Processing¶
Process multiple items efficiently using the batch API:
Using the Python API¶
from fairsense_agentix import FairSense
engine = FairSense()
# Prepare batch items
texts = [
"Job posting 1...",
"Job posting 2...",
"Job posting 3...",
]
# Process in batch (runs sequentially with progress tracking)
results = []
for i, text in enumerate(texts, 1):
print(f"Processing {i}/{len(texts)}...")
result = engine.analyze_text(text)
results.append(result)
# Aggregate results
biased_count = sum(1 for r in results if r.bias_detected)
print(f"\n{biased_count}/{len(results)} items flagged")
Using the REST API¶
import requests
import time
# Submit batch job
batch_request = {
"items": [
{"content": "Text 1", "input_type": "bias_text"},
{"content": "Text 2", "input_type": "bias_text"},
{"content": "Text 3", "input_type": "bias_text"},
]
}
response = requests.post(
"http://localhost:8000/v1/batch",
json=batch_request
)
job_id = response.json()["job_id"]
# Poll for completion
while True:
status_response = requests.get(
f"http://localhost:8000/v1/batch/{job_id}"
)
status = status_response.json()
print(f"Progress: {status['completed']}/{status['total']}")
if status["status"] in ["completed", "failed"]:
break
time.sleep(5)
# Access results
results = status["results"]
REST API Usage¶
Analyze Text¶
import requests
response = requests.post(
"http://localhost:8000/v1/analyze",
json={
"content": "Your text here...",
"input_type": "bias_text", # Optional: auto-detected if omitted
"options": {} # Optional configuration
}
)
result = response.json()
print(result["bias_detected"])
Analyze Image (File Upload)¶
import requests
with open("image.jpg", "rb") as f:
files = {"file": f}
data = {"input_type": "bias_image"}
response = requests.post(
"http://localhost:8000/v1/analyze/upload",
files=files,
data=data
)
result = response.json()
WebSocket Streaming (Real-Time Events)¶
import websockets
import asyncio
import json
import requests
async def stream_analysis():
# Start analysis
response = requests.post(
"http://localhost:8000/v1/analyze/start",
json={"content": "Text to analyze..."}
)
run_id = response.json()["run_id"]
# Connect to event stream
uri = f"ws://localhost:8000/v1/stream/{run_id}"
async with websockets.connect(uri) as websocket:
async for message in websocket:
event = json.loads(message)
print(f"[{event['event']}] {event['context'].get('message', '')}")
# Check for completion
if event["event"] == "analysis_complete":
result = event["context"]["result"]
print(f"\n✅ Complete: {result['summary']}")
break
asyncio.run(stream_analysis())
Health Check¶
import requests
response = requests.get("http://localhost:8000/v1/health")
print(response.json()) # {"status": "ok"}
Best Practices¶
1. Use Refinement for Critical Applications¶
# Production: Enable refinement for high-stakes use cases
result = engine.analyze_text(
job_posting,
enable_refinement=True,
max_refinement_iterations=2
)
# Development/Testing: Disable for speed
result = engine.analyze_text(
test_text,
enable_refinement=False
)
2. Cache Results¶
# Enable caching to avoid re-analyzing identical content
from fairsense_agentix.configs.settings import Settings
settings = Settings(
cache_enabled=True,
cache_ttl_seconds=3600 # 1 hour
)
engine = FairSense(settings=settings)
3. Handle Errors Gracefully¶
from fairsense_agentix import FairSense
engine = FairSense()
try:
result = engine.analyze_text(text)
except Exception as e:
print(f"Analysis failed: {e}")
# Fallback logic or error reporting
4. Monitor Execution Time¶
result = engine.analyze_text(text)
# Check performance
exec_time = result.metadata.execution_time_seconds
print(f"Completed in {exec_time:.2f}s")
if exec_time > 60:
print("⚠️ Slow analysis - consider disabling refinement")
5. Aggregate Results for Reporting¶
# Process multiple documents
results = [engine.analyze_text(doc) for doc in documents]
# Generate summary report
total_biases = sum(len(r.bias_instances) for r in results)
avg_risk = sum(1 for r in results if r.risk_level == "high") / len(results)
print(f"Analysis Summary:")
print(f" Documents: {len(results)}")
print(f" Total Biases: {total_biases}")
print(f" High Risk: {avg_risk * 100:.1f}%")
Next Steps¶
- API Reference - Complete API documentation
- Server Guide - Running the web interface and REST API
- GitHub Examples - Additional code samples
Troubleshooting¶
"Analysis taking too long"¶
Cause: Refinement loop running multiple iterations
Solution:
# Reduce refinement iterations
result = engine.analyze_text(
text,
max_refinement_iterations=1
)
# Or disable entirely
result = engine.analyze_text(text, enable_refinement=False)
"Model download failed"¶
Cause: Network issues or disk space
Solution:
1. Check internet connection
2. Verify disk space: df -h ~/.cache/huggingface
3. Clear cache if needed: rm -rf ~/.cache/huggingface
"API rate limit exceeded"¶
Cause: Too many LLM API calls
Solution:
# Enable caching to reduce API calls
settings = Settings(cache_enabled=True)
engine = FairSense(settings=settings)
# Or use a local model
settings = Settings(
llm_provider="openai",
llm_base_url="http://localhost:11434/v1"
)
Need more help? Check the Getting Started guide or open an issue.