LangGraph Integration
The Dragon LangGraph backend lets existing LangGraph
multi-agent graphs run on a HPC cluster with zero changes to the
graph definition or the node functions. Agent nodes are placed on Dragon
AgentHost processes across cluster nodes, while graph topology, routing, and
checkpointing remain entirely LangGraph’s responsibility.
A single DragonExecutor owns one or more shared
Dragon Channel completion lanes (num_shards, default 1) over which all
agent results are transported inline; cross-node sends use Dragon’s transport
(HSTA/RDMA when remote, shared memory when local). Bulk scientific data (tensors,
arrays, datasets) stays the user’s
responsibility: create your own Dragon DDict, pass its handle
into your agent functions, store artifacts there, and return only a lightweight
handle/key through LangGraph state.
Note
This module is experimental and not yet in its final state. It requires
langgraph to be installed in the Dragon environment.
For the underlying architecture and components, see LangGraph Integration. For examples, see Dragon + LangGraph Examples.
Quick Start
import dragon
import multiprocessing as mp
from langgraph.graph import StateGraph, START, END
from dragon.ai.langgraph import DragonExecutor
mp.set_start_method("dragon")
def researcher(state): ...
def writer(state): ...
with DragonExecutor() as executor:
# One launch_host() call = one Dragon process hosting these agents
# as threads. Call it again (with a Policy) to place agents on
# other cluster nodes.
executor.launch_host(agents={
"researcher": researcher,
"writer": writer,
})
builder = StateGraph(State)
builder.add_node("researcher", executor.node("researcher"))
builder.add_node("writer", executor.node("writer"))
builder.add_edge(START, "researcher")
builder.add_edge("researcher", "writer")
builder.add_edge("writer", END)
graph = builder.compile()
result = graph.invoke({"messages": [...]})
Run it on a cluster with the Dragon launcher:
dragon my_graph.py
Python Reference
Executor
Lifecycle manager for Dragon AgentHost processes. Spawns the hosts that run
agent functions, and exposes a fn(state) -> dict callable for each agent
that plugs directly into StateGraph.add_node.
Manages the lifecycle of Dragon AgentHost processes. |
Executor API Detail
The DragonExecutor is the only public class in this module. It manages the
full lifecycle of Dragon processes that execute LangGraph agent functions.
Constructor:
DragonExecutor(
*,
max_concurrent_tasks: int = 64,
num_shards: int = 1,
)
Parameter |
Default |
Description |
|---|---|---|
|
|
Maximum concurrent in-flight tasks across the whole executor. Acts as a backpressure limit — when hit, further dispatches block until a task completes. Size to your expected peak fan-out. |
|
|
Number of independent completion lanes (each a Dragon |
Methods:
Method |
Description |
|---|---|
|
Spawn one persistent Dragon |
|
Spawn multiple AgentHost processes in one call — one per entry in hosts.
Each entry in policies is applied to the corresponding host. Returns a
list of |
|
Return a LangGraph |
|
Stop all AgentHost processes and the watcher thread. Called automatically
when used as a context manager ( |
Properties:
Property |
Type |
Description |
|---|---|---|
|
|
Maximum number of tasks allowed in flight at once. |
|
|
Number of independent completion lanes in the watcher. |
Context manager:
with DragonExecutor(max_concurrent_tasks=128) as executor:
executor.launch_host(agents={"a": fn_a, "b": fn_b})
# ... build and run graph ...
# shutdown() is called automatically here
launch_host Parameters
Parameter |
Default |
Description |
|---|---|---|
|
(required) |
|
|
|
Optional |
|
|
Seconds before a task is considered timed out. |
|
|
Maximum concurrent threads in the host’s |
Returns: Process — the Dragon Process
running this AgentHost. Useful for monitoring, joining, or killing the host
externally.
Raises: ValueError if any node_name in agents was already
registered in a previous launch_host() call.
launch_hosts Parameters
Convenience wrapper that spawns multiple hosts in one call, mirroring the Dragon convention of passing a list of policies (one per item).
executor.launch_hosts(
hosts=[agent_dict_0, agent_dict_1, ...],
policies=[policy_0, policy_1, ...],
)
Parameter |
Default |
Description |
|---|---|---|
|
(required) |
|
|
|
Optional |
|
|
Seconds before a task is considered timed out (applied to every host). |
|
|
Max threads per host. |
Returns: list[dragon.native.process.Process] — one Process per host, in
the same order as hosts.
Raises: ValueError if policies is provided but its length differs
from hosts.
Internal Components
These are internal implementation classes not intended for direct use. They are documented here for developers maintaining or extending the integration.
DragonAgentNode (_node.py)
The per-node callable that LangGraph invokes. Users get this through
executor.node(name) — they never instantiate it directly. Provides:
__call__(state) -> dict— sync path forgraph.invoke().acall(state) -> dict— async path forgraph.ainvoke().
DragonWatcher (_watcher.py)
The blocking-recv result router. Owns the shared completion Channel(s) and resolves task Futures. One watcher per executor, one recv thread per shard.
agent_host_entry (_host.py)
The entry-point function that runs inside each Dragon AgentHost process.
Receives task messages via a Dragon Queue, dispatches to agent functions
in a ThreadPoolExecutor, and sends completion envelopes inline on the
shared completion Channel.
Completion envelope (_constants.py)
The host and watcher agree on a small cloudpickle’d dict per completion:
{
"task_id": str, # routes to the pending Future
"status": "done" | "error",
"payload": <result_dict | exception>,
}
Constants:
Constant |
Value |
Description |
|---|---|---|
|
|
Agent function completed successfully. |
|
|
Agent function raised an exception. |
|
|
Envelope field: routes the envelope to the correct Future. |
|
|
Envelope field: success or failure. |
|
|
Envelope field: the result dict or exception object. |
Usage Patterns
Single host, all agents together (simplest):
with DragonExecutor() as executor:
executor.launch_host(agents={"a": fn_a, "b": fn_b, "c": fn_c})
builder = StateGraph(State)
builder.add_node("a", executor.node("a"))
builder.add_node("b", executor.node("b"))
builder.add_node("c", executor.node("c"))
# ... add edges ...
Multi-node, explicit placement:
from dragon.infrastructure.policy import Policy
from dragon.native.machine import Node, System
system = System()
node0 = Node(system.nodes[0]).hostname
node1 = Node(system.nodes[1]).hostname
with DragonExecutor() as executor:
executor.launch_hosts(
hosts=[
{"researcher": fn_research},
{"writer": fn_write, "analyzer": fn_analyze},
],
policies=[
Policy(placement=Policy.Placement.HOST_NAME, host_name=node0),
Policy(placement=Policy.Placement.HOST_NAME, host_name=node1),
],
)
With Dragon Inference (on-cluster LLM):
from dragon.ai.inference.llm_proxy import DragonQueueLLMProxy
from dragon.native.queue import Queue
inference_queue = Queue()
# ... start inference pipeline on GPU node ...
llm = DragonQueueLLMProxy(inference_queue)
with DragonExecutor() as executor:
executor.launch_host(agents={
"researcher": lambda state: researcher_fn(state, llm),
})
Agent with user-managed DDict (bulk data stays node-local):
from dragon.data.ddict import DDict
sim_data = DDict(managers_per_node=1, total_mem=10_000_000_000)
def simulation_agent(state):
result = run_simulation(state)
sim_data["output_key"] = result # bulk stays node-local
return {"result_key": "output_key"} # handle only
with DragonExecutor() as executor:
executor.launch_host(agents={"simulate": simulation_agent})
Error Handling
Scenario |
Behavior |
|---|---|
Agent function raises |
Exception packed into error envelope, sent inline on the completion Channel. Coordinator re-raises it. LangGraph sees a normal exception. |
Unpicklable exception |
Falls back to |
Unknown |
Host sends a |
Task timeout |
|
Host process crashes |
No envelope arrives; |
Persistence
A DDict-backed checkpointer and store are not currently provided. Use any
standard LangGraph checkpointer/store with DragonExecutor:
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
graph = builder.compile(
checkpointer=InMemorySaver(),
store=InMemoryStore(),
)
For production fault tolerance, use SqliteSaver or PostgresSaver so a
restarted coordinator can resume from the last checkpoint.
See Also
LangGraph Integration — architecture walkthrough and component deep-dive.
Dragon + LangGraph Examples — guided examples (quickstart, multinode, inference, supervision, data locality).