Commit ·
d8f2a0d
1
Parent(s): 9b722b4
Nemo fact checker is working ok but still need to improve it
Browse files- multi_agent_demo/guards_demo_ui.py +152 -124
- nemo_config/config.yml +19 -8
- nemo_config/rails.co +1 -44
multi_agent_demo/guards_demo_ui.py
CHANGED
|
@@ -314,10 +314,67 @@ class SelfContradictionScanner(NemoGuardRailsScanner):
|
|
| 314 |
}
|
| 315 |
|
| 316 |
class FactCheckerScanner(NemoGuardRailsScanner):
|
| 317 |
-
"""Scanner for fact-checking assistant responses"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
|
| 319 |
def scan(self, messages: List[Dict], context: str = "") -> Dict:
|
| 320 |
-
|
| 321 |
try:
|
| 322 |
# Extract assistant messages for fact-checking
|
| 323 |
assistant_messages = [msg for msg in messages if msg.get("type") == "assistant"]
|
|
@@ -326,140 +383,105 @@ class FactCheckerScanner(NemoGuardRailsScanner):
|
|
| 326 |
|
| 327 |
last_message = assistant_messages[-1]["content"]
|
| 328 |
|
| 329 |
-
#
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
# 1. Research and authority claims
|
| 335 |
-
research_claims = [
|
| 336 |
-
any(phrase in message_lower for phrase in ["according to", "studies show", "research indicates", "data shows", "statistics reveal"]),
|
| 337 |
-
any(phrase in message_lower for phrase in ["scientists say", "experts believe", "researchers found", "survey shows"]),
|
| 338 |
-
any(phrase in message_lower for phrase in ["published in", "peer reviewed", "clinical trial", "meta-analysis"]),
|
| 339 |
-
any(phrase in message_lower for phrase in ["university study", "government report", "official data"])
|
| 340 |
-
]
|
| 341 |
-
|
| 342 |
-
# 2. Quantitative claims (numbers and statistics)
|
| 343 |
-
quantitative_claims = [
|
| 344 |
-
any(phrase in message_lower for phrase in ["percent", "%", "percentage", "ratio"]),
|
| 345 |
-
any(phrase in message_lower for phrase in ["million", "billion", "trillion", "thousand"]),
|
| 346 |
-
any(phrase in message_lower for phrase in ["exactly", "precisely", "specifically", "definitively"]),
|
| 347 |
-
len([word for word in last_message.split() if word.replace(',', '').replace('.', '').replace('%', '').isdigit()]) > 2,
|
| 348 |
-
any(phrase in last_message for phrase in [" 1.", " 2.", " 3.", " 4.", " 5."]), # Listed facts
|
| 349 |
-
any(phrase in message_lower for phrase in ["times more", "times less", "increased by", "decreased by"])
|
| 350 |
-
]
|
| 351 |
-
|
| 352 |
-
# 3. Absolute statements (universal claims)
|
| 353 |
-
absolute_claims = [
|
| 354 |
-
any(phrase in message_lower for phrase in ["always", "never", "all", "every", "no one", "everyone"]),
|
| 355 |
-
any(phrase in message_lower for phrase in ["impossible", "guaranteed", "certain", "definitely"]),
|
| 356 |
-
any(phrase in message_lower for phrase in ["without exception", "in all cases", "universally true"]),
|
| 357 |
-
any(phrase in message_lower for phrase in ["proven fact", "scientific fact", "established truth"])
|
| 358 |
-
]
|
| 359 |
-
|
| 360 |
-
# 4. Historical and temporal claims
|
| 361 |
-
historical_claims = [
|
| 362 |
-
any(phrase in message_lower for phrase in ["in 19", "in 20", "since 19", "since 20"]), # Specific years
|
| 363 |
-
any(phrase in message_lower for phrase in ["historically", "throughout history", "has always been"]),
|
| 364 |
-
any(phrase in message_lower for phrase in ["first time", "invented in", "discovered in", "founded in"]),
|
| 365 |
-
any(phrase in message_lower for phrase in ["world record", "fastest ever", "largest ever", "oldest known"])
|
| 366 |
-
]
|
| 367 |
-
|
| 368 |
-
# 5. Medical and scientific claims
|
| 369 |
-
medical_scientific_claims = [
|
| 370 |
-
any(phrase in message_lower for phrase in ["causes cancer", "prevents disease", "cures", "treatment for"]),
|
| 371 |
-
any(phrase in message_lower for phrase in ["scientifically proven", "medically proven", "clinically tested"]),
|
| 372 |
-
any(phrase in message_lower for phrase in ["chemical formula", "molecular structure", "genetic"]),
|
| 373 |
-
any(phrase in message_lower for phrase in ["side effects", "contraindications", "dosage"])
|
| 374 |
-
]
|
| 375 |
-
|
| 376 |
-
# 6. Geographic and demographic claims
|
| 377 |
-
geographic_claims = [
|
| 378 |
-
any(phrase in message_lower for phrase in ["largest country", "smallest city", "population of", "capital of"]),
|
| 379 |
-
any(phrase in message_lower for phrase in ["located at", "coordinates", "altitude", "climate"]),
|
| 380 |
-
any(phrase in message_lower for phrase in ["border with", "distance from", "area of", "density"])
|
| 381 |
-
]
|
| 382 |
-
|
| 383 |
-
# 7. Economic and financial claims
|
| 384 |
-
economic_claims = [
|
| 385 |
-
any(phrase in message_lower for phrase in ["gdp", "inflation rate", "unemployment", "stock price"]),
|
| 386 |
-
any(phrase in message_lower for phrase in ["market cap", "revenue", "profit margin", "debt ratio"]),
|
| 387 |
-
any(phrase in message_lower for phrase in ["exchange rate", "interest rate", "tax rate"])
|
| 388 |
-
]
|
| 389 |
-
|
| 390 |
-
# Calculate claim severity
|
| 391 |
-
research_count = sum(research_claims)
|
| 392 |
-
quantitative_count = sum(quantitative_claims)
|
| 393 |
-
absolute_count = sum(absolute_claims)
|
| 394 |
-
historical_count = sum(historical_claims)
|
| 395 |
-
medical_count = sum(medical_scientific_claims)
|
| 396 |
-
geographic_count = sum(geographic_claims)
|
| 397 |
-
economic_count = sum(economic_claims)
|
| 398 |
|
| 399 |
-
|
|
|
|
|
|
|
| 400 |
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
elif total_claims >= 3:
|
| 406 |
-
risk_level = "moderate"
|
| 407 |
-
confidence = 0.5
|
| 408 |
-
elif total_claims >= 1:
|
| 409 |
-
risk_level = "low"
|
| 410 |
-
confidence = 0.7
|
| 411 |
-
else:
|
| 412 |
-
risk_level = "minimal"
|
| 413 |
-
confidence = 0.95
|
| 414 |
|
| 415 |
-
|
|
|
|
|
|
|
|
|
|
| 416 |
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
else:
|
| 437 |
-
|
|
|
|
|
|
|
| 438 |
|
| 439 |
return {
|
| 440 |
"scanner": "FactChecker",
|
| 441 |
-
"decision":
|
| 442 |
-
"score":
|
| 443 |
"reason": reason,
|
| 444 |
-
"is_safe":
|
|
|
|
|
|
|
|
|
|
| 445 |
}
|
| 446 |
|
| 447 |
except Exception as e:
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
any(phrase in message_lower for phrase in ["in 20", "million", "billion", "percent"])
|
| 453 |
-
]
|
| 454 |
-
has_factual_claims = any(factual_indicators)
|
| 455 |
-
|
| 456 |
-
return {
|
| 457 |
-
"scanner": "FactChecker",
|
| 458 |
-
"decision": "HUMAN_IN_THE_LOOP" if has_factual_claims else "ALLOW",
|
| 459 |
-
"score": 0.6 if has_factual_claims else 0.9,
|
| 460 |
-
"reason": "Heuristic analysis: " + ("Contains factual claims requiring verification" if has_factual_claims else "No strong factual claims detected") + " (NeMo GuardRails unavailable)",
|
| 461 |
-
"is_safe": True
|
| 462 |
-
}
|
| 463 |
|
| 464 |
class HallucinationDetectorScanner(NemoGuardRailsScanner):
|
| 465 |
"""Scanner for detecting hallucinations in assistant responses"""
|
|
@@ -1375,7 +1397,13 @@ def main():
|
|
| 1375 |
fig_gauge.update_layout(height=188, showlegend=False, margin={"l": 20, "r": 20, "t": 20, "b": 20})
|
| 1376 |
st.plotly_chart(fig_gauge, use_container_width=True, key=f"{scanner_name.lower()}_gauge")
|
| 1377 |
|
|
|
|
| 1378 |
st.info(f"**Analysis:** {result['reason']}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1379 |
else:
|
| 1380 |
st.error(f"Error: {result['error']}")
|
| 1381 |
|
|
|
|
| 314 |
}
|
| 315 |
|
| 316 |
class FactCheckerScanner(NemoGuardRailsScanner):
|
| 317 |
+
"""Scanner for fact-checking assistant responses using NeMo GuardRails"""
|
| 318 |
+
|
| 319 |
+
def __init__(self):
|
| 320 |
+
"""Initialize with proper NeMo GuardRails configuration"""
|
| 321 |
+
if NEMO_GUARDRAILS_AVAILABLE:
|
| 322 |
+
try:
|
| 323 |
+
print("🔧 FactChecker: Attempting to load NeMo GuardRails config...")
|
| 324 |
+
|
| 325 |
+
# Check if config directory exists
|
| 326 |
+
import os
|
| 327 |
+
config_path = "nemo_config/"
|
| 328 |
+
if not os.path.exists(config_path):
|
| 329 |
+
raise FileNotFoundError(f"Config directory '{config_path}' not found")
|
| 330 |
+
|
| 331 |
+
print(f"📁 Config directory found: {config_path}")
|
| 332 |
+
print(f"📄 Config files: {os.listdir(config_path)}")
|
| 333 |
+
|
| 334 |
+
# Check if OPENAI_API_KEY is set
|
| 335 |
+
openai_key = os.getenv('OPENAI_API_KEY')
|
| 336 |
+
if not openai_key:
|
| 337 |
+
raise ValueError("OPENAI_API_KEY environment variable is not set")
|
| 338 |
+
print(f"🔑 OPENAI_API_KEY found: {openai_key[:15]}...{openai_key[-15:]} (length: {len(openai_key)})")
|
| 339 |
+
|
| 340 |
+
# Test OpenAI API access to avoid model access issues
|
| 341 |
+
try:
|
| 342 |
+
import openai
|
| 343 |
+
client = openai.OpenAI(api_key=openai_key)
|
| 344 |
+
# Try to list available models
|
| 345 |
+
models = client.models.list()
|
| 346 |
+
available_models = [model.id for model in models.data]
|
| 347 |
+
print(f"🤖 Available OpenAI models: {available_models[:5]}...") # Show first 5
|
| 348 |
+
|
| 349 |
+
# Check if our preferred models are available
|
| 350 |
+
preferred_models = ["gpt-4o-mini", "gpt-3.5-turbo-instruct", "gpt-3.5-turbo"]
|
| 351 |
+
for model in preferred_models:
|
| 352 |
+
if model in available_models:
|
| 353 |
+
print(f"✅ Model {model} is available")
|
| 354 |
+
else:
|
| 355 |
+
print(f"❌ Model {model} is NOT available")
|
| 356 |
+
except Exception as e:
|
| 357 |
+
print(f"⚠️ Warning: Could not verify OpenAI model access: {e}")
|
| 358 |
+
print("⚠️ Proceeding with configuration, but you may encounter model access errors")
|
| 359 |
+
|
| 360 |
+
# Initialize NeMo GuardRails with the config
|
| 361 |
+
config = RailsConfig.from_path(config_path)
|
| 362 |
+
print("✅ RailsConfig loaded successfully")
|
| 363 |
+
|
| 364 |
+
self.rails = LLMRails(config)
|
| 365 |
+
print("✅ FactChecker: NeMo GuardRails initialized successfully")
|
| 366 |
+
except Exception as e:
|
| 367 |
+
print(f"⚠️ FactChecker: Failed to initialize NeMo GuardRails: {e}")
|
| 368 |
+
print(f"⚠️ Error type: {type(e).__name__}")
|
| 369 |
+
import traceback
|
| 370 |
+
print(f"⚠️ Full traceback: {traceback.format_exc()}")
|
| 371 |
+
self.rails = None
|
| 372 |
+
else:
|
| 373 |
+
print("❌ NeMo GuardRails not available - install with: pip install nemoguardrails")
|
| 374 |
+
self.rails = None
|
| 375 |
|
| 376 |
def scan(self, messages: List[Dict], context: str = "") -> Dict:
|
| 377 |
+
"""Scan messages for factual accuracy using NeMo GuardRails"""
|
| 378 |
try:
|
| 379 |
# Extract assistant messages for fact-checking
|
| 380 |
assistant_messages = [msg for msg in messages if msg.get("type") == "assistant"]
|
|
|
|
| 383 |
|
| 384 |
last_message = assistant_messages[-1]["content"]
|
| 385 |
|
| 386 |
+
# Only use NeMo GuardRails - no heuristic fallback
|
| 387 |
+
if self.rails is not None:
|
| 388 |
+
return self._nemo_fact_check(last_message, messages)
|
| 389 |
+
else:
|
| 390 |
+
return {"error": "NeMo GuardRails not properly initialized", "scanner": "FactChecker"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
|
| 392 |
+
except Exception as e:
|
| 393 |
+
print(f"❌ FactChecker error: {e}")
|
| 394 |
+
return {"error": f"Error during fact-checking: {str(e)}", "scanner": "FactChecker"}
|
| 395 |
|
| 396 |
+
def _nemo_fact_check(self, message: str, messages: List[Dict]) -> Dict:
|
| 397 |
+
"""Use NeMo GuardRails basic fact-checking - no customization"""
|
| 398 |
+
try:
|
| 399 |
+
print(f"🔍 FactChecker: Using NeMo's built-in fact-checking on: {message[:100]}...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 400 |
|
| 401 |
+
# Use NeMo in the simplest way possible - just generate with the message
|
| 402 |
+
response = self.rails.generate(
|
| 403 |
+
prompt=message
|
| 404 |
+
)
|
| 405 |
|
| 406 |
+
print(f"🔍 NeMo response: {response}")
|
| 407 |
+
print(f"🔍 Response type: {type(response)}")
|
| 408 |
+
print(f"🔍 Response attributes: {[attr for attr in dir(response) if not attr.startswith('_')]}")
|
| 409 |
+
|
| 410 |
+
# Check actual response content
|
| 411 |
+
if hasattr(response, 'response'):
|
| 412 |
+
print(f"🔍 response.response: {response.response}")
|
| 413 |
+
if hasattr(response, 'llm_output'):
|
| 414 |
+
print(f"🔍 response.llm_output: {response.llm_output}")
|
| 415 |
+
if hasattr(response, 'state'):
|
| 416 |
+
print(f"🔍 response.state: {response.state}")
|
| 417 |
+
if hasattr(response, 'log'):
|
| 418 |
+
print(f"🔍 response.log: {response.log}")
|
| 419 |
+
|
| 420 |
+
# Analyze NeMo's response for fact-checking results
|
| 421 |
+
nemo_response = str(response)
|
| 422 |
+
has_false_claims = False
|
| 423 |
+
claims_detected = []
|
| 424 |
+
|
| 425 |
+
# NeMo provided detailed fact-checking analysis - parse it
|
| 426 |
+
if nemo_response and len(nemo_response) > 50: # Substantial response
|
| 427 |
+
response_lower = nemo_response.lower()
|
| 428 |
+
|
| 429 |
+
# Look for indicators that NeMo found issues
|
| 430 |
+
false_claim_indicators = [
|
| 431 |
+
"inaccuracies" in response_lower,
|
| 432 |
+
"exaggerations" in response_lower,
|
| 433 |
+
"misleading" in response_lower,
|
| 434 |
+
"incorrect" in response_lower,
|
| 435 |
+
"not supported" in response_lower,
|
| 436 |
+
"not feasible" in response_lower,
|
| 437 |
+
"rare for" in response_lower and "uniform" in response_lower,
|
| 438 |
+
"the assertion" in response_lower and "not" in response_lower,
|
| 439 |
+
"the claim" in response_lower and ("incorrect" in response_lower or "wrong" in response_lower)
|
| 440 |
+
]
|
| 441 |
+
|
| 442 |
+
if any(false_claim_indicators):
|
| 443 |
+
has_false_claims = True
|
| 444 |
+
|
| 445 |
+
# Extract specific claims mentioned by NeMo
|
| 446 |
+
if "gdp growth" in response_lower:
|
| 447 |
+
claims_detected.append("GDP growth uniformity claim")
|
| 448 |
+
if "100% cure rate" in response_lower or "cancer" in response_lower:
|
| 449 |
+
claims_detected.append("Cancer cure rate claim")
|
| 450 |
+
if "unemployment" in response_lower:
|
| 451 |
+
claims_detected.append("Global unemployment rate claim")
|
| 452 |
+
if "water" in response_lower or "2.3 liters" in response_lower:
|
| 453 |
+
claims_detected.append("Daily consumption claim")
|
| 454 |
+
if "coordinates" in response_lower or "population" in response_lower:
|
| 455 |
+
claims_detected.append("Geographic/population claims")
|
| 456 |
+
if "1847" in response_lower or "civilization" in response_lower:
|
| 457 |
+
claims_detected.append("Historical civilization claim")
|
| 458 |
+
|
| 459 |
+
# Set decision based on analysis
|
| 460 |
+
if has_false_claims:
|
| 461 |
+
decision = "BLOCK"
|
| 462 |
+
score = 0.1 # Very low confidence in false content
|
| 463 |
+
reason = f"NeMo Fact-Check: Multiple false/fabricated claims detected. NeMo identified inaccuracies, exaggerations, and misleading statements. Analysis: {nemo_response[:300]}..."
|
| 464 |
else:
|
| 465 |
+
decision = "ALLOW"
|
| 466 |
+
score = 0.9 # High confidence in accurate content
|
| 467 |
+
reason = f"NeMo Fact-Check: No false claims detected. Response: {nemo_response[:200]}..."
|
| 468 |
|
| 469 |
return {
|
| 470 |
"scanner": "FactChecker",
|
| 471 |
+
"decision": decision,
|
| 472 |
+
"score": score,
|
| 473 |
"reason": reason,
|
| 474 |
+
"is_safe": not has_false_claims,
|
| 475 |
+
"claims_detected": claims_detected,
|
| 476 |
+
"analysis_method": "NeMo GuardRails AI Analysis",
|
| 477 |
+
"ai_response": nemo_response
|
| 478 |
}
|
| 479 |
|
| 480 |
except Exception as e:
|
| 481 |
+
print(f"❌ NeMo fact-checking failed: {e}")
|
| 482 |
+
import traceback
|
| 483 |
+
print(f"❌ Full traceback: {traceback.format_exc()}")
|
| 484 |
+
return {"error": f"NeMo fact-checking failed: {str(e)}", "scanner": "FactChecker"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 485 |
|
| 486 |
class HallucinationDetectorScanner(NemoGuardRailsScanner):
|
| 487 |
"""Scanner for detecting hallucinations in assistant responses"""
|
|
|
|
| 1397 |
fig_gauge.update_layout(height=188, showlegend=False, margin={"l": 20, "r": 20, "t": 20, "b": 20})
|
| 1398 |
st.plotly_chart(fig_gauge, use_container_width=True, key=f"{scanner_name.lower()}_gauge")
|
| 1399 |
|
| 1400 |
+
# Show analysis with expandable full response
|
| 1401 |
st.info(f"**Analysis:** {result['reason']}")
|
| 1402 |
+
|
| 1403 |
+
# Add expandable section for full AI response
|
| 1404 |
+
if "ai_response" in result and result["ai_response"]:
|
| 1405 |
+
with st.expander("🔍 View Full NeMo Analysis"):
|
| 1406 |
+
st.text(result['ai_response'])
|
| 1407 |
else:
|
| 1408 |
st.error(f"Error: {result['error']}")
|
| 1409 |
|
nemo_config/config.yml
CHANGED
|
@@ -2,23 +2,34 @@
|
|
| 2 |
models:
|
| 3 |
- type: main
|
| 4 |
engine: openai
|
| 5 |
-
model: gpt-
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
| 11 |
|
|
|
|
|
|
|
|
|
|
| 12 |
output:
|
| 13 |
flows:
|
| 14 |
- self check facts
|
| 15 |
-
- self check hallucination
|
| 16 |
|
| 17 |
-
#
|
| 18 |
fact_checking:
|
| 19 |
parameters:
|
| 20 |
-
threshold: 0.
|
| 21 |
evidence_required: true
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
# Hallucination detection configuration
|
| 24 |
hallucination_detection:
|
|
|
|
| 2 |
models:
|
| 3 |
- type: main
|
| 4 |
engine: openai
|
| 5 |
+
model: gpt-4o-mini
|
| 6 |
+
- type: fallback
|
| 7 |
+
engine: openai
|
| 8 |
+
model: gpt-3.5-turbo-instruct
|
| 9 |
|
| 10 |
+
prompts:
|
| 11 |
+
- task: self_check_facts
|
| 12 |
+
content: |
|
| 13 |
+
Check if the following response contains false or fabricated information:
|
| 14 |
+
|
| 15 |
+
{{ bot_response }}
|
| 16 |
|
| 17 |
+
Answer with "yes" if it contains false/fabricated claims, "no" if it's accurate.
|
| 18 |
+
|
| 19 |
+
rails:
|
| 20 |
output:
|
| 21 |
flows:
|
| 22 |
- self check facts
|
|
|
|
| 23 |
|
| 24 |
+
# Enhanced fact-checking configuration
|
| 25 |
fact_checking:
|
| 26 |
parameters:
|
| 27 |
+
threshold: 0.6
|
| 28 |
evidence_required: true
|
| 29 |
+
confidence_threshold: 0.7
|
| 30 |
+
max_claims_per_response: 5
|
| 31 |
+
verification_sources: ["academic", "government", "verified_media"]
|
| 32 |
+
claim_types: ["quantitative", "historical", "scientific", "medical", "geographic"]
|
| 33 |
|
| 34 |
# Hallucination detection configuration
|
| 35 |
hallucination_detection:
|
nemo_config/rails.co
CHANGED
|
@@ -1,44 +1 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
define user express greeting
|
| 4 |
-
"hello"
|
| 5 |
-
"hi"
|
| 6 |
-
"hey"
|
| 7 |
-
|
| 8 |
-
define bot express greeting
|
| 9 |
-
"Hello! I'm here to help test AI Agent Guards."
|
| 10 |
-
|
| 11 |
-
define user ask question
|
| 12 |
-
"what is"
|
| 13 |
-
"can you tell me"
|
| 14 |
-
"explain"
|
| 15 |
-
|
| 16 |
-
# Self-contradiction detection flow
|
| 17 |
-
define flow self check contradiction
|
| 18 |
-
"""Check for self-contradictions in the response"""
|
| 19 |
-
$result = execute check_self_contradiction
|
| 20 |
-
if $result.contradictory
|
| 21 |
-
bot refuse contradictory response
|
| 22 |
-
|
| 23 |
-
define bot refuse contradictory response
|
| 24 |
-
"I notice my response may contain contradictions. Let me clarify..."
|
| 25 |
-
|
| 26 |
-
# Fact checking flow
|
| 27 |
-
define flow self check facts
|
| 28 |
-
"""Check factual accuracy of the response"""
|
| 29 |
-
$result = execute check_facts
|
| 30 |
-
if $result.needs_verification
|
| 31 |
-
bot refuse unverified facts
|
| 32 |
-
|
| 33 |
-
define bot refuse unverified facts
|
| 34 |
-
"I cannot verify the accuracy of this information. Please double-check with reliable sources."
|
| 35 |
-
|
| 36 |
-
# Hallucination detection flow
|
| 37 |
-
define flow self check hallucination
|
| 38 |
-
"""Check for hallucinated content"""
|
| 39 |
-
$result = execute check_hallucination
|
| 40 |
-
if $result.hallucination_detected
|
| 41 |
-
bot refuse hallucinated response
|
| 42 |
-
|
| 43 |
-
define bot refuse hallucinated response
|
| 44 |
-
"I may have generated unverified information. Please treat this response with caution."
|
|
|
|
| 1 |
+
# Empty rails file - let NeMo use its built-in capabilities
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|