
    52iK                     4   S r SSKJrJrJrJrJrJr  SSKJ	r	  SSK
r
SSKJr   SSKJrJr  SSKJr  SrSSKJr  SSKJr   " S S\5      r " S S5      r " S S5      r " S S5      r " S S5      r " S S5      r " S S5      r " S S5      rS\S\S\4S  jr \!S!:X  aa  \" S"5        \" S#5        \" S$5        \" S%5        \" S&5        \" S'5        \" S(5        \" S)5        \" S*5        \" S+5        \" S,5        \" S-5        gg! \ a    S	r\" S
5         Nf = f).aP  
Modular RAG Orchestrator using LangGraph

This implements a multi-agent RAG system where specialized sub-agents handle
different aspects of the retrieval and generation pipeline. The orchestrator
coordinates these agents using LangGraph for complex workflows.

Architecture Overview:
- QueryAnalyzer: Classifies questions, extracts entities, determines strategy
- RetrieverAgent: Handles multi-modal retrieval (semantic, keyword, hybrid)
- KnowledgeSynthesizer: Combines retrieved info with existing knowledge
- AnswerGenerator: Uses LLM to generate coherent responses
- FactChecker: Validates claims against sources
- MemoryManager: Maintains conversation context
- EntityGraphAgent: Manages entity relationships and multi-hop queries

The orchestrator routes queries through appropriate agent combinations based on
question type and complexity.
    )DictListAnyOptional	TypedDict	Annotated)PathN)datetime)
StateGraphEND)BaseMessageTFzEWarning: LangGraph not available. Install with: pip install langgraph)RAGAgent)VectorStorec                       \ rS rSr% Sr\\S'   \\S'   \\   \S'   \\\\	4      \S'   \\\\	4      \S'   \\S'   \\S	'   \\\\	4      \S
'   \\   \S'   \\   \S'   \
\S'   \\S'   \\S'   Srg)
AgentState'   z+State passed between agents in the workflowquestionquestion_typeentitiessearch_resultsdistilled_insightscontextanswersourcesmemoryentity_hints
confidenceneeds_fact_checkfinal_answer N)__name__
__module____qualname____firstlineno____doc__str__annotations__r   r   r   floatbool__static_attributes__r        modular_orchestrator.pyr   r   '   s    5M3ic3h((T#s(^,,LK$sCx.!!Is)r+   r   c                       \ rS rSrSrS\4S jrS\S\\\	4   4S jr
S\S\\   4S jrS\S	\\   S\4S
 jrS\S\S\\   4S jrS\S	\\   S\4S jrSrg)QueryAnalyzer8   z3Analyzes questions to determine processing strategy	rag_agentc                     Xl         g Nr0   selfr0   s     r,   __init__QueryAnalyzer.__init__;       "r+   r   returnc                     U R                   R                  U5      nU R                  U5      nU R                  X5      nUUUU R	                  X$5      U R                  X#5      S.$ )z6Analyze question and return processing recommendations)r   r   
