Tool Selection for LLM Agents: Routing Strategies and Implementation › Worked Example: Multi-Tool Selection
Language AI HandbookAll chapters 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:
- Calculator: Mathematical computations
- Calendar: Schedule checking and event creation
- Email: Sending messages
- Search: Web information retrieval
- 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.
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 paramsselector = 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)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.

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.