AI Agents and Agentic Systems
Intermediate 15 min Module 6 of 6
Module 6 of 6

Building Your First Agent

Everything you have learned in this course comes together here. This module gives you a concrete, step-by-step method for planning and building an agent for a real task you actually have. It is not about writing code; it is about the decisions that determine whether an agent works before you write a single line.

By the end of this module you will be able to

The First Rule: Start Narrow

The most common mistake in first agent builds is picking a task that is too broad. "Build an agent to help me with my email" will fail, because email involves reading, summarizing, drafting, sending, organizing, scheduling follow-ups, and flagging urgent items, and each of those is a separate task with different tools, different risk profiles, and different success criteria.

"Build an agent that monitors my inbox for messages from five specific clients, summarizes each one in two sentences, and adds the summary to a daily briefing document" is specific enough to build, test, and trust. Start there. Broaden it only after the narrow version works reliably.

The right scope question If you cannot write the agent's success criteria in two sentences, the scope is too broad. Keep narrowing until you can.
Fig 6 · Agent Build Process
1. Define Goal narrow + criteria 2. Choose Tools read vs write 3. Set Memory context strategy 4. Add Guardrails limits + approvals 5. Evaluate dry-run + real tests 6. Deploy monitor + iterate

The Six-Step Build Process

Step 1
Define the task and success criteria
Write one sentence describing what the agent does and one sentence describing how you will know it succeeded. No vague terms. "Summarizes" means what? A bullet list? A paragraph? How long? Write it down.
Step 2
List the tools the agent needs
Walk through the task manually. Every place you would look something up, call an API, read a file, or write something, that is a tool the agent needs. List them. For each one, note whether it is read or write, and whether mistakes are reversible.
Step 3
Write the system prompt
The system prompt tells the agent its role, its task, its constraints, and its exit conditions. Include: what it is trying to accomplish, what tools it has and what each one does, what to do when it is uncertain, and when to stop and ask a human rather than proceeding.
Step 4
Set limits
Add a maximum step count. Add a maximum cost or token budget. Add explicit conditions under which the agent should stop rather than continue. These are not optional safety theater; they are essential guardrails that prevent the infinite loops and runaway behavior from Module 5.
Step 5
Run a dry-run test
Use dry-run mode if your framework supports it, or manually review the agent's plan before letting it take write actions. Ask: does the plan match the task? Are there any steps that look unexpected or out of scope? Catch problems here before they cause real effects.
Step 6
Test on real inputs and iterate
Run the agent on three to five real examples of the task. Compare the output to what you would have done manually. Note where it failed, where it was right but slow, and where it was genuinely better than the manual approach. Adjust the system prompt and tool descriptions based on what you find.

Your Pre-Launch Checklist

Before you let an agent run unsupervised on real tasks, go through this checklist. Click each item as you complete it.

Task and success criteria are written in two sentences or fewer
All tools are listed with clear read/write classification
System prompt includes goal, tools, constraints, and exit conditions
Maximum step count and cost limit are set
Dry-run review completed, plan looks correct
Tested on at least three real examples and output reviewed
Human-in-the-loop checkpoint added for any irreversible action

When to Hand Off to a Human

One of the most important design decisions in any agent is knowing when the agent should stop and ask rather than continue and act. The answer depends on the stakes of the next action. Here are the three cases where human approval should be required before the agent proceeds:

Irreversible actions. Any action that cannot be undone without significant cost or effort. Sending an email, processing a payment, deleting data, submitting a form, publishing content. The agent should present the proposed action and wait for approval.

Ambiguous instructions. If the original task is unclear about how to handle a situation the agent has encountered, it is better to ask than to guess. A guess that is wrong in an irreversible action context is far more costly than the brief interruption of asking.

Unusual observations. If the agent encounters something that does not match the normal pattern of the task, for example, an unusually large file, an unexpected error code, or data that contradicts what it expected, it should flag this for human review rather than proceeding on a best guess.

Why System Prompt Quality Determines Agent Quality

The system prompt is the most leveraged document in your agent's design. It is the only persistent context the agent has for every reasoning step. A weak system prompt produces an agent that wanders: it interprets ambiguous situations however feels right in the moment, takes actions you did not intend, and produces outputs you cannot predict. A strong system prompt produces an agent that stays in scope, escalates appropriately, and behaves consistently across many different inputs.

A strong system prompt for an agent has five components: role definition ("You are a contract review specialist"), task definition ("Your task is to identify deviations from the standard clauses listed below"), tool descriptions ("You have access to the following tools: [list]"), escalation conditions ("Stop and ask a human if you encounter X, Y, or Z"), and exit conditions ("Once you have reviewed all clauses or after 25 reasoning steps, whichever comes first, output your findings and stop").

Notice that the escalation and exit conditions do the heavy lifting for safety. Without explicit exit conditions, the agent runs until it decides it is done, which may be later than you intended and after actions you did not anticipate. Without escalation conditions, the agent guesses when it should ask, and guessing under ambiguity is exactly the scenario most likely to produce a wrong irreversible action.

Common misconception "I can fix a bad system prompt by using a smarter model." Model capability helps with reasoning quality, but it does not substitute for clear constraints. A highly capable model with a vague system prompt will confidently take actions outside your intended scope. A moderately capable model with a precise system prompt that specifies exactly what to do, what not to do, and when to ask a human will be far more reliable. Write the system prompt first; upgrade the model only if the reasoning quality is genuinely the bottleneck.

Testing Before You Trust

An agent you have not tested is a bet you have not placed yet. Before you let an agent run on real data with real consequences, you need to know how it behaves on at least three types of inputs: a normal input that represents the task as designed, an edge case that is technically within scope but unusual, and a malicious or adversarial input that represents the kind of bad input a prompt injection or user error might produce.

For a contract review agent, a normal input is a standard vendor contract. An edge case is a contract written in a language you did not anticipate, or a contract that is 400 pages rather than the typical 20. A malicious input is a contract that contains text designed to override the agent's instructions (a prompt injection attempt embedded in a clause). Knowing how the agent responds to all three categories before you deploy is what separates an enterprise pilot from a prototype.

Python · Full Minimal Agent Scaffold
import json, openai
from typing import Callable

# Tool registry: name -> (function, is_reversible)
TOOLS: dict[str, tuple[Callable, bool]] = {}

def register_tool(name: str, fn: Callable, reversible: bool = True):
    TOOLS[name] = (fn, reversible)

class Agent:
    def __init__(self, goal: str, tool_schemas: list,
                 max_steps: int = 20):
        self.goal = goal
        self.tool_schemas = tool_schemas
        self.max_steps = max_steps
        self.messages = [
            {"role": "system", "content":
             f"Goal: {goal}. Stop and ask a human if uncertain "
             f"or if you encounter anything unexpected."}
        ]

    def run(self, task: str) -> str:
        self.messages.append({"role": "user", "content": task})

        for step in range(self.max_steps):
            response = openai.chat.completions.create(
                model="gpt-4o",
                messages=self.messages,
                tools=self.tool_schemas
            )
            msg = response.choices[0].message
            self.messages.append(msg)

            if not msg.tool_calls:
                return msg.content  # agent finished

            for call in msg.tool_calls:
                result = self._execute(call)
                self.messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": str(result)
                })

        return self._escalate("Step limit reached.")

    def _execute(self, call) -> str:
        name = call.function.name
        args = json.loads(call.function.arguments)

        if name not in TOOLS:
            return f"Error: unknown tool {name}"

        fn, reversible = TOOLS[name]
        if not reversible:
            if not self._human_check(name, args):
                return "Action rejected by human reviewer."

        return fn(**args)

    def _human_check(self, name: str, args: dict) -> bool:
        print(f"\n[HUMAN CHECK] About to call {name}({args})")
        return input("Allow? (yes/no): ").lower() == "yes"

    def _escalate(self, reason: str) -> str:
        print(f"\n[ESCALATION] Agent stopped: {reason}")
        return f"Escalated to human: {reason}"

# Register tools
register_tool("search_web", web_search, reversible=True)
register_tool("send_email", send_email, reversible=False)

# Run the agent
agent = Agent(
    goal="Monitor inbox for messages from five named clients and summarize each",
    tool_schemas=[search_schema, email_schema]
)
result = agent.run("Check for new client emails from today")
Try this

Choose one tool from the list you wrote in Module 2. Write the three test cases you would run before deploying an agent that uses that tool: (1) a normal input that represents the typical use case, (2) an edge case that is technically valid but unusual (an empty result, a very large input, an unexpected data type), and (3) a malicious input designed to confuse or override the agent's instructions. What would the correct agent response be to each one?

Knowledge check
What is the first rule of building a first agent?
Correct. Narrow scope is the foundation of a reliable first agent. Broad tasks have too many edge cases to test properly before deployment.
The first rule is narrow scope. A task that is too broad has too many tools, too many edge cases, and no clear success criterion. Narrow it until you can write the success criteria in two sentences.
Which type of action should always require human approval before the agent proceeds?
Exactly. Irreversible actions are the ones where a wrong decision is hardest to fix. Require human approval before any action that cannot be undone without significant cost.
Irreversible actions are the ones that require human approval. Read actions can be undone by simply discarding the result. Sending an email or processing a payment cannot be as easily reversed.
Interactive 6: Agent Config Checker Try it

Toggle each build step on to see your agent's readiness score. At 6/6 the readiness bar turns green and the agent is cleared for deployment.

Readiness: 0/6    Missing: all steps
Before you go
Your next step: pick one real task from your work, apply the six-step process, and build your first agent this week. Write the system prompt before you write any code. If the system prompt is unclear, the agent will be unclear.
You might also like
Was this module helpful?
← Module 5: Failure Modes Capstone: Build Your Agent →