AgentBot Tutorial
Welcome to the AgentBot tutorial! In this tutorial, we will guide you through the process of building an agent that uses PocketFlow for graph-based tool orchestration. AgentBot automatically wraps your functions as tools and uses a decision node to orchestrate tool execution through a flow graph.
Prerequisites
Before you begin, ensure you have the following:
- Basic knowledge of Python programming
- Familiarity with the concept of bots and automation
- Access to a Python environment with the necessary libraries installed
What is AgentBot?
AgentBot is a graph-based agent that uses PocketFlow to orchestrate tool execution. Unlike traditional agents that use loops, AgentBot builds a flow graph where:
- A decision node (DecideNode) analyzes the conversation and selects which tool to execute
- Tool nodes execute the selected tools
- Tools can loop back to the decision node (except terminal tools
like
respond_to_user) - The flow continues until a terminal node is reached
This graph-based approach provides:
- Visual flow representation: You can visualize the agent's flow graph
- Flexible orchestration: Tools are connected in a graph, not a linear sequence
- Automatic tool wrapping: You provide plain callables; AgentBot handles the rest
- Default tools:
today_dateandrespond_to_userare always available
Part 1: Basic Usage
Step 1: Setting Up the Environment
First, ensure you have the llamabot library installed:
pip install llamabot
Step 2: Creating a Simple AgentBot
The simplest way to create an AgentBot is to provide a list of callable functions:
import llamabot as lmb
def get_weather(city: str) -> str:
"""Get the current weather for a city.
:param city: The name of the city
:return: Weather information
"""
# In practice, you'd call a real weather API
return f"The weather in {city} is sunny, 72°F"
# Create an AgentBot with your function
agent = lmb.AgentBot(
tools=[get_weather],
model_name="gpt-4o-mini"
)
# Use the agent
result = agent("What's the weather in New York?")
print(result)
What happens behind the scenes:
- AgentBot automatically wraps
get_weatherwith@tooland@nodeifydecorators - Default tools (
today_dateandrespond_to_user) are added automatically - A
DecideNodeis created to decide which tool to use - The flow graph is built connecting the decision node to all tools
- When you call the agent, it runs the flow with your query
Step 3: Understanding Default Tools
AgentBot always includes two default tools:
today_date: Returns the current date (loops back to decide node)respond_to_user: Sends a response to the user (terminal node, no loopback)
These tools are automatically available, so you don't need to provide them:
agent = lmb.AgentBot(tools=[])
# The agent can still use today_date and respond_to_user
result = agent("What's today's date?")
Part 2: Building a Financial Analysis Agent
Let's create a more sophisticated agent that can analyze financial data using multiple tools.
Step 1: Defining Custom Tools
You can define tools as plain Python functions - no decorators needed:
def get_stock_price(symbol: str) -> float:
"""Get the current stock price for a given symbol.
:param symbol: The stock symbol (e.g., 'AAPL', 'MSFT', 'GOOGL')
:return: The current stock price
"""
# This is a simplified example - in practice, you'd use a real API
mock_prices = {
'AAPL': 150.25,
'MSFT': 300.50,
'GOOGL': 2800.75,
'TSLA': 200.30
}
if symbol.upper() not in mock_prices:
raise ValueError(f"Symbol {symbol} not found")
return mock_prices[symbol.upper()]
def calculate_percentage_change(old_price: float, new_price: float) -> float:
"""Calculate the percentage change between two prices.
:param old_price: The original price
:param new_price: The new price
:return: The percentage change (positive for increase, negative for decrease)
"""
return ((new_price - old_price) / old_price) * 100
def analyze_portfolio(prices: list[float]) -> dict:
"""Analyze a portfolio of stock prices.
:param prices: List of stock prices
:return: Analysis results including average, min, max, and trend
"""
if not prices:
return {"error": "No prices provided"}
avg_price = sum(prices) / len(prices)
min_price = min(prices)
max_price = max(prices)
# Simple trend analysis
if len(prices) >= 2:
trend = "upward" if prices[-1] > prices[0] else "downward"
else:
trend = "insufficient data"
return {
"average": avg_price,
"minimum": min_price,
"maximum": max_price,
"trend": trend,
"count": len(prices)
}
Step 2: Creating the Financial Agent
# Create a financial analysis agent
financial_agent = lmb.AgentBot(
tools=[get_stock_price, calculate_percentage_change, analyze_portfolio],
model_name="gpt-4o-mini"
)
Step 3: Using the Agent for Analysis
# Ask the agent to analyze multiple stocks
result = financial_agent("""
Please analyze the following stocks:
1. Get the current price of AAPL
2. Get the current price of MSFT
3. Calculate the percentage change from yesterday's prices (AAPL: $145, MSFT: $295)
4. Analyze the portfolio performance
""")
print(result)
The agent will:
- Use the decision node to select
get_stock_pricefor AAPL - Loop back to decide, then select
get_stock_pricefor MSFT - Loop back to decide, then select
calculate_percentage_changefor both stocks - Loop back to decide, then select
analyze_portfolio - Finally, use
respond_to_user(terminal) to provide the final answer
Part 3: Visualizing the Flow Graph
One of the powerful features of AgentBot is the ability to visualize the flow graph. If you're using Marimo notebooks, you can display the graph:
agent = lmb.AgentBot(tools=[get_stock_price, calculate_percentage_change])
# In a Marimo notebook, this will display the flow graph
agent
The graph shows:
- The decision node (DecideNode)
- All tool nodes (with their function names)
- Edges showing how tools connect back to the decision node
- Terminal nodes (like
respond_to_user) that don't loop back
Part 4: Custom Decision Nodes
By default, AgentBot uses DecideNode which uses ToolBot to decide
which tool to execute. You can provide a custom decision node:
from llamabot.components.pocketflow import DecideNode
# Create a custom decision node with a specific model
custom_decide = DecideNode(
tools=[], # Will be set by AgentBot
model_name="gpt-4.1"
)
agent = lmb.AgentBot(
tools=[get_stock_price],
decide_node=custom_decide
)
Part 5: Advanced Features
Terminal Tools
By default, all tools loop back to the decision node. However,
respond_to_user is a terminal tool that ends the flow. You can
create your own terminal tools using the nodeify decorator:
from llamabot.components.pocketflow import nodeify
from llamabot.components.tools import tool
# Terminal node - no loopback
@nodeify(loopback_name=None)
@tool
def final_answer(message: str) -> str:
"""Provide the final answer to the user.
:param message: The final answer message
:return: The message
"""
return message
Using Already-Decorated Tools
If you have functions that are already decorated with @tool, that's
fine too:
@lmb.tool
def my_tool(arg: str) -> str:
"""My tool function."""
return f"Result: {arg}"
# AgentBot will still wrap it with @nodeify
agent = lmb.AgentBot(tools=[my_tool])
Accessing the Flow
You can access the underlying PocketFlow flow for advanced use cases:
agent = lmb.AgentBot(tools=[get_stock_price])
# Access the flow
flow = agent.flow
# Access individual nodes
decide_node = agent.decide_node
tools = agent.tools
Part 6: Best Practices
1. Write Clear Function Documentation
Good docstrings help the decision node choose the right tool:
def analyze_sentiment(text: str) -> dict:
"""Analyze the sentiment of text using a simple algorithm.
This tool performs basic sentiment analysis by counting positive and
negative words. It's useful for getting a quick understanding of
text sentiment.
:param text: The text to analyze
:return: Dictionary with 'sentiment' (positive/negative/neutral),
'score' (0-1), and 'confidence'
"""
# Implementation here
pass
2. Design Tools for Specific Use Cases
Keep tools focused and single-purpose:
def get_user_profile(user_id: str) -> dict:
"""Get user profile information.
:param user_id: The user's unique identifier
:return: User profile dictionary
"""
# Implementation
pass
def update_user_profile(user_id: str, updates: dict) -> dict:
"""Update user profile information.
:param user_id: The user's unique identifier
:param updates: Dictionary of fields to update
:return: Updated user profile
"""
# Implementation
pass
3. Handle Errors Gracefully
Tools should handle errors and return meaningful results:
def safe_api_call(url: str, timeout: int = 10) -> dict:
"""Safely make an API call with error handling.
:param url: The URL to call
:param timeout: Request timeout in seconds, by default 10
:return: API response or error information
"""
import requests
try:
response = requests.get(url, timeout=timeout)
response.raise_for_status()
return {
"status": "success",
"data": response.json(),
"status_code": response.status_code
}
except requests.RequestException as e:
return {
"status": "error",
"error": str(e),
"url": url
}
Part 7: Understanding the Flow
How Tools Are Wrapped
When you provide a function to AgentBot:
- The function is wrapped with
@toolto create a tool schema - The tool is wrapped with
@nodeifyto create a PocketFlow node - The node is connected to the decision node
- If not terminal, the node loops back to the decision node
Flow Execution
When you call the agent:
- Your query is added to the shared state's memory
- The flow starts at the decision node
- The decision node uses ToolBot to select a tool
- The selected tool executes with arguments from the decision node
- The result is added to memory
- If the tool loops back, the flow returns to the decision node
- This continues until a terminal tool (like
respond_to_user) is reached
Shared State
The flow uses a shared state dictionary that contains:
memory: List of conversation messages and tool resultsfunc_call: Dictionary of function arguments (set by decision node)result: Tool execution results
Conclusion
Congratulations! You now understand how to use AgentBot with PocketFlow for graph-based tool orchestration. AgentBot provides:
- Automatic tool wrapping: Just provide plain callables
- Graph-based orchestration: Visual flow representation
- Default tools:
today_dateandrespond_to_useralways available - Flexible decision making: Custom decision nodes supported
- Terminal nodes: Control flow termination with terminal tools
The graph-based approach makes it easy to visualize and understand how your agent works, while the automatic wrapping makes it simple to add new tools. Happy coding!