Every time your LangGraph agent sees "check nginx logs", it might call a different tool.
That's not an exaggeration. LangGraph's routing is driven by an LLM prompt β and prompts aren't reproducible. Same input, different day, different LLM mood, different tool selected.
I spent months debugging this. Every wrong route meant tweaking a prompt, hoping the next call would be better. It never was.
So I wrote something different.
LangGraph is great at orchestrating multi-step agent workflows. But the first step β "what tool should I use?" β is a black box.
You define a prompt, the LLM decides. If it chooses wrong, you can't debug it. You can only guess: was the prompt not specific enough? Too specific? Wrong example?
This is the routing problem: given user input, which domain or tool should handle it? LangGraph leaves this to the LLM. I think it shouldn't.
from decide_router import RouteTable
rt = RouteTable("routes.yaml")
rule, _ = rt.match("check nginx error logs")
No LLM call. No prompt. Just a YAML file and 50 lines of matching logic.
The YAML defines domains with keywords and regex patterns:
domains:
monitoring:
priority: 100
keywords: [log, error, nginx, monitor, health, status]
patterns: ["(check|look).*(log|status|error)"]
coding:
priority: 100
keywords: [code, script, deploy, write]
human:
priority: 100
keywords: [delete production, restart cluster]
require_confirm: true
Plug it into LangGraph as a node:
from langgraph.graph import Graph
from decide_router import RouteTable
rt = RouteTable("routes.yaml")
def routing_node(state):
rule, _ = rt.match(state["input"])
state["domain"] = rule.domain if rule else "unknown"
return state
graph = Graph()
graph.add_node("decide_route", routing_node)
graph.set_entry_point("decide_route")
Your LangGraph agent now routes with rules, not guesses. Same input β same domain. Every time.
The best part wasn't planned β it emerged from using it.
I noticed I kept correcting wrong routes. "That's monitoring, not coding." Every correction was a signal. So I added a feedback cache:
rt.record_feedback("check nginx errors", "monitoring")
Same correction 3 times β becomes a permanent routing rule at priority 70. Rules not used in 30 days auto-delete. The system gets smarter with every correction. No fine-tuning. No prompt engineering.
The core module is one file, 200 lines of Python. Read the whole thing in 5 minutes.
pip install decide-router
Or browse the code: github.com/chex0210-crypto/decide-router
I built this because I was tired of guessing why my agent picked the wrong tool. If you've had the same frustration, star the repo β it helps other people find it.