YanBoChen commited on
Commit
4d836bc
Β·
1 Parent(s): 9731a88

fix(MedicalAdviceGenerator): enhance fallback generation with primary result simplification and increased token limits

Browse files
dataset/keywords/special_terms_emergency.json CHANGED
@@ -1,26 +1,31 @@
1
  {
2
- "cardiac": {
3
- "mi": ["mi", "m.i.", "myocardial infarction", "MI"],
4
- "acs": ["acs", "ACS", "acute coronary syndrome"]
5
- },
6
- "respiratory": {
7
- "ards": ["ards", "ARDS", "acute respiratory distress syndrome"],
8
- "respiratory_failure": ["respiratory failure", "resp failure", "RF"]
9
- },
10
- "neurological": {
11
- "loc": ["loc", "LOC", "loss of consciousness"],
12
- "cva": ["cva", "CVA", "stroke", "cerebrovascular accident"]
13
- },
14
- "shock": {
15
- "shock": ["shock", "circulatory failure"],
16
- "septic_shock": ["septic shock", "sepsis induced shock"]
17
- },
18
- "bleeding": {
19
- "gi_bleed": ["gi bleed", "gi bleeding", "gastrointestinal hemorrhage", "GI hemorrhage"],
20
- "hemorrhage": ["hemorrhage", "bleeding", "blood loss"]
21
- },
22
- "vital_signs": {
23
- "hypotension": ["hypotension", "low bp", "low blood pressure"],
24
- "tachycardia": ["tachycardia", "elevated heart rate", "fast heart rate"]
25
- }
26
- }
 
 
 
 
 
 
1
  {
2
+ "cardiac": {
3
+ "mi": ["mi", "m.i.", "myocardial infarction", "MI", "STEMI", "NSTEMI"],
4
+ "acs": ["acs", "ACS", "acute coronary syndrome"]
5
+ },
6
+ "respiratory": {
7
+ "ards": ["ards", "ARDS", "acute respiratory distress syndrome"],
8
+ "respiratory_failure": ["respiratory failure", "resp failure", "RF"]
9
+ },
10
+ "neurological": {
11
+ "loc": ["loc", "LOC", "loss of consciousness"],
12
+ "cva": ["cva", "CVA", "stroke", "cerebrovascular accident"]
13
+ },
14
+ "shock": {
15
+ "shock": ["shock", "circulatory failure"],
16
+ "septic_shock": ["septic shock", "sepsis induced shock"]
17
+ },
18
+ "bleeding": {
19
+ "gi_bleed": [
20
+ "gi bleed",
21
+ "gi bleeding",
22
+ "gastrointestinal hemorrhage",
23
+ "GI hemorrhage"
24
+ ],
25
+ "hemorrhage": ["hemorrhage", "bleeding", "blood loss"]
26
+ },
27
+ "vital_signs": {
28
+ "hypotension": ["hypotension", "low bp", "low blood pressure"],
29
+ "tachycardia": ["tachycardia", "elevated heart rate", "fast heart rate"]
30
+ }
31
+ }
src/generation.py CHANGED
@@ -31,14 +31,14 @@ logger = logging.getLogger(__name__)
31
  # Fallback Generation Configuration
32
  FALLBACK_TIMEOUTS = {
33
  "primary": 30.0, # Primary Med42-70B with full RAG context
34
- "fallback_1": 15.0, # Simplified Med42-70B without RAG
35
  "fallback_2": 1.0 # RAG template generation (instant)
36
  }
37
 
38
  FALLBACK_TOKEN_LIMITS = {
39
- "primary": 1200, # Full comprehensive medical advice
40
- "fallback_1": 600, # Concise medical guidance
41
- "fallback_2": 0 # Template-based, no LLM tokens
42
  }
43
 
44
  FALLBACK_CONFIDENCE_SCORES = {
@@ -363,8 +363,9 @@ class MedicalAdviceGenerator:
363
  # Check for API errors in response
364
  if result.get('error'):
365
  logger.warning(f"⚠️ Med42-70B returned error: {result['error']}")
366
- # Attempt fallback instead of raising exception
367
- return self._attempt_fallback_generation(prompt, result['error'])
 
368
 
369
  # Check for empty response
370
  if not result.get('raw_response', '').strip():
@@ -514,7 +515,7 @@ class MedicalAdviceGenerator:
514
  "disclaimer": "This system experienced a technical error. Please consult with qualified healthcare providers for medical decisions."
515
  }
516
 
517
- def _attempt_fallback_generation(self, original_prompt: str, primary_error: str) -> Dict[str, Any]:
518
  """
519
  Orchestrate fallback generation attempts with detailed logging
520
 
@@ -524,20 +525,38 @@ class MedicalAdviceGenerator:
524
  Args:
525
  original_prompt: The complete RAG prompt that failed in primary generation
526
  primary_error: Error details from the primary generation attempt
 
527
 
528
  Returns:
529
  Dict containing successful fallback response or final error response
530
  """
531
  logger.info("πŸ”„ FALLBACK: Attempting fallback generation strategies")
532
 
533
- # Fallback 1: Simplified Med42-70B without RAG context
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  try:
535
  logger.info("πŸ“ FALLBACK 1: Med42-70B without RAG context")
536
  fallback_1_result = self._attempt_simplified_med42(original_prompt, primary_error)
537
 
538
  if not fallback_1_result.get('error'):
539
  logger.info("βœ… FALLBACK 1: Success - Med42-70B without RAG")
540
- # Mark response as fallback method 1
541
  fallback_1_result['fallback_method'] = 'med42_simplified'
542
  fallback_1_result['primary_error'] = primary_error
543
  return fallback_1_result
@@ -588,6 +607,66 @@ class MedicalAdviceGenerator:
588
  'latency': 0.0
589
  }
590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  def _attempt_simplified_med42(self, original_prompt: str, primary_error: str) -> Dict[str, Any]:
592
  """
593
  Attempt Med42-70B generation with simplified prompt (Fallback 1)
 
31
  # Fallback Generation Configuration
32
  FALLBACK_TIMEOUTS = {
33
  "primary": 30.0, # Primary Med42-70B with full RAG context
34
+ "fallback_1": 15.0, # Simplified primary generation
35
  "fallback_2": 1.0 # RAG template generation (instant)
36
  }
37
 
38
  FALLBACK_TOKEN_LIMITS = {
39
+ "primary": 1600, # Full comprehensive medical advice (increased)
40
+ "fallback_1": 1200, # Simplified primary result (increased)
41
+ "fallback_2": 0 # Template-based, no LLM tokens
42
  }
43
 
44
  FALLBACK_CONFIDENCE_SCORES = {
 
363
  # Check for API errors in response
364
  if result.get('error'):
365
  logger.warning(f"⚠️ Med42-70B returned error: {result['error']}")
366
+ # Pass any available content for potential simplification
367
+ primary_content = result.get('raw_response', '')
368
+ return self._attempt_fallback_generation(prompt, result['error'], primary_content)
369
 
370
  # Check for empty response
371
  if not result.get('raw_response', '').strip():
 
515
  "disclaimer": "This system experienced a technical error. Please consult with qualified healthcare providers for medical decisions."
516
  }
517
 
518
+ def _attempt_fallback_generation(self, original_prompt: str, primary_error: str, primary_result: str = None) -> Dict[str, Any]:
519
  """
520
  Orchestrate fallback generation attempts with detailed logging
521
 
 
525
  Args:
526
  original_prompt: The complete RAG prompt that failed in primary generation
527
  primary_error: Error details from the primary generation attempt
528
+ primary_result: Primary result content (if available) for simplification
529
 
530
  Returns:
531
  Dict containing successful fallback response or final error response
532
  """
533
  logger.info("πŸ”„ FALLBACK: Attempting fallback generation strategies")
534
 
535
+ # Fallback 1: Try to simplify primary result first (if available)
536
+ if primary_result and primary_result.strip():
537
+ try:
538
+ logger.info("πŸ“ FALLBACK 1: Simplifying primary result")
539
+ user_query = self._extract_user_query_from_prompt(original_prompt)
540
+ fallback_1_result = self._simplify_primary_result(primary_result, user_query or "medical query")
541
+
542
+ if not fallback_1_result.get('error'):
543
+ logger.info("βœ… FALLBACK 1: Success - Primary result simplified")
544
+ fallback_1_result['fallback_method'] = 'primary_simplified'
545
+ fallback_1_result['primary_error'] = primary_error
546
+ return fallback_1_result
547
+ else:
548
+ logger.warning(f"❌ FALLBACK 1: Simplification failed - {fallback_1_result.get('error')}")
549
+
550
+ except Exception as e:
551
+ logger.error(f"❌ FALLBACK 1: Exception during simplification - {e}")
552
+
553
+ # Fallback 1 Alternative: Med42-70B without RAG context (if no primary result)
554
  try:
555
  logger.info("πŸ“ FALLBACK 1: Med42-70B without RAG context")
556
  fallback_1_result = self._attempt_simplified_med42(original_prompt, primary_error)
557
 
558
  if not fallback_1_result.get('error'):
559
  logger.info("βœ… FALLBACK 1: Success - Med42-70B without RAG")
 
560
  fallback_1_result['fallback_method'] = 'med42_simplified'
561
  fallback_1_result['primary_error'] = primary_error
562
  return fallback_1_result
 
607
  'latency': 0.0
608
  }
609
 
610
+ def _simplify_primary_result(self, primary_result: str, user_query: str) -> Dict[str, Any]:
611
+ """
612
+ Simplify the primary result into concise key points (Fallback 1)
613
+
614
+ This method takes the successful primary result and simplifies it using Med42-70B
615
+ to create a more concise version while preserving medical accuracy.
616
+
617
+ Args:
618
+ primary_result: The successful primary generation result
619
+ user_query: Original user query for context
620
+
621
+ Returns:
622
+ Dict with simplified result or error details
623
+ """
624
+ logger.info("πŸ“ FALLBACK 1: Simplifying primary result")
625
+
626
+ try:
627
+ # Create simplification prompt
628
+ simplification_prompt = f"""Summarize the following medical advice into concise, actionable key points:
629
+
630
+ Original Medical Advice:
631
+ {primary_result}
632
+
633
+ Original Query: {user_query}
634
+
635
+ Provide a clear, concise summary focusing on immediate clinical actions and key recommendations."""
636
+
637
+ logger.info(f"πŸ”„ FALLBACK 1: Simplifying with Med42-70B (max_tokens={FALLBACK_TOKEN_LIMITS['fallback_1']}, timeout={FALLBACK_TIMEOUTS['fallback_1']}s)")
638
+
639
+ # Call Med42-70B for simplification
640
+ result = self.llm_client.analyze_medical_query(
641
+ query=simplification_prompt,
642
+ max_tokens=FALLBACK_TOKEN_LIMITS["fallback_1"],
643
+ timeout=FALLBACK_TIMEOUTS["fallback_1"]
644
+ )
645
+
646
+ if result.get('status') == 'success' and result.get('response'):
647
+ simplified_advice = result['response'].strip()
648
+
649
+ if simplified_advice and len(simplified_advice) > 10:
650
+ logger.info("βœ… FALLBACK 1: Successfully simplified primary result")
651
+ return {
652
+ 'medical_advice': simplified_advice,
653
+ 'confidence_score': FALLBACK_CONFIDENCE_SCORES["fallback_1"],
654
+ 'latency': result.get('latency', 0.0),
655
+ 'fallback_method': 'primary_simplified',
656
+ 'error': None
657
+ }
658
+ else:
659
+ logger.error("❌ FALLBACK 1: Simplified result too short")
660
+ return {'error': 'Simplified result too short or empty'}
661
+ else:
662
+ error_msg = result.get('error', 'Unknown error during simplification')
663
+ logger.error(f"❌ FALLBACK 1: Simplification failed - {error_msg}")
664
+ return {'error': f'Simplification failed: {error_msg}'}
665
+
666
+ except Exception as e:
667
+ logger.error(f"❌ FALLBACK 1: Exception during simplification - {e}")
668
+ return {'error': f'Exception during simplification: {str(e)}'}
669
+
670
  def _attempt_simplified_med42(self, original_prompt: str, primary_error: str) -> Dict[str, Any]:
671
  """
672
  Attempt Med42-70B generation with simplified prompt (Fallback 1)