Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
28 minLesson 31 of 34
Python for AI

Automate Tasks with AI Agents

Automate Tasks with AI Agents

AI agents go beyond chatbots — they take actions, use tools, browse the web, write files, and complete multi-step tasks autonomously. This lesson builds a practical AI agent framework you can extend for any automation task.

What Makes an Agent

Task: "Research the top 5 Python web frameworks, compare their GitHub stars, 
       and create a summary report."

Agent Loop:
  Step 1: Reason: I need to search for Python web frameworks
  Step 2: Act: web_search("top Python web frameworks 2024")
  Step 3: Observe: Results with Flask, Django, FastAPI, etc.
  
  Step 4: Reason: I need GitHub star counts for each framework
  Step 5: Act: get_github_stats("tiangolo/fastapi"), get_github_stats("pallets/flask"), ...
  Step 6: Observe: Star counts and other stats
  
  Step 7: Reason: I have enough data to write the report
  Step 8: Act: write_file("web_frameworks_report.md", content)
  Step 9: Final answer: "Report saved to web_frameworks_report.md"

Building a Tool-Using Agent

import os
import json
import subprocess
from pathlib import Path
from openai import OpenAI
from dotenv import load_dotenv
import requests

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# ── Tool Definitions ────────────────────────────────────────
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "Read the contents of a file",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "File path to read"}
                },
                "required": ["path"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "Write content to a file",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string"},
                    "content": {"type": "string"}
                },
                "required": ["path", "content"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "run_python",
            "description": "Execute Python code and return output",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {"type": "string", "description": "Python code to execute"}
                },
                "required": ["code"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "Search the web for information",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "num_results": {"type": "integer", "default": 5}
                },
                "required": ["query"]
            }
        }
    }
]

# ── Tool Implementations ─────────────────────────────────────
def read_file(path: str) -> dict:
    try:
        content = Path(path).read_text(encoding='utf-8')
        return {"success": True, "content": content, "size": len(content)}
    except FileNotFoundError:
        return {"success": False, "error": f"File not found: {path}"}
    except Exception as e:
        return {"success": False, "error": str(e)}

def write_file(path: str, content: str) -> dict:
    try:
        p = Path(path)
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(content, encoding='utf-8')
        return {"success": True, "bytes_written": len(content), "path": str(p.absolute())}
    except Exception as e:
        return {"success": False, "error": str(e)}

def run_python(code: str) -> dict:
    import tempfile
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
        f.write(code)
        temp_path = f.name
    
    try:
        result = subprocess.run(
            ["python", temp_path],
            capture_output=True, text=True, timeout=30
        )
        return {
            "stdout": result.stdout,
            "stderr": result.stderr,
            "returncode": result.returncode
        }
    except subprocess.TimeoutExpired:
        return {"error": "Code execution timed out (30s limit)"}
    finally:
        os.unlink(temp_path)

def search_web(query: str, num_results: int = 5) -> list:
    """Mock search — replace with Brave Search API, SerpAPI, etc."""
    # In production: use os.getenv("BRAVE_API_KEY") and call API
    return [
        {"title": f"Result {i+1} for: {query}", 
         "url": f"https://example.com/result-{i+1}",
         "snippet": f"Information about {query} from source {i+1}..."}
        for i in range(num_results)
    ]

# Tool dispatcher
TOOL_MAP = {
    "read_file": read_file,
    "write_file": write_file,
    "run_python": run_python,
    "search_web": search_web
}

def execute_tool(name: str, arguments: dict) -> str:
    if name not in TOOL_MAP:
        return json.dumps({"error": f"Unknown tool: {name}"})
    try:
        result = TOOL_MAP[name](**arguments)
        return json.dumps(result)
    except Exception as e:
        return json.dumps({"error": str(e)})

# ── The Agent Loop ──────────────────────────────────────────
class Agent:
    def __init__(self, system_prompt: str, model: str = "gpt-4o", max_steps: int = 10):
        self.system_prompt = system_prompt
        self.model = model
        self.max_steps = max_steps
        self.messages = []
        self.step_count = 0
    
    def run(self, task: str) -> str:
        self.messages = [{"role": "user", "content": task}]
        self.step_count = 0
        
        print(f"\n{'='*60}")
        print(f"TASK: {task}")
        print(f"{'='*60}\n")
        
        while self.step_count < self.max_steps:
            self.step_count += 1
            print(f"Step {self.step_count}:", end=' ')
            
            response = client.chat.completions.create(
                model=self.model,
                messages=[{"role": "system", "content": self.system_prompt}] + self.messages,
                tools=TOOLS,
                tool_choice="auto"
            )
            
            choice = response.choices[0]
            self.messages.append(choice.message)
            
            if choice.finish_reason == "stop":
                final = choice.message.content
                print(f"DONE\n\nFINAL ANSWER:\n{final}")
                return final
            
            # Execute tool calls
            for tool_call in choice.message.tool_calls:
                name = tool_call.function.name
                args = json.loads(tool_call.function.arguments)
                print(f"{name}({', '.join(f'{k}={repr(v)[:30]}' for k,v in args.items())})")
                
                result = execute_tool(name, args)
                
                self.messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": result
                })
        
        return "Maximum steps reached. Task incomplete."

# ── Usage Examples ──────────────────────────────────────────
AGENT_SYSTEM_PROMPT = """You are an autonomous AI agent with access to tools.
Complete tasks step by step, using tools as needed.
Be methodical: plan, execute, verify, and summarize your work.
When you have completed the task, provide a clear summary of what was done."""

agent = Agent(system_prompt=AGENT_SYSTEM_PROMPT)

# Example 1: File analysis task
result = agent.run("""
Analyze a sales dataset: create a file called 'sample_data.csv' with 
10 rows of sales data (columns: month, revenue, units), then write a 
Python script to calculate and print the average monthly revenue.
""")

# Example 2: Research task
result = agent.run("""
Search for information about Python asyncio, then write a 
summary file at 'asyncio_summary.md' with the key concepts.
""")

Specialized Agents

# Code Review Agent
code_reviewer = Agent(
    system_prompt="""You are a senior Python developer doing code reviews.
    Read code files, identify issues, and produce a detailed review report."""
)

# Data Analysis Agent  
data_analyst = Agent(
    system_prompt="""You are a data analyst. Analyze data files, compute
    statistics, generate visualizations, and write clear reports."""
)

# Each agent can be given specific tasks
code_reviewer.run("Review all .py files in the current directory and create a code_review.md report")

Safety and Guardrails

import re

DANGEROUS_PATTERNS = [
    r'rm\s+-rf',
    r'os\.system\(',
    r'subprocess.*shell=True',
    r'__import__.*os',
    r'eval\(',
]

def safe_run_python(code: str) -> dict:
    """Execute Python code with safety checks."""
    for pattern in DANGEROUS_PATTERNS:
        if re.search(pattern, code, re.IGNORECASE):
            return {"error": f"Unsafe code detected: {pattern}"}
    
    # Run in restricted environment
    return run_python(code)

# Always limit what tools an agent can access based on the task
# A research agent shouldn't have write_file access
# A data analysis agent shouldn't have web access to your internal DB

AI agents are the frontier of Python development in 2026. The patterns here — tool execution, agent loops, safety checks — are directly applicable to building production AI systems.

Next lesson: Project: CLI Data Analysis Tool — putting it all together.

📱

Get this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!