Engineering the Agentic Stack · Deel 3

AI Agent-toolgebruik: MCP, CLI, Skills en code-executie

Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.

In deel 1 kwamen reasoning loops aan bod en in deel 2 agent memory. Dit artikel voegt de actielaag toe: hoe een agent tools beschikbaar maakt, selecteert en uitvoert. Memory bepaalt wat de agent aan het begin van een turn weet; deze laag bepaalt wat de agent daarmee kan doen. In deel 4 behandelen we de check die bepaalt of een benoemde call überhaupt wordt uitgevoerd, en in deel 6 de harness die zowel de call als de check uitvoert. In dit artikel betekent harness het control program dat elke prompt samenstelt, de geaccepteerde tool calls dispatcht en bepaalt wanneer de taak klaar is — alles rond het model dat uit gewone code bestaat die je zelf schrijft.

Het tooling-landschap veranderde in 2025–2026. MCP, het Model Context Protocol, gaf vendors één gedeelde manier om externe services beschikbaar te maken. Code-executing agents lieten zien dat een model soms efficiënter een klein programma kan samenstellen dan een lange reeks JSON calls kan uitsturen. Anthropic rapporteerde een 98,7% reductie in tokens voor één Google Drive-naar-Salesforce-workflow, en het CodeAct-paper rapporteerde verbeteringen tot 20% binnen zijn benchmarkopzet. Die resultaten beschrijven hun taken en harnesses, geen universeel voordeel van code-executie.

Ik vergelijk JSON tool calling, MCP, Skills, CLI-tools en code-executie in die volgorde. Een latere sectie past Agent-Computer Interface (ACI)-ontwerpprincipes toe op de Market Analyst Agent, een kleine LangGraph research-agent die ik voor deel 1 heb gebouwd en die marktdata ophaalt en een analistenrapport schrijft.

Zie voor de korte interfacekeuze AI Agent Tool Interfaces.


Vijf manieren waarop AI agents tools gebruiken

In deel 1 koos de reasoning loop de volgende stap. Deel 2 sloeg de state op die nodig was om de loop te hervatten. De tool boundary bevindt zich tussen beide: deze valideert wat de loop voorstelt, geeft de call door voor execution en retourneert het resultaat naar de loop. Deze vijf patronen maken verschillende trade-offs op het gebied van tokenkosten, flexibiliteit en afdwingbaarheid.

Vijf AI agent-toolmodaliteiten en hun trade-offsVijf AI agent-toolmodaliteiten en hun trade-offs

1. JSON tool calling: de baseline

Het oorspronkelijke patroon: je definieert tool schemas als JSON, de LLM emit structured function calls en je code voert ze uit. Dit is goed begrepen en werkt prima voor kleine toolsets.

# Traditional tool definition — each tool consumes ~550-1,400 tokens (Apideck benchmark)
tools = [
    {
        "name": "get_stock_price",
        "description": "Get the current stock price for a ticker symbol",
        "input_schema": {
            "type": "object",
            "properties": {
                "ticker": {"type": "string", "description": "Stock ticker (e.g., NVDA)"}
            },
            "required": ["ticker"]
        }
    }
]

Bij 5–10 tools is de overhead acceptabel. Het probleem ontstaat bij schaal: elke tooldefinitie kost 550–1.400 tokens. Bij 20 tools besteed je 11–28K tokens voordat de agent überhaupt aan reasoning begint.

2. MCP voor gedeelde integraties

MCP is de standaard waarop de meeste vendors zijn uitgekomen. Een MCP-server is een process dat via een gedefinieerd wire protocol een lijst tools adverteert — stdio voor een lokaal process en HTTP voor een remote process. Je agent draait een MCP-client die verbinding maakt, de server vraagt welke tools beschikbaar zijn en de calls van het model doorstuurt, zodat dezelfde server werkt met elke client die het protocol spreekt. Anthropic schonk het protocol in december 2025 aan de Linux Foundation, onder de Agentic AI Foundation die het samen met OpenAI en Block oprichtte. Google, Microsoft en AWS steunen de foundation als platinum members. OpenAI voegde MCP-support toe aan zijn Responses API. Volgens Anthropic’s aankondiging van de schenking in december 2025 telde het ecosysteem 10.000+ actieve publieke MCP-servers en 97M+ maandelijkse SDK-downloads over de Python- en TypeScript-SDKs.

MCP past bij SaaS-integratie over meerdere vendors heen (Figma, Notion, Salesforce), services zonder CLI-equivalenten en omgevingen die OAuth-orchestration nodig hebben. De waarde zit in een gedeelde discovery- en transportlaag. Governance blijft afhankelijk van de authentication-, authorization-, logging- en deployment-controls van de server.

Het production-verhaal is rommeliger dan de headline-nummers suggereren.

Het security-oppervlak is het eerste probleem. Het Vulnerable MCP Project houdt 50 vulnerabilities in MCP-servers bij, waarvan 13 als Critical zijn beoordeeld, aangebracht door 32 security researchers. De attack classes omvatten prompt injection, fouten in input validation, authentication gaps en network security holes. De eerste kwaadaardige MCP-server in de praktijk verscheen in september 2025: een package met de naam postmark-mcp dat elke uitgaande e-mail via BCC naar het adres van een aanvaller stuurde.

Tool poisoning is de attack class waar ik me het meest zorgen over maak. Invariant Labs demonstreerde dat poisoned MCP-tools data kunnen exfiltreren, zelfs wanneer ze nooit worden aangeroepen. Alleen het lezen van de metadata van de tool door het model is al voldoende om de aanval te activeren. MCPTox-benchmarks die 20 LLM-agents tegen 45 MCP-servers uit de praktijk testten, vonden attack success rates tot 72,8%.

Tokenoverhead is het operationele probleem. Een team dat MCP-servers voor GitHub, Slack en Sentry draaide (~40 tools in totaal), ontdekte dat 55.000 tokens aan schemadefinities werden geïnjecteerd voordat een gebruiker iets vroeg. Een ander team rapporteerde dat 143.000 van de 200.000 beschikbare tokens (72%) alleen al door tooldefinities werden verbruikt.

Vergelijking van tokenoverheadVergelijking van tokenoverhead

Anthropic’s Tool Search Tool-rapport mat een reductie van 85% in het totale contextgebruik — van ongeveer 77.000 tokens voordat het werk begint naar 8.700 — waarbij in de traditionele setup ongeveer 72.000 tokens uit tooldefinities bestonden. De aanpak laadt alleen de drie tot vijf tools die een request nodig heeft, maar voegt vóór invocation een discovery-stap toe; voor kleine, compacte toolsets waarvan de tools in elke sessie vaak worden gebruikt, is dit minder nuttig.

3. Skills verpakken expertise, geen execution

Agent skills zijn een open format voor het verpakken van instructies en ondersteunende bestanden. Tools leveren capabilities (wat agents kunnen doen) en skills leveren expertise (wat agents weten over hoe ze complexe taken moeten uitvoeren).

Het SKILL.md-format definieert een skill als een markdownbestand met YAML frontmatter. De open standaard vereist alleen name en description; het onderstaande voorbeeld gebruikt daarnaast twee Claude Code-extensies, argument-hint en user-invocable, plus de positional-argument-placeholder $0:

---
name: deploy
description: Deploy the application to production
argument-hint: "[environment]"
user-invocable: true
---
Deploy the application to the $0 environment (default: staging).
Steps:
1. Run the test suite
2. Build the production bundle
3. Deploy using the deploy script
4. Verify the deployment health check

Skills gebruiken progressive disclosure. Bij startup wordt ongeveer 100 tokens aan metadata geladen; volledige instructies worden pas geladen wanneer de skill actief is. Vergelijk dat met de ongeveer 55.000 tokens die circa 40 MCP-tools kunnen verbruiken voordat reasoning begint.

Gebruik skills voor domeinkennis, multi-step procedures en terugkerend werk, zoals databasemigraties of payment-integrations. Ze passen bij taken waarbij de agent instructies nodig heeft over hoe een bestaande capability moet worden gebruikt.

4. CLI- en shell-tools

CLI-interfaces kunnen in de context veel goedkoper zijn wanneer het model het commando al kent. Scalekit rapporteerde een tokenverschil van 4–32x tussen zijn CLI- en MCP-paden over 75 runs. Die case study meet de tools en taken van Scalekit; hij vervangt geen vergelijking op basis van je eigen tooldefinities en commandoutput.

Veelgebruikte en goed gedocumenteerde commando’s zoals git, docker, kubectl, gh, curl en jq hebben vaak weinig inleidende schematekst nodig. Minder bekende of interne CLIs hebben nog steeds discoverable help, voorbeelden en stabiele machine-readable output nodig.

Ugo Enyioha’s guide “Writing CLI Tools That AI Agents Actually Want to Use” legde acht ontwerpregels vast:

  1. Structured output is verplicht — ondersteun --json
  2. Exit codes zijn control flow — gebruik verschillende codes voor verschillende error types
  3. Commando’s moeten idempotent zijn
  4. Self-documenting --help met realistische voorbeelden
  5. Ontwerp voor composability--quiet voor pure waarden en ondersteuning voor stdin
  6. Bied --dry-run- en --yes-flags
  7. Ondersteun version introspection
  8. Verwerk auth via environment variables

CLI heeft geen protocol-level discovery. JSON tool calling kan typed schemas bevatten, terwijl MCP tool discovery standaardiseert en voor HTTP-transports een authorization model biedt. Geen van beide levert op zichzelf governance: de host, server of harness moet policy afdwingen en de calls registreren die moeten worden geaudit. Het patroon waar de meeste teams op uitkomen is CLI voor development en lokale operations, en MCP voor gedeelde integratie met externe services.

5. Code-executie voor multi-step werk

Dit is de verandering in agent tooling die ik het meest consequential vind. In plaats van structured JSON te emitten om predefined functions één voor één aan te roepen, schrijft de agent een Python- of bash-script. Het script roept meerdere tools aan, verwerkt resultaten met loops en conditionals en retourneert alleen de uiteindelijke samenvatting naar de modelcontext.

Anthropic introduceerde Programmatic Tool Calling (PTC) als een van drie beta-features in de Claude API. De academische basis is het CodeAct-paper (Wang et al., ICML 2024), dat tests uitvoerde met 17 LLMs en vond dat code actions tot 20% hogere task success rates en 30% minder stappen bereikten dan JSON-alternatieven.

Code-executieflowCode-executieflow

Drie first-party case studies laten zien waar dit patroon kan helpen: Vercel en Cloudflare hieronder, gevolgd door Anthropic’s expense-analysis-voorbeeld. Beschouw ze als vendor evidence en herhaal de vergelijking voor je eigen taken.

  • Vercel bouwde d0 opnieuw, zijn natural-language-to-SQL data agent. Het oude codevoorbeeld benoemt 17 tools; het nieuwe codevoorbeeld stelt ExecuteCommand en ExecuteSQL beschikbaar. Vercel beschrijft het redesign als het verwijderen van 80% van zijn tools, maar dat is Vercel’s headline en geen percentage dat uit de benoemde tools in de voorbeelden volgt. Over vijf representatieve queries rapporteert Vercel dat task success steeg van 4/5 naar 5/5, de gemiddelde execution time 3,5x daalde (274,8 s naar 77,4 s) en het gemiddelde tokengebruik met 37% afnam (~102k naar ~61k). Hun formulering: “The best agents might be the ones with the fewest tools.”

  • Cloudflare ontwikkelde “Code Mode,” waarmee agents TypeScript kunnen schrijven om hun API aan te roepen in plaats van tool schemas te definiëren, wat de contextoverhead verlaagt. Hun redenering: “LLMs have an enormous amount of real-world TypeScript in their training set, but only a small set of contrived examples of tool calls.”

Hier zie je het patroon uit Anthropic’s PTC-documentatie. In Anthropic’s sequential expense-analysis-illustratie vereist traditioneel tool calling 20+ afzonderlijke inference passes, waarbij intermediate data door de context stroomt. Na de team lookup kan een host die parallel tool calls ondersteunt de onafhankelijke expense requests batchen; de 20+-waarde maakt dat niet onmogelijk. Anthropic rapporteert dat generated code voor dezelfde vraag de hoeveelheid data die de context bereikt, terugbrengt van 200 KB aan ruwe expense rows — meer dan 2.000 line items — naar 1 KB aan resultaten. Met code-executie schrijft de agent één script:

# Agent generates this code, executes in sandbox
import asyncio
import json

async def main() -> None:
    team = await get_team_members("engineering")
    levels = list(set(member["level"] for member in team))
    budgets = dict(zip(
        levels,
        await asyncio.gather(*(get_budget_by_level(level) for level in levels)),
    ))
    expenses = await asyncio.gather(
        *(get_expenses(member["id"], "Q3") for member in team)
    )
    over_budget = []
    for member, employee_expenses in zip(team, expenses):
        total = sum(expense["amount"] for expense in employee_expenses)
        limit = budgets[member["level"]]["travel_limit"]
        if total > limit:
            over_budget.append(
                {"name": member["name"], "spent": total, "limit": limit}
            )
    # Only this final summary returns to the LLM context
    print(json.dumps(over_budget))

asyncio.run(main())

De LLM ziet alleen de uiteindelijke JSON-summary, niet de duizenden expense line items die in de sandbox zijn verwerkt. De besparing is niet specifiek voor expense reports: Anthropic’s afzonderlijke write-up over code-executie noemt het scherpste cijfer voor dit patroon, een Google Drive-naar-Salesforce-workflow die daalde van ~150.000 tokens naar ~2.000, een reductie van 98,7%.

Tokenefficiency is de voor de hand liggende winst. Loops en conditionals kosten niets extra’s en code-executie kan errors afhandelen met expliciete handlers, in plaats van het model failures in natuurlijke taal te laten beredeneren. Een code-execution-pad kan gevoelige intermediate data buiten de modelcontext houden, maar dat is geen confidentiality: isolation, egress controls, scoped credentials en logging moeten afzonderlijk worden afgedwongen.

Wanneer JSON tool calling nog steeds zinvol is: voor single atomic operations, omgevingen zonder sandboxing-infrastructuur, kleinere models met zwakke codegeneratie of auditvereisten waarbij elke afzonderlijke tool invocation moet worden gelogd.


Vergelijkingstabel voor AI agent-tool calling

DimensieJSON Tool CallingMCPSkills (SKILL.md)CLI/BashCode Execution (PTC)
Best voorSimple, single actionsCross-vendor SaaSDomeinexpertiseDev-workflows, lokale opsMulti-step orchestration
TokenoverheadHoog (550–1.400/tool)Zeer hoog (veel tools tegelijk)Zeer laag (~100 tokens)Bijna nulLaag (2 meta-tools)
Task evidenceBaseline in aangehaalde studiesAfhankelijk van server en taakN.v.t. (expertiselaag)Meten op CLI-native takenCodeAct rapporteert tot +20%
ComposabilityHarness-directed; dependent calls voegen turns toeHarness-directed; dependent calls voegen turns toeHoog (procedural knowledge)Hoog (pipes, chaining)Zeer hoog (code-side flow/filtering)
Security-oppervlakGemiddeldHoog (50 tracked vulns)Host/resource-dependentHoog (shell access)Hoog (heeft sandboxing nodig)
SetupcomplexiteitLaagGemiddeld (serverdeployment)Zeer laag (markdown)Zeer laag (bestaande CLIs)Gemiddeld (sandbox-infra)
Latency voor dependent callsGewoonlijk 1 modelturn/callGewoonlijk 1 modelturn + transport/callN.v.t. (instruction layer)Gewoonlijk 1 modelturn/call1 script-generation turn; host voert de flow uit
DebuggingGoed (structured I/O)Gemiddeld (transportlaag)Goed (leesbare markdown)Uitstekend (zichtbaar)Goed (leesbare code)

“Meta-tools” in de rij voor tokenoverhead betekent het kleine aantal generieke entry points dat een code-executing agent nodig heeft — bijvoorbeeld Vercel’s ExecuteCommand en ExecuteSQL — in plaats van één schema per onderliggende operation. De rijen voor composability en latency gaan over calls waarvan latere argumenten afhangen van eerdere resultaten in de besproken harness of loop. JSON tool calling en MCP kunnen onafhankelijke calls gezamenlijk emitten, en een host kan ze concurrency uitvoeren; dependent calls hebben meestal een nieuwe modelturn nodig om de volgende action te kiezen. PTC verplaatst de dependent control flow en code-side filtering naar het script en retourneert vervolgens een summary naar het model; het kan ook onafhankelijke calls concurrency uitvoeren. De token- en task-success-cellen vatten de aangehaalde voorbeelden samen, niet één gecontroleerde benchmark over alle vijf kolommen.


De Agent-Computer Interface (ACI) voor AI agent-tools

