top of page

Welcome
to NumpyNinja Blogs

NumpyNinja: Blogs. Demystifying Tech,

One Blog at a Time.
Millions of views. 

Orchestrator workflow in Langgraph

Feb 19
4 min read

The Orchestrator -worker architecture


As a manager in your company, you are responsible for organizing, coordinating, and managing complex tasks to ensure that they function cohesively and are completed successfully. To accomplish this, you will divide your work into sections — such as Section 1, Section 2, and Section 3 — and assign these sections to your team members. For example, you might assign Section 1 and Section 3 to Worker A and Section 2 to Worker B.


All workers will perform their tasks simultaneously, and you will dynamically delegate work as needed. Once a worker completes their task, they will wait idly until the next assignment is given. After all tasks are completed, you will combine their outputs successfully — essentially synthesizing their work into a final product.


This process can be likened to an orchestrator-worker architecture, which enhances flexibility by breaking tasks down into subtasks that can be worked on in parallel. Each worker focuses on their

subtasks independently, allowing for efficient completion, and you will then synthesize their outputs into a cohesive final result.


Created By : Gemini Nano Banana Image
Created By : Gemini Nano Banana Image

The Orchestrator: The Manager who plans and breaks down the “multifaceted” goal.

Delegation: Assign sub-tasks to the right workers.

Parallelization: allows Workers A, B, and C to work simultaneously, saving time.

The Idle State: Workers wait quietly once their specific job is done.

Synthesis: The Manager’s final “glue” that creates a cohesive result or output.


Simple Orchestrator and Orchestrator–Worker :

Let’s understand the difference between Simple Orchestrator and Orchestrator–Worker.

A Simple Orchestrator : Let’s consider a real-life example regarding school admissions. When students apply for school admission, their application must be reviewed by multiple departments, so the administration divides the tasks into four categories:

  1. 📚 Academic Department

  2. 🌍 Visa Check

  3. 🏥 Healthcare Department

  4. 💰 Finance Department

Here, an admission coordinator or administrator can decide which department runs next.

So the Langraph concept is normal for this scenario.


An Orchestrator–Worker : Let’s consider a real-life example regarding academic evaluation of multiple subjects such as English, Mathematics, Science (Biology, Chemistry, Physics), Humanities (History, Geography, Economics), and Languages, Technologies, and Physical Education. So we don’t know how many subjects students submit, how many subject tasks there are, and based on this, we can evaluate their final results.

Let’s understand this example :


STEP 1 :Define Structured Output for Planning: A schema for organized output to utilize in planning activities

# Individual Section (Task)
from pydantic import BaseModel, Field
from typing import List

class Section(BaseModel):
   """
   One evaluation task for a subject.
   """
   name: str = Field(description="Task name, e.g., subject to evaluate")
   description: str = Field(description="Instructions for this evaluation")

# Collection of Sections (Task)
class Sections(BaseModel):
   sections: List[Section] = Field(
       		description="List of dynamic evaluation tasks for subjects"
   )

# Augment the LLM with schema for structured output
planner = llm.with_structured_output(Sections)

STEP 2 : Expand Graph State

from typing import TypedDict, List,Annotated 
from langgraph.types import Send import operator 

# Graph state
class State(TypedDict):
   student_id: str
   subjects : List[str]       # List of transcripts to evaluate
   sections: List[Section]    # Planned evaluation tasks
   completed_evaluations: Annotated[List[str], operator.add] 
                              # combined Worker outputs collected
   final_report: str

STEP 3 : A worker state Each worker receives their own assigned task, which is subject to evaluation.

# Worker state
class WorkerState(TypedDict):
section: Section
completed_evaluations: List[str]  
# list of outputs; each worker appends their results here.

STEP 4 : Define Nodes

Node 1 : An Orchestrator Node: Create a section and delegate to this worker using the send API, which dynamically generates a worker node.

def orchestrator(state: State)-> List[Section]:
   """
   Generate dynamic sections (tasks) from subjects.
   """
   subjects = state["subjects"]
   sections = [
       			Section(
           				name=subject,
           				description=f"Evaluate performance in {subject}"
       					)
      			 for subject in subjects
   			]
   return {"sections": sections}

