0% complete
Agent Track Easy 2-4 hours

Build a ReAct Agent from Scratch

Create a minimal agent using raw API calls. Understand the core loop before using frameworks.

🎯 The Mission

Before you can effectively work with Tenzai's agent architecture, you need to understand what's happening under the hood. Frameworks like LangGraph and Pydantic AI abstract away the core mechanicsβ€”but you need to see them raw first.

Your mission: Build a simple agent that can reason about a problem, choose tools, execute them, observe results, and iterate until it solves a task. No frameworks. Just you and the API.

What You'll Learn

The Task

Build an agent that can answer questions requiring multiple steps. For example:

Implementation Guide

Step 1: Define Your Tools

Create 2-3 simple tools with clear JSON schemas:

tools = [
    {
        "type": "function",
        "function": {
            "name": "calculator",
            "description": "Perform arithmetic calculations",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "Math expression to evaluate, e.g., '25 * 17 + 89'"
                    }
                },
                "required": ["expression"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "Read contents of a file",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "File path to read"}
                },
                "required": ["path"]
            }
        }
    }
]

Step 2: Build the ReAct Loop

def run_agent(user_task: str, max_iterations: int = 10):
    messages = [
        {"role": "system", "content": "You are a helpful assistant. Use tools when needed."},
        {"role": "user", "content": user_task}
    ]
    
    for i in range(max_iterations):
        # 1. REASON: Call the LLM
        response = client.chat.completions.create(
            model="gpt-4",
            messages=messages,
            tools=tools
        )
        
        assistant_message = response.choices[0].message
        messages.append(assistant_message)
        
        # 2. Check if done (no tool calls = final answer)
        if not assistant_message.tool_calls:
            return assistant_message.content
        
        # 3. ACT: Execute each tool call
        for tool_call in assistant_message.tool_calls:
            result = execute_tool(tool_call.function.name, tool_call.function.arguments)
            
            # 4. OBSERVE: Add tool result to conversation
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": str(result)
            })
    
    return "Max iterations reached"

Step 3: Implement Tool Execution

def execute_tool(name: str, arguments: str) -> str:
    args = json.loads(arguments)
    
    if name == "calculator":
        # WARNING: eval is dangerous! Use a safe math parser in production
        result = eval(args["expression"])
        return f"Result: {result}"
    
    elif name == "read_file":
        with open(args["path"], "r") as f:
            return f.read()
    
    return f"Unknown tool: {name}"

Resources

πŸ“– Anthropic: Building Effective Agents

The definitive guide to agent patterns and best practices

πŸ“– OpenAI Function Calling Guide

Official docs on tool/function calling API

πŸ“– Anthropic Tool Use

Claude's approach to tool calling

πŸ’» SimpleAIChat

Reference implementation for minimal chat agents

βœ“ Success Criteria

πŸ“‹ Progress Checklist

Stretch Goals