Nagendravarma commited on
Commit
bbbbe2c
Β·
1 Parent(s): c3938e0

Optimize latency: parallelize retrievals and reduce artificial stream delay

Browse files
Files changed (2) hide show
  1. backend/main.py +1 -1
  2. orchestration/orchestrator.py +44 -28
backend/main.py CHANGED
@@ -253,7 +253,7 @@ async def chat_stream(session_id: str, query: str, plan_tier: str = "Unknown"):
253
  # Emit individual sub-steps (each line from steps_log) with a small delay
254
  for step in new_steps:
255
  yield emit({"type": "substep", "node": node, "intent": intent, "step": step, "all_steps": current_steps})
256
- await asyncio.sleep(0.45) # pause between sub-steps so the user can see each node light up
257
 
258
  # Signal node completion
259
  final_answer = state.get("answer", "")
 
253
  # Emit individual sub-steps (each line from steps_log) with a small delay
254
  for step in new_steps:
255
  yield emit({"type": "substep", "node": node, "intent": intent, "step": step, "all_steps": current_steps})
256
+ await asyncio.sleep(0.05) # minimal pause for smooth UI without blocking stream
257
 
258
  # Signal node completion
259
  final_answer = state.get("answer", "")
orchestration/orchestrator.py CHANGED
@@ -35,6 +35,8 @@ Architecture (5 nodes in a directed StateGraph):
35
  import os
36
  import sys
37
  from typing import TypedDict, List
 
 
38
 
39
  # Ensure project root is on sys.path so `config` and sibling packages resolve
40
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
@@ -202,17 +204,23 @@ def retrieve(state: AgentState) -> AgentState:
202
  internal_logs = []
203
  token = trace_log.set(internal_logs)
204
 
 
 
 
205
  # ── SIMPLE_LOOKUP ────────────────────────────────────────────
206
  if intent == "SIMPLE_LOOKUP":
207
- log.append("πŸ“Š [SIMPLE_LOOKUP] Step 1 β€” Graph entity lookup")
208
- graph_ctx = relational_search.invoke({"query": query})
209
- if graph_ctx and "No structured" not in graph_ctx:
210
- parts.append(f"[STRUCTURED GRAPH FACTS]\n{graph_ctx}")
211
-
212
- log.append("πŸ“„ [SIMPLE_LOOKUP] Step 2 β€” Hybrid document retrieval")
213
- policy_ctx = policy_search.invoke({"query": query})
214
- if policy_ctx and "No relevant" not in policy_ctx:
215
- parts.append(f"[POLICY DOCUMENTS]\n{policy_ctx}")
 
 
 
216
 
217
  # ── POLICY_QUESTION ──────────────────────────────────────────
218
  elif intent == "POLICY_QUESTION":
@@ -223,28 +231,36 @@ def retrieve(state: AgentState) -> AgentState:
223
 
224
  # ── MULTI_HOP ────────────────────────────────────────────────
225
  elif intent == "MULTI_HOP":
226
- log.append("πŸ”— [MULTI_HOP] Step 1 β€” Graph entity lookup")
227
- graph_ctx = relational_search.invoke({"query": query})
228
- if graph_ctx and "No structured" not in graph_ctx:
229
- parts.append(f"[STRUCTURED GRAPH FACTS]\n{graph_ctx}")
230
-
231
- log.append("πŸ”— [MULTI_HOP] Step 2 β€” Hybrid policy retrieval")
232
- policy_ctx = policy_search.invoke({"query": query})
233
- if policy_ctx and "No relevant" not in policy_ctx:
234
- parts.append(f"[POLICY DOCUMENTS]\n{policy_ctx}")
235
-
236
- log.append("πŸ”— [MULTI_HOP] Step 3 β€” Prior authorization check")
237
- auth_ctx = prior_auth_search.invoke({"query": query})
238
- if auth_ctx and "No prior authorization" not in auth_ctx:
239
- parts.append(f"[PRIOR AUTHORIZATION RULES]\n{auth_ctx}")
 
 
 
240
 
241
  # ── COMPARISON ───────────────────────────────────────────────
242
  elif intent == "COMPARISON":
