# Configuring Tool Routing and Conditional Execution in Agent Graphs: A LangGraph Production Guide

> Master tool routing and conditional execution in agent graphs. Learn to register tools and use ConditionalEdge for dynamic workflow control in this LangGraph production guide.

- Repository: [NirDiamant/agents-towards-production](https://github.com/nirdiamant/agents-towards-production)
- Tags: how-to-guide
- Published: 2026-05-18

---

**Tool routing and conditional execution in agent graphs are configured by registering functions with the `@tool` decorator to enable automatic dispatch, then implementing `ConditionalEdge` predicates that inspect message metadata and tool outputs at runtime to determine the next workflow node.**

The `NirDiamant/agents-towards-production` repository demonstrates production-ready patterns for building stateful agent workflows using LangGraph's graph-based orchestration engine. This guide examines how to configure dynamic tool routing and conditional logic by analyzing the actual implementation patterns found in the RunPod GPU deployment tutorial and secure Arcade tool-calling examples.

## Understanding Agent Graph Architecture

LangGraph structures agent workflows as **directed graphs** composed of nodes and edges. Each **node** represents either an agent or a tool, while **edges** define the permissible transitions between them.

When an agent completes a step, it emits a `Message` object containing two critical routing fields:

- **`tool_call`** – A string identifying the specific tool to invoke (for example, *Research Tool* as registered in [`handler.py`](https://github.com/NirDiamant/agents-towards-production/blob/main/handler.py))
- **`metadata`** – Optional key-value pairs that conditional edges inspect to determine execution paths

The graph runtime evaluates the `tool_call` field and automatically routes the message to the corresponding tool node. This routing mechanism is implemented in [`tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py), where the `@tool` decorator registers functions that the graph can dynamically dispatch.

## Implementing Tool Routing with Decorators

Tool routing relies on explicit registration to map string identifiers to executable functions. The `crewai.tools` module provides the **`@tool`** decorator for this purpose.

### Registering a Tool

When you decorate a function with `@tool("Tool Name")`, LangGraph adds it to the graph's routable registry:

```python
from crewai.tools import tool

@tool("Research Tool")
def fake_research(topic: str) -> str:
    """Retrieves academic papers and summaries for the given topic."""
    results = fetch_papers(topic)
    return f"Research findings: {results}"

```

The string *Research Tool* becomes the routing key. When an agent's output contains `tool_call: "Research Tool"`, the graph automatically forwards execution to this function. This pattern is demonstrated in [`tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py), where the RunPod serverless handler builds a graph that routes between blog writing agents and research tools.

## Building Conditional Execution Flows

Beyond static tool routing, production graphs require **conditional edges** that branch based on runtime state. LangGraph implements this through the `ConditionalEdge` class, which accepts a predicate function that inspects the current state dictionary.

### Defining Conditional Logic

Conditional edges evaluate boolean functions that receive the complete `state` object (including `metadata` and previous tool outputs) and return a decision:

```python
from langgraph.graph import StateGraph, ConditionalEdge

graph = StateGraph()

# Define nodes

graph.add_node("writer", writer_agent)
graph.add_node("research", fake_research)
graph.add_node("final", output_formatter)

# Static transition

graph.add_edge("writer", "research")

# Dynamic transition based on metadata inspection

def needs_research(state):
    """Check if the message metadata indicates research is required."""
    return "needs_research" in state.get("metadata", {})

graph.add_conditional_edge(
    "writer",
    ConditionalEdge(
        condition=needs_research,
        target="research",
        fallback="final"
    )
)

```

In this configuration, the graph routes from `writer` to `research` only when the `needs_research` predicate returns `True`; otherwise, it proceeds directly to the `final` node.

### Routing Based on Tool Output

You can also route based on the content returned by tools. The following pattern from `tutorials/LangGraph-agent/langgraph_tutorial.ipynb` demonstrates inspecting tool outputs to decide whether to summarize or re-search:

```python
def enough_info(state):
    """Determine if search returned sufficient information."""
    return "relevant" in state.get("output", "").lower()

graph.add_conditional_edge(
    "search",
    ConditionalEdge(
        condition=enough_info,
        target="summarise",
        fallback="search_again"
    )
)

```

Here, the condition function examines the `output` field populated by the previous tool execution, creating a feedback loop that continues researching until quality criteria are met.

## Production Security and Deployment Patterns

Production deployments often require secure, multi-user tool routing where requests are vetted before execution. The **Arcade** tutorial in [`tutorials/arcade-secure-tool-calling/README.md`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/arcade-secure-tool-calling/README.md) demonstrates this pattern by inserting a **guardrail** node between the agent and tool execution.

In this architecture, the graph still routes based on `tool_call`, but an intermediate node inspects the `tool_call` value and user authentication context before forwarding to the actual tool node. This ensures that sensitive tools (like email senders or database writers) cannot be invoked without explicit user approval and authorization checks.

### FastAPI Integration for External Routing

For external API exposure, [`tutorials/fastapi-agent/app.py`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/fastapi-agent/app.py) demonstrates wrapping the agent graph in a FastAPI endpoint. This allows external systems to trigger graph execution while maintaining internal routing logic:

```python

# handler.py pattern from RunPod tutorial

def handler(job):
    topic = job["input"].get("topic", "technology")
    blog = create_blog_post(topic)   # Internally builds and runs a LangGraph

    return {"status": "success", "blog_post": blog}

```

The `create_blog_post` function internally constructs a `StateGraph`, adds conditional edges for research validation, and executes the workflow, abstracting the routing complexity from the API consumer.

## Summary

- **Tool registration** uses the `@tool` decorator to map string identifiers to functions, enabling the graph runtime to route `tool_call` values to the correct executable node.
- **Conditional execution** relies on `ConditionalEdge` objects that accept predicate functions inspecting the `state` dictionary (including `metadata` and `output` fields) to determine the next node.
- **State inspection** allows graphs to create loops and branches based on tool results, message metadata, or external context flags.
- **Security patterns** from the Arcade tutorial demonstrate inserting guardrail nodes between routing decisions and tool execution for authorization checks.
- **Deployment flexibility** is achieved by wrapping graphs in FastAPI or RunPod handlers while preserving internal routing logic defined in files like [`tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py).

## Frequently Asked Questions

### How does LangGraph automatically route to the correct tool?

LangGraph matches the `tool_call` string in the agent's output message against registered tool names. When you decorate a function with `@tool("Tool Name")`, that name is added to the graph's routing table. Upon execution, if `state["tool_call"] == "Tool Name"`, the graph invokes the corresponding function. This automatic dispatch is demonstrated in [`tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/runpod-gpu-deploy/crew-ai-ollama-runpod-tutorial/handler.py).

### What data structure holds state in conditional edges?

The state is a Python dictionary passed to condition functions, typically containing keys like `metadata` (for routing flags set by agents), `output` (containing the last tool's return value), and `messages` (the conversation history). According to the `NirDiamant/agents-towards-production` source code, you inspect these fields to implement logic such as `return "needs_research" in state["metadata"]`.

### How do you create loops in agent graphs for iterative refinement?

Define a conditional edge where the `fallback` parameter points back to the previous node or agent. For example, if a research tool's output fails a quality check in the condition function, set `fallback="search_again"` to route back to the search node, creating a loop that exits only when the condition returns `True` and routes to the `target` node.

### Where can I find examples of secure tool routing with user isolation?

The [`tutorials/arcade-secure-tool-calling/README.md`](https://github.com/NirDiamant/agents-towards-production/blob/main/tutorials/arcade-secure-tool-calling/README.md) file demonstrates secure routing patterns where tool requests are intercepted by a guardrail node. This node validates user permissions and context before allowing the graph to proceed to the actual tool execution node, ensuring that multi-user agents cannot execute unauthorized operations.