Spaces:
Sleeping
Sleeping
Deploy v1 — single-Docker FastAPI + Next.js + RAG + voice + faithfulness
Browse files- backend/orchestrator.py +33 -2
backend/orchestrator.py
CHANGED
|
@@ -202,10 +202,41 @@ async def handle_turn(
|
|
| 202 |
user_text=user_text,
|
| 203 |
run_llm_judge=True,
|
| 204 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
blocked = False
|
|
|
|
| 206 |
if not verdict.passed:
|
| 207 |
-
|
| 208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
|
| 210 |
# 6. Citations (derived from retrieved chunks)
|
| 211 |
citations = [
|
|
|
|
| 202 |
user_text=user_text,
|
| 203 |
run_llm_judge=True,
|
| 204 |
)
|
| 205 |
+
|
| 206 |
+
# 5a. CROSS-CHECK RETRY — if faithfulness blocked AND the failure isn't
|
| 207 |
+
# Gate 1 (no evidence at all), try a DIFFERENT-FAMILY brain. The most
|
| 208 |
+
# common Sarvam-M failure mode is over-confident cross-policy citations
|
| 209 |
+
# (e.g. answering about "Activ Health" but citing "Activ Secure" chunks).
|
| 210 |
+
# A fresh DeepSeek-V3 pass with the same chunks tends to handle this
|
| 211 |
+
# better. Capped at ONE retry — no loops.
|
| 212 |
blocked = False
|
| 213 |
+
retry_used = False
|
| 214 |
if not verdict.passed:
|
| 215 |
+
gate1_failure = any("gate1_retrieval" in r for r in verdict.reasons)
|
| 216 |
+
primary_was_sarvam = pick.provider.name == "sarvam-m"
|
| 217 |
+
if (not gate1_failure) and primary_was_sarvam:
|
| 218 |
+
try:
|
| 219 |
+
secondary = OpenRouterLLM()
|
| 220 |
+
retry_used = True
|
| 221 |
+
second = await secondary.chat(messages=messages, temperature=0.1, max_tokens=1500)
|
| 222 |
+
second_reply = strip_think_tags(second.text)
|
| 223 |
+
second_verdict = await check_faithfulness(
|
| 224 |
+
reply=second_reply, chunks=chunks, user_text=user_text, run_llm_judge=True,
|
| 225 |
+
)
|
| 226 |
+
if second_verdict.passed:
|
| 227 |
+
# Use the second-brain reply
|
| 228 |
+
reply = second_reply
|
| 229 |
+
pick = BrainPick(secondary, f"crosscheck-rescued-{pick.provider.name}")
|
| 230 |
+
verdict = second_verdict
|
| 231 |
+
else:
|
| 232 |
+
blocked = True
|
| 233 |
+
reply = verdict.suggested_reply or "I don't have grounded evidence for that. Could you rephrase?"
|
| 234 |
+
except Exception:
|
| 235 |
+
blocked = True
|
| 236 |
+
reply = verdict.suggested_reply or "I don't have grounded evidence for that. Could you rephrase?"
|
| 237 |
+
else:
|
| 238 |
+
blocked = True
|
| 239 |
+
reply = verdict.suggested_reply or "I don't have grounded evidence for that. Could you rephrase?"
|
| 240 |
|
| 241 |
# 6. Citations (derived from retrieved chunks)
|
| 242 |
citations = [
|