Skip to main content
Version: 9.2.11

Agents

This document provides a technical overview of the agent module in underthesea, including architecture, tools, and comparison with other popular agent frameworks.

Overview​

The agent module provides conversational AI capabilities with support for:

  1. Simple Agent (agent): Singleton instance for quick conversational AI
  2. Custom Agent (Agent): Class-based agent with custom tools support
  3. Tool System (Tool): Function-to-tool wrapper with OpenAI function calling
  4. LLM Client (LLM): Provider-agnostic LLM client (OpenAI, Azure OpenAI)
User Message β†’ [Agent] β†’ [LLM] β†’ Tool Calls? β†’ [Tool Execution] β†’ Response
↑ ↓
└── History β†β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Installation​

pip install "underthesea[agent]"

# Set API key
export OPENAI_API_KEY="sk-..."
# Or for Azure OpenAI:
export AZURE_OPENAI_API_KEY="..."
export AZURE_OPENAI_ENDPOINT="https://xxx.openai.azure.com"

Architecture​

Module Structure​

underthesea/agent/
β”œβ”€β”€ __init__.py # Exports: agent, Agent, Tool, LLM, default_tools
β”œβ”€β”€ agent.py # _AgentInstance (singleton) and Agent class
β”œβ”€β”€ llm.py # LLM client for OpenAI/Azure
β”œβ”€β”€ tools.py # Tool class for function wrapping
└── default_tools.py # Pre-built utility tools

Component Diagram​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Agent β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ LLM β”‚ β”‚ Tools β”‚ β”‚ History β”‚ β”‚ Instruction β”‚ β”‚
β”‚ β”‚ (client) β”‚ β”‚ (list) β”‚ β”‚ (list) β”‚ β”‚ (str) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β–Ό β–Ό β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ __call__() β”‚ β”‚
β”‚ β”‚ 1. Add user message to history β”‚ β”‚
β”‚ β”‚ 2. If tools: _call_with_tools() β”‚ β”‚
β”‚ β”‚ - Loop: LLM β†’ Tool calls? β†’ Execute β†’ Repeat β”‚ β”‚
β”‚ β”‚ 3. Else: Simple chat completion β”‚ β”‚
β”‚ β”‚ 4. Add assistant response to history β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Core Components​

1. LLM Client​

The LLM class provides a unified interface for OpenAI and Azure OpenAI.

Provider Detection:

PriorityConditionProvider
1AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT setAzure
2OPENAI_API_KEY setOpenAI
3Neither setError

Parameters:

ParameterTypeDefaultDescription
providerstrAuto-detect"openai" or "azure"
modelstrgpt-4o-miniModel/deployment name
api_keystrFrom envAPI key
azure_endpointstrFrom envAzure endpoint URL
azure_api_versionstr2024-02-01Azure API version

2. Tool Class​

The Tool class wraps Python functions for OpenAI function calling.

Automatic Schema Extraction:

def get_weather(location: str, unit: str = "celsius") -> dict:
"""Get weather for a location."""
return {"temp": 25, "unit": unit}

tool = Tool(get_weather)
# Extracts:
# - name: "get_weather"
# - description: "Get weather for a location."
# - parameters: {"location": {"type": "string", "required": true},
# "unit": {"type": "string", "required": false}}

Type Mapping:

Python TypeJSON Schema Type
strstring
intinteger
floatnumber
boolboolean
listarray

3. Agent Class​

The Agent class supports custom tools via OpenAI function calling.

Constructor:

ParameterTypeDefaultDescription
namestrRequiredAgent identifier
toolslist[Tool][]Available tools
instructionstr"You are a helpful assistant."System prompt
max_iterationsint10Max tool calling loops

Tool Calling Flow:

1. User sends message
2. Agent builds messages: [system, ...history, user]
3. Send to LLM with tools
4. If LLM returns tool_calls:
a. Execute each tool
b. Add tool results to messages
c. Go to step 3 (repeat until no tool calls or max_iterations)
5. Return final assistant message

Default Tools​

Tool Collections​

CollectionCountDescription
default_tools12All default tools
core_tools4Safe utilities (no external calls)
web_tools3Web/network operations
system_tools5File and system operations

Core Tools​

ToolFunctionDescription
current_datetime_toolget_current_datetime()Returns date, time, weekday, timestamp
calculator_toolcalculator(expression)Evaluates math (sqrt, sin, cos, log, pi, e)
string_length_toolstring_length(text)Counts characters, words, lines
json_parse_toolparse_json(json_string)Parses JSON strings

Web Tools​

ToolFunctionDescription
web_search_toolweb_search(query)DuckDuckGo search (no API key)
fetch_url_toolfetch_url(url)Fetch URL content
wikipedia_toolwikipedia(query, lang)Wikipedia search (vi/en)

System Tools​

ToolFunctionDescription
read_file_toolread_file(path)Read file content
write_file_toolwrite_file(path, content)Write to file
list_directory_toollist_directory(path)List files/directories
shell_toolrun_shell(command)Execute shell command
python_toolrun_python(code)Execute Python code

Usage Examples​

Simple Agent (Singleton)​

from underthesea import agent

# Basic conversation
response = agent("Xin chΓ o!")
print(response)

# With custom system prompt
response = agent("NLP lΓ  gΓ¬?", system_prompt="BαΊ‘n lΓ  chuyΓͺn gia NLP")

# Check history
print(agent.history)

# Reset conversation
agent.reset()

Custom Agent with Tools​

from underthesea.agent import Agent, Tool

def search_database(query: str) -> list:
"""Search internal database."""
return [{"id": 1, "title": f"Result for {query}"}]

def send_email(to: str, subject: str, body: str) -> dict:
"""Send an email."""
return {"status": "sent", "to": to}

agent = Agent(
name="assistant",
tools=[
Tool(search_database),
Tool(send_email, description="Send email to user"),
],
instruction="You are a helpful office assistant."
)

response = agent("Find documents about AI and email the results to john@example.com")

Using Default Tools​

from underthesea.agent import Agent, default_tools, core_tools, web_tools

# All tools
full_agent = Agent(name="full", tools=default_tools)

# Safe agent (no system access)
safe_agent = Agent(name="safe", tools=core_tools)

# Web-enabled agent
web_agent = Agent(name="web", tools=core_tools + web_tools)

# Use agent
response = full_agent("What time is it and what's the weather in Hanoi?")

Direct Tool Usage​

from underthesea.agent import calculator_tool, wikipedia_tool

# Use tools without LLM
result = calculator_tool(expression="sqrt(144) + 2**10")
print(result) # {'expression': '...', 'result': 1036.0}

wiki = wikipedia_tool(query="HΓ  Nα»™i", lang="vi")
print(wiki["summary"])

Comparison with Other Frameworks​

Feature Comparison​

FeatureundertheseaLangChainOpenAI SDKCrewAIPhidata
Setup ComplexityLowMediumLowMediumLow
Tool DefinitionFunction + decoratorClass-basedFunctionClass-basedToolkit
Multi-agentManualLangGraphBuilt-inBuilt-inBuilt-in
MemoryIn-memoryMultipleSessionBuilt-inBuilt-in
MCP SupportNoYesYesNoYes
ProvidersOpenAI, Azure100+OpenAIOpenAI+50+

Tool Count Comparison​

FrameworkBuilt-in ToolsTool Categories
underthesea12Core, Web, System
LangChain50+Search, Code, API, DB
OpenAI SDK5 hosted + localSearch, File, Code, Computer
CrewAI30+File, Web, Search, Document
Phidata/Agno45+Search, Finance, News, DB, Media
smolagents10Search, Web, Code, Speech
Pydantic AI7Search, Code, Image, Memory

Design Philosophy​

FrameworkPhilosophy
undertheseaSimple, Vietnamese NLP focused, minimal dependencies
LangChainComprehensive, composable chains, large ecosystem
OpenAI SDKOfficial, production-ready, OpenAI optimized
CrewAIRole-based multi-agent collaboration
PhidataPerformance-focused, 45+ pre-built toolkits
smolagentsLightweight, HuggingFace integration

Performance Considerations​

Latency Sources​

SourceTypical TimeNotes
LLM API call500ms - 5sDepends on model and prompt length
Tool executionVariableDepends on tool (web search ~1s)
First call+2-5sClient initialization

Best Practices​

  1. Reuse Agent Instances: Avoid creating new agents per request
  2. Limit Tools: Only include necessary tools (reduces prompt size)
  3. Set max_iterations: Prevent infinite tool loops
  4. Use core_tools for Safety: Avoid system tools in production

Memory Usage​

ComponentMemory
Agent instance~1KB
LLM client~5KB
Per tool~500B
History (per message)~1KB

Security Considerations​

Tool Safety Levels​

LevelToolsRisk
Safecore_toolsNo external access
Networkweb_toolsHTTP requests only
Systemsystem_toolsFile/shell access

Recommendations​

  1. Production: Use only core_tools unless necessary
  2. Shell Tool: Blocks dangerous commands (rm -rf, mkfs, etc.)
  3. Python Tool: Runs in restricted globals
  4. File Tools: Validate paths before use

Blocked Shell Commands​

dangerous = ["rm -rf", "mkfs", "dd if=", ":(){", "fork bomb", "> /dev/"]

API Reference​

Module Exports​

from underthesea.agent import (
# Core
agent, # Singleton agent instance
Agent, # Agent class with tools
LLM, # LLM client
Tool, # Function-to-tool wrapper

# Tool collections
default_tools, # All 12 tools
core_tools, # 4 safe tools
web_tools, # 3 web tools
system_tools, # 5 system tools

# Individual tools
current_datetime_tool,
calculator_tool,
string_length_tool,
json_parse_tool,
web_search_tool,
fetch_url_tool,
wikipedia_tool,
read_file_tool,
write_file_tool,
list_directory_tool,
shell_tool,
python_tool,
)

Testing​

# Run all agent tests
uv run python -m unittest discover tests.agent

# Run specific test modules
uv run python -m unittest tests.agent.test_agent
uv run python -m unittest tests.agent.test_tools
uv run python -m unittest tests.agent.test_llm

# Lint
ruff check underthesea/agent/

Changelog​

Unreleased​

  • Add Agent class with custom tools support (GH-712)
  • Add Tool class for function wrapping
  • Add 12 default tools: calculator, datetime, web_search, wikipedia, shell, python, file operations

v9.1.5 (2026-01-29)​

  • Add agent singleton and LLM client (GH-745)
  • Support OpenAI and Azure OpenAI providers

References​

OpenAI Function Calling​