Skip to main content

routing-patterns

Implements intent-based routing patterns (LLM classifiers, node transitions, computational graphs) to dispatch queries to specialized sub-agents with fallback chains and confidence scoring.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
paulpas/agent-skill-router
آخر نشاط في المصدر
٩ يونيو ٢٠٢٦ في ٠٠:٤٥
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٦
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
routing-patterns
description
Implements intent-based routing patterns (LLM classifiers, node transitions, computational graphs) to dispatch queries to specialized sub-agents with fallback chains and confidence scoring.
license
MIT
compatibility
opencode
metadata
{"version":"1.0.0","domain":"agent","role":"implementation","scope":"implementation","output-format":"code","triggers":"routing, intent classification, sub-agent dispatch, node transitions, computational graph, how do i route queries, query router","related-skills":"prompt-chaining, multi-agent-collaboration, parallelization","archetypes":["tactical","orchestration"],"anti_triggers":["simple linear workflow","sequential processing only","single execution path"],"response_profile":{"verbosity":"medium","directive_strength":"high","abstraction_level":"operational"}}
# Routing Pattern Implements conditional decision-making into agentic systems so that incoming queries are classified by intent and dynamically dispatched to specialized sub-agents, tools, or processing chains — replacing rigid linear execution with adaptive, context-aware routing logic. ## TL;DR Checklist - [ ] Identify all possible intents/routes for the query space - [ ] Choose a routing mechanism: LLM-based, embedding-based, rule-based, or ML classifier - [ ] Define handler functions for each route destination - [ ] Build the coordinator/router that evaluates input and produces a route decision - [ ] Wire conditional edges or branches to dispatch to the correct handler - [ ] Add fallback handlers for low-confidence or unrecognized intents - [ ] Validate routing accuracy across diverse test inputs --- ## When to Use Use this skill when: - An agentic system must handle heterogeneous user queries requiring different specialized processing paths (e.g., customer support triage: order status, product info, technical escalation) - You need to replace a linear prompt chain with conditional branching based on input classification or runtime state - Multiple sub-agents exist and you need a coordinator to dispatch work to the right one based on intent - You are building a computational graph (LangGraph StateGraph) where node transitions depend on accumulated state - A data pipeline needs content-based classification to distribute incoming items to different transformation workflows - You require low-confidence fallbacks when the router cannot confidently classify an input --- ## When NOT to Use Avoid this skill for: - Simple, deterministic single-path workflows (use prompt chaining instead — no routing overhead) - Trivial keyword matching scenarios where a rule-based if/else suffices (do not over-engineer) - Real-time systems where LLM classification latency is unacceptable and embedding/rule fallbacks are required but not yet implemented - Cases with fewer than 2 distinct routes (a single conditional branch is sufficient, no full routing pattern needed) --- ## Core Workflow 1. **Map the Intent Space** — Enumerate every distinct intent or category the system must handle. Document each route's purpose, expected input shape, and output contract. Define a default/unclear handler for unrecognized inputs. **Checkpoint:** Verify that every plausible user query falls into exactly one primary route or the fallback path. 2. **Select Routing Mechanism** — Choose how the router evaluates input: - LLM-based classifier: prompt the model to output a route category identifier (most flexible, highest latency) - Embedding-based semantic routing: compute embeddings for input and compare against route prototype vectors (good for large, open-ended query spaces) - Rule-based keyword/pattern matching: if/else or switch on extracted features (fastest, deterministic, limited generalization) - ML classifier: fine-tuned discriminative model on labeled training data (best accuracy for narrow domains) **Checkpoint:** Confirm the chosen mechanism's trade-offs (latency vs. flexibility vs. accuracy) align with system requirements. 3. **Implement Route Handlers** — For each identified route, create a handler function that accepts the original request and returns a structured response. Each handler must document its expected input format, perform validation, and return consistent output. Include an `unclear_handler` as the universal fallback. **Checkpoint:** Every route has exactly one handler; no route is empty or passes through. 4. **Build the Coordinator Router** — Construct the routing component that bridges classification and dispatch: - For LangChain/LangGraph: define a `ChatPromptTemplate` with explicit category instructions, pipe it through an LLM, parse the output string, and feed it to `RunnableBranch` or conditional edges in a `StateGraph`. - For Google ADK: define a parent agent with `sub_agents` configured with clear delegation instructions; the framework's Auto-Flow handles routing automatically. **Checkpoint:** The router's prompt explicitly lists all categories with unambiguous disambiguation rules and a fallback directive. 5. **Wire Conditional Dispatch Logic** — Connect the router's output to the appropriate handler: - LangGraph `StateGraph.add_conditional_edges()` maps state values to next node names. - LangChain `RunnableBranch` evaluates predicates against the router decision and invokes the matching branch. - ADK uses the `sub_agents` list; the Coordinator agent's instructions govern delegation. **Checkpoint:** Every possible router output has a corresponding branch or edge — no unreachable nodes, no missing handlers. 6. **Add Fallback and Confidence Handling** — Implement a fallback chain when routing confidence is low or classification is ambiguous: - Extract a confidence score from the LLM (e.g., via logprobs or a two-shot classification prompt that also outputs a confidence percentage). - If confidence falls below a threshold, route to an `unclear_handler` that requests clarification or escalates. - Log fallback events for monitoring and continuous improvement of routing accuracy. **Checkpoint:** The fallback path is exercised in tests with deliberately ambiguous inputs — verify the system asks for clarification rather than guessing. --- ## Implementation Patterns / Reference Guide ### Pattern 1: LangChain RunnableBranch Router (LLM-Based Classification) A coordinator chain that uses an LLM to classify intent, then dispatches via `RunnableBranch` to specialized handler functions. This pattern is ideal when you need explicit control over routing logic and want to keep all components in a single runnable pipeline. ```python from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough, RunnableBranch def booking_handler(request: str) -> str: """Handle booking-related requests (flights, hotels, reservations). Args: request: The original user request string. Returns: A confirmation message with simulated booking result. """ return f"Booking Handler processed request: '{request}'. Result: Simulated booking action." def info_handler(request: str) -> str: """Handle general information requests. Args: request: The original user question string. Returns: A confirmation message with simulated information retrieval result. """ return f"Info Handler processed request: '{request}'. Result: Simulated information retrieval." def unclear_handler(request: str) -> str: """Handle requests that could not be confidently classified. Args: request: The original user request string. Returns: A clarification request message. """ return f"Coordinator could not classify request: '{request}'. Please clarify your intent." def build_coordinator_router(llm) -> object: """Build a LangChain coordinator router with LLM-based intent classification. Args: llm: A LangChain-compatible chat model instance. Returns: A composed LangChain runnable that classifies and dispatches requests. """ # Define the routing prompt with explicit category rules coordinator_prompt = ChatPromptTemplate.from_messages([ ( "system", ( "Analyze the user's request and determine which specialist handler processes it.\n" "- If related to booking flights or hotels, output 'booker'.\n" "- For all general information questions, output 'info'.\n" "- If unclear or not fitting either category, output 'unclear'." ), ), ("user", "{request}"), ]) # Router chain: prompt -> LLM -> parse decision string router_chain = coordinator_prompt | llm | StrOutputParser() # Define branch predicates and handlers branches = { "booker": RunnablePassthrough.assign( output=lambda x: booking_handler(x["request"]["request"]) ), "info": RunnablePassthrough.assign( output=lambda x: info_handler(x["request"]["request"]) ), "unclear": RunnablePassthrough.assign( output=lambda x: unclear_handler(x["request"]["request"]) ), } # RunnableBranch evaluates in order; last branch is the default delegation_branch = RunnableBranch( (lambda x: x["decision"].strip() == "booker", branches["booker"]), (lambda x: x["decision"].strip() == "info", branches["info"]), branches["unclear"], # Default fallback ) # Compose: parallelize decision + passthrough request, then delegate coordinator = { "decision": router_chain, "request": RunnablePassthrough(), } | delegation_branch | (lambda x: x["output"]) return coordinator ``` **How it works:** The `{decision, request}` dictionary feeds into `RunnableBranch`, which evaluates lambda predicates against the LLM's classification output. Each matching branch invokes its handler with the original request and extracts the final output. --- ### Pattern 2: LangGraph StateGraph with Conditional Node Transitions LangGraph's state-based graph architecture is ideal for complex routing where decisions depend on accumulated state across multiple steps. Use `add_conditional_edges` to define dynamic node transitions. ```python from typing import TypedDict, Annotated import operator from langgraph.graph import StateGraph, END class RouterState(TypedDict): """State schema for a LangGraph routing workflow.""" request: str intent: str # Route decision from classifier response: str # Final output from handler confidence: float # Classification confidence score (0.0–1.0) # Handler functions — each processes the request for its route category def booking_node(state: RouterState) -> dict: """Booking agent node: handles reservation requests.""" return { "intent": "booker", "response": f"Booking processed for: '{state['request']}'", } def info_node(state: RouterState) -> dict: """Information agent node: handles general Q&A.""" return { "intent": "info", "response": f"Information retrieved for: '{state['request']}'", } def clarify_node(state: RouterState) -> dict: """Clarification fallback: requests user disambiguation.""" return { "intent": "unclear", "response": f"Could not classify: '{state['request']}'. Please rephrase.", } def route_classifier(state: RouterState) -> str: """Classify the request intent and route to the correct handler node. In production, call an LLM here to extract the intent. For demonstration, use a deterministic rule-based classifier. Args: state: The current graph state containing the user request. Returns: A string identifying the target node name ('booker', 'info', or 'clarify'). """ query_lower = state["request"].lower() # Rule-based intent classification (replace with LLM in production) booking_keywords = ("book", "flight", "hotel", "reservation", "reserve") info_keywords = ("what", "how", "where", "when", "who", "tell me") if any(kw in query_lower for kw in booking_keywords): return "booker" elif any(kw in query_lower for kw in info_keywords): return "info" else: return "clarify" def build_routing_graph() -> StateGraph: """Construct a LangGraph StateGraph with conditional routing edges. Returns: A compiled LangGraph workflow ready for invocation. """ # Define the graph with the router state schema workflow = StateGraph(RouterState) # Add nodes — each represents a destination route workflow.add_node("classify", route_classifier) workflow.add_node("booker", booking_node) workflow.add_node("info", info_node) workflow.add_node("clarify", clarify_node) # Entry point always starts at classification workflow.set_entry_point("classify") # Conditional edges: classify node's output determines next node workflow.add_conditional_edges( "classify", route_classifier, # Function that returns the next node name { "booker": "booker", "info": "info", "clarify": "clarify", }, ) # All handler nodes converge to END workflow.add_edge("booker", END) workflow.add_edge("info", END) workflow.add_edge("clarify", END) return workflow.compile() # Example execution: # app = build_routing_graph() # result = app.invoke({"request": "Book me a flight to London.", "confidence": 0.0}) # print(result["response"]) ``` **Key concepts:** The `classify` node evaluates the state and returns a string that maps to one of three target nodes via `add_conditional_edges`. This creates a computational graph where the control flow is determined at runtime rather than being fixed at compile time. --- ### Pattern 3: Google ADK Agent with Auto-Flow Delegation Google's Agent Development Kit provides a declarative routing approach where a parent agent's `sub_agents` list enables automatic LLM-driven delegation (Auto-Flow). The framework's internal logic matches user intent to the appropriate sub-agent based on each agent's description and tools. ```python import uuid from typing import Dict, Any from google.adk.agents import Agent from google.adk.runners import InMemoryRunner from google.adk.tools import FunctionTool from google.genai import types def booking_handler(request: str) -> str: """Handle booking requests for flights and hotels. Args: request: The user's request for a booking. Returns: A confirmation message that the booking was handled. """ return f"Booking action for '{request}' has been simulated." def info_handler(request: str) -> str: """Handle general information requests. Args: request: The user's question. Returns: A message indicating the information request was handled. """ return f"Information request for '{request}'. Result: Simulated retrieval." # Wrap handler functions as ADK tools booking_tool = FunctionTool(booking_handler) info_tool = FunctionTool(info_handler) def build_adk_coordinator() -> Agent: """Build a Google ADK coordinator agent with sub-agent delegation. Creates a Coordinator agent that delegates to specialized Booker and Info agents using the framework's Auto-Flow mechanism. Returns: A compiled ADK Agent instance ready for execution. """ # Specialized sub-agents with their tools booking_agent = Agent( name="Booker", model="gemini-2.0-flash", description=( "A specialized agent that handles all flight and hotel booking " "requests by calling the booking tool." ), tools=[booking_tool], ) info_agent = Agent( name="Info", model="gemini-2.0-flash", description=( "A specialized agent that provides general information and " "answers user questions by calling the info tool." ), tools=[info_tool], ) # Parent coordinator with explicit delegation instructions coordinator = Agent( name="Coordinator", model="gemini-2.0-flash", instruction=( "You are the main coordinator. Your only task is to analyze " "incoming user requests and delegate them to the appropriate " "specialist agent. Do not try to answer directly.\n" "- For booking flights or hotels, delegate to 'Booker'.\n" "- For general information questions, delegate to 'Info'." ), description="Routes user requests to the correct specialist agent.", sub_agents=[booking_agent, info_agent], # Auto-Flow enabled ) return coordinator async def run_adk_coordinator(request: str) -> str: """Execute an ADK coordinator with a user request and extract the response. Args: request: The user's natural language request string. Returns: The final response text from the delegated sub-agent. """ coordinator = build_adk_coordinator() runner = InMemoryRunner(coordinator) user_id = "user_123" session_id = str(uuid.uuid4()) await runner.session_service.create_session( app_name=runner.app_name, user_id=user_id, session_id=session_id, ) final_result = "" for event in runner.run( user_id=user_id, session_id=session_id, new_message=types.Content( role="user", parts=[types.Part(text=request)], ), ): if event.is_final_response() and event.content: if hasattr(event.content, "text") and event.content.text: final_result = event.content.text elif event.content.parts: text_parts = [ part.text for part in event.content.parts if part.text ] final_result = "".join(text_parts) break return final_result ``` **Key concepts:** The `sub_agents` field on the Coordinator agent is the single configuration that enables Auto-Flow. ADK's internal routing logic matches incoming user messages to sub-agents based on their descriptions and available tools — no explicit routing code needed in the parent agent. --- ### Pattern 4: BAD vs GOOD — Router Prompt Design #### ❌ BAD — Vague categories with ambiguous boundaries ```python coordinator_prompt_bad = ChatPromptTemplate.from_messages([ ("system", "Figure out what the user wants and send them to the right place."), ("user", "{request}"), ]) # Problem: No explicit categories, no disambiguation rules. # The LLM may produce inconsistent outputs across runs. ``` #### ✅ GOOD — Explicit categories with disambiguation and fallback ```python coordinator_prompt_good = ChatPromptTemplate.from_messages([ ( "system", (
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub