AI Agents & Tool Use

AI Agents & Tool Use

AI Agents — What Makes Something “Agentic” vs a Chatbot

A chatbot, in the strict sense, does one thing per turn: take input, generate text output, return it to the user. Single forward pass through the request-response cycle, no autonomous follow-through.

An agent is a system where the model doesn’t just respond — it operates in a loop: observe the current state → decide on an action → execute that action (often via a tool call) → observe the result → decide the next action → repeat until the goal is satisfied or it hits a stopping condition. The defining property is autonomous multi-step decision-making toward a goal, without a human in the loop dictating each individual step.

Concretely, the architectural difference:

  • Chatbot: user asks “what’s the weather in Chennai,” model answers from training knowledge or a single tool call, done.
  • Agent: user asks “book me the cheapest flight to Chennai next week that arrives before 6pm” — the system has to search flights (tool call), evaluate results against constraints, possibly search again with refined parameters, check the user’s calendar for conflicts (another tool call), and only then either book or present options. Each step’s output feeds the next decision. The model is making a sequence of judgment calls, not just answering once.

The three properties that actually distinguish “agentic” from “just calling tools in a chatbot”:

  1. Planning — breaking a goal into sub-steps without being told each sub-step explicitly.
  2. Tool use embedded in a loop — not one tool call and done, but the ability to chain calls based on intermediate results.
  3. Self-correction — noticing when a step failed or returned something unexpected, and adjusting the plan rather than blindly continuing.

A system that calls one API and returns the result isn’t really “agentic” — it’s a chatbot with a tool. Agentic behavior shows up when the model is making sequential, conditional decisions about what to do next based on what just happened.


Tool Use / Function Calling — How Models Call APIs

The mechanism, stripped to its essentials:

  1. You declare the available tools in the API request — each with a name, a natural-language description, and a JSON schema for its parameters. The model never executes anything itself; it only ever decides whether and how to call a tool.
  2. The model decides, based on the user’s request, whether a tool call is needed, and if so, emits a structured output (typically JSON) specifying which tool and with what arguments — instead of a free-text response.
  3. Your application code intercepts that structured output, actually executes the real function/API call against your system (database query, external API, file read), and gets a result.
  4. You feed that result back into the model’s context as a new message, and the model continues — either calling another tool or producing a final natural-language answer incorporating the result.

The critical architectural point: the model never has direct access to your systems. It only ever produces a structured intent (“call this function with these arguments”). Your application layer is the actual executor and the security boundary — every permission check, every input validation, every rate limit belongs in that layer, not in the model. This is exactly the same trust boundary discipline you’d apply to any API gateway sitting in front of backend services — the model is just another untrusted caller proposing requests, not a privileged actor.

This is also why tool descriptions matter so much in practice — the model selects and parameterizes tools based purely on the natural-language description and schema you provide. Vague or overlapping tool descriptions cause exactly the kind of selection ambiguity you’d expect from poorly documented APIs.


Multi-Agent Systems — Orchestration Patterns

Once a single agent’s task gets complex enough, splitting work across multiple specialized agents — each with a narrower scope, its own tools, and its own context — tends to outperform one generalist agent trying to do everything in one context window. The common orchestration patterns:

  • Orchestrator–worker (hub and spoke). One “lead” agent receives the goal, decomposes it into subtasks, and dispatches each to a specialized worker agent (e.g., a research agent, a code-writing agent, a verification agent). Workers report results back to the orchestrator, which synthesizes the final output. This is the most common production pattern — directly analogous to a microservices architecture with an API gateway/orchestrator coordinating downstream service calls, except the “services” are themselves model-driven and the “calls” are natural-language task delegations.
  • Sequential pipeline. Agents run in a fixed order, each consuming the previous one’s output (research agent → drafting agent → editing/critique agent). Predictable, easy to debug, but inflexible if a downstream step reveals the upstream work needs revisiting.
  • Debate/critique pattern. Multiple agents (or the same model in different roles) produce independent answers or critique each other’s work before a final synthesis — used to catch errors a single pass would miss, at the cost of more inference calls.
  • Parallel fan-out / fan-in. Independent subtasks dispatched concurrently to multiple agents, results aggregated once all return — useful when subtasks don’t depend on each other (e.g., researching five independent topics simultaneously), directly analogous to a scatter-gather pattern in distributed systems.

The real engineering challenges that mirror distributed systems problems you already know: context isolation (each agent needs only the context relevant to its subtask, or costs and confusion balloon), state/handoff management (what exactly gets passed between agents — full transcripts are expensive, summaries lose fidelity), and failure handling (what happens when a worker agent fails or returns garbage — same retry/circuit-breaker thinking you’d apply to any service call, just with less deterministic failure modes).


MCP (Model Context Protocol) — The New Integration Standard

MCP is an open protocol (originated by Anthropic, now broadly adopted) that standardizes how AI applications connect to external tools, data sources, and systems — solving the same problem USB-C solved for device connectors, or that ODBC/JDBC solved for database access: instead of every AI app writing custom, one-off integration code for every tool/data source, both sides implement the protocol once.

Before MCP, if you wanted Claude (or any model) to access Slack, GitHub, and your internal ticketing system, you wrote three bespoke integrations, each with its own auth handling, schema definitions, and error conventions. With MCP:

  • MCP servers expose tools, resources, and prompts from a given system (GitHub, Slack, a database, your internal API) in a standardized way.
  • MCP clients (the AI application — Claude.ai, Claude Code, an IDE, a custom agent) connect to any MCP server and immediately get a consistent interface to discover and call what that server exposes — no custom integration code per server.
  • This means a tool builder writes one MCP server once, and it works with any MCP-compatible client — and a client builder gets access to the entire ecosystem of existing MCP servers without writing per-integration glue code.

The architectural payoff is the same one you’d recognize from any standardization effort in your career: it converts an N×M integration problem (N apps × M tools, each needing custom glue) into an N+M problem (each side implements the standard once). For someone building delivery-managed integration projects, this is the direct equivalent of “why did we standardize on REST/OpenAPI specs instead of bespoke point-to-point integrations” — same economic logic, applied to AI tool access.


Agentic Coding Tools (Claude Code, Copilot, Cursor) — How They Actually Work

These tools differ significantly in how “agentic” they actually are, which matters more than the marketing copy:

GitHub Copilot (classic mode) — primarily an autocomplete-style tool: it suggests code completions inline as you type, based on surrounding file context. The newer “Copilot Workspace”/agent modes add more autonomous multi-file editing, but the core product DNA is inline suggestion, not autonomous task execution.

Cursor — an IDE (a VS Code fork) with deeply integrated AI: inline completion like Copilot, plus a chat/agent mode that can read multiple files across the codebase, propose multi-file edits, and apply them with your review. It operates inside the editor’s file system directly, with the editor’s own indexing of your codebase feeding context to the model.

Claude Code — a different category: a terminal-native, agentic coding tool rather than an editor plugin. It operates in a loop similar to the agent pattern described above: it reads files, runs shell commands, executes tests, greps the codebase, edits files, and iterates based on the actual results of running things — checking whether tests pass, whether a build succeeds — rather than just generating a plausible-looking diff and stopping. The key architectural distinction: Claude Code’s loop includes real execution and verification as part of its own process, not just code generation. It can be invoked from the command line, the desktop app, or the mobile app, and supports MCP server integration so it can extend beyond the local filesystem into your other tools (issue trackers, docs, internal APIs).

The common thread across all three, underneath the product differences: they’re applying the agent loop (act → observe result → adjust) to a domain (codebases) where verification is unusually cheap and reliable — you can run the test suite, check the linter, see the compile error — which is exactly why coding has become one of the most successful early domains for agentic AI. The feedback signal is fast, objective, and machine-checkable, which removes a lot of the ambiguity that makes agentic loops harder to trust in other domains.