From MPI processes to proactive agents
14 August 2026
A tiny tutorial for HPC people curious about agentic workflows.
Image generated by ChatGPT.
At EPCC, many of us are very comfortable with distributed computation. We split work across processes, send messages, gather results, think about data movement, and worry about correctness, performance, and scalability. In other words: MPI is familiar territory.
And yes, before anyone says it: MPI is a standard, not a language. It has standard C and Fortran bindings, and many C++ codes use the C bindings too.
In this tutorial, however, I am using mpi4py on purpose, because the goal is not to demonstrate peak MPI performance or win the approval of every MPICH/Open MPI purist in the building. Sorry. The goal is to make the coordination pattern easy to read, easy to understand, easy to run in a notebook, and easy to compare with agent-based workflows.
So, with apologies to the low-level communication connoisseurs: we are doing MPI in Python.
But only briefly :-)
The real goal is to ask a simple question: how do we move from distributed computation to distributed, adaptive agentic coordination? And, because the words agentic AI are now often used as if they automatically imply an LLM, a second question matters too: where does a language model genuinely add something useful?
The Google Colab notebook that we are using in this blog is available here open the seven-step Google Colab tutorial. The notebook and other examples are also collected in the Agentic AI Workflows repository [1]. For readers new to agentic AI, the repository Wiki includes Agentic AI: A Beginner-Friendly Glossary [2].
The journey in one view
The notebook changes one idea at a time:
MPI4py scatter/gather
↓
MPI ranks described as manager and workers
↓
Plain Python agents requesting work
↓
Basic LangGraph workflow
↓
Proactive LangGraph validation
↓
Deterministic LangGraph task-control loop
↓
LLM-powered IoT sensor triage with LangChain
Before we begin: what do these words mean?
For readers new to agentic AI, only a few distinctions are needed here. An agent is a component with a role, relevant context, and actions it can take towards a goal; it does not have to contain an LLM. LangGraph [3] provides stateful workflow orchestration, while LangChain [4] is used later to connect to the language model. An LLM is introduced only when language interpretation becomes useful.
A LangGraph node is not automatically an agent. Some nodes simply prepare, validate, route, or merge data; a node becomes agent-like through its behaviour. For example, by inspecting a situation, choosing among permitted actions, updating state, and continuing towards a goal.
For a fuller beginner-friendly explanation of agents, reasoning, state, evidence, tools, actions, agent loops, LangChain and LangGraph see the repository Wiki: Agentic AI: A Beginner-Friendly Glossary [2]
The toy problem: add +1 to an array
In our notebook, we are using during the first six steps a deliberately tiny problem. We start with an array of 100 positions:
[0, 1, 2, 3, ..., 99]
The task that we want to do with this array is very simple. Just to add +1 to every position and get the final array back:
[1, 2, 3, 4, ..., 100]
Clearly, nobody needs AI agents to do this. Nobody really needs a notebook, a workflow graph, or a philosophical debate about autonomy to add one to an integer. That is exactly the point.
By choosing a trivial computation, we can focus on the coordination pattern: who owns the data, who receives work, who checks results, who decides what happens when something goes wrong, and how the result is assembled. In Step 7, we change the scenario to IoT sensors because that is the first point at which an LLM has a meaningful job.
Step 1: the familiar MPI4py version
The notebook starts with a basic mpi4py program. Rank 0 owns the full array. The array is split across MPI ranks. Each rank adds +1 to its local chunk. Rank 0 then gathers the chunks back and validates the answer.
rank 0 creates the array
↓
Scatterv distributes chunks to ranks
↓
each rank adds +1 to its local chunk
↓
Gatherv reconstructs the array on rank 0
↓
rank 0 validates the result
This is the standard HPC view: distribute data, compute locally, collect the result. Scatterv and Gatherv are used because the chunks do not have to be exactly the same size.
The workers do not need to know why the computation is happening. They do not inspect the task, decide whether it is valid, or ask for clarification. They compute exactly what they were told to compute.
Step 2: describing MPI ranks as manager and worker agents
The next version keeps MPI, but changes the vocabulary and the shape of the messages. Rank 0 becomes ArrayManagerAgent. The other ranks become PlusOneAgents.
The manager owns the array, creates task dictionaries, sends chunks to specialist workers, and receives result dictionaries back.
ArrayManagerAgent
↓ sends a task
PlusOneAgent
↓ returns a result
ArrayManagerAgent reconstructs the array
This is still MPI. The workers are not genuinely autonomous yet: they receive a fixed task and execute a fixed function. Calling them agents does not magically give them reasoning.
However, the language shift is useful. It helps us see a familiar parallel program as a coordination pattern involving roles, messages, tasks, state, and results. That is the bridge to the later examples.
Step 3: a simple agentic version without MPI
The notebook then removes MPI completely and uses ordinary Python classes. The manager owns a task queue. Instead of being passively given work, each PlusOneAgent asks the manager for work when it is ready.
PlusOneAgent: Do you have work for me?
ManagerAgent: Yes, here is a chunk.
PlusOneAgent: I processed it and validated the result.
ManagerAgent: Thank you, I will store it.
PlusOneAgent: Do you have more work?
This is the first recognisably agentic step. The important difference is not the arithmetic; it is the interaction pattern. The worker participates in the workflow. It requests a task, processes it, validates its own result, reports back, and asks whether more work remains.
The agents are still deterministic Python objects. They do not contain an LLM. Their capabilities are methods written by the programmer.
There is one deliberate simplification in the notebook: the agent objects are called sequentially rather than running in parallel. The goal is to make the pull-based conversation between manager and workers easy to see, not to benchmark a concurrent implementation.
Step 4: introducing LangGraph
After that, the notebook introduces LangGraph [3]. LangGraph lets us represent the application as a stateful graph. The state is the information the workflow remembers: the array, task list, returned results, audit log, and final answer. A node is a Python function that performs one step and returns state updates. An edge says which node runs next. A conditional edge, or router, is a Python function that chooses between possible next nodes.
START
↓
Manager splitter node
↓
PlusOneAgent worker branches
↓
Manager merge node
↓
END
The manager creates tasks. LangGraph fans them out to worker branches. The workers process chunks. Their returned lists are combined, and the manager reconstructs the final result.
This is still deterministic. LangGraph is not deciding what +1 means or inventing the route. We define the nodes, edges, state fields, and routing functions in Python. LangGraph executes that design.
The main gain is clarity and extensibility: instead of hiding all control flow inside one large loop, the workflow is represented explicitly as state, steps, branches, and transitions.
Step 5: proactive inspection and validation
In the fifth step, the worker does more than blindly calculate x + 1. It inspects the task before acting.
receive task
↓
is the operation supported?
↓
are all inputs valid integers?
↓
perform +1
↓
does every output equal input + 1?
↓
return a validated result
If the operation is unsupported, the input is malformed, or the output fails validation, the node raises an error. The worker has become more proactive because it checks its capability, checks the data, and checks its own output.
But it is not yet adaptive. A failed check stops the workflow. The worker cannot split an oversized task, correct an ambiguous instruction, or requeue work for another agent. Those behaviours arrive in Step 6.
There is still no LLM. The worker is applying if/else conditions written in Python. It is inspecting structured data, not interpreting open-ended language.
Step 6: a deterministic LangGraph task-control loop
Step 6 is where the graph becomes much more adaptive. The workflow now maintains a pending-task queue and repeatedly runs a worker until no work remains.
create initial task
↓
worker takes the next pending task
↓
apply programmed decision rules
↓
update tasks, results, and audit log
↓
pending tasks remain?
yes → worker again
no → merge and validate
The worker can now ask for clarification when the operation is wrong, split a chunk that is too large, report invalid values, requeue a task after a simulated failure, allow another named worker to take over, validate completed work, and request another task.
This is the point at which one particular node becomes clearly agent-like. The advanced_plus_one_agent node has a specialist role, reads the current task and workflow state, selects between several possible actions, updates the queue or results, and continues working towards completion.
Its decision tree is still entirely programmed:
operation is wrong? → clarify and requeue
chunk is too large? → split into smaller tasks
bad value detected? → record a problem
first attempt must fail? → requeue for takeover
otherwise → process and validate
Step 6 does not use an LLM, and every action comes from explicit Python rules. However, Step 6 matters because it shows that agentic coordination does not require generative AI. A deterministic workflow can still inspect, branch, loop, recover, reassign, validate, and stop safely.
Step 7: adding an LLM-powered agent with LangChain
The final step changes the scenario slightly, because adding an LLM to the +1 example would not be particularly useful. Instead, we use a small IoT sensor-monitoring workflow.
The workflow receives numerical sensor readings together with short diagnostic notes. Clear rules remain deterministic. For example, a battery below 10% automatically triggers maintenance, while an implausible temperature is sent for human review. Other cases require interpretation. A note saying that two packets were lost after a brief network interruption probably suggests retrying the reading. A note mentioning uncertain moisture or intermittent buzzing may need human review.
take the next sensor reading
↓
deterministic precheck
├─ battery below 10% → maintenance
├─ implausible temperature → human review
└─ no hard rule applies
↓
LLM interprets the note
↓
select one bounded action
accept | retry | maintenance | human_review
↓
ordinary Python executes the action
↓
LangGraph records the result and continues
This is also where we introduce LangChain [4], which provides the interface to the OpenAI model and asks it to return a structured response.
In this step, the llm_sensor_agent node is an agent because it has a sensor-triage role, receives the current sensor reading and note, follows a policy, and chooses between four permitted actions. Unlike Step 6, its choice is not made by a fixed if/else tree. The LLM interprets the natural-language note.
Note: Step 7 uses an OpenAI API key, and the notebook asks for it at runtime.
What have we changed across the seven steps?
We started with a familiar MPI scatter-and-gather program, where every process performs a fixed operation. We then gradually gave the workers more responsibility: first by describing them as manager and specialist agents, then by allowing them to request work, inspect tasks, validate results, split oversized chunks, and recover from failures.
LangGraph allowed us to represent this coordination explicitly as a stateful workflow with nodes, transitions, branches, and loops. Importantly, these workflows did not initially require an LLM. Steps 3-6 are agentic, but their decisions are deterministic Python rules.
Only in Step 7 did we add an LLM, and only for a task where language interpretation was genuinely useful. LangChain connects the application to the LLM, while LangGraph continues to manage the wider workflow.
MPI → efficient distributed computation
LangGraph → stateful workflow orchestration
LangChain → model connection and structured responses
LLM → interpretation where fixed rules are not enough
Python → deterministic actions, validation, and safety rules
An agent does not necessarily need an LLM. An LLM is one possible component inside an agentic workflow, not the whole workflow.
So, are agents replacing MPI?
No. This is probably the most important point.
MPI is not going away, and AI agents are not a replacement for MPI in the places where MPI is strongest. MPI remains the right tool when we need high-performance numerical computation, tightly coupled communication, deterministic behaviour, low-latency message passing, large-scale parallelism, precise control over data movement, and efficient use of HPC systems.
If the task is "run this simulation efficiently across thousands of cores", MPI remains fundamental. Agents are useful at a different level.
They become interesting when the workflow involves decisions, adaptation, heterogeneous tools, uncertainty, validation, interpretation, or recovery. An agentic layer might decide which analysis to run next, inspect logs, retry a failed tool with different parameters, validate provenance, summarise results, reassign work, or ask a human for clarification.
A more useful framing is:
- MPI for efficient distributed computation.
- Agents for adaptive distributed coordination.
- LLMs, selectively, for interpretation where deterministic rules are not enough.
We are beginning to see these layers combined in current scientific systems, although not always yet in a single end-to-end workflow. Recent work has connected LangGraph and LangChain agents to the Parsl [6] workflow system, allowing agents to launch and manage molecular-dynamics simulations on the Polaris supercomputer [7]. Other work has demonstrated bounded, plan-based agentic execution with checkpointing and optional human approval in a deployment at the Advanced Light Source [8].
In the Agentic AI Workflows repository [1], we have also created an agentic workflow using dispel4py [5].
References
[1] Agentic AI Workflows repository
[2] Agentic AI: A Beginner-Friendly Glossary
[7] Connecting Large Language Model Agent to High Performance Computing Resource
[8] Alpha Berkeley: A Scalable Framework for the Orchestration of Agentic Systems