Create a minimal agent using raw API calls. Understand the core loop before using frameworks.
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.
Build an agent that can answer questions requiring multiple steps. For example:
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"]
}
}
}
]
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"
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}"
The definitive guide to agent patterns and best practices
Official docs on tool/function calling API
Claude's approach to tool calling
Reference implementation for minimal chat agents
web_search tool using a real API (SerpAPI, Tavily, etc.)