Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tool, Skill, and Sub Agent: Three Layers of Capability Abstraction

🎯 "Tools are hands, Skills are abilities, Sub Agents are team members — understanding the relationship between the three is key to designing good Agent architectures."

In previous chapters, we learned about tool calling (Chapter 4), skill systems (Chapter 10), and multi-Agent collaboration (Chapter 14). This section brings them together for a unified comparison and review — helping you make the right architectural choices in real development.

Tool · Skill · Sub Agent Three-Layer Capability Abstraction

An Intuitive Analogy

ConceptRestaurant AnalogySoftware Analogy
ToolChef's knife, wok, ovenA single API call, a function
Skill"Sichuan cooking", "French pastry making"A set of tools + strategy + knowledge encapsulation
Sub AgentA professional chefAn independent Agent with its own reasoning loop
  • Tools are the smallest execution units — a knife doesn't cook by itself
  • Skills are methods for combining tools — knowing when to use which tool and how
  • Sub Agents are independent decision-makers with skills — a chef can autonomously decide the cooking process

Three-Layer Capability Model

# ──────────── Layer 1: Tool ────────────
# Smallest execution unit: input → execute → output, stateless, no decision-making
def search_web(query: str) -> list[str]:
    """Search the web, return list of results"""
    return search_engine.search(query)

def read_file(path: str) -> str:
    """Read file contents"""
    return open(path).read()

def execute_sql(query: str) -> list[dict]:
    """Execute SQL query"""
    return database.execute(query)


# ──────────── Layer 2: Skill ────────────
# Combination of tools + strategy + knowledge encapsulation
class DataAnalysisSkill:
    """Data analysis skill: encapsulates multiple tools + analysis strategy + domain knowledge"""
    tools = [execute_sql, create_chart, calculate_statistics]
    
    system_prompt = """You are a data analysis expert. Follow these strategies when analyzing data:
    1. First understand data structure and data quality
    2. Choose appropriate analysis methods based on problem type
    3. Use visualization to help explain conclusions"""
    
    def execute(self, task: str) -> str:
        """Execute one data analysis (usually a single LLM call + tool combination)"""
        return llm.chat(system=self.system_prompt, tools=self.tools,
                       messages=[{"role": "user", "content": task}])


# ──────────── Layer 3: Sub Agent ────────────
# Independent reasoning loop: has its own memory, planning, decision-making capabilities
class DataAnalystAgent:
    """Data analyst Agent: has skill library + independent memory + autonomous planning"""
    skills = [DataAnalysisSkill(), ReportWritingSkill(), DataCleaningSkill()]
    memory = WorkingMemory()
    
    def run(self, objective: str) -> str:
        """Autonomously execute multi-step tasks with a complete reasoning loop"""
        plan = self.plan(objective)
        for step in plan:
            skill = self.select_skill(step)
            result = skill.execute(step)
            self.memory.store(step, result)
            if self.should_replan(result):
                plan = self.replan(objective, self.memory)
        return self.synthesize(self.memory)

Core Differences: Comparison Across Five Dimensions

DimensionToolSkillSub Agent
Abstraction levelLowest — single operationMiddle — operation combinationHighest — autonomous entity
Decision-making❌ No decision, pure execution⚠️ Limited decisions (within strategy)✅ Fully autonomous decisions
State managementStatelessLightweight stateIndependent memory + working state
Reasoning loopNoneUsually single-passMulti-step loop (Plan-Act-Observe)
ComposabilityCalled by skills and AgentsCalled by AgentsOrchestrated by parent Agents

Progressive Decision-Making Capability

Tool:       input → output                (deterministic mapping)
Skill:      input → [strategy selection] → output     (limited conditional branching)
Sub Agent:  objective → [plan→act→reflect→adjust]* → output  (autonomous reasoning loop)

A practical example to feel this progression:

# Task: Prepare a quarterly sales report for the user

# ── Using only Tools ──
# Agent must make all decisions itself, calling tools one by one
result1 = execute_sql("SELECT * FROM sales WHERE quarter = 'Q4'")
result2 = calculate_statistics(result1)
result3 = create_chart(result2, chart_type="bar")
result4 = format_report(result2, result3)
# The Agent itself bears all "how to do it" decisions

# ── Using Skills ──
# Agent only needs to specify "what to do", Skill handles "how to do it" internally
report = data_analysis_skill.execute("Generate Q4 sales report with trend analysis and charts")

# ── Using Sub Agent ──
# Main Agent only states the "objective", Sub Agent autonomously completes everything
report = data_analyst_agent.run(
    "Comprehensively analyze Q4 sales data, identify problems and opportunities, write management report"
)
# Sub Agent plans steps, selects skills, handles exceptions, iterates multiple times

When to Use What? Decision Framework

def choose_abstraction(task_requirements: dict) -> str:
    """Choose the appropriate capability abstraction level"""
    complexity = task_requirements.get("complexity")
    autonomy = task_requirements.get("autonomy_needed")
    steps = task_requirements.get("estimated_steps")
    
    if complexity == "simple" and steps <= 1:
        return "Tool"      # Search web, read file, call API
    
    if complexity == "medium" or (steps <= 5 and autonomy == "medium"):
        return "Skill"     # Data analysis, code review, document generation
    
    if complexity == "complex" or autonomy == "high" or steps > 5:
        return "Sub Agent"  # Autonomous research, project planning, cross-system coordination
    
    return "Tool"

Selection Guide for Real Scenarios

