By Sagar Shankaran, Founder of CallSphere
Master Python asyncio from the ground up. Learn coroutines, tasks, event loops, and async/await patterns essential for building high-throughput AI agent systems.
Key takeaways
AI agent systems spend most of their time waiting. Waiting for LLM API responses, waiting for database queries, waiting for tool call results. A synchronous agent that makes five sequential LLM calls taking two seconds each wastes eight seconds doing nothing. With asyncio, those same five calls complete in roughly two seconds total.
asyncio is Python's built-in library for writing concurrent code using the async/await syntax. It uses a single-threaded event loop to multiplex I/O-bound operations, making it the ideal foundation for AI agent architectures where network latency dominates execution time.
A coroutine is a function defined with async def. When called, it returns a coroutine object that must be awaited to produce a result.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
import asyncio
async def call_llm(prompt: str) -> str:
"""Simulate an LLM API call with network latency."""
print(f"Sending prompt: {prompt[:40]}...")
await asyncio.sleep(1.5) # Simulates network round-trip
return f"Response to: {prompt[:20]}"
async def main():
# Awaiting a single coroutine
result = await call_llm("Explain quantum computing in one sentence")
print(result)
asyncio.run(main())
The await keyword suspends the current coroutine, yields control back to the event loop, and resumes once the awaited operation completes. This is the mechanism that allows other work to happen during I/O waits.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
The event loop is the scheduler at the heart of asyncio. It maintains a queue of ready tasks and switches between them whenever one yields control via await.
import asyncio
import time
async def agent_step(step_name: str, delay: float) -> str:
print(f"[{time.monotonic():.2f}] Starting {step_name}")
await asyncio.sleep(delay)
print(f"[{time.monotonic():.2f}] Completed {step_name}")
return f"{step_name} done"
async def main():
start = time.monotonic()
# Sequential execution — total time is sum of delays
r1 = await agent_step("retrieve_context", 1.0)
r2 = await agent_step("call_llm", 2.0)
print(f"Sequential: {time.monotonic() - start:.2f}s")
asyncio.run(main())
# Output: Sequential: ~3.00s
Tasks wrap coroutines and schedule them on the event loop immediately. Use asyncio.create_task() to run multiple operations concurrently.
async def main():
start = time.monotonic()
# Concurrent execution — total time is max of delays
task1 = asyncio.create_task(agent_step("retrieve_context", 1.0))
task2 = asyncio.create_task(agent_step("call_llm", 2.0))
task3 = asyncio.create_task(agent_step("fetch_tools", 1.5))
# Wait for all tasks to complete
r1 = await task1
r2 = await task2
r3 = await task3
print(f"Concurrent: {time.monotonic() - start:.2f}s")
asyncio.run(main())
# Output: Concurrent: ~2.00s (limited by slowest task)
asyncio.gather() is the most common pattern for running multiple coroutines concurrently and collecting their results in order.
async def process_agent_batch(prompts: list[str]) -> list[str]:
"""Process a batch of prompts concurrently."""
results = await asyncio.gather(
*[call_llm(prompt) for prompt in prompts]
)
return results
async def main():
prompts = [
"Summarize this document",
"Extract key entities",
"Generate follow-up questions",
"Classify sentiment",
]
results = await process_agent_batch(prompts)
for prompt, result in zip(prompts, results):
print(f"{prompt[:30]} -> {result}")
asyncio.run(main())
The results list preserves the same order as the input coroutines, regardless of which completes first.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
A real-world pattern is initializing an agent's subsystems concurrently at startup.
async def load_vector_store() -> dict:
await asyncio.sleep(0.5) # Simulate loading embeddings
return {"type": "vector_store", "docs": 15000}
async def connect_database() -> dict:
await asyncio.sleep(0.3) # Simulate DB connection
return {"type": "db", "connected": True}
async def load_tool_registry() -> dict:
await asyncio.sleep(0.2) # Simulate tool loading
return {"type": "tools", "count": 12}
async def initialize_agent():
"""Initialize all agent subsystems concurrently."""
vector_store, db, tools = await asyncio.gather(
load_vector_store(),
connect_database(),
load_tool_registry(),
)
print(f"Agent ready: {vector_store['docs']} docs, "
f"{tools['count']} tools, db={db['connected']}")
return {"vector_store": vector_store, "db": db, "tools": tools}
asyncio.run(initialize_agent())
# Total startup: ~0.5s instead of ~1.0s sequential
await with async libraries like httpx, aiohttp, or asyncpg instead of requests or psycopg2.asyncio.run() as your single entry point — do not create event loops manually.create_task() over raw await when you want concurrency within a single function.await is a potential context switch — the event loop may run other tasks at that point.Use asyncio for I/O-bound workloads like LLM API calls, database queries, and HTTP requests. asyncio is more lightweight than threads (no GIL contention, lower memory per task) and scales to thousands of concurrent operations. Use threading only when you must call blocking libraries that have no async equivalent.
Yes, but carefully. Use asyncio.to_thread() to run blocking functions without freezing the event loop. For example, result = await asyncio.to_thread(some_blocking_function, arg1) offloads the blocking call to a thread pool while keeping the event loop responsive.
asyncio tasks are extremely lightweight — a single process can manage tens of thousands of concurrent tasks. The practical limit is usually the external resource (API rate limits, database connection pools), not the event loop itself.
#Python #Asyncio #Concurrency #AIAgents #EventLoop #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
A founder's guide to the personal AI assistant market: best AI assistant apps, business-grade options, and how CallSphere's voice agent fits in.
A founder's guide to free AI agents, low-code AI agent builders, and how to know when you should pay for a real platform like CallSphere.
Graphiti is the open-source temporal knowledge graph for AI agents in 2026. Learn how bi-temporal memory beats vector RAG for voice agents and long-running LLMs.
Chatbot app vs ChatGPT in 2026: a founder's clear take on the difference, when to use which, and how a real AI chatbot app development works.
How we built a fault-tolerant HVAC emergency triage and tech-dispatch platform on Kubernetes — three-tier CQRS, 11 micro-agents on the OpenAI Agents SDK + LangGraph, NATS JetStream, DTMF/SMS/WebSocket acceptance, circuit breakers, and an evaluation pipeline that catches regressions before they wake a tech at 3 AM.
Head-to-head: OpenAI Frontier and Anthropic's managed agent stack — strengths, fit, and what each means for enterprise AI voice and chat deployment.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI