Module 1 · Lesson 10
Build Your First AI Agent in Python
In this lesson we will build a small tool-using agent with the current OpenAI Agents SDK, then map the code back to the agent loop you learned earlier.
What we are building
The agent will answer developer-support questions. It will have one deterministic tool that returns the deployment status of a project. The example is intentionally small so you can see the architecture clearly.
Prerequisites
- Python 3
- An OpenAI API key
- A terminal and virtual environment
The current OpenAI Agents SDK quickstart installs the package as openai-agents.
1. Create a project
mkdir first-agent
cd first-agent
python -m venv .venv
source .venv/bin/activateOn Windows, activate the virtual environment using the appropriate .venv\Scripts\activate command.
2. Install the SDK
pip install openai-agentsSet your API key in the environment rather than hard-coding it into source control.
export OPENAI_API_KEY="your-key-here"3. Create a basic agent
from agents import Agent, Runner
agent = Agent(
name="Developer Support Agent",
instructions=(
"Help developers understand project status. "
"Be concise and do not invent deployment information."
),
)
result = Runner.run_sync(
agent,
"Explain what a health check endpoint is."
)
print(result.final_output)This already uses an agent runtime, but it behaves much like a normal model-backed assistant because we have not added any external capability.
4. Add a function tool
The Agents SDK can turn a Python function into a tool and derive a schema from its type annotations and documentation.
from agents import Agent, Runner, function_tool
@function_tool
def get_deployment_status(project: str) -> str:
"""Return the current deployment status for a known project."""
statuses = {
"api": "healthy",
"worker": "degraded",
"dashboard": "healthy",
}
return statuses.get(project.lower(), "unknown project")
agent = Agent(
name="Developer Support Agent",
instructions=(
"Help developers investigate deployment status. "
"Use the deployment-status tool when status data is needed. "
"Never invent a status."
),
tools=[get_deployment_status],
)
result = Runner.run_sync(
agent,
"Is the worker healthy right now?"
)
print(result.final_output)What happens during this run?
- The runner sends the user request, instructions and tool definition to the model.
- The model sees that current deployment status requires the tool.
- It requests
get_deployment_statuswith an argument such as{"project":"worker"}. - The SDK executes your Python function.
- The result
degradedis returned to the model. - The model produces the final user-facing answer.
That is the agent loop in practical form.
5. Replace the toy dictionary with a real service
In production, the tool can call an internal API or service layer. Keep credentials and authorization in your application, not in model context.
@function_tool
def get_deployment_status(project: str) -> dict:
"""Fetch deployment health for one approved project."""
if project not in ALLOWED_PROJECTS:
return {"ok": False, "error": "unknown_project"}
response = deployment_client.get_status(project)
return {
"ok": True,
"project": project,
"status": response.status,
"checked_at": response.checked_at,
}Why normalize the result?
Your downstream API might return logs, internal hostnames and dozens of fields. The model only needs the information required for the next decision. A small structured response is cheaper, safer and easier to reason about.
6. Add tool errors intentionally
Do not return stack traces to the model. Convert expected failures into a small domain-level result.
{
"ok": false,
"error": "service_unavailable",
"message": "Deployment status is temporarily unavailable."
}Your application can separately log the real exception with correlation IDs for debugging.
7. Add limits before adding more autonomy
A production agent should have explicit boundaries: tool timeouts, request timeouts, step limits, read/write separation and human approval for sensitive actions. The exact controls depend on your runtime and product.
8. Inspect traces
OpenAI's current Agents SDK includes tracing for agent runs, model generations, function tool calls, handoffs and guardrails. Tracing helps answer questions such as: Why did the model choose this tool? How many turns did the task require? Which tool failed?
Common beginner mistakes
Putting business logic in the prompt
“Only deploy if tests pass” is useful guidance, but the deploy function itself should verify test status before making a deployment.
Giving the agent one giant generic tool
A tool like run_admin_action(action, payload) is difficult to secure and difficult for the model to use reliably. Prefer narrow business capabilities.
Hard-coding secrets
Keep API keys in environment variables or a secret manager. Never return credentials in tool output.
Skipping evaluation
Create a small test set before adding more tools. Include cases where the correct behavior is to ask for clarification or refuse to call a tool.
Where MCP fits next
Our tool currently lives directly inside the agent application. That is fine for local capabilities. MCP becomes valuable when you want a standardized server that can expose tools, resources or prompts to multiple AI clients. The later modules of this course will build those servers from scratch.