Skip to content

focused-dot-io/remote-graph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

remote-graph-spike

A minimal example of using RemoteGraph to call a subgraph that is running on its own langgraph dev server.

parent (port 2024)  ──HTTP──▶  subgraph (port 2025)

Parent is on 2024 because that's the default langgraph dev port and the one Studio opens into — you want Studio pointed at the top-level graph you're driving. The subgraph is a dependency, so it sits on 2025.

Both graphs share the same keys (message, steps), but only the parent puts a reducer on steps — see the "Gotcha" section below for why:

class ParentState(TypedDict):
    message: str
    steps: Annotated[list[str], operator.add]

class SubgraphState(TypedDict):
    message: str
    steps: list[str]  # no reducer

The parent invokes three nodes in order: beforeremoteafter, where remote is a RemoteGraph pointed at the subgraph server. The steps list accumulates across the HTTP boundary, so a successful run produces:

{
  "message": "[subgraph] hello",
  "steps": ["parent-before", "subgraph-processed", "parent-after"]
}

Setup

uv sync

Run it

You need two terminals. Start the subgraph first so the parent can reach it.

Terminal 1 — subgraph on port 2025:

cd subgraph
uv run langgraph dev --port 2025 --no-browser

Terminal 2 — parent on port 2024:

cd parent
uv run langgraph dev --port 2024

The second server will open LangGraph Studio in your browser (pointed at the parent). Invoke the parent graph with:

{ "message": "hello", "steps": [] }

…and watch the run. You will see the remote node make an HTTP call to localhost:2025, which is visible as a separate run in the subgraph server's logs / Studio instance.

Alternative: invoke from Python

With both servers running:

from langgraph.pregel.remote import RemoteGraph

parent = RemoteGraph("parent", url="http://localhost:2024")
result = parent.invoke({"message": "hello", "steps": []})
print(result)

Configuration

The parent reads the subgraph URL from SUBGRAPH_URL (defaults to http://localhost:2025). Set it in .env if you need to point at a different host or port.

Gotcha: reducers at the RemoteGraph boundary

RemoteGraph returns the full remote state as the node's update, not just the subgraph's delta. If both the parent and the subgraph declare operator.add on the same list key, items the subgraph received as input come back in its return value and the parent's reducer double-counts them.

The fix used here: the subgraph does not put a reducer on steps — it returns only its own contribution, and the parent's reducer handles the accumulation. See the comment in subgraph/graph.py.

Other options for more complex cases:

  • Use different keys in the parent and subgraph so they can't collide
  • Wrap the RemoteGraph call in a custom node that extracts only the fields you want from the remote result before returning the update

Layout

remote-graph-spike/
├── pyproject.toml          # shared deps (langgraph, langgraph-cli[inmem], …)
├── subgraph/
│   ├── langgraph.json      # exposes "subgraph", deps: [".."]
│   └── graph.py
├── parent/
│   ├── langgraph.json      # exposes "parent", deps: [".."]
│   └── graph.py            # uses RemoteGraph
└── README.md

Both langgraph.json files declare "dependencies": [".."] so each dev server picks up the root pyproject.toml, and "env": "../.env" so they share a single .env at the repo root (e.g. for SUBGRAPH_URL).

Credits

This was made at a Friday afternoon code club at Focused. Contributors included Jordan Kamm and Emilio Navarro driving, with Prachi More, Kevin Solorio, and Jonathan Eyler-Werve. Focused.io an enterprise agent consultancy that partners with Langchain on implementation of agents on LangChain, LangGraph and LangSmith and related technologies.

About

Spiking around on RemoteGraph functionality in LangGraph

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages