Tool Selection for LLM Agents: Routing Strategies and Implementation › Worked Example: Multi-Tool Selection

Michael BrenndoerferFebruary 4, 20265 min read
Language AI HandbookAll chapters
Part 48 of 67Tool Use and Agents
Chapter 366Tool Selection for LLM Agents: Routing Strategies and Implementation › Worked Example: Multi-Tool Selection
Reading section 6 of 11 · Worked Example: Multi-Tool Selection · 5 minSection 6 of 11 · 5 min

Book contents

Section 6 of 11 · 5 min read

Tool Selection for LLM Agents: Routing Strategies and Implementation › Worked Example: Multi-Tool SelectionOne section · Sections in this chapter6 / 11 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Let's walk through a concrete example showing how an LLM works within a complex tool ecosystem. Consider a personal assistant with access to five tools:

  1. Calculator: Mathematical computations
  2. Calendar: Schedule checking and event creation
  3. Email: Sending messages
  4. Search: Web information retrieval
  5. Notes: Saving and retrieving personal notes

User query: "I need to prepare a presentation for next week's team meeting. Can you find the sales figures from Q3, calculate the growth rate from Q2, and schedule 3 hours this Friday to work on slides? Also, remind me to email the team about it."

This query requires decomposing intent across multiple tools, recognizing dependencies between data retrieval and computation, and scheduling actions in the correct temporal order. The LLM must simultaneously parse several sub-goals from a single, complex sentence and construct an execution plan that respects their interdependencies.

In[13]:
Code
class ToolSelector:
    def __init__(self):
        self.tools = {
            "calculator": {
                "desc": "Perform mathematical calculations",
                "triggers": [
                    "calculate",
                    "compute",
                    "growth rate",
                    "percentage",
                    "sum",
                    "average",
                ],
            },
            "calendar": {
                "desc": "Schedule events and check availability",
                "triggers": [
                    "schedule",
                    "meeting",
                    "remind",
                    "block time",
                    "available",
                    "friday",
                    "next week",
                ],
            },
            "email": {
                "desc": "Send emails and messages",
                "triggers": ["email", "send", "message", "write to", "notify"],
            },
            "search": {
                "desc": "Find information and facts",
                "triggers": [
                    "find",
                    "look up",
                    "search",
                    "get",
                    "figures",
                    "data",
                    "q3",
                    "sales",
                ],
            },
            "notes": {
                "desc": "Save and retrieve notes",
                "triggers": ["save", "remember", "note", "write down", "store"],
            },
        }

    def analyze_intent(self, query):
        """Simple keyword-based analysis for demonstration."""
        query_lower = query.lower()
        detected_tools = []

        for tool_name, metadata in self.tools.items():
            score = sum(
                1 for trigger in metadata["triggers"] if trigger in query_lower
            )
            if score > 0:
                detected_tools.append((tool_name, score))

        # Sort by relevance score
        detected_tools.sort(key=lambda x: x[1], reverse=True)
        return detected_tools

    def create_execution_plan(self, query):
        """Create ordered plan based on dependencies."""
        tools_needed = self.analyze_intent(query)

        # Define dependencies: some tools must run before others
        dependencies = {
            "email": ["calendar"],  # Need meeting scheduled before emailing
            "calculator": ["search"],  # Need Q3 data before calculating growth
        }

        plan = []
        completed = set()

        while len(plan) < len(tools_needed):
            added_this_round = False
            for tool_name, score in tools_needed:
                if tool_name in completed:
                    continue

                # Check if dependencies satisfied
                deps = dependencies.get(tool_name, [])
                if all(d in completed for d in deps):
                    plan.append(
                        {
                            "tool": tool_name,
                            "reason": f"Detected intent: '{self.tools[tool_name]['desc']}'",
                            "params": self._extract_params(tool_name, query),
                        }
                    )
                    completed.add(tool_name)
                    added_this_round = True

            if not added_this_round and len(plan) < len(tools_needed):
                # Circular dependency or missing tool
                break

        return plan

    def _extract_params(self, tool_name, query):
        # Simplified parameter extraction
        params = {}
        if tool_name == "calendar":
            if "friday" in query.lower():
                params["day"] = "Friday"
            if "3 hours" in query:
                params["duration"] = "3 hours"
        elif tool_name == "search":
            if "Q3" in query and "sales" in query:
                params["query"] = "Q3 sales figures"
        elif tool_name == "calculator":
            params["task"] = "growth rate Q2 to Q3"
        elif tool_name == "email":
            params["recipient"] = "team"
            params["subject"] = "Presentation preparation"

        return params
In[14]:
Code
selector = ToolSelector()
complex_query = "I need to prepare a presentation for next week's team meeting. Can you find the sales figures from Q3, calculate the growth rate from Q2, and schedule 3 hours this Friday to work on slides? Also, remind me to email the team about it."
intent_analysis = selector.analyze_intent(complex_query)
plan = selector.create_execution_plan(complex_query)
Out[15]:
Console
Query Analysis:
============================================================
User: 'I need to prepare a presentation for next week's team meeting. Can you find the sales figures from Q3, calculate the growth rate from Q2, and schedule 3 hours this Friday to work on slides? Also, remind me to email the team about it.'

Detected tool intents (by keyword matching):
  - calendar: relevance 5
  - search: relevance 4
  - calculator: relevance 2
  - email: relevance 1

============================================================
Execution Plan:

Step 1: CALENDAR
  Reason: Detected intent: 'Schedule events and check availability'
  Parameters: {'day': 'Friday', 'duration': '3 hours'}

Step 2: SEARCH
  Reason: Detected intent: 'Find information and facts'
  Parameters: {'query': 'Q3 sales figures'}

Step 3: CALCULATOR
  Reason: Detected intent: 'Perform mathematical calculations'
  Parameters: {'task': 'growth rate Q2 to Q3'}

Step 4: EMAIL
  Reason: Detected intent: 'Send emails and messages'
  Parameters: {'recipient': 'team', 'subject': 'Presentation preparation'}

The execution plan demonstrates how the system decomposes a complex, multi-part request into discrete tool invocations ordered by their data dependencies. The keyword-based detection successfully identified four relevant tools, with the dependency graph so that data-retrieval steps (search) precede computation steps (calculator). Notice that the email step is deferred to last because it depends on the calendar event being scheduled first.

Out[16]:
Visualization
Horizontal flow diagram showing calendar, search, calculator, and email as colored rectangles connected by arrows in execution order.
Sequential execution plan for the multi-step presentation query. Tools are ordered left to right by their data dependencies: search must complete before calculator can compute the growth rate, and calendar must complete before email can reference the scheduled session.

The analysis reveals four distinct tool invocations. The implicit dependencies (calculator needs search results; email needs calendar event) are automatically resolved by the dependency-aware planner. A sophisticated tool selector recognizes these constraints and orders execution accordingly, or makes parallel calls where independence allows.

In a real LLM-based system, this dependency reasoning happens inside the model's forward pass rather than through explicit dependency graph construction. The model has learned from training data that certain sequences of tool calls commonly appear together, and that certain parameter values are derived from previous tool outputs. This learned co-occurrence pattern effectively captures the dependency structure without requiring the developer to manually enumerate it.