ScenarioRecommended AbstractionReason
Call a weather APIToolSingle, deterministic operation
Query database and return resultsToolClear input/output
Analyze a dataset and generate visualizationsSkillNeeds to combine multiple tools + analysis strategy
Translate a document into 3 languagesSkillFixed process, tools + domain knowledge
Autonomously complete code review and submit PRSub AgentNeeds to understand code, make judgments, multi-step operations
Manage an entire data analysis projectSub AgentNeeds to orchestrate multiple subtasks and sub-Agents

Composition Pattern: Hierarchical Architecture

In real Agent systems, the three layers of abstraction are typically used in a nested fashion:

Orchestrator Agent
├── Research Sub Agent
│   ├── Web Search Skill
│   │   ├── search_web()    [Tool]
│   │   ├── fetch_page()    [Tool]
│   │   └── extract_text()  [Tool]
│   └── Summary Skill
│       ├── chunk_text()    [Tool]
│       └── summarize()     [Tool]
│
├── Coding Sub Agent
│   ├── Code Analysis Skill
│   │   ├── read_file()     [Tool]
│   │   └── search_code()   [Tool]
│   └── Code Edit Skill
│       ├── write_file()    [Tool]
│       └── run_tests()     [Tool]
│
└── Report Sub Agent
    └── Report Writing Skill
        ├── create_chart()  [Tool]
        └── render_pdf()    [Tool]
class ProductionAgent:
    """Code implementation of hierarchical architecture"""
    def __init__(self):
        self.sub_agents = {
            "researcher": ResearchAgent(skills=[WebSearchSkill(), SummarySkill()]),
            "coder": CodingAgent(skills=[CodeAnalysisSkill(), CodeEditSkill()]),
            "reporter": ReportAgent(skills=[ReportWritingSkill()]),
        }
    
    def handle_task(self, task: str):
        plan = self.plan(task)
        for step in plan:
            agent_name = self.route(step)
            result = self.sub_agents[agent_name].run(step)
            self.collect_result(step, result)
        return self.synthesize_results()

Common Pitfalls and Best Practices

❌ Pitfall 1: Using Sub Agents for Everything

# Anti-pattern: creating a full Sub Agent for a simple search
class OverEngineeredSearchAgent:
    """Don't do this! Searching the web only needs a Tool"""
    def __init__(self):
        self.memory = WorkingMemory()   # Not needed
        self.planner = Planner()        # Not needed
    def run(self, query):
        plan = self.planner.plan(f"Search: {query}")
        # Just to call one search() function? Way too heavy!

❌ Pitfall 2: Stuffing Complex Logic into a Single Tool

# Anti-pattern: a "tool" containing too much logic
def analyze_and_report(data_path, output_format, language, chart_type, ...):
    """This is not a Tool — it should be a Skill or Sub Agent! Tools should be atomic operations with single responsibility"""
    data = load(data_path)
    cleaned = clean_data(data)
    analyzed = run_analysis(cleaned)
    chart = create_chart(analyzed, chart_type)
    report = write_report(analyzed, chart, language)
    return export(report, output_format)

✅ Best Practice: Progressive Upgrade

# Phase 1: Start with Tools for quick validation
tools = [search_web, read_file, execute_sql]
agent = SimpleReActAgent(tools=tools)
# When Prompt is full of "if...then..." conditional logic → upgrade to Skill

# Phase 2: Encapsulate recurring patterns as Skills
data_skill = DataAnalysisSkill(tools=[execute_sql, calculate, create_chart])
code_skill = CodeReviewSkill(tools=[read_file, search_code, lint])
agent = SkillBasedAgent(skills=[data_skill, code_skill])
# When a single Agent's Prompt exceeds 4K tokens → consider splitting into Sub Agents

# Phase 3: Split independent functional domains into Sub Agents
analyst = DataAnalystAgent(skills=[data_skill])
reviewer = CodeReviewAgent(skills=[code_skill])
orchestrator = OrchestratorAgent(sub_agents=[analyst, reviewer])

Relationship with Communication Protocols

The three layers of abstraction are closely related to the communication protocols we learn in Chapter 15:

Abstraction LayerTypical Communication ProtocolDescription
ToolMCP (Model Context Protocol)MCP defines the standard interface between Agents and tools
SkillFramework internal interfaceSkills are usually in the same process, no cross-process protocol needed
Sub AgentA2A (Agent-to-Agent)Sub Agents communicate and coordinate via A2A protocol
# Complete picture of MCP connecting tools → A2A connecting Agents
#
# [Orchestrator Agent]
#     │
#     ├── A2A ──→ [Research Agent]
#     │               ├── MCP ──→ [Web Search Server]
#     │               └── MCP ──→ [Database Server]
#     │
#     └── A2A ──→ [Coding Agent]
#                     ├── MCP ──→ [File System Server]
#                     └── MCP ──→ [Git Server]

Section Summary

Key PointDescription
Three-layer progressionTool (atomic operation) → Skill (strategy encapsulation) → Sub Agent (autonomous entity)
Core differenceDifferent levels of decision-making capability and autonomy
Selection principleStart with the simplest, upgrade as needed — don't over-engineer
Composition patternThree-layer nesting is a common architecture for production-grade Agents
Progressive evolutionTools first for validation → Skills for encapsulation and reuse → Sub Agents for splitting and autonomy

📖 Understanding the relationship between these three layers of abstraction is the key leap from "being able to write an Agent" to "being able to design an Agent system."


Related chapters: Chapter 4 Tool Calling · Chapter 10 Skill System · Chapter 14 Multi-Agent Collaboration · Chapter 15 Agent Communication Protocols