English | 简体中文
EasyAgent is a lightweight agent SDK organised as a small set of composable layers. The goal is to let you learn agent design step by step: start with a single model call, then add memory and context, build up to a ReAct loop with tools and skills, drop into a sandbox, and finally orchestrate multiple agents through the Entity-World-Schedule architecture.
pip install easy-agent-sdkFrom source:
git clone https://github.com/SNHuan/EasyAgent.git
cd EasyAgent
pip install -e ".[dev]"Optional extras:
pip install easy-agent-sdk[sandbox]
pip install easy-agent-sdk[web]
pip install easy-agent-sdk[all]import asyncio
from easyagent import LiteLLMModel, ReactAgent
async def main():
agent = ReactAgent(
model=LiteLLMModel("gpt-4o-mini"),
system_prompt="You are a concise assistant.",
max_iterations=5,
)
result = await agent.run("What is 2 + 2?")
print(result.final_output)
asyncio.run(main())Create easyagent/config/config.yaml or configure LiteLLM through environment
variables:
debug: false
models:
gpt-4o-mini:
api_type: openai
base_url: https://api.openai.com/v1
api_key: sk-xxxEasyAgent is organised around three layers:
Single-agent: Model + Memory + Context + Tool → Agent / ReactAgent / SkillAgent / SandboxAgent
Multi-agent: Entity + World + Schedule → Runtime
Presets: sequential / fanout / debate / chatroom / groupchat
- Model — provider adapter and message schema.
- Memory + Context — store conversation history and decide what reaches the model each turn.
- Agent — composes a model, memory, context, and any tools/skills/sandbox.
Four built-in classes:
Agent(single-turn) →ReactAgent(ReAct loop) →SkillAgent/SandboxAgent. - Entity — wraps an Agent (or any async actor) for multi-agent participation.
Protocol:
idproperty +async act(Perception) -> Action | None. - World — the environment entities perceive and act upon.
Built-ins:
ConversationWorld,PipelineWorld,SpatialWorld,StatefulWorld. - Schedule — determines who acts next.
Built-ins:
TakeTurns,RoundRobin,AllParallel,Reactive,MaxTicks,UntilIdle. - Runtime — the perceive-act-apply loop wiring Entity + World + Schedule.
See docs/architecture.md for the full design guide.
The root package exposes the common SDK surface:
from easyagent import (
# single-agent
Agent, ReactAgent, SkillAgent, SandboxAgent,
AgentSession, AgentRunResult,
LiteLLMModel, Message,
EventBus, MessageEvent,
ToolManager, SkillManager, register_tool,
# multi-agent protocols
Entity, World, Schedule, Runtime, RuntimeResult,
# perception & action types
Perception, Speak, Silent, ChatMessage,
# entities
LLMEntity, TeamEntity, HumanEntity,
# worlds
ConversationWorld, PipelineWorld, SpatialWorld, StatefulWorld, SharedState,
# schedules
TakeTurns, RoundRobin, AllParallel, MaxTicks, UntilIdle, Reactive,
# presets
sequential, fanout, debate, chatroom, groupchat,
)The examples are ordered by layer. Each one introduces one new idea:
# Single agent (00–06)
python examples/00_model_call.py # Just call the model
python examples/01_single_turn_agent.py # Compose a minimal Agent
python examples/02_memory_and_context.py # Memory + Context
python examples/03_react_with_tools.py # ReactAgent + tool calls
python examples/04_skills_lazy_loading.py # SkillAgent (SKILL.md packages)
python examples/05_sandbox_agent.py # SandboxAgent (bash, write/read file)
python examples/06_custom_tool.py # Define your own tool
# Multi-agent: Entity-World-Schedule (07–14)
python examples/07_two_agents_talk.py # LLMEntity + ConversationWorld + RoundRobin
python examples/08_sequential.py # sequential() preset
python examples/09_chatroom.py # Manual turn-taking + if/else
python examples/10_groupchat.py # Reactive schedule, LLM picks next
python examples/11_debate_and_judge.py # Third-party judge after debate
python examples/12_nested.py # TeamEntity: Runtime-as-Entity nesting
python examples/13_shared_state.py # SharedState + StatefulWorld blackboard
python examples/14_advanced_runtime.py # SpatialWorld: 2D grid + range-limited perceptionfrom easyagent import LiteLLMModel, ReactAgent, register_tool
@register_tool
class GetWeather:
name = "get_weather"
type = "function"
description = "Get weather for a city."
parameters = {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
}
def init(self) -> None: ...
def execute(self, city: str) -> str:
return f"Sunny in {city}."
agent = ReactAgent(
model=LiteLLMModel("gpt-4o-mini"),
tools=[GetWeather],
)Pass tool classes or instances directly via tools=[...]. The agent
automatically registers an end tool — call it to terminate the loop early.
Skills are directory packages loaded on demand. SKILL.md is the required
entry file; supporting files can live alongside it:
skills/my-skill/
├── SKILL.md
├── references/
├── templates/
├── assets/
└── scripts/
from easyagent import LiteLLMModel, SkillAgent
agent = SkillAgent(
model=LiteLLMModel("gpt-4o-mini"),
skills=["my-skill"],
skill_root="./skills",
)Wrap any Agent as an LLMEntity, then compose with presets:
from easyagent import LiteLLMModel, ReactAgent, LLMEntity, sequential
model = LiteLLMModel("gpt-4o-mini")
researcher = LLMEntity("researcher", ReactAgent(model=model, name="researcher", system_prompt="..."))
writer = LLMEntity("writer", ReactAgent(model=model, name="writer", system_prompt="..."))
reviewer = LLMEntity("reviewer", ReactAgent(model=model, name="reviewer", system_prompt="..."))
result = await sequential([researcher, writer, reviewer], "Write a product blurb.")
print(result.last_speech)Available presets: sequential / fanout / chatroom / groupchat /
debate. For recursive nesting, wrap an inner Runtime as a TeamEntity
and drop it into any outer pipeline. See examples/07_* through
examples/14_* for walkthroughs.
The architecture is extensible beyond conversation. Swap the World to get entirely different behaviour with the same Entity and Schedule:
from easyagent import SpatialWorld, Grid2D, Runtime, RoundRobin, MaxTicks
grid = Grid2D()
grid.place("alice", (0, 0))
grid.place("bob", (5, 5))
world = SpatialWorld(grid=grid, listen_radius=3.0)
schedule = MaxTicks(inner=RoundRobin(ids=["alice", "bob"]), n=10)
rt = Runtime(world=world, entities={"alice": alice, "bob": bob}, schedule=schedule)
result = await rt.run("Start exploring")easyagent/
├── agent/ # Agent, ReactAgent, SkillAgent, SandboxAgent, AgentSession
├── core/ # Entity, World, Schedule protocols + Runtime loop
├── entities/ # LLMEntity, TeamEntity, HumanEntity
├── worlds/ # ConversationWorld, PipelineWorld, SpatialWorld, StatefulWorld
├── presets.py # sequential, fanout, debate, chatroom, groupchat
├── context/ # SlidingWindowContext, SummaryContext, MultiAgentFormatter
├── events/ # MessageEvent, EventBus, telemetry events
├── memory/ # InMemoryMemory
├── model/ # LiteLLMModel + Message schema
├── prompt/ # System-prompt builders
├── sandbox/ # Local / Docker sandboxes
├── skill/ # SKILL.md loading
├── tool/ # Tool registry + built-ins (bash, file, web, end)
├── config/ # Config loading
└── debug/ # Logging
MIT License © 2025 Yiran Peng