Implementing Tool Granularity Tradeoffs: Integration vs. Separation in AI Agent Frameworks

Tool granularity tradeoffs determine whether to merge related capabilities into a unified tool or split them into separate, specialized tools—balancing LLM cognitive load against implementation complexity and performance transparency.

When building AI agent systems, every tool you expose to the language model consumes part of its reasoning budget. The repository bojieli/ai-agent-book examines this design dilemma extensively in Chapter 4 – Tools, where the author frames tool granularity as a fundamental architectural decision that directly impacts agent reliability and scalability.

Why Tool Granularity Matters

The granularity of your tool catalog creates a tension between two failure modes:

  • Too fine-grained: Each API endpoint becomes its own tool (extract_pdf_text, extract_docx_content, extract_pptx_content). The LLM must learn separate names, signatures, and usage patterns. According to the source analysis, this overwhelms the selection process once the toolbox exceeds approximately 100 tools【https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md#L55-L58】.

  • Too coarse-grained: A single "monster" tool attempts everything. The prompt must describe many optional parameters, the implementation validates a huge combinatorial space, and the model struggles to supply correct arguments.

The optimal position balances functional similarity and overlap of usage scenarios. Tools sharing the same core operation (e.g., "read a document") should be integrated; tools with dramatically different parameters or performance characteristics (e.g., OCR on images versus key-frame extraction from video) should remain separate【https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md#L59-L62】.

When to Apply the Integration Strategy

Integrate tools when they share a common abstraction with minimal variation in their contracts.

Four-Step Integration Process

  1. Identify common abstraction — Find the minimal operation capturing shared intent across tool variants.

  2. Expose single entry point — Define one tool (e.g., read_document) accepting a discriminating argument like file_type or format.

  3. Delegate internally — Dispatch to appropriate backend parsers based on the argument value.

  4. Document boundaries — Specify supported formats, error codes, and latency characteristics per format.

Benefits of Integration

  • Reduces the number of names the model must memorize
  • Provides a single, consistent schema for LLM reasoning
  • Enables format extensions by modifying only the internal dispatcher

When to Apply the Separation Strategy

Keep tools distinct when any of these conditions hold:

  • Parameter sets differ significantly — OCR requires image resolution and language model selection; video key-frame extraction needs frame-rate and timestamp parameters.

  • Performance/latency profiles vary — Heavy video analysis takes seconds; simple text extraction operates at millisecond scale. Merging them hides cost signals the model could use for efficient planning.

  • Security or permission boundaries differ — A tool writing to production databases requires stricter access control than read-only search tools.

The repository illustrates this in chapter8/browser-use-rpa/browser-use/integrations/gmail/actions.py, where gmail_fetch maintains its own permission model precisely because email access carries distinct security requirements.

MCP-Based Architectural Blueprint

The ai-agent-book repository implements tools through the Model Context Protocol (MCP). The integration versus separation choice appears directly in server configuration files.

Integrated Tool: Unified Document Reader

{
  "tool_name": "read_document",
  "description": "Read a document and return its text. Unified entry for PDFs, DOCX, PPTX.",
  "parameters": {
    "type": "object",
    "properties": {
      "path":   { "type": "string", "description": "Absolute file path" },
      "format": { "type": "string", "enum": ["pdf","docx","pptx"], "description": "Document format" }
    },
    "required": ["path", "format"]
  },
  "returns": {
    "type": "string",
    "description": "Plain-text content of the document (truncated to 10k characters)."
  }
}

Separate Tools: Format-Specific Extraction

For the separation approach, the MCP server exposes three distinct entries:

  • extract_pdf_text with PDF-specific schema
  • extract_docx_content with Office document schema
  • extract_pptx_content with presentation-specific schema

The choice of which JSON to publish constitutes the concrete manifestation of your granularity tradeoff.

Critical design rule from Chapter 4: Never silently rewrite parameters. Any normalization (e.g., file extension conversion) must be documented in the description to avoid the "silent input transformation" pitfall【https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md#L87-L94】.

Practical Implementation Examples

The following Python implementations demonstrate both strategies, assuming an agent framework invoking MCP-registered tools via call_tool(name, args).

Integrated read_document Implementation


# integrated_tool.py

import json
from pathlib import Path
from pdfminer.high_level import extract_text as pdf_text
from docx import Document as DocxDocument
from pptx import Presentation as PptxPresentation

