Agentic-RagBot / src /agents /clinical_guidelines.py
Nikhil Pravin Pise
Refactor: Improve code quality, security, and configuration
ad2e847
raw
history blame
10.1 kB
"""
MediGuard AI RAG-Helper
Clinical Guidelines Agent - Retrieves evidence-based recommendations
"""
from pathlib import Path
from typing import List
from src.state import GuildState, AgentOutput
from src.llm_config import llm_config
from langchain_core.prompts import ChatPromptTemplate
class ClinicalGuidelinesAgent:
"""Agent that retrieves clinical guidelines and recommendations using RAG"""
def __init__(self, retriever):
"""
Initialize with a retriever for clinical guidelines.
Args:
retriever: Vector store retriever for guidelines documents
"""
self.retriever = retriever
self.llm = llm_config.explainer
def recommend(self, state: GuildState) -> GuildState:
"""
Retrieve clinical guidelines and generate recommendations.
Args:
state: Current guild state
Returns:
Updated state with clinical recommendations
"""
print("\n" + "="*70)
print("EXECUTING: Clinical Guidelines Agent (RAG)")
print("="*70)
model_prediction = state['model_prediction']
disease = model_prediction['disease']
confidence = model_prediction['confidence']
# Get biomarker analysis
biomarker_analysis = state.get('biomarker_analysis') or {}
safety_alerts = biomarker_analysis.get('safety_alerts', [])
# Retrieve guidelines
print(f"\nRetrieving clinical guidelines for {disease}...")
query = f"""What are the clinical practice guidelines for managing {disease}?
Include lifestyle modifications, monitoring recommendations, and when to seek medical care."""
docs = self.retriever.invoke(query)
print(f"Retrieved {len(docs)} guideline documents")
# Generate recommendations
if state['sop'].require_pdf_citations and not docs:
recommendations = {
"immediate_actions": [
"Insufficient evidence available in the knowledge base. Please consult a healthcare provider."
],
"lifestyle_changes": [],
"monitoring": [],
"citations": []
}
else:
recommendations = self._generate_recommendations(
disease,
docs,
safety_alerts,
confidence,
state
)
# Create agent output
output = AgentOutput(
agent_name="Clinical Guidelines",
findings={
"disease": disease,
"immediate_actions": recommendations['immediate_actions'],
"lifestyle_changes": recommendations['lifestyle_changes'],
"monitoring": recommendations['monitoring'],
"guideline_citations": recommendations['citations'],
"safety_priority": len(safety_alerts) > 0,
"citations_missing": state['sop'].require_pdf_citations and not docs
}
)
# Update state
print("\nRecommendations generated")
print(f" - Immediate actions: {len(recommendations['immediate_actions'])}")
print(f" - Lifestyle changes: {len(recommendations['lifestyle_changes'])}")
print(f" - Monitoring recommendations: {len(recommendations['monitoring'])}")
return {'agent_outputs': [output]}
def _generate_recommendations(
self,
disease: str,
docs: list,
safety_alerts: list,
confidence: float,
state: GuildState
) -> dict:
"""Generate structured recommendations using LLM and guidelines"""
# Format retrieved guidelines
guidelines_context = "\n\n---\n\n".join([
f"Source: {doc.metadata.get('source', 'Unknown')}\n\n{doc.page_content}"
for doc in docs
])
# Build safety context
safety_context = ""
if safety_alerts:
safety_context = "\n**CRITICAL SAFETY ALERTS:**\n"
for alert in safety_alerts[:3]:
safety_context += f"- {alert.get('biomarker', 'Unknown')}: {alert.get('message', '')}\n"
prompt = ChatPromptTemplate.from_messages([
("system", """You are a clinical decision support system providing evidence-based recommendations.
Based on clinical practice guidelines, provide actionable recommendations for patient self-assessment.
Structure your response with these sections:
1. IMMEDIATE_ACTIONS: Urgent steps (especially if safety alerts present)
2. LIFESTYLE_CHANGES: Diet, exercise, and behavioral modifications
3. MONITORING: What to track and how often
Make recommendations specific, actionable, and guideline-aligned.
Always emphasize consulting healthcare professionals for diagnosis and treatment."""),
("human", """Disease: {disease}
Prediction Confidence: {confidence:.1%}
{safety_context}
Clinical Guidelines Context:
{guidelines}
Please provide structured recommendations for patient self-assessment.""")
])
chain = prompt | self.llm
try:
response = chain.invoke({
"disease": disease,
"confidence": confidence,
"safety_context": safety_context,
"guidelines": guidelines_context
})
recommendations = self._parse_recommendations(response.content)
except Exception as e:
print(f"Warning: LLM recommendation generation failed: {e}")
recommendations = self._get_default_recommendations(disease, safety_alerts)
# Add citations
recommendations['citations'] = self._extract_citations(docs)
return recommendations
def _parse_recommendations(self, content: str) -> dict:
"""Parse LLM response into structured recommendations"""
recommendations = {
"immediate_actions": [],
"lifestyle_changes": [],
"monitoring": []
}
current_section = None
lines = content.split('\n')
for line in lines:
line_stripped = line.strip()
line_upper = line_stripped.upper()
# Detect section headers
if 'IMMEDIATE' in line_upper or 'URGENT' in line_upper:
current_section = 'immediate_actions'
elif 'LIFESTYLE' in line_upper or 'CHANGES' in line_upper or 'DIET' in line_upper:
current_section = 'lifestyle_changes'
elif 'MONITORING' in line_upper or 'TRACK' in line_upper:
current_section = 'monitoring'
# Add bullet points or numbered items
elif current_section and line_stripped:
# Remove bullet points and numbers
cleaned = line_stripped.lstrip('•-*0123456789. ')
if cleaned and len(cleaned) > 10: # Minimum length filter
recommendations[current_section].append(cleaned)
# If parsing failed, create default structure
if not any(recommendations.values()):
sentences = content.split('.')
recommendations['immediate_actions'] = [s.strip() for s in sentences[:2] if s.strip()]
recommendations['lifestyle_changes'] = [s.strip() for s in sentences[2:4] if s.strip()]
recommendations['monitoring'] = [s.strip() for s in sentences[4:6] if s.strip()]
return recommendations
def _get_default_recommendations(self, disease: str, safety_alerts: list) -> dict:
"""Provide default recommendations if LLM fails"""
recommendations = {
"immediate_actions": [],
"lifestyle_changes": [],
"monitoring": []
}
# Add safety-based immediate actions
if safety_alerts:
recommendations['immediate_actions'].append(
"Consult healthcare provider immediately regarding critical biomarker values"
)
recommendations['immediate_actions'].append(
"Bring this report and recent lab results to your appointment"
)
else:
recommendations['immediate_actions'].append(
f"Schedule appointment with healthcare provider to discuss {disease} findings"
)
# Generic lifestyle changes
recommendations['lifestyle_changes'].extend([
"Follow a balanced, nutrient-rich diet as recommended by healthcare provider",
"Maintain regular physical activity appropriate for your health status",
"Track symptoms and biomarker trends over time"
])
# Generic monitoring
recommendations['monitoring'].extend([
f"Regular monitoring of {disease}-related biomarkers as advised by physician",
"Keep a health journal tracking symptoms, diet, and activities",
"Schedule follow-up appointments as recommended"
])
return recommendations
def _extract_citations(self, docs: list) -> List[str]:
"""Extract citations from retrieved guideline documents"""
citations = []
for doc in docs:
source = doc.metadata.get('source', 'Unknown')
# Clean up source path
if '\\' in source or '/' in source:
source = Path(source).name
citations.append(source)
return list(set(citations)) # Remove duplicates
def create_clinical_guidelines_agent(retriever):
"""Factory function to create agent with retriever"""
return ClinicalGuidelinesAgent(retriever)