Node 2: Worker Node : Runs one section or subject at a time.

def  llm_call_to_evaluate_subject(state: WorkerState):
   """ Each worker evaluates a single assigned section (subject) 
      and returns the evaluation."""
   section = state["section"]

   # Simulate evaluation — replace with actual LLM call if needed
   eval_summary = f"Evaluated {section.name}.Done 👍"

   # Return result to shared state
   return {"completed_evaluations": [eval_summary]}

Each worker has its own state, represented by the class `WorkerState`, and all worker outputs are written to a shared state key. This key is accessible to the orchestrator graph, allowing the Orchestrator to access all worker outputs and synthesize them into a final output using the Synthesizer Node.


Node 3 : Synthesizer Node

def synthesizer(state: State):
    """ 
     Synthesize all completed evaluations into a final report.
	"""
   completed = state.get("completed_evaluations", [])
   combined_report = "\n\n".join(completed)
   return {"final_report": f"Final academic evaluation:\n{combined_report}"}

Conditional Edge : A function to create llm_call workers that each evaluate.

def assign_workers(state: State):
   """
   Assign a worker to each section using Send API.
   """
   sections = state.get("sections", [])

   # Dynamically create worker nodes using Send()
   return [Send("llm_call_to_evaluate_subject", {"section": s}) 
           for s in sections]

A graph-based agent orchestration framework allows you to connect nodes—each representing actions—via edges that determine the task flow. These edges keep the sequence, while conditional edges enable branching depending on decisions, creating a workflow that is flexible and adaptable.


from langgraph.graph import StateGraph, START, END
from langgraph.types import Send
from IPython.display import display, Image, Markdown

STEP 5 : Create Builder

 orchestrator_worker_builder = StateGraph(State) 

STEP 6: Add Nodes

orchestrator_worker_builder.add_node("orchestrator", orchestrator)

orchestrator_worker_builder.add_node(
   								"llm_call_to_evaluate_subject",
   								llm_call_to_evaluate_subject
								)

orchestrator_worker_builder.add_node("synthesizer", synthesizer)

STEP 7 : Add Edges

# Start → Orchestrator
orchestrator_worker_builder.add_edge(START, "orchestrator")


# Orchestrator → Worker (dynamic via Send)
orchestrator_worker_builder.add_conditional_edges(
   "orchestrator",
   assign_workers,
   ["llm_call_to_evaluate_subject"])


# Worker → Synthesizer
orchestrator_worker_builder.add_edge(
   "llm_call_to_evaluate_subject",
   "synthesizer"
)


# Synthesizer → End
orchestrator_worker_builder.add_edge("synthesizer", END)

STEP 8 : Compile Workflow

orchestrator_worker = orchestrator_worker_builder.compile()

STEP 9 : Invoke Workflow

state = orchestrator_worker.invoke({
   "student_id": "S123",
   "subjects": ["Math", "Physics", "Chemistry"],
   "sections": [],
   "completed_evaluations": [],
   "final_report": ""
})

STEP 10 : Show Final Synthesised Report

display(Markdown(state["final_report"]))

Mermaid Image :Orchestrator–Worker Workflow in LangGraph



In summary :

  • Worker State: Each worker only sees the section they are assigned to, keeping the prompt clean.

  • Shared State: Employing operator.add guarantees the automatic aggregation of parallel outputs.

  • Scalability: Whether a student submits two subjects or twenty, the Send() API dynamically scales the workers.


Ultimately, the decision between a simple orchestrator and an orchestrator–worker depends on the nature of the task. The Orchestrator–Worker model dynamically divides the workload, allowing for massively parallel processing and handling an infinite amount of data, making it suitable for data processing, research, and analysis. In contrast, a simple orchestrator follows a fixed blueprint used for business workflows such as approvals and KYC, with known work.



References :


 
 

+1 (302) 200-8320

NumPy_Ninja_Logo (1).png

Numpy Ninja Inc. 8 The Grn Ste A Dover, DE 19901

© Copyright 2025 by Numpy Ninja Inc.

  • Twitter
  • LinkedIn
bottom of page