The parallel graph
The strengths analyzer and the weaknesses analyzer do not depend on each other. They both read the CV and the structured job analysis. Running them back to back is a choice, not a constraint. LangGraph lets you fan out from a single node into multiple branches and merge them back with a single join.
Fan out, fan in
Independent agents run in parallel. A single join node waits for both to finish.
# Fan out from analyze_jd into two independent branches
workflow.add_edge("analyze_jd", "analyze_strengths")
workflow.add_edge("analyze_jd", "analyze_weaknesses")
# Both branches converge on the suggester. LangGraph waits for both
# to finish before running generate_suggestions.
workflow.add_edge("analyze_strengths", "generate_suggestions")
workflow.add_edge("analyze_weaknesses", "generate_suggestions")
workflow.add_edge("generate_suggestions", "score_cv")
workflow.add_edge("score_cv", "analyze_ats")
workflow.add_edge("analyze_ats", END)Two edges out of the same node fan out into parallel execution. Two edges into the same node implicitly join. LangGraph handles the synchronization.
# Alternative: fan out inside a single node using asyncio.gather
import asyncio
async def analyze_both(self, state: CVAnalysisState) -> CVAnalysisState:
"""Run strengths and weaknesses concurrently inside one node."""
strengths_task = self.strengths_analyzer.analyze_strengths(state.copy())
weaknesses_task = self.weaknesses_analyzer.analyze_weaknesses(state.copy())
strengths_state, weaknesses_state = await asyncio.gather(
strengths_task, weaknesses_task
)
state["strengths"] = strengths_state.get("strengths", [])
state["weaknesses"] = weaknesses_state.get("weaknesses", [])
return stateWhen native fan-out feels heavy, asyncio.gather inside a single node is a pragmatic alternative. Same latency win, slightly less visible in the graph.
Only when the branches are genuinely independent and each one takes real time. If the strengths analyzer takes two seconds and the weaknesses analyzer takes two seconds, running them in parallel saves two seconds per request. If one of them only takes a hundred milliseconds, the coordination cost can dominate. Measure, then decide.
Checkpoint: Orchestration checkpoint
Loading practice…