Building a Minimalist AI Agent Framework: Theory, Architecture, and Code Walkthrough

This article explains the fundamentals of AI agents, compares major frameworks, introduces the ReAct, Plan‑and‑Execute, and Reflection paradigms, and provides a step‑by‑step Python implementation of a lightweight agent loop with LLM calls, tool execution, and context engineering, complete with usage examples and references.

Tencent Cloud Developer
Tencent Cloud Developer
Tencent Cloud Developer
Building a Minimalist AI Agent Framework: Theory, Architecture, and Code Walkthrough

AI agents are software systems that use large language models (LLMs) to achieve goals on behalf of users, combining reasoning, planning, and autonomous execution. The most influential paradigms are ReAct (reasoning + acting), Plan‑and‑Execute (plan first, then act), and Reflection (verbal self‑feedback).

1. Theory of AI Agent Frameworks

1.1 AI Agent Basics

According to Google Cloud, an AI agent performs reasoning, planning, and memory tasks with a degree of autonomy, allowing it to learn, adapt, and make decisions.

1.2 ReAct Mode

Proposed by Yao et al. (2022) in "ReAct: Synergizing Reasoning and Acting in Language Models," ReAct integrates Chain‑of‑Thought reasoning with tool interaction, addressing the lack of external feedback in pure CoT.

Reasoning : LLM analyzes the current task and generates internal thoughts (CoT).

Acting : Executes actions such as function calls, shell commands, or code execution.

Observation : Observes results and feeds them back into the next reasoning step.

1.3 Plan‑and‑Execute Mode

Based on the "Plan‑and‑Solve Prompting" paper (2023) and the BabyAGI project, this mode first creates a complete multi‑step plan and then executes it step by step, which is suitable for long‑running, well‑structured tasks but less dynamic.

1.4 Reflection Mode

Key papers include "Reflexion: Language Agents with Verbal Reinforcement Learning" and "Self‑Refine: Iterative Refinement with Self‑Feedback," which introduce verbal self‑feedback loops and iterative improvement without weight updates. These ideas extend ReAct with richer self‑correction mechanisms.

1.5 Comparison of Popular Frameworks

LangChain – mature, extensive toolchain, multi‑LLM support.

LlamaIndex – focuses on data indexing and retrieval (RAG).

AutoGPT/AutoGen – multi‑agent collaboration.

CrewAI – role‑based team simulation.

LangGraph – state‑graph workflow control.

Semantic Kernel – lightweight, Azure‑integrated.

Selection advice: use LangChain for quick prototypes, LlamaIndex for RAG, AutoGen or CrewAI for multi‑agent collaboration, LangGraph for complex workflows, and Semantic Kernel for .NET environments.

2. Practical Implementation

2.1 Core Architecture

The agent consists of three essential parts:

LLM Call : Standardized API wrapper (e.g., OpenAI SDK) that handles model invocation.

Tools Call : Executes external actions (shell, file I/O, Python code) via OpenAI‑style function calling.

Context Engineering : Manages system prompts, user messages, and tool results within a message list that serves as the agent’s state.

In practice, the DeepSeek deepseek-chat model is used because it supports tool calls and is compatible with the OpenAI SDK.

2.2 Agent Loop

# ============================================================
# Agent Loop — core
# ============================================================
MAX_TURNS = 20

def agent_loop(user_message: str, messages: list, client: OpenAI) -> str:
    """Agent Loop: while‑loop driving LLM reasoning and tool calls.
    Steps:
    1. Append user message to messages.
    2. Call LLM with current messages and tool schemas.
    3. If tool_calls are present, execute each tool, append results, and continue.
    4. If no tool_calls, return the assistant's final response.
    5. Stop after MAX_TURNS iterations.
    """
    messages.append({"role": "user", "content": user_message})
    tool_schemas = [t["schema"] for t in TOOLS.values()]
    for turn in range(1, MAX_TURNS + 1):
        # --- LLM Call ---
        response = client.chat.completions.create(
            model="deepseek-chat",
            messages=messages,
            tools=tool_schemas,
        )
        choice = response.choices[0]
        assistant_msg = choice.message
        messages.append(assistant_msg.model_dump())
        # Termination condition: no tool_calls
        if not assistant_msg.tool_calls:
            return assistant_msg.content or ""
        # Execute each tool_call
        for tool_call in assistant_msg.tool_calls:
            name = tool_call.function.name
            raw_args = tool_call.function.arguments
            try:
                args = json.loads(raw_args)
            except json.JSONDecodeError:
                args = {}
            tool_entry = TOOLS.get(name)
            if tool_entry is None:
                result = f"[error] unknown tool: {name}"
            else:
                result = tool_entry["function"](**args)
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": result,
            })
    return "[agent] reached maximum turns, stopping."

2.3 Tools Implementation and Registration

# ============================================================
# Tools implementation — 4 functions
# ============================================================
def shell_exec(command: str) -> str:
    """Execute a shell command and return stdout + stderr."""
    try:
        result = subprocess.run(
            command, shell=True, capture_output=True, text=True, timeout=30
        )
        output = result.stdout
        if result.stderr:
            output += "
[stderr]
" + result.stderr
        if result.returncode != 0:
            output += f"
[exit code: {result.returncode}]"
        return output.strip() or "(no output)"
    except subprocess.TimeoutExpired:
        return "[error] command timed out after 30s"
    except Exception as e:
        return f"[error] {e}"

def file_read(path: str) -> str:
    """Read file content."""
    try:
        with open(path, "r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        return f"[error] {e}"

def file_write(path: str, content: str) -> str:
    """Write content to a file, creating parent directories if needed."""
    try:
        os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
        with open(path, "w", encoding="utf-8") as f:
            f.write(content)
        return f"OK — wrote {len(content)} chars to {path}"
    except Exception as e:
        return f"[error] {e}"

def python_exec(code: str) -> str:
    """Execute Python code in a subprocess and return its output."""
    try:
        with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False, encoding="utf-8") as tmp:
            tmp.write(code)
            tmp_path = tmp.name
        result = subprocess.run([sys.executable, tmp_path], capture_output=True, text=True, timeout=30)
        output = result.stdout
        if result.stderr:
            output += "
[stderr]
" + result.stderr
        return output.strip() or "(no output)"
    except subprocess.TimeoutExpired:
        return "[error] execution timed out after 30s"
    except Exception as e:
        return f"[error] {e}"
    finally:
        try:
            os.unlink(tmp_path)
        except OSError:
            pass

# ============================================================
# Tools registration — name → (function, OpenAI schema)
# ============================================================
TOOLS = {
    "shell_exec": {
        "function": shell_exec,
        "schema": {
            "type": "function",
            "function": {
                "name": "shell_exec",
                "description": "Execute a shell command and return its output.",
                "parameters": {
                    "type": "object",
                    "properties": {"command": {"type": "string", "description": "The shell command to execute."}},
                    "required": ["command"]
                }
            }
        }
    },
    "file_read": {
        "function": file_read,
        "schema": {
            "type": "function",
            "function": {
                "name": "file_read",
                "description": "Read the contents of a file at the given path.",
                "parameters": {
                    "type": "object",
                    "properties": {"path": {"type": "string", "description": "Absolute or relative file path."}},
                    "required": ["path"]
                }
            }
        }
    },
    "file_write": {
        "function": file_write,
        "schema": {
            "type": "function",
            "function": {
                "name": "file_write",
                "description": "Write content to a file (creates parent directories if needed).",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "path": {"type": "string", "description": "Absolute or relative file path."},
                        "content": {"type": "string", "description": "Content to write."}
                    },
                    "required": ["path", "content"]
                }
            }
        }
    },
    "python_exec": {
        "function": python_exec,
        "schema": {
            "type": "function",
            "function": {
                "name": "python_exec",
                "description": "Execute Python code in a subprocess and return its output.",
                "parameters": {
                    "type": "object",
                    "properties": {"code": {"type": "string", "description": "Python source code to execute."}},
                    "required": ["code"]
                }
            }
        }
    }
}

2.4 System Prompt

SYSTEM_PROMPT = """You are a helpful AI assistant with access to the following tools:
1. shell_exec — run shell commands
2. file_read — read file contents
3. file_write — write content to a file
4. python_exec — execute Python code
Think step by step. Use tools when needed. When the task is complete, respond directly without calling any tool."""

2.5 CLI Interface

def main():
    api_key = os.environ.get("DEEPSEEK_API_KEY")
    if not api_key:
        print("Error: please set DEEPSEEK_API_KEY environment variable.")
        sys.exit(1)
    client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")
    messages = [{"role": "system", "content": SYSTEM_PROMPT}]
    print("Agent ready. Type your message (or 'exit' to quit, 'clear' to reset).
")
    while True:
        try:
            user_input = input("You> ").strip()
        except (EOFError, KeyboardInterrupt):
            print("
Bye.")
            break
        if not user_input:
            continue
        if user_input.lower() == "exit":
            print("Bye.")
            break
        if user_input.lower() == "clear":
            messages.clear()
            messages.append({"role": "system", "content": SYSTEM_PROMPT})
            print("(context cleared)
")
            continue
        reply = agent_loop(user_input, messages, client)
        print(f"
Agent> {reply}
")

2.6 Demonstration

The demo shows the agent listing directory contents, counting lines of code, and performing simple file operations, illustrating how the loop continuously calls tools, updates context, and produces final answers.

3. Conclusions and Outlook

The minimalist framework demonstrates that the essential components of an AI agent are LLM calls, tool calls, and context engineering. While the implementation lacks advanced features such as streaming, robust error handling, and sophisticated tool registries, it provides a clear, educational baseline for understanding and extending AI agents.

Future work should focus on improving robustness, adding security sandboxes for tool execution, supporting asynchronous tool calls, and integrating richer context management (long‑term memory, retrieval‑augmented generation, and domain‑specific skills).

References

Google Cloud definition: https://cloud.google.com/discover/what-are-ai-agents

ReAct paper: https://arxiv.org/abs/2210.03629

Plan‑and‑Solve Prompting: https://arxiv.org/abs/2305.04091

BabyAGI project: https://github.com/yoheinakajima/babyagi

Plan‑and‑Execute blog: https://blog.langchain.com/plan-and-execute-agents/

Reflexion paper: https://arxiv.org/abs/2303.11366

Self‑Refine paper: https://arxiv.org/abs/2303.17651

CRITIC paper: https://arxiv.org/abs/2305.11738

CodeBuddy Agent SDK: https://www.codebuddy.cn/docs/cli/sdk

WorkBuddy application: https://www.codebuddy.cn/work/

Context Engineering for AI Agents (Manus blog): https://manus.im/zh-cn/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus

Executable Code Actions paper: https://arxiv.org/abs/2402.01030

Anthropic MCP code execution article: https://www.anthropic.com/engineering/code-execution-with-mcp

OpenClaw documentation: https://docs.openclaw.ai/reference/AGENTS.default

Shunyu Yao article on Context difficulty: https://mp.weixin.qq.com/s?__biz=MzkwODU2OTQyNQ==∣=2247497329&idx=1&sn=59de1b66fa0e9da3bc9a2e371eeab4ae

Pi Agent core description: https://lucumr.pocoo.org/2026/1/31/pi/

PythonLLMReActAI AgentContext Engineering
Tencent Cloud Developer
Written by

Tencent Cloud Developer

Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.