Галоўная / Артыкулы / LangGraph Conditional Edges: Routing a Graph With State and Decisions

Артыкул апублікаваны на англійскай мове.

LangGraph Conditional Edges: Routing a Graph With State and Decisions

Learn how LangGraph conditional edges work: write a router that stores its decision in state, map outcomes to nodes and send each path where it should go.

1120 слоў

A quick refresher on the first part of this LangGraph series helps before adding decisions. LangGraph is essentially a set of connected functions, each handling one job. Three pieces carry the idea.

State is the object that moves through the graph holding all the information. Any node can read from it and write to it.

state = {
    'a': 2,
    'b': 3,
    'sum': None
}

Nodes are plain functions. A node receives the state, does some work, and returns only the values it wants to change.

def add(state):
    total = state['a'] + state['b']
    return {'sum': total}

Edges decide which node runs next, for instance:

add → multiply → final

The state travels along that path while the nodes run in turn. A node doesn't have to be an ordinary Python function, either, since it can wrap an LLM call. So far, though, every graph has followed one fixed route. The next question is how to let a graph choose between routes, and the answer is conditional edges.

The idea behind a conditional edge

Software gets much of its usefulness from making choices: yes or no, this or that. Graphs need that too, so some functions exist purely to decide.

Suppose a graph greets someone according to the time of day. In the morning, the output is:

Good Morning

At night, it is:

Good Night

The shape of the graph changes as a result. It is no longer the straight line

A → B → C

but a fork:

→ Morning → Good Morning
            /
User → Router
            \
             → Night → Good Night

A Router picks the branch. That, in a nutshell, is a conditional edge.

Trying it in plain Python first

Before bringing LangGraph in, here's the same idea as an ordinary function. It needs the current time:

from datetime import datetime

And the function itself:

def router():    hour = datetime.now().hour

    if 5 <= hour < 12:
        return "Morning"
    else:
        return "Night"

Notice how little this function does. It performs no big operation. It decides. A current hour from 5 AM up to noon gives back

Morning

and anything else gives back

Night

Placed inside a graph, that return value can choose the next node. There's a second trick as well: the decision can be saved in the state. Add a field for it:

state = {
    'time_per': None
}

Now the router can write its choice into the state. It takes the state as an argument:

def router(state):

And inside it computes the hour and records the result:

    hour = datetime.now().hour

    if 5 <= hour < 12:
        return {'time_per': 'Morning'}
    else:
        return {'time_per': 'Night'}

Afterward the state holds the decision:

{
    'time_per': 'Morning'
}

That's the key point. State stores information, and the conditional edge reads that information to steer the graph. Two things happen in sequence:

Router
  ↓
updates state
  ↓
time_per = "Morning"
  ↓
conditional edge checks it
  ↓
Morning node

This is where State and Edges begin to cooperate.

The same thing in LangGraph

First, the state needs a typed definition. Import TypedDict:

from typing import TypedDict

Then declare the schema:

class State(TypedDict):
    time_per: str

Next come the nodes. The router decides whether it's morning or night, and it needs the clock:

from datetime import datetime

The router node itself:

def router(state):    hour = datetime.now().hour    if 5 <= hour < 12:
        return {'time_per': 'Morning'}
    else:
        return {'time_per': 'Night'}

Two further nodes handle each outcome. One covers the morning:

def morning(state):
    return {'time_per': 'Good Morning'}

The other covers the night:

def night(state):
    return {'time_per': 'Good Night'}

Now for the important part. LangGraph needs a function that says which path to follow. It receives the state:

def decide_time(state):

and simply hands back the stored decision:

    return state['time_per']

So it returns either

Morning

or

Night

That function plugs into a conditional edge:

graph.add_conditional_edges(
    "router",
    decide_time,
    {
        "Morning": "morning",
        "Night": "night"
    }
)

Here's what each piece means. The opening of the call is

graph.add_conditional_edges(
    "router",

which tells LangGraph that once the router node finishes, the graph shouldn't jump to one fixed node. A decision takes over. The next argument is

decide_time,

the function that makes the decision. The last argument is

{
    "Morning": "morning",
    "Night": "night"
}

a mapping from each possible decision to the node that should follow. If decide_time() returns

Morning

the graph follows

router → morning

and if it returns

Night

the graph follows

router → night

The full graph now looks like this:

→ morning → END
                 /
START → router
                 \
                  → night → END

That's the difference between the two kinds of edge. A normal edge always says

A → B

with no exceptions, while a conditional edge says

A → ?

and lets the decision fill in the question mark.

Why this matters

Here's where LangGraph gets interesting. The flow works like a cycle of dependencies:

updates
           State
             ↑
             |
          Router
             |
             ↓
     Conditional Edge
        ↙         ↘
   Morning        Night

A node can update the state. The routing function can read that state. And the routing function then decides which node runs next. The graph stops being a pile of connected functions and turns into one where the current state can change its own path. Complex workflows need exactly that.

A realistic case is a question router:

User Question
      ↓
   Classifier
      ↓
   State
      ↓
 ┌────┴─────┐
 ↓          ↓
Coding    General
 ↓          ↓
Code      Normal
Answer    Answer

The classifier might write something like this into the state:

{
    'type': 'coding'
}

The conditional edge reads that value and asks whether to send the request to the coding node or to the general one. At this point the workflow is no longer a simple sequence. It's a graph that makes decisions. The next step is loops, where a graph goes back, repeats a step and tries again.