~/TechPurAI
~/tutorials/building-ai-agents/how-ai-agents-use-apis-and-external-tools
intermediate·part 9 of 22·3 min read

How AI Agents Use APIs and External Tools

Updated Aug 16, 2026AI

Every tool this series has built so far reads from an in-memory Python dictionary. Real, production agents connect to genuine, external systems — this part covers that real bridge, using GreenDesk's actual CRM as the concrete example.

The real, structural pattern: a tool function wraps a real API call

python
import requests

def get_customer_from_crm(customer_id: str) -> dict:
    response = requests.get(
        f"https://api.greendesk-crm.example.com/customers/{customer_id}",
        headers={"Authorization": f"Bearer {CRM_API_KEY}"},
        timeout=10,
    )
    response.raise_for_status()
    return response.json()

This is genuinely no different, structurally, from part 6's check_inventory() — from the agent's perspective, it's still just a real Python function matching a real tool schema. The actual, meaningful difference is entirely inside the function: a genuine, real network call to an external system instead of an in-memory dictionary lookup.

Real, practical authentication, following this series' established discipline

text
# .env
CRM_API_KEY=your-real-crm-api-key

This directly follows the exact real security discipline established across the AI Projects series' own API key handling — a real, external CRM credential is exactly as sensitive as the LLM provider's own API key, and deserves identical, real treatment: environment variables, never hardcoded, never committed.

Translating a real, external API's response into something the model can use well

python
def get_customer_from_crm(customer_id: str) -> dict:
    response = requests.get(...)
    raw = response.json()

    # a real, deliberate translation step — not just passing the
    # raw, real API response straight through
    return {
        "name": raw["full_name"],
        "plan": raw["subscription"]["tier_name"],
        "account_status": raw["status"]["display_label"],
    }

A real, external API's raw response format is often genuinely verbose, deeply nested, or full of internal fields irrelevant to the agent's actual task — translating it into a real, clean, minimal structure before returning it from the tool function is a genuine, practical improvement, directly reducing real token cost (fewer, more relevant fields) and improving the model's ability to reason over the real result correctly.

Why it matters

This translation step is easy to skip when a tool function could technically just return response.json() directly — but a real, raw API response often buries the genuinely relevant field three levels deep in a structure the model has to parse itself, at real, unnecessary token cost and real, added risk of misreading it.

Real, practical rate limit handling for external tools

python
from tenacity import retry, wait_exponential, stop_after_attempt

@retry(wait=wait_exponential(min=1, max=10), stop=stop_after_attempt(3))
def get_customer_from_crm(customer_id: str) -> dict:
    response = requests.get(..., timeout=10)
    response.raise_for_status()
    return response.json()

This directly extends the AI Projects series' own rate-limiting awareness to the OTHER side of the equation — an agent calling a real, external API needs to respect that API's own real rate limits too, with genuine, automatic retry-with-backoff (tenacity, a real, widely used Python library for exactly this) rather than failing the entire agent task on one transient, real rate-limit response.

A real, honest failure mode unique to external tools

text
An in-memory dictionary lookup (part 6): essentially never fails
A real, external API call: can genuinely fail for real reasons
  entirely outside the agent's control — the CRM is down, a real
  network timeout, an expired real credential

This directly sets up part 18's error-recovery coverage — a real agent connected to genuine external systems needs to reason about and gracefully handle real, external failures, a genuinely different and harder problem than anything this series' earlier, simplified in-memory examples required.

A real, practical checklist for wrapping any external API as a tool

text
[ ] Real, secure credential handling (environment variables)
[ ] A real timeout on every network call — never an unbounded wait
[ ] Real retry logic for transient failures
[ ] A real translation step — clean, minimal output, not raw passthrough
[ ] A real, explicit error case the agent can reason about and
    recover from (part 18)

Next: real-world tool integrations — concrete, working examples connecting agents to web search, weather, and other real, common external services.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous8. Giving Your Agent Persistent Memorynext →10. Real-World Tool Integrations