RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Fredoline Eruo
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /Introduction to AI Agents
  6. /Ch. 9
Introduction to AI Agents

09. Multi-Tool Agents

Chapter 9 of 16 · 15 min
KEY INSIGHT

Multi-tool agents require clear tool descriptions so the model can route tasks correctly. Parallel execution speeds up multi-tool calls but adds complexity to result handling.

When an agent has access to multiple tools, it must decide which tool to use and in what order. This introduces the tool selection problem: the model must reason about tool capabilities and pick the right one for each sub-task.

Multi-tool routing

import ollama
from typing import List, Dict, Any

def multi_tool_agent(task: str, tools: List[Tool], max_turns: int = 10) -> str:
    tool_map = {t.name: t for t in tools}
    tool_schemas = [t.to_openai_schema() for t in tools]
    
    messages = [
        {"role": "system", "content": (
            "You have access to multiple tools. Choose the right tool for each step. "
            "You may call multiple tools if they are independent. "
            "When you have all the information needed, respond with your final answer."
        )},
        {"role": "user", "content": task}
    ]
    
    for turn in range(max_turns):
        response = ollama.chat(
            model="llama3.2",
            messages=messages,
            tools=tool_schemas
        )
        
        if not response.message.tool_calls:
            messages.append({"role": "assistant", "content": response.message.content})
            return response.message.content
        
        for call in response.message.tool_calls:
            fn = call.function
            if fn.name not in tool_map:
                result = f"Error: Unknown tool '{fn.name}'"
            else:
                result = tool_map[fn.name].invoke(**fn.arguments)
            
            messages.append({"role": "assistant", "content": "", "tool_calls": [call]})
            messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})
    
    return "Max turns exceeded"

Parallel tool calls

Ollama supports parallel tool calls in a single response. When the model returns multiple tool_calls, execute them concurrently:

import concurrent.futures

if response.message.tool_calls:
    with concurrent.futures.ThreadPoolExecutor() as executor:
        futures = {
            executor.submit(tool_map[call.function.name].invoke, **call.function.arguments): call
            for call in response.message.tool_calls
            if call.function.name in tool_map
        }
        
        for future in concurrent.futures.as_completed(futures):
            call = futures[future]
            try:
                result = future.result()
            except Exception as e:
                result = f"Error: {e}"
            
            messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})

Tool selection failures

Models sometimes call the wrong tool. A web_search tool cannot answer "calculate 15% of 200" because the model chose search instead of calculator. Mitigate this by:

  • Writing distinct, non-overlapping tool descriptions
  • Adding explicit lists of tool capabilities in the system prompt
  • Providing a retry mechanism that asks the model to reconsider
EXERCISE

Register three tools (web search, calculator, file reader) and test the agent with a compound query that requires all three. Log which tool was called at each step and verify the execution order makes sense.

← Chapter 8
Building a Calculator Tool
Chapter 10 →
Agent Memory