De term “Agent-Computer Interface” (ACI) werd bedacht door John Yang, Carlos E. Jimenez en collega’s aan Princeton in hun SWE-agent-paper (NeurIPS 2024). Voor de kwaliteit van human interfaces bestaat een volledige discipline — human-computer interaction, of HCI. Het paper betoogt dat language-model agents dezelfde behandeling verdienen: ze zijn “a new category of end users with their own needs and abilities, and would benefit from specially-built interfaces.”

Hun ablation results maken dat kwantitatief. Met hetzelfde GPT-4 Turbo-basemodel bereikte de SWE-bench Lite-ablation in het paper 18,0% met SWE-agent’s volledige ACI op 300 taken, tegenover 7,3% voor de shell-only-conditie zonder een uitgewerkt voorbeeld en 11,0% met één voorbeeld. De vergelijking laat zien dat de interface- en demonstration-condities de prestaties in deze setup materieel veranderden; ze isoleert interface design niet van elk ander verschil en toont niet aan dat het model geen werk deed. Binnen dezelfde interface-ablation verhoogde het inschakelen van linting de edit-conditie van 15,0% naar 18,0%; over de volledige SWE-bench-testset bereikte 51,7% van SWE-agent’s runs minstens één edit die de linter afwees voordat die kon worden doorgezet.

ACI-ontwerpprincipesACI-ontwerpprincipes

Anthropic nam ACI over als foundational concept in zijn guide “Building Effective Agents”, waar het als een van drie core principles wordt genoemd: “Carefully craft your agent-computer interface through thorough tool documentation and testing.” Hun praktische advies: “One rule of thumb is to think about how much effort goes into human-computer interfaces, and plan to invest just as much effort in creating good agent-computer interfaces.”

Vier ACI-principes in de praktijk

1. Acties moeten eenvoudig en begrijpelijk zijn. De meest voorkomende fout is API-endpoints één-op-één wrappen. Implementeer in plaats van list_users, list_events, create_event één schedule_event die availability vindt en in één call inplant. Implementeer in plaats van read_logs een search_logs die alleen de relevante regels met context retourneert.

2. Acties moeten compact en efficiënt zijn. Consolideer belangrijke operations in zo weinig mogelijk actions. In de Market Analyst Agent combineer ik price fetching met basic metrics in één get_stock_snapshot-tool, in plaats van aparte calls te vereisen voor price, volume, market cap en PE ratio.

3. Environment feedback moet informatief maar beknopt zijn. Vermijd raw HTML of volledige API-payloads. Vertaal cryptische IDs naar semantic names. Anthropic’s testing voegde een response_format-enum toe, zodat de agent om een beknopte (~72 tokens) of gedetailleerde (~206 tokens) response kan vragen — ongeveer een verschil van 3x in tokenkosten.

4. Validation moet error propagation beperken. Automatische error detection helpt agents fouten snel te herkennen en corrigeren. In SWE-agent weigert een custom file editor met geïntegreerde linting automatisch syntax errors — de validatiestap achter het bovenstaande cijfer van 51,7%. Dit is validation van toolinputs en -outputs, niet de content filtering rond een model call die de guardrail-producten in deel 4 uitvoeren; hetzelfde woord wordt voor beide gebruikt. Ik pas hetzelfde principe toe in de Market Analyst Agent door toolargumenten vóór execution te valideren met Pydantic schemas:

from pydantic import BaseModel, Field, field_validator

from market_analyst.utils import normalize_ticker

class StockQuery(BaseModel):
    """Validated input for stock queries.

    Pydantic catches malformed tickers before the API call,
    preventing error propagation through the reasoning loop.
    """
    ticker: str = Field(description="Stock ticker symbol (e.g., NVDA)")

    @field_validator("ticker")
    @classmethod
    def validate_ticker(cls, v: str) -> str:
        return normalize_ticker(v)

class StockHistoryQuery(StockQuery):
    """Validated input for price history queries."""

    period: str = Field(default="1mo", description="Time period: 1d, 5d, 1mo, 3mo, 6mo, 1y")

    @field_validator("period")
    @classmethod
    def validate_period(cls, v: str) -> str:
        valid = {"1d", "5d", "1mo", "3mo", "6mo", "1y"}
        if v not in valid:
            raise ValueError(f"Invalid period: {v}. Must be one of {valid}")
        return v

De gedeelde normalizer trimt de waarde en zet deze om naar uppercase, en accepteert vervolgens ticker digits en dotted of hyphenated suffixes zoals BRK.B en BF-B; StockHistoryQuery, niet StockQuery, beheert period.


AI agent-tooldesignpatronen die werken

Anthropic’s guide “Writing effective tools for agents” beschrijft tools als “a new kind of software which reflects a contract between deterministic systems and non-deterministic agents.”

Behandel tooldescriptions als prompt engineering

Descriptions moeten minstens drie of vier zinnen bevatten over wanneer de tool moet worden gebruikt, verplichte versus optionele parameters, het outputformaat en edge cases. Anthropic rapporteert dat de keuze tussen prefix- en suffix-based namespacing (asana_search versus search_asana) “non-trivial effects” had op zijn eigen tool-use-evaluations. Het zegt niet welke aanpak wint, dus test beide op je toolset in plaats van prefixes als vanzelfsprekend te nemen. Anthropic voerde ook de transcripts van zijn evaluation agents terug naar Claude Code en liet het de tools herschrijven. Op held-out testsets vond die loop verdere verbeteringen, “even beyond what we achieved with ‘expert’ tool implementations” — ongeacht of die tools handmatig door researchers waren geschreven of door Claude waren gegenereerd.

# Bad: vague, no context for when to use
tools = [{
    "name": "search",
    "description": "Search for items",
}]

# Good: specific, with input examples and edge cases
tools = [{
    "name": "search_news",
    "description": (
        "Search for recent news articles about a specific stock or company. "
        "Use this tool when the user asks about recent events, earnings, "
        "announcements, or market-moving news for a specific ticker. "
        "Returns up to 10 articles sorted by relevance. "
        "For company competitors rather than news, use search_competitors instead."
    ),
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Search query. Examples: 'NVDA earnings Q3 2025', 'Tesla delivery numbers'"
            },
            "max_results": {
                "type": "integer",
                "description": "Max articles to return (1-10, default 5)",
                "default": 5
            }
        },
        "required": ["query"]
    }
}]

Anthropic’s interne testing liet zien dat toevoeging van een input_examples-field de accuracy bij complex parameter handling verhoogde van 72% naar 90%.

Retourneer high-signal, machine-readable output

Vermijd low-level identifiers (uuid, mime_type). Vertaal cryptische IDs naar semantic names. Structureer de response zo dat de agent erover kan redeneren zonder boilerplate te hoeven parsen:

# Bad: raw API response dumped to agent
def get_stock_snapshot(ticker: str) -> dict:
    response = api.get(f"/v1/quotes/{ticker}")
    return response.json()  # 500+ tokens of nested JSON

# Good: high-signal summary the agent can immediately reason about
def get_stock_snapshot(ticker: str) -> dict:
    data = api.get(f"/v1/quotes/{ticker}").json()
    return {
        "ticker": ticker,
        "price": data["regularMarketPrice"],
        "change_pct": round(data["regularMarketChangePercent"], 2),
        "volume": data["regularMarketVolume"],
        "market_cap_b": round(data["marketCap"] / 1e9, 1),
        "pe_ratio": data.get("trailingPE"),
        "summary": f"{ticker} at ${data['regularMarketPrice']:.2f} "
                   f"({'up' if data['regularMarketChangePercent'] > 0 else 'down'} "
                   f"{abs(data['regularMarketChangePercent']):.1f}%)"
    }

Retourneer errors waarop de loop kan handelen

Error handling vereist vier afzonderlijke mechanismen, omdat ze verschillende failure classes afhandelen:

  1. Retry met exponential backoff voor transient errors
  2. Model fallback chains bij provider outages
  3. Error-classification routing — transient errors worden opnieuw geprobeerd, LLM-recoverable errors gaan met context terug naar de agent en errors waarvoor een mens nodig is worden geëscaleerd
  4. Checkpoint recovery om crashes te overleven

Anthropic’s “Writing effective tools for agents” pleit voor duidelijke tool errors en evaluation-driven tool design, maar geeft geen universeel cijfer voor wat deze vier mechanismen herstellen. Meet recovery rate, retries en escalations op je eigen task suite.

import httpx
from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential

def is_transient_error(error: BaseException) -> bool:
    if isinstance(error, (httpx.TimeoutException, httpx.NetworkError)):
        return True
    if isinstance(error, httpx.HTTPStatusError):
        return error.response.status_code == 429 or 500 <= error.response.status_code < 600
    return False

@retry(
    retry=retry_if_exception(is_transient_error),
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    reraise=True,
)
def call_stock_api(ticker: str) -> dict:
    """Fetch stock data with automatic retry on transient failures.

    Mechanism 1 of the four above: exponential backoff for rate limits
    and network blips.
    If all retries fail, the error propagates to the agent with
    enough context to decide whether to try a different approach.
    """
    response = httpx.get(
        f"https://api.example.com/v1/quotes/{ticker}",
        timeout=10.0,
    )
    response.raise_for_status()
    return response.json()

De patronen toepassen op de Market Analyst Agent

De Market Analyst Agent uit deel 1 maakt het effect van de interface zichtbaar.

Tool consolidation

De oorspronkelijke toolmodules definieerden get_stock_price, get_company_metrics, get_price_history, twee search tools en execute_trade. Voor een basic analysis moest de agent zowel de price- als de metrics-call kiezen; market cap en P/E waren velden van get_company_metrics, geen zelfstandige tools. De broncode van vóór de consolidation laat dat eerdere oppervlak zien.

Ik heb het market-data-oppervlak omgevormd tot 5 high-level tools, volgens het ACI-principe van compacte, efficiënte acties. De ReAct-tool list in de repo bevat daarnaast nog vier tools — een skill loader, twee CLI wrappers en een restricted in-process Python evaluator (een AST-allowlist, geen sandbox; deel 4 gaat hierop in) — waarmee drie van de vijf bovenstaande modaliteiten worden afgedekt. MCP verschijnt als sidecar en niet als tool in deze lijst:

Voorheen (oorspronkelijke tools)Hierna (market-data-tools)Waarom
get_stock_price + get_company_metricsget_stock_snapshotEén call retourneert de basic price- en valuation-snapshot
get_price_historyget_price_historyBehouden met gevalideerde periods en average-volume-summary
search_newssearch_newsRetourneert structured items met geëxtraheerde key points
search_competitorssearch_competitorsBehoudt de competitor-focused search action
Geen financial-statement-toolget_financialsSelecteert income-, balance-sheet- of cash-flowdata via parameter

Hiermee worden price en valuation samengebracht in één task-shaped definition en worden financial statements toegevoegd als expliciete action. Of dit de toolselectie verbetert, is een claim die je moet testen met representatieve requests en traces.

Structured outputs voor tool results

De stock- en news-tools retourneren Pydantic-gevalideerde responses. De CLI- en code-execution-wrappers retourneren str, dus de onderstaande models beschrijven de structured tool results en niet elke wrapper in de repository:

from pydantic import BaseModel

class StockSnapshot(BaseModel):
    """Structured tool response — the agent never sees raw API noise."""
    ticker: str
    price: float
    change_pct: float
    volume: int
    market_cap_b: float
    pe_ratio: float | None
    summary: str  # Human-readable one-liner for direct use in reports

class NewsItem(BaseModel):
    """One news item pre-processed for agent consumption."""
    headline: str
    source: str
    date: str
    relevance_score: float  # Pre-ranked so the agent doesn't waste tokens sorting
    key_points: list[str]  # Extracted by the tool, not the agent

class NewsSearchResult(BaseModel):
    query: str
    results: list[NewsItem]
    summary: str

Het veld summary geeft de agent een direct bruikbare string die rechtstreeks in een report kan worden opgenomen. NewsItem.key_points worden door de tool geëxtraheerd in plaats van door de agent, waardoor inference tokens worden bespaard die anders nodig zouden zijn om article bodies te parsen.


Trade-offs en overwegingen

Naast de caveats die specifiek zijn voor elk patroon hierboven, bepalen enkele cross-cutting concerns de keuze:

  • Operationele kosten variëren per dimensie. Code-executie bespaart tokens, maar voegt sandbox cold-start-latency toe. MCP bespaart developmenttijd voor SaaS-integraties, maar voegt overhead voor serverdeployment toe. CLI is gratis om mee te starten, maar moeilijker op schaal te governen. Optimaliseer voor je werkelijke bottleneck, of dat nu tokenkosten, latency of operationele complexiteit is.

  • Teamvaardigheden zijn belangrijk. Code-executie veronderstelt dat je agents (en de models daarachter) betrouwbare Python of TypeScript kunnen genereren. CLI veronderstelt vertrouwdheid met Unix-conventies. MCP vereist inzicht in transportprotocollen en OAuth-flows. Stem de modaliteit af op de sterke punten van je team.

  • Tool consolidation kan te ver gaan. Als één tool ongerelateerde modes en arguments opstapelt, krijgt de agent binnen het schema een ander selectieprobleem. Gebruik tool-selection- en task-success-evaluations om het juiste oppervlak voor je workload te vinden.

  • Skills zijn prompt-based, niet enforced. Een skill bevat instructies die de agent zou moeten volgen, geen guardrails die de agent moet volgen. Een skill bundle kan willekeurige bestanden en executable scripts bevatten, dus vertrouw de bron, review de bundle en laat de host de permissions afdwingen voor elke resource die de agent kan lezen, wijzigen of uitvoeren. Combineer skills voor kritieke workflows met deterministic validation.

  • Auditvereisten beïnvloeden de keuze. Structured MCP- en JSON-calls zijn handige events om te loggen, maar geen van beide protocollen creëert out of the box een volledige audit trail. De host, server of harness moet invocations en resultaten registreren en vervolgens authorization, policy, retention en review afdwingen. Code-executie vereist dezelfde instrumentation rond de sandbox; het script en de output alleen vormen geen compliance record.


Drie richtingen voor AI agent-tooling op schaal

De eerste is tool RAG voor scaling. In de benchmarktaken en de MCP-stresstest van RAG-MCP was de baseline tool-selection-accuracy 13,62%; retrieval verhoogde deze naar 43,13%, een verbetering van 3,2x, terwijl het aantal prompt tokens met meer dan 50% daalde. Het resultaat is evidence voor die evaluatiesetup, geen universeel percentage voor naive selection wanneer toolsets groeien.

De tweede is dat agents hun eigen tools creëren. Het LATM-framework (“LLMs As Tool Makers”) introduceerde een two-phase paradigm waarin een krachtige LLM reusable Python functions creëert en een lightweight LLM ze gebruikt. Op ToolMaker’s benchmark met 15 taken over papers met publieke code repositories, aangeleverd als GitHub-URLs en korte taakbeschrijvingen, implementeerde het model 80% van de taken correct. Beide ontwikkelingen wijzen voorbij tool use naar tool creation en vervolgens naar het beheren van een library met generated tools.

De derde is de dual-protocol-stack van A2A + MCP. Google droeg A2A in juni 2025 over aan de Linux Foundation. De A2A-protocoldocumentatie scheidt hun verantwoordelijkheden: MCP koppelt een agent aan tools en resources, terwijl A2A onafhankelijke agents elkaar laat ontdekken, interacties laat onderhandelen, gedeelde taken laat beheren en werk laat delegeren.


Belangrijkste conclusies

  1. Kies de interface op basis van de action: JSON calling voor kleine typed operations, MCP voor shared services, Skills voor procedures, CLI voor established commands en sandboxed code voor lokale composition.
  2. Houd benchmarkcondities gekoppeld aan het resultaat. CodeAct, Anthropic, Vercel, Cloudflare, Apideck en Scalekit maten verschillende models, taken, tools en harnesses.
  3. ACI-kwaliteit blijft relevant bij protocolwijzigingen. Duidelijke acties, compacte feedback, validation en bruikbare errors helpen elke modaliteit.
  4. Consolideer overlappende tools alleen wanneer evaluaties aantonen dat het kleinere oppervlak de selectie of task success verbetert.
  5. Security beweegt mee met execution power. Shell- en code-interfaces hebben sandboxing nodig; MCP heeft scoped identity en server policy nodig; Skills blijven instructies en zijn geen enforcement.

De volgende laag is policy

Deel 4, AI Agent Security, plaatst een policy check tussen een voorgestelde tool call en execution. Het is dezelfde tool boundary die hierboven is beschreven, maar bekeken vanuit de kant die nee zegt. Deel 5 plaatst de tool en zijn sandbox vervolgens in een recoverable runtime, en deel 6 voegt een tweede contract toe dat het model nooit ziet: een effect category, een retry rule en een structured result dat een acceptance check kan lezen zonder prose te hoeven parsen.


Referenties

Papers

Anthropic engineering

Protocol specifications

Industry case studies

Security

CLI design

Demo project


De volledige code van de Market Analyst Agent, inclusief de tool designs die in dit artikel worden beschreven, staat op GitHub.