top of page
Search

Building a Real Python Agent (Without Hype) for Instructors

  • Writer: Mark Kendall
    Mark Kendall
  • Feb 11
  • 4 min read

Building a Real Python Agent (Without Hype)




Part Two — Modular Architecture & System Evolution



In Part One, we built a working CLI-based Python agent.


It:


  • Read a code file

  • Called an LLM

  • Produced structured feedback

  • Maintained in-memory state

  • Used clean separation of concerns



That was foundational.


In Part Two, we move from:


“Building an agent”


to


“Proving it is a system.”





The Goal of Part Two



You are no longer trying to make it work.


You are trying to prove:


  • It is modular

  • It is composable

  • It is replaceable

  • It is evolvable

  • It respects architectural boundaries



This is where engineers become architects.





The Core Principle



If you cannot replace a component without rewriting everything else,

you built a script.


If you can swap a module cleanly,

you built a system.


Part Two is about forcing that proof.





Architecture Review



From Part One, we had:

Agent (Orchestrator)

Memory (State)

LLM Client (Execution)

Tool (Reasoning Strategy)

CLI (Operational Interface)

Each of these was isolated intentionally.


Now we test the integrity of those boundaries.





Exercise 1 — Replace the Memory Layer



In Part One:

class SessionMemory:

    def init(self):

        self.history = []


    def add(self, role: str, content: str):

        self.history.append({"role": role, "content": content})


    def get(self):

        return self.history

This is in-memory only.


Now replace it with persistent storage.


Example: SQLite-backed memory.

# persistent_memory.py

import sqlite3


class PersistentMemory:


    def init(self, db_path="memory.db"):

        self.conn = sqlite3.connect(db_path)

        self._create_table()


    def createtable(self):

        self.conn.execute("""

        CREATE TABLE IF NOT EXISTS history (

            id INTEGER PRIMARY KEY AUTOINCREMENT,

            role TEXT,

            content TEXT

        )

        """)


    def add(self, role: str, content: str):

        self.conn.execute(

            "INSERT INTO history (role, content) VALUES (?, ?)",

            (role, content)

        )

        self.conn.commit()


    def get(self):

        cursor = self.conn.execute("SELECT role, content FROM history")

        return [{"role": row[0], "content": row[1]} for row in cursor.fetchall()]

Then in agent.py, change only:

from persistent_memory import PersistentMemory

self.memory = PersistentMemory()

If nothing else breaks,

your architecture is sound.





Exercise 2 — Replace the Tool



Originally:

class CodeReviewTool:

Now build a Security Audit Tool.

class SecurityAuditTool:


    @staticmethod

    def build_prompt(code: str) -> str:

        return f"""

You are a senior security engineer.


Analyze the following code and provide:


1. Security vulnerabilities

2. Injection risks

3. Data exposure risks

4. Missing validation

5. Logging weaknesses


Code:

{code}

"""

In your agent:

from tools import SecurityAuditTool

prompt = SecurityAuditTool.build_prompt(code)

Nothing else changes.


You just proved tool abstraction works.





Exercise 3 — Swap the Interface



Remove CLI entirely.


Wrap the agent with FastAPI.

from fastapi import FastAPI

from agent import DevAssistAgent


app = FastAPI()

agent = DevAssistAgent()


@app.post("/analyze")

def analyze(payload: dict):

    code = payload.get("code")

    result = agent.analyze_code(code)

    return {"analysis": result}

You just moved from CLI utility to microservice.


The core logic did not change.


That is composability.





Exercise 4 — Add Retry Logic



Inside llm.py:

import time


def chat(self, messages):

    retries = 3

    for attempt in range(retries):

        try:

            response = self.client.chat.completions.create(

                model=Config.MODEL,

                messages=messages,

                temperature=0.2

            )

            return response.choices[0].message.content

        except Exception:

            if attempt < retries - 1:

                time.sleep(2 ** attempt)

            else:

                raise

Now you are thinking production.





Why This Matters



These exercises teach:


  • Layering

  • Abstraction boundaries

  • Dependency direction

  • System composability

  • Infrastructure replaceability



You are no longer just “using AI.”


You are engineering around it.





The Curriculum Structure




Beginner Track (Part One)



  • Build CLI agent

  • Understand components

  • See orchestration




Intermediate Track (Part Two)



  • Swap memory

  • Swap tool

  • Swap interface

  • Add resiliency

  • Add persistence




Advanced Track (Optional)



  • Add Redis memory

  • Add async execution

  • Add OpenTelemetry tracing

  • Add usage tracking

  • Add CI integration

  • Add guardrails

  • Add multi-tool selection logic



Each level forces architectural maturity.





The Real Teaching Objective



Students must understand:


This is not about LLM prompts.


This is about system design.


If they can:


  • Replace storage

  • Replace execution layer

  • Replace reasoning tool

  • Replace interface



without rewriting the system,


then they understand:


Architecture.





A Structured Instructor Recommendation



If you are using this as part of a class or training program:


  1. Require students to build Part One exactly as written.

  2. For final evaluation, require them to replace one module.

  3. They must demonstrate:


    • No cascading rewrites

    • Clean integration

    • Preserved boundaries




If they succeed:


They built a system.


If they fail:


They built a script.


That distinction is the entire point of this exercise.





Layering Philosophy



This is Learn • Teach • Master in practice:


Learn — Build it exactly as designed.

Teach — Explain why the layers exist.

Master — Replace one without breaking the others.


That is skill compounding.





Final Thought



Most AI tutorials teach you how to call an API.


Very few teach you how to design around it.


If your agent collapses when one component changes,

it was never architecture.


Build foundations.


Modularize.


Swap components.


Prove composability.


That is how engineers evolve into architects.


— LearnTeachMaster

 
 
 

Recent Posts

See All

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
Post: Blog2_Post

Subscribe Form

Thanks for submitting!

©2020 by LearnTeachMaster DevOps. Proudly created with Wix.com

bottom of page