Skip to content

Liang-HZ/Liangent

Liangent: Minimalist Lightweight Agent

PyPI version Python 3.9+ License: MIT CI

Slogan: Minimalist lightweight agent, your first usable agent.

English | δΈ­ζ–‡


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 (;, &, `, $()
  • 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 @tool decorator
  • 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 results
  • debug=True: See token usage, costs, and detailed step info
  • show_prompts=True: See complete prompts (System + History) sent to LLM

☁️ Serverless Ready

  • Built-in fc_handler.py for 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 sandbox
  • shell_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

  1. Set environment variables in FC console:

    • OPENAI_API_KEY
    • OPENAI_BASE_URL
    • MODEL_NAME
  2. Use fc_handler.py as entry point:

# fc_handler.py is included in the package
# Handler function: handler
  1. 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

About

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.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors