{"slug": "langgraph-s-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it", "title": "LangGraph's Routing Is LLM-Guessing. I Wrote 50 Lines of Code to Make It Deterministic.", "summary": "A developer created a deterministic routing system for LangGraph agents, replacing LLM-based routing with a 50-line rule-matching module. The solution uses a YAML-defined route table with keywords and regex patterns, ensuring the same input always maps to the same domain. A feedback cache automatically promotes frequently corrected routes to permanent rules, eliminating prompt engineering and guesswork.", "body_md": "Every time your LangGraph agent sees \"check nginx logs\", it might call a different tool.\n\nThat'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.\n\nI spent months debugging this. Every wrong route meant tweaking a prompt, hoping the next call would be better. It never was.\n\nSo I wrote something different.\n\nLangGraph is great at orchestrating multi-step agent workflows. But the first step — \"what tool should I use?\" — is a black box.\n\nYou 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?\n\nThis 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.\n\n``` python\nfrom decide_router import RouteTable\n\nrt = RouteTable(\"routes.yaml\")\nrule, _ = rt.match(\"check nginx error logs\")\n# rule.domain → \"monitoring\" — always, every time\n```\n\nNo LLM call. No prompt. Just a YAML file and 50 lines of matching logic.\n\nThe YAML defines domains with keywords and regex patterns:\n\n```\ndomains:\n  monitoring:\n    priority: 100\n    keywords: [log, error, nginx, monitor, health, status]\n    patterns: [\"(check|look).*(log|status|error)\"]\n  coding:\n    priority: 100\n    keywords: [code, script, deploy, write]\n  human:\n    priority: 100\n    keywords: [delete production, restart cluster]\n    require_confirm: true\n```\n\nPlug it into LangGraph as a node:\n\n``` python\nfrom langgraph.graph import Graph\nfrom decide_router import RouteTable\n\nrt = RouteTable(\"routes.yaml\")\n\ndef routing_node(state):\n    rule, _ = rt.match(state[\"input\"])\n    state[\"domain\"] = rule.domain if rule else \"unknown\"\n    return state\n\ngraph = Graph()\ngraph.add_node(\"decide_route\", routing_node)\ngraph.set_entry_point(\"decide_route\")\n```\n\nYour LangGraph agent now routes with **rules**, not guesses. Same input → same domain. Every time.\n\nThe best part wasn't planned — it emerged from using it.\n\nI noticed I kept correcting wrong routes. \"That's monitoring, not coding.\" Every correction was a signal. So I added a feedback cache:\n\n```\n# User corrects once → remembers immediately\nrt.record_feedback(\"check nginx errors\", \"monitoring\")\n```\n\nSame 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.\n\nThe core module is one file, 200 lines of Python. Read the whole thing in 5 minutes.\n\n```\npip install decide-router\n```\n\nOr browse the code: [github.com/chex0210-crypto/decide-router](https://github.com/chex0210-crypto/decide-router)\n\n*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.*", "url": "https://wpnews.pro/news/langgraph-s-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it", "canonical_source": "https://dev.to/chex0210crypto/langgraphs-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it-deterministic-24oj", "published_at": "2026-06-25 13:18:34+00:00", "updated_at": "2026-06-25 13:43:50.707578+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "large-language-models", "natural-language-processing"], "entities": ["LangGraph", "decide-router", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/langgraph-s-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it", "markdown": "https://wpnews.pro/news/langgraph-s-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it.md", "text": "https://wpnews.pro/news/langgraph-s-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it.txt", "jsonld": "https://wpnews.pro/news/langgraph-s-routing-is-llm-guessing-i-wrote-50-lines-of-code-to-make-it.jsonld"}}