complexityrequired_agentsretrieval_strategy)r0   analyze_question_extract_entities_assess_complexity_get_required_agents_choose_retrieval_strategy)r5   r   r   r   r;   s        r,   analyzeQueryAnalyzer.analyze>   sk    77A ))(3 ,,X@
 + $#88S"&"A"A-"Z
 	
r+   c                     UR                  5       R                  5       n/ nU H?  nUS   R                  5       (       d  M  [        U5      S:  d  M.  UR	                  U5        MA     [        [        U5      5      $ )z$Extract named entities from questionr      )lowersplitisupperlenappendlistset)r5   r   wordsr   words        r,   r?   QueryAnalyzer._extract_entitiesP   sb      &&( DAw  SY]%  CM""r+   r   c                     [        UR                  5       5      nUS:  d  [        U5      S:  a  gUS:  d  [        U5      S:  a  gg)zAssess question complexity   rF   high
      mediumlow)rJ   rH   )r5   r   r   
word_counts       r,   r@    QueryAnalyzer._assess_complexity]   s@    )*
?c(ma/"_H 1r+   r   r;   c                     SS/nUS:X  a  UR                  SS/5        U$ US:X  a  UR                  S5        U$ US:X  a  UR                  S5        U$ )z!Determine which agents are needed	retrieveranswer_generatorrS   knowledge_synthesizerfact_checkerfactualcomparative)extendrK   )r5   r   r;   base_agentss       r,   rA   "QueryAnalyzer._get_required_agentsh   sp    "$67 7HI  i'~.  m+67r+   c                 2    US:X  a  g[        U5      S:  a  gg)z!Choose optimal retrieval approachsource_lookupkeyword   hybridsemantic)rJ   )r5   r   r   s      r,   rB   (QueryAnalyzer._choose_retrieval_strategyu   s    O+]Qr+   r3   N)r!   r"   r#   r$   r%   r   r6   r&   r   r   rC   r   r?   r@   rA   rB   r*   r    r+   r,   r.   r.   8   s    =#( #
 
S#X 
$## #$s) #	3 	$s) 	 	# 3 4PS9  tCy UX r+   r.   c                   X    \ rS rSrSrS\S\4S jrSS\S\S\	S	\
\\\4      4S
 jjrSrg)RetrieverAgent   z(Handles multi-modal retrieval operationsvector_storer0   c                     Xl         X l        g r2   )rn   r0   )r5   rn   r0   s      r,   r6   RetrieverAgent.__init__   s    ("r+   querystrategykr9   c                     US:X  a  U R                   R                  XS9$ US:X  a  U R                   R                  XS9$ US:X  a  U R                   R                  XS9$ U R                   R                  XS9$ )z)Execute retrieval with specified strategyri   )rs   rf   rh   )rn   searchkeyword_searchhybrid_search)r5   rq   rr   rs   s       r,   retrieveRetrieverAgent.retrieve   s    z!$$++E+77"$$33E3??!$$2252>>$$++E+77r+   r0   rn   N)ri      )r!   r"   r#   r$   r%   r   r   r6   r&   intr   r   r   rx   r*   r    r+   r,   rl   rl      sP    2#[ #X #	8c 	8S 	8# 	8dSWX[]`X`SaNb 	8 	8r+   rl   c                   |    \ rS rSrSrS\4S jrS\\\	\
4      S\	S\\	\
4   4S jrS	\\\	\
4      S
\	S\	4S jrSrg)KnowledgeSynthesizer   z6Combines retrieved information with existing knowledger0   c                     Xl         g r2   r3   r4   s     r,   r6   KnowledgeSynthesizer.__init__   r8   r+   r   r   r9   c                     U R                   R                  U5      nU R                   R                  U5      nUUU R                  X45      S.$ )*Synthesize knowledge from multiple sources)r   r   synthesis_summary)r0   collect_distilled_insights_format_entity_graph_hints_create_synthesis_summary)r5   r   r   r   r   s        r,   
synthesizeKnowledgeSynthesizer.synthesize   sP     "^^FF~V ~~@@J #5(!%!?!?@R!a
 	
r+   insightsr   c                    U(       d  g/ nUSS  HI  nUR                  SS5      nUR                  SS5      SS nU(       d  M3  UR                  U S	U 35        MK     U(       a  UR                  S
USS  35        SR                  U5      $ )z1Create a concise synthesis of available knowledgez No distilled insights available.NrF   titlezUnknown sourceoverview d   z: zEntity connections:    z | )getrK   join)r5   r   r   summary_partsinsightr   r   s          r,   r   .KnowledgeSynthesizer._create_synthesis_summary   s    5|GKK)9:E{{:r24C8Hx$$wb
%;<	 $   #7Tc8J7K!LMzz-((r+   r3   N)r!   r"   r#   r$   r%   r   r6   r   r   r&   r   r   r   r*   r    r+   r,   r~   r~      sn    @#( #
d38n)= 
 
QUVY[^V^Q_ 
)$tCH~2F )VY )^a )r+   r~   c                   b    \ rS rSrSrS\4S jrS\S\S\\\	4   S\S	\
\\\	4      S
\4S jrSrg)AnswerGenerator   z9Generates final answers using LLM with enhanced promptingr0   c                     Xl         g r2   r3   r4   s     r,   r6   AnswerGenerator.__init__   r8   r+   r   r   r   r   r   r9   c                 8    U R                   R                  UUUS9$ )z5Generate answer using the enhanced reasoning pipeline)r   r   r   )r0   generate_extraction_answer)r5   r   r   r   r   r   s         r,   generateAnswerGenerator.generate   s)    
 ~~88) 9 
 	
r+   r3   N)r!   r"   r#   r$   r%   r   r6   r&   r   r   r   r   r*   r    r+   r,   r   r      sX    C#( #	
 	
s 	
d38n 	
"	
48c3h4H	
MP	
r+   r   c                       \ rS rSrSrS\4S jrS\S\\	\\
4      S\	\\
4   4S jrS\S\\   4S	 jrS
\S\\	\\
4      S\	\\
4   4S jrS\\	\\
4      S\\   4S jrSrg)FactChecker   z(Validates claims against source materialr0   c                     Xl         g r2   r3   r4   s     r,   r6   FactChecker.__init__   r8   r+   r   r   r9   c                    U R                  U5      n/ nU H3  nU R                  XR5      nUR                  UUS   US   US   S.5        M5     U(       a  [        S U 5       5      [	        U5      -  OSnUUU R                  U5      S.$ )z#Verify factual claims in the answerverifiedr   r   )claimr   r   supporting_sourcesc              3   *   #    U  H	  oS    v   M     g7f)r   Nr    ).0rs     r,   	<genexpr>+FactChecker.check_claims.<locals>.<genexpr>   s      O:NQ<:Ns   g      ?)verification_resultsoverall_confidencerecommendations)_extract_claims_verify_claimrK   sumrJ   _generate_recommendations)r5   r   r   claimsr   r   verificationr   s           r,   check_claimsFactChecker.check_claims   s    %%f-!E--e=L ''(4*<8&29&=	)   pDS O:N OORUVjRkk  JM %9"4#==>RS
 	
r+   c                     UR                  S5       Vs/ s H)  o"R                  5       (       d  M  UR                  5       PM+     nnU$ s  snf )z"Extract factual claims from answer.)rH   strip)r5   r   s	sentencess       r,   r   FactChecker._extract_claims   s=     )/S(9G(91WWYYQWWY(9	G Hs
   AAr   c                 4   SSS.nU Hm  nUR                  SS5      R                  5       nUR                  5       nXe;   a
  SUS   S.n  O/SSKJn  UR	                  Xe5      S	-  nXS
   :  d  Mf  XS   S.nMo     US
   S:  US
   US   (       a  US   /S.$ / S.$ )z%Verify a single claim against sourcesr   N)scoresourcecontentr   g?r   )fuzzg      Y@r   ffffff?)r   r   r   )r   rG   	rapidfuzzr   partial_ratio)	r5   r   r   
best_matchr   r   claim_lowerr   r   s	            r,   r   FactChecker._verify_claim   s      !D1
FjjB/557G++-K %'*fX6FG
 '&&{<uDE'**',x8HI
   #7+c1$W-1;H1E
8,-
 	
 LN
 	
r+   r   c                 $   / nU Vs/ s H  o3S   S:  d  M  UPM     nnU(       a  UR                  S[        U5       S35        U Vs/ s H  o3S   (       a  M  UPM     nnU(       a  UR                  S[        U5       S35        U$ s  snf s  snf )z6Generate recommendations based on verification resultsr   g333333?z!Consider additional research for z claims with low confidencer   zUnable to verify z! claims against available sources)rK   rJ   )r5   r   r   r   low_confidence_claimsunverified_claimss         r,   r   %FactChecker._generate_recommendations  s    ,@ Z,@qlOVYDY,@ Z ""%FsK`GaFbb}#~(<R(<1jMQ(<R""%6s;L7M6NNo#pq ![ Ss   BBBBr3   N)r!   r"   r#   r$   r%   r   r6   r&   r   r   r   r   r   r   r   r*   r    r+   r,   r   r      s    2#( #
3 
d38n1E 
$sTWx. 
,c d3i 
3 
d38n1E 
$sTWx. 
4d4S>>R W[\_W` r+   r   c                   L    \ rS rSrSrSS\4S jjrS\4S jrS\4S jr	S	 r
S
rg)MemoryManageri  z2Manages conversation context and short-term memory
max_memoryc                     / U l         Xl        g r2   )short_term_memoryr   )r5   r   s     r,   r6   MemoryManager.__init__  s    ,.$r+   itemc                     U R                   R                  U5        [        U R                   5      U R                  :  a   U R                   U R                  * S U l         gg)zAdd item to short-term memoryN)r   rK   rJ   r   )r5   r   s     r,   add_to_memoryMemoryManager.add_to_memory  sO    %%d+t%%&8%)%;%;T__<L<M%ND" 9r+   r9   c                 j    U R                   (       d  gSR                  S U R                    5       5      $ )zGet formatted memory contextzNone recorded.
c              3   ,   #    U  H
  nS U 3v   M     g7f)z- Nr    )r   notes     r,   r   3MemoryManager.get_memory_context.<locals>.<genexpr>&  s     H1G2dV1Gs   )r   r   r5   s    r,   get_memory_context MemoryManager.get_memory_context"  s)    %%#yyH1G1GHHHr+   c                     / U l         g)zClear all memoryN)r   r   s    r,   clear_memoryMemoryManager.clear_memory(  s
    !#r+   )r   r   N)   )r!   r"   r#   r$   r%   r|   r6   r&   r   r   r   r*   r    r+   r,   r   r     s2    <%3 %O# OIC I$r+   r   c                       \ rS rSrSrS\S\4S jrS\4S jr	S\
S\
4S	 jrS\
S\
4S
 jrS\
S\
4S jrS\
S\
4S jrS\
S\
4S jrS\
S\
4S jrS\
S\4S jrS\S\\\4   4S jrS\S\\\4   4S jrSrg)ModularRAGOrchestratori-  z5Main orchestrator that coordinates specialized agentsr0   rn   c                 *   Xl         X l        [        U5      U l        [	        X!5      U l        [        U5      U l        [        U5      U l	        [        U5      U l        [        5       U l        [        (       a  U R                  5       U l        g S U l        g r2   )r0   rn   r.   query_analyzerrl   r[   r~   r]   r   r\   r   r^   r   memory_managerLANGGRAPH_AVAILABLE_build_workflowworkflow)r5   r0   rn   s      r,   r6   ModularRAGOrchestrator.__init__0  sw    "( ,I6'@%9)%D" /	 :'	2+o 3F2E,,.4r+   r9   c                    [        [        5      nUR                  SU R                  5        UR                  SU R                  5        UR                  SU R
                  5        UR                  SU R                  5        UR                  SU R                  5        UR                  SU R                  5        UR                  S5        UR                  SU R                  SSSS.5        UR                  SS5        UR                  SS5        UR                  SS5        UR                  SS5        UR                  S5        UR                  5       $ )z(Build the agent workflow using LangGraphanalyze_queryretrieve_infosynthesize_knowledgegenerate_answer
fact_checkfinalize)simplecomplexr_   )r   r   add_node_analyze_query_node_retrieve_info_node_synthesize_knowledge_node_generate_answer_node_fact_check_node_finalize_nodeset_entry_pointadd_conditional_edges_route_after_analysisadd_edgeset_finish_pointcompile)r5   r   s     r,   r   &ModularRAGOrchestrator._build_workflow?  s1   j) 	/4+C+CD/4+C+CD0$2Q2QR+T-G-GH,(=(=>*d&9&9: 	  1 	&&&&)1'	
 	/+<=02CD+\:,
3!!*-!!r+   statec                 \    U R                   R                  US   5      n0 UEUS   US   S.E$ )zAnalyze the incoming queryr   r   r   )r   r   )r   rC   )r5   r  analysiss      r,   r   *ModularRAGOrchestrator._analyze_query_nodeb  sD    &&..uZ/@A

%o6 ,
 	
r+   c                     U R                   R                  US   5      nU R                  R                  US   US   S9nU R                  R                  X1S   S9n0 UEUUS.E$ )zRetrieve relevant informationr   r=   rr   r   )r   r   )r   rC   r[   rx   r0   format_context)r5   r  r  r   r   s        r,   r   *ModularRAGOrchestrator._retrieve_info_nodek  s    &&..uZ/@A00*23 1 

 ..//zIZ/[

,
 	
r+   c                 d    U R                   R                  US   US   5      n0 UEUS   US   S.E$ )r   r   r   r   r   r   r   )r]   r   )r5   r  	synthesiss      r,   r   1ModularRAGOrchestrator._synthesize_knowledge_node{  sQ    ..99"#*
	


"+,@"A%n5
 	
r+   c           	          U R                   R                  US   US   UR                  S/ 5      UR                  S/ 5      S.US   US   S9n0 UES	U0E$ )
zGenerate the final answerr   r   r   r   r  r   r   )r   r   r   r   r   r   )r\   r   r   )r5   r  r   s      r,   r   ,ModularRAGOrchestrator._generate_answer_node  s~    &&//)$:&&+ii0Db&I %		." =  0 !12 0 	


f
 	
r+   c                 j    U R                   R                  US   US   5      n0 UEUS   US   S:  S.E$ )zVerify the generated answerr   r   r   r   )r   r   )r^   r   )r5   r  r   s      r,   r   'ModularRAGOrchestrator._fact_check_node  sV    ((55(O"#



&';< ,-A BS H
 	
r+   c                     U R                   R                  US   5      nU R                  R                  SUS   SS  SUS   SS  S35        0 UEUUS   S	.E$ )
zFinalize the responser   zQ: r   N2   z... A: r   z...)r   r   )r0   prepare_source_summariesr   r   )r5   r  r   s      r,   r   %ModularRAGOrchestrator._finalize_node  s    ..99%@P:QR 	))Cj0A#20F/GwuU]_b`bOcNddg*hi

!(O
 	
r+   c                     U R                   R                  US   UR                  S/ 5      5      nUS:X  a  gUS   S:X  a  gg)z0Route to appropriate next step based on analysisr   r   rS   r   r   r_   r   )r   r@   r   )r5   r  r;   s      r,   r   ,ModularRAGOrchestrator._route_after_analysis  sN    ((;;*IIj"%


 ?#y0r+   r   c                     U R                   (       a?  [        US/ / / SS/ / / SSSS9nU R                   R                  U5      nUS   US   US   S.$ U R                  U5      $ )	zMain entry point for queriesr   g        F)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   invoke_simple_query)r5   r   initial_stateresults       r,   rq   ModularRAGOrchestrator.query  s    ==&! !#%!&M  ]]))-8F 0!),$\2  %%h//r+   c                    U R                   R                  U5      nU R                  R                  XS   S9nU R                  R                  X1S9nU R                  R                  XAU5      nU R                  R                  U5      nUUSS.$ )z-Simplified query processing without LangGraphr=   r  r	  g?r  )r   rC   r[   rx   r0   r
  r   r  )r5   r   r  r   r   r   r   s          r,   r  $ModularRAGOrchestrator._simple_query  s     &&..x8 00MaDb0c..///R ::7n]..99.I 
 	
r+   )	r\   r^   r]   r   r   r0   r[   rn   r   N)r!   r"   r#   r$   r%   r   r   r6   r   r   r   r   r   r   r   r   r   r&   r   r   r   rq   r  r*   r    r+   r,   r   r   -  s    ?P( P+ P!" !"F
 

 

 

 
 

 
z 

: 
* 
$
j 
Z 

J 
: 
: # 0c 0d38n 0<
c 
d38n 
r+   r   r0   rn   r9   c                     [        X5      $ )z/Factory function to create modular orchestrator)r   rz   s     r,   create_modular_orchestratorr$    s    !)::r+   __main__zModular RAG Orchestrator Designz(========================================zEThis module provides a blueprint for breaking the monolithic RAGAgentzEinto specialized sub-agents that can be orchestrated using LangGraph.z
Key Components:zH- QueryAnalyzer: Classifies questions and determines processing strategyz;- RetrieverAgent: Handles semantic/keyword/hybrid retrievalz?- KnowledgeSynthesizer: Combines insights from multiple sourcesz3- AnswerGenerator: Uses LLM with enhanced promptingz/- FactChecker: Validates claims against sourcesz/- MemoryManager: Maintains conversation contextzB
To use: Install langgraph, then integrate with existing RAGSystem)"r%   typingr   r   r   r   r   r   pathlibr	   jsonr
   langgraph.graphr   r   langchain.schemar   r   ImportErrorprintmistral_integrationr   rn   r   r   r.   rl   r~   r   r   r   r   r$  r!   r    r+   r,   <module>r.     sI  ( C B   S/,
 ) $ "D DN8 8&#) #)L
 
$H HV$ $0D
 D
P;8 ;; ;Si ;
 z	
+,	(O	
QR	
QR	
	
TU	
GH	
KL	
?@	
;<	
;<	
OP w  S	
QRSs   D DD