A lightweight agent framework
Project description
Liangent: Minimalist Lightweight Agent
Slogan: Minimalist lightweight agent, your first usable agent.
Liangent is a lightweight, extensible, and memory-aware agent framework designed for building LLM-based applications. It is designed to be a teaching prototype and a practical solution for simple tasks.
Unlike complex frameworks that rely on heavy planning steps, Liangent focuses on solving problems through forced tool usage constraints and dynamic prompt injection. This approach significantly reduces hallucinations and improves usability for everyday tasks.
✨ Key Features
🛡️ Local Code Sandbox
- Safely execute Python code with AST-based validation
- Safely execute Shell commands with whitelist/blacklist control
- Double Security Guarantee:
- Python: Allowed modules whitelist (
math,datetime,json,random,re,collections,itertools,functools,statistics) - Python: Blacklisted built-in functions (
open,exec,eval,compile, etc.) - Shell: Command whitelist (
python3,ls,grep,cat,date,find) - Shell: Dangerous pattern blocking (
;,&,`,$()
- Python: Allowed modules whitelist (
- Process isolation with timeout protection
📉 Hallucination Reduction via Dynamic Constraints
- Minimum Tool Usage (
min_tool_use): Force the agent to use tools before answering - Maximum Tool Usage (
max_tool_use): Prevent infinite tool calling loops - Dynamic Prompt Injection: If the agent attempts to answer too early, the system intercepts and forces reflection
🔧 Simple Tool Registration
- Register tools using a simple
@tooldecorator - Dual Mode Support:
- Native Function Calling: Works with models that support FC API (GPT-4, Claude 3, etc.)
- Prompt-based Mode: Parses JSON from text output, compatible with any LLM
- Automatic JSON Schema generation from Google-style docstrings
💾 Minimalist SQLite Storage
- Zero-config persistent sessions and logs
- Full traceability for every step
- Support for PostgreSQL and other databases
🔍 High Observability
verbose=True: See tool calls, thoughts, and resultsdebug=True: See token usage, costs, and detailed step infoshow_prompts=True: See complete prompts (System + History) sent to LLM
☁️ Serverless Ready
- Built-in
fc_handler.pyfor Aliyun Function Compute - Adaptable to AWS Lambda, Google Cloud Functions, etc.
🚀 Getting Started
1. Installation
pip install liangent
2. Initialize Project
liangent init
This generates:
.env: Configuration file (API Keys, limits, etc.)AGENTS.md: Agent identity and behavior guidelines
Edit .env:
OPENAI_API_KEY=sk-your-key-here
OPENAI_BASE_URL=https://api.openai.com/v1
MODEL_NAME=gpt-3.5-turbo
# Tool Usage Policy
MIN_TOOL_USE=1
MAX_TOOL_USE=15
MAX_STEPS=20
# Enable native function calling for supported models
SUPPORTS_FUNCTION_CALLING=False
3. Basic Usage
Synchronous Chat
from liangent import Liangent
client = Liangent(verbose=True)
response = client.chat("What is 123 * 456?")
print(response)
Streaming Mode
from liangent import Liangent
client = Liangent()
for event in client.stream("List files in current directory"):
evt_type = event.get("event")
if evt_type == "thought":
print(f"[Thinking] {event.get('content')}")
elif evt_type == "item.started":
item = event.get("data", {}).get("item", {})
print(f"[Tool Call] {item.get('tool')}({item.get('args')})")
elif evt_type == "item.completed":
item = event.get("data", {}).get("item", {})
print(f"[Tool Result] {item.get('aggregated_output')}")
elif evt_type == "final_answer":
print(f"[Answer] {event.get('content')}")
elif evt_type == "usage_stats":
content = event.get("content", {})
print(f"[Usage] {content.get('usage')}")
print(f"[Cost] {content.get('cost')}")
⚙️ Configuration Options
Liangent Client Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str | None | OpenAI API Key (falls back to env) |
base_url |
str | None | OpenAI Base URL (falls back to env) |
model_name |
str | None | Model name (falls back to env) |
db_url |
str | None | Database URL (:memory: if not set) |
tools |
List[str] | None | List of tool names to enable (all if None) |
verbose |
bool | False | Print thinking process and tool execution |
debug |
bool | False | Print full debug info (implies verbose) |
show_prompts |
bool | False | Print complete prompts for each step |
min_tool_use |
int | 1 | Minimum tool calls before final answer |
max_tool_use |
int | 15 | Maximum tool calls allowed |
max_steps |
int | 20 | Maximum agent steps |
Example: Forcing Tool Usage
from liangent import Liangent
# Agent must use at least 2 tools before answering
client = Liangent(
min_tool_use=2,
max_tool_use=10,
max_steps=15,
verbose=True
)
response = client.chat("What's the weather like?")
🖥️ CLI Commands
Interactive Chat
liangent chat
Start API Server
liangent start --port 8000
- API Endpoint:
http://localhost:8000/api/chat - API Docs:
http://localhost:8000/docs
Initialize Configuration
liangent init
🔧 Custom Tools
Register custom tools using the @tool decorator. Google-style docstrings are mandatory as they generate the tool schema.
from liangent import tool
@tool
def get_weather(city: str, unit: str = "celsius") -> str:
"""
Get current weather for a city.
Args:
city: Name of the city.
unit: Temperature unit (celsius or fahrenheit).
"""
# Your implementation
return f"Weather in {city}: 22°C, Sunny"
@tool
def search_database(query: str, limit: int = 10) -> list:
"""
Search the database for records.
Args:
query: Search query string.
limit: Maximum number of results.
"""
# Your implementation
return [{"id": 1, "name": "Result 1"}]
Built-in Tools
python: Execute Python code in sandboxshell_execute: Execute shell commands with security restrictions
📝 Customizing Agent Behavior
The AGENTS.md file defines your agent's persona and rules. It is automatically injected into the System Prompt.
# Agent Guidelines
## Identity
You are a senior Python engineer with expertise in data analysis.
## Behavior Rules
- Be concise and professional
- Always verify code logic using the python tool
- When handling file operations, list files first before reading
## Domain Knowledge
- Python best practices
- Data analysis workflows
🌐 API Server
Endpoint: POST /api/chat
Request Body
{
"query": "Your question here",
"session_id": "optional-session-id",
"user_id": "default_user",
"stream": true
}
SSE Events (when stream=true)
| Event | Description |
|---|---|
meta |
Session metadata |
status |
Current step status |
thought |
Agent's thinking process |
item.started |
Tool execution started |
item.completed |
Tool execution completed |
final_answer |
Final response |
done |
Completion with usage stats |
error |
Error occurred |
☁️ Serverless Deployment
Aliyun Function Compute
-
Set environment variables in FC console:
OPENAI_API_KEYOPENAI_BASE_URLMODEL_NAME
-
Use
fc_handler.pyas entry point:
# fc_handler.py is included in the package
# Handler function: handler
- Deploy and invoke:
{
"query": "Calculate 123 * 456"
}
📊 Event Types Reference
| Event | Data Fields | Description |
|---|---|---|
input_received |
content |
User query received |
status |
content |
Step status (e.g., "Thinking (Step 1)...") |
thought |
content |
Agent's reasoning |
item.started |
data.item.id, tool, args |
Tool execution begins |
item.completed |
data.item.id, tool, aggregated_output, exit_code |
Tool execution ends |
prompt_info |
data.step, system_prompt, history |
Full prompt details |
debug |
data.step, current_usage, total_cost |
Debug statistics |
final_answer |
content |
Final response |
usage_stats |
content.usage, content.cost |
Token usage and costs |
error |
content |
Error message |
🔒 Security Features
Python Sandbox
- Allowed Modules:
math,datetime,json,random,re,collections,itertools,functools,statistics - Blocked Functions:
open,exec,eval,compile,input,globals,locals - Process Isolation: 5-second timeout, separate process execution
- AST Validation: Pre-execution security check
Shell Sandbox
- Allowed Commands:
python3,ls,grep,cat,date,find - Blocked Patterns:
;,&,`,$( - Path Restriction: No
..traversal, project directory only - Timeout: 60 seconds default
📦 Project Structure
liangent/
├── __init__.py # Exports: Liangent, tool
├── client.py # High-level Liangent client
├── config.py # Settings and init_config
├── cli.py # CLI commands (init, start, chat)
├── server.py # FastAPI server
├── types.py # AgentState, MessageRole enums
├── core/
│ ├── agent.py # ContextAgent implementation
│ ├── llm.py # LLMClient (OpenAI compatible)
│ └── prompt_engine.py # Jinja2 template rendering
├── memory/
│ ├── db.py # Database initialization
│ ├── models.py # SQLAlchemy models
│ └── manager.py # SessionManager
├── tools/
│ ├── registry.py # @tool decorator and ToolRegistry
│ ├── sandbox.py # Python sandbox (SafeExecutor)
│ ├── shell_env.py # Shell sandbox
│ └── builtin/
│ └── shell.py # shell_execute tool
└── prompts/
└── system.j2 # System prompt template
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file liangent-0.0.18.tar.gz.
File metadata
- Download URL: liangent-0.0.18.tar.gz
- Upload date:
- Size: 34.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39c92455d17d3fcf540b9adc99da243a2a2b4fa404b15c5ae63226ba6e9950a5
|
|
| MD5 |
6ec07792ca8d7f0bf7f5927b4bcabc8f
|
|
| BLAKE2b-256 |
44c8467d5cea747fe3f98757e77be6648dc721054d21e73fc3574a0f74267ea5
|
File details
Details for the file liangent-0.0.18-py3-none-any.whl.
File metadata
- Download URL: liangent-0.0.18-py3-none-any.whl
- Upload date:
- Size: 36.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c9c0f36a239add7ead131a084c6a61e3938246f5ea1260b7298829429e601ee
|
|
| MD5 |
836f0012d2eb94f73483bb31ef4326cd
|
|
| BLAKE2b-256 |
7dc24bde6148d5efbcc43863a2e8106f8d084cc8764d20a7e388f635f2c0682d
|