243
- for tier in ("Bronze", "Silver", "Gold"):
244
- log.append(f"βš–οΈ [COMPARISON] Retrieving {tier} plan context")
245
- tier_ctx = plan_comparison_search.invoke({"query": query, "tier": tier})
246
- if tier_ctx and f"No {tier}" not in tier_ctx:
247
- parts.append(f"[{tier.upper()} PLAN]\n{tier_ctx}")
 
 
 
 
 
248
 
249
  separator = "\n\n" + "─" * 60 + "\n\n"
250
  full_context = separator.join(parts) if parts else "No relevant context found."
 
35
  import os
36
  import sys
37
  from typing import TypedDict, List
38
+ import concurrent.futures
39
+ import contextvars
40
 
41
  # Ensure project root is on sys.path so `config` and sibling packages resolve
42
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
204
  internal_logs = []
205
  token = trace_log.set(internal_logs)
206
 
207
+ def _run_tool(tool_func, kwargs):
208
+ return contextvars.copy_context().run(tool_func, kwargs)
209
+
210
  # ── SIMPLE_LOOKUP ────────────────────────────────────────────
211
  if intent == "SIMPLE_LOOKUP":
212
+ log.append("πŸ“Š [SIMPLE_LOOKUP] Executing Graph & Hybrid retrieval concurrently")
213
+ with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
214
+ fut_g = executor.submit(_run_tool, relational_search.invoke, {"query": query})
215
+ fut_p = executor.submit(_run_tool, policy_search.invoke, {"query": query})
216
+
217
+ graph_ctx = fut_g.result()
218
+ if graph_ctx and "No structured" not in graph_ctx:
219
+ parts.append(f"[STRUCTURED GRAPH FACTS]\n{graph_ctx}")
220
+
221
+ policy_ctx = fut_p.result()
222
+ if policy_ctx and "No relevant" not in policy_ctx:
223
+ parts.append(f"[POLICY DOCUMENTS]\n{policy_ctx}")
224
 
225
  # ── POLICY_QUESTION ──────────────────────────────────────────
226
  elif intent == "POLICY_QUESTION":
 
231
 
232
  # ── MULTI_HOP ────────────────────────────────────────────────
233
  elif intent == "MULTI_HOP":
234
+ log.append("πŸ”— [MULTI_HOP] Executing Graph, Policy, and Prior-Auth retrievals concurrently")
235
+ with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
236
+ fut_g = executor.submit(_run_tool, relational_search.invoke, {"query": query})
237
+ fut_p = executor.submit(_run_tool, policy_search.invoke, {"query": query})
238
+ fut_a = executor.submit(_run_tool, prior_auth_search.invoke, {"query": query})
239
+
240
+ graph_ctx = fut_g.result()
241
+ if graph_ctx and "No structured" not in graph_ctx:
242
+ parts.append(f"[STRUCTURED GRAPH FACTS]\n{graph_ctx}")
243
+
244
+ policy_ctx = fut_p.result()
245
+ if policy_ctx and "No relevant" not in policy_ctx:
246
+ parts.append(f"[POLICY DOCUMENTS]\n{policy_ctx}")
247
+
248
+ auth_ctx = fut_a.result()
249
+ if auth_ctx and "No prior authorization" not in auth_ctx:
250
+ parts.append(f"[PRIOR AUTHORIZATION RULES]\n{auth_ctx}")
251
 
252
  # ── COMPARISON ───────────────────────────────────────────────
253
  elif intent == "COMPARISON":
254
+ log.append(f"βš–οΈ [COMPARISON] Retrieving Bronze, Silver, and Gold plan contexts concurrently")
255
+ with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
256
+ futures = {
257
+ tier: executor.submit(_run_tool, plan_comparison_search.invoke, {"query": query, "tier": tier})
258
+ for tier in ("Bronze", "Silver", "Gold")
259
+ }
260
+ for tier in ("Bronze", "Silver", "Gold"):
261
+ tier_ctx = futures[tier].result()
262
+ if tier_ctx and f"No {tier}" not in tier_ctx:
263
+ parts.append(f"[{tier.upper()} PLAN]\n{tier_ctx}")
264
 
265
  separator = "\n\n" + "─" * 60 + "\n\n"
266
  full_context = separator.join(parts) if parts else "No relevant context found."