def read_document(path: str, fmt: str) -> str:
    """Unified document reader used by the Agent."""
    file_path = Path(path)
    if fmt == "pdf":
        return pdf_text(file_path)          # ← PDF parser

    if fmt == "docx":
        doc = DocxDocument(file_path)
        return "\n".join(p.text for p in doc.paragraphs)
    if fmt == "pptx":
        prs = PptxPresentation(file_path)
        return "\n".join(
            shape.text for slide in prs.slides for shape in slide.shapes
            if hasattr(shape, "text")
        )
    raise ValueError(f"Unsupported format: {fmt}")

# Example usage from an Agent prompt

response = call_tool(
    name="read_document",
    args={"path": "/data/report.pdf", "format": "pdf"}
)
print("Document excerpt:", response[:200])

This approach succeeds because the LLM only needs to know the single tool name read_document with arguments path and format. Adding support for OpenDocument Text (odt) extends the internal if chain without changing the tool interface.

Separate Tools Implementation


# separate_tools.py

def extract_pdf_text(path: str) -> str:
    from pdfminer.high_level import extract_text
    return extract_text(path)

def extract_docx_content(path: str) -> str:
    from docx import Document
    doc = Document(path)
    return "\n".join(p.text for p in doc.paragraphs)

def extract_pptx_content(path: str) -> str:
    from pptx import Presentation
    prs = Presentation(path)
    return "\n".join(
        shape.text for slide in prs.slides for shape in slide.shapes
        if hasattr(shape, "text")
    )

# Agent invokes the appropriate tool directly

pdf = call_tool(name="extract_pdf_text", args={"path": "/data/report.pdf"})
docx = call_tool(name="extract_docx_content", args={"path": "/data/notes.docx"})
pptx = call_tool(name="extract_pptx_content", args={"path": "/data/slides.pptx"})

Separate tools work well when the LLM already knows the exact file type from context, eliminating the format argument. The cost is three distinct tool names to remember—a burden that compounds as the toolbox scales.

Hybrid Adaptive Pattern

def read_document_adaptive(path: str) -> str:
    """Hybrid: try the integrated tool, fall back to specialised ones."""
    ext = Path(path).suffix.lower()
    fmt = {"pdf": "pdf", "docx": "docx", "pptx": "pptx"}.get(ext)
    if fmt:
        return call_tool("read_document", {"path": path, "format": fmt})
    # If a new/unsupported extension appears, delegate to a dedicated tool

    if ext == ".txt":
        return call_tool("read_text_file", {"path": path})
    raise ValueError(f"Cannot handle {ext}")

This pattern embodies the integration-when-possible, separation-when-necessary principle.

Key Source Files and Their Roles

File Role Granularity Relevance
book-en/chapter4.md Architectural rationale and design guidelines【https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md】 Primary source for integration vs. separation framework
chapter8/browser-use-rpa/browser-use/integrations/gmail/actions.py gmail_fetch with distinct permission model Separation required for security boundaries
chapter8/gaia-experience/AWorld/examples/gaia/mcp_collections/tools/search.py Unified search handling multiple backends Real-world integration example
scripts/sync_chapter2_figures.py Visualization synchronization for tool documentation Demonstrates UI impact of tool count on cognitive load

Summary

  • Start with integration for tools sharing core purpose and similar parameters
  • Separate when parameter space, latency, or security models diverge sharply
  • Document every decision in MCP schema descriptions so the LLM makes informed selections
  • Never silently transform inputs—document all normalization explicitly
  • Reference the repository's MCP-based definitions as proven templates for your implementations

Frequently Asked Questions

How many tools is too many for an LLM to handle effectively?

The source analysis suggests cognitive overload begins around 100 distinct tools in the catalog【https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md#L55-L58】. Beyond this threshold, the model's ability to select appropriate tools degrades due to the sheer number of names, signatures, and usage patterns it must retain. Integration strategies become essential for scaling past this boundary.

Should I integrate tools with different latency characteristics?

Generally no. When one operation completes in milliseconds and another requires seconds, separation preserves important cost signals. The LLM can use latency awareness for efficient planning—choosing faster tools for iterative exploration and slower ones for comprehensive analysis. Merging them obscures this decision-relevant information.

How do I document parameter normalization in MCP schemas?

Describe any transformations directly in the tool's description field. For example: "The format parameter accepts file extensions (pdf, docx) or MIME types (application/pdf, application/vnd.openxmlformats-officedocument.wordprocessingml.document); both are normalized internally." This follows the repository's explicit prohibition against silent input transformation【https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md#L87-L94】.

Can I change granularity decisions after deployment?

Yes, but treat it as a breaking change. Switching from three separate tools to one integrated tool (or vice versa) alters the model's available action space. Version your MCP server configurations and update agent prompts accordingly. The repository's examples in chapter8/ demonstrate how different projects made irreversible granularity commitments based on their specific constraints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →