How AI Agents Use APIs and External Tools
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
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
# .env
CRM_API_KEY=your-real-crm-api-keyThis 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
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.
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
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
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 credentialThis 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
[ ] 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.