Nagendravarma commited on
Commit ·
3ccaa67
1
Parent(s): 9b91537
Fix semantic cache false hits by adding plan tier, drug, specialty, and location entity matching
Browse files- orchestration/semantic_cache.py +52 -10
orchestration/semantic_cache.py
CHANGED
|
@@ -179,12 +179,41 @@ class SemanticCache:
|
|
| 179 |
logger.warning(f"Failed to normalize query: {e}. Using original query.")
|
| 180 |
return query
|
| 181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
def check(self, query: str, plan_tier: str = "Unknown", normalized_query: Optional[str] = None) -> Optional[dict]:
|
| 183 |
"""
|
| 184 |
Check the semantic cache for a match.
|
| 185 |
|
| 186 |
Returns:
|
| 187 |
-
|
| 188 |
"""
|
| 189 |
if not query or len(query.strip()) < 4:
|
| 190 |
return None
|
|
@@ -211,6 +240,13 @@ class SemanticCache:
|
|
| 211 |
if item.get("plan_tier", "Unknown").lower() != plan_tier.lower():
|
| 212 |
continue
|
| 213 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
sim = self._cosine_similarity(query_vector, item["vector"])
|
| 215 |
if sim > best_score:
|
| 216 |
best_score = sim
|
|
@@ -249,15 +285,21 @@ class SemanticCache:
|
|
| 249 |
similarity = 1.0 - (distance / 2.0)
|
| 250 |
|
| 251 |
if similarity >= SEMANTIC_CACHE_THRESHOLD:
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
|
| 262 |
except Exception as e:
|
| 263 |
logger.error(f"Error checking semantic cache: {e}")
|
|
|
|
| 179 |
logger.warning(f"Failed to normalize query: {e}. Using original query.")
|
| 180 |
return query
|
| 181 |
|
| 182 |
+
def _extract_entities(self, text: str) -> set:
|
| 183 |
+
"""Extract key plan tiers, drugs, specialties, and locations from query to prevent false semantic matches."""
|
| 184 |
+
key_entities = {
|
| 185 |
+
# Tiers
|
| 186 |
+
"bronze", "silver", "gold",
|
| 187 |
+
# Drugs
|
| 188 |
+
"metformin", "lisinopril", "amlodipine", "atorvastatin", "lipitor", "omeprazole",
|
| 189 |
+
"levothyroxine", "sertraline", "escitalopram", "fluoxetine", "alprazolam",
|
| 190 |
+
"lorazepam", "metoprolol", "carvedilol", "furosemide", "hydrochlorothiazide",
|
| 191 |
+
"tirzepatide", "etanercept", "spironolactone",
|
| 192 |
+
# Specialties
|
| 193 |
+
"pulmonology", "oncology", "pediatrics", "ophthalmology", "cardiology",
|
| 194 |
+
"urology", "hematology", "rheumatology", "nephrology", "dermatology", "dermatologist",
|
| 195 |
+
# Cities
|
| 196 |
+
"chicago", "rockford", "miami", "joliet", "naperville", "brooklyn",
|
| 197 |
+
"queens", "oakland", "springfield"
|
| 198 |
+
}
|
| 199 |
+
text_lower = text.lower()
|
| 200 |
+
found = set()
|
| 201 |
+
for ent in key_entities:
|
| 202 |
+
if ent in text_lower:
|
| 203 |
+
found.add(ent)
|
| 204 |
+
# Handle some common typos/synonyms
|
| 205 |
+
if "silbr" in text_lower:
|
| 206 |
+
found.add("silver")
|
| 207 |
+
if "dermatologist" in found:
|
| 208 |
+
found.add("dermatology")
|
| 209 |
+
return found
|
| 210 |
+
|
| 211 |
def check(self, query: str, plan_tier: str = "Unknown", normalized_query: Optional[str] = None) -> Optional[dict]:
|
| 212 |
"""
|
| 213 |
Check the semantic cache for a match.
|
| 214 |
|
| 215 |
Returns:
|
| 216 |
+
dict containing the response data and hit metadata if found, else None.
|
| 217 |
"""
|
| 218 |
if not query or len(query.strip()) < 4:
|
| 219 |
return None
|
|
|
|
| 240 |
if item.get("plan_tier", "Unknown").lower() != plan_tier.lower():
|
| 241 |
continue
|
| 242 |
|
| 243 |
+
# Entity safeguard check: ensure the key entities (tiers, drugs, specialties, locations)
|
| 244 |
+
# mentioned in the user's query match the cached item's query.
|
| 245 |
+
user_entities = self._extract_entities(norm_query)
|
| 246 |
+
cached_entities = self._extract_entities(item["query"])
|
| 247 |
+
if user_entities != cached_entities:
|
| 248 |
+
continue
|
| 249 |
+
|
| 250 |
sim = self._cosine_similarity(query_vector, item["vector"])
|
| 251 |
if sim > best_score:
|
| 252 |
best_score = sim
|
|
|
|
| 285 |
similarity = 1.0 - (distance / 2.0)
|
| 286 |
|
| 287 |
if similarity >= SEMANTIC_CACHE_THRESHOLD:
|
| 288 |
+
# Entity safeguard check
|
| 289 |
+
user_entities = self._extract_entities(norm_query)
|
| 290 |
+
cached_query = doc.metadata.get("original_query", doc.page_content)
|
| 291 |
+
cached_entities = self._extract_entities(cached_query)
|
| 292 |
+
|
| 293 |
+
if user_entities == cached_entities:
|
| 294 |
+
response_json = doc.metadata.get("response_json")
|
| 295 |
+
if response_json:
|
| 296 |
+
response = json.loads(response_json)
|
| 297 |
+
response["cached"] = True
|
| 298 |
+
response["cache_similarity"] = round(similarity * 100, 1)
|
| 299 |
+
response["matched_query"] = doc.metadata.get("original_query", doc.page_content)
|
| 300 |
+
|
| 301 |
+
logger.info(f"⚡ Local ChromaDB Cache HIT (Plan: {plan_tier}, Similarity: {response['cache_similarity']}%) in {time.time() - start_time:.3f}s")
|
| 302 |
+
return response
|
| 303 |
|
| 304 |
except Exception as e:
|
| 305 |
logger.error(f"Error checking semantic cache: {e}")
|