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
최근 소스 활동
2026년 6월 9일 00:45
감지된 SKILL.md 언어
영어
스타
4
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 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에서 보기