Skip to main content

build-your-own-openclaw-agent-tutorial

Step-by-step guide to building AI agents from simple chat loops to autonomous multi-agent systems with tools, memory, and event-driven architecture

Zur Installation springen

Quellinformationen

Repository
reason-machines/hermes-skills
Letzte Quellaktivität
23. Mai 2026 um 00:34
Erkannte Sprache von SKILL.md
Englisch
Sterne
5
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
build-your-own-openclaw-agent-tutorial
description
Step-by-step guide to building AI agents from simple chat loops to autonomous multi-agent systems with tools, memory, and event-driven architecture
triggers
["how do I build an AI agent from scratch","teach me to create an autonomous agent","show me how to build an OpenClaw-style agent","guide me through building an agent with tools and memory","help me create a multi-agent system","how to build an event-driven AI agent","create an agent with scheduled tasks and persistence","build an agent that can use tools and skills"]
# Build Your Own OpenClaw Agent Tutorial > Skill by [ara.so](https://ara.so) — Hermes Skills collection. A comprehensive tutorial for building AI agents progressively, from a basic chat loop to a production-ready autonomous agent system. This project walks through 18 steps covering single-agent capabilities, event-driven architecture, multi-agent collaboration, and production features like memory and concurrency control. ## What This Tutorial Teaches The tutorial is organized into 4 phases: 1. **Phase 1 (Steps 0-6)**: Single agent with tools, skills, persistence, and web access 2. **Phase 2 (Steps 7-10)**: Event-driven architecture with multi-platform support 3. **Phase 3 (Steps 11-15)**: Autonomous agents with routing and collaboration 4. **Phase 4 (Steps 16-17)**: Production features like concurrency and long-term memory ## Initial Setup ### Clone the Repository ```bash git clone https://github.com/czl9707/build-your-own-openclaw.git cd build-your-own-openclaw ``` ### Configure API Keys ```bash # Copy example config cp default_workspace/config.example.yaml default_workspace/config.user.yaml ``` Edit `default_workspace/config.user.yaml`: ```yaml llm: model: "gpt-4" # or anthropic/claude-3-5-sonnet-20241022, etc. api_key: "${OPENAI_API_KEY}" # Use environment variable # See https://docs.litellm.ai/docs/providers for all providers # Optional: Add additional services web: search_api_key: "${SERPER_API_KEY}" ``` ### Install Dependencies (for each step) ```bash cd 00-chat-loop # or any step directory pip install -r requirements.txt ``` ## Phase 1: Building a Capable Single Agent ### Step 0: Basic Chat Loop The foundation - a simple conversation loop with an LLM. ```python # 00-chat-loop/main.py from litellm import completion def chat_loop(): messages = [] while True: user_input = input("You: ") if user_input.lower() in ['/exit', '/quit']: break messages.append({"role": "user", "content": user_input}) response = completion( model="gpt-4", messages=messages, api_key="${OPENAI_API_KEY}" ) assistant_message = response.choices[0].message.content messages.append({"role": "assistant", "content": assistant_message}) print(f"Assistant: {assistant_message}") if __name__ == "__main__": chat_loop() ``` Run it: ```bash cd 00-chat-loop python main.py ``` ### Step 1: Adding Tools Give your agent function-calling capabilities. ```python # 01-tools/tools.py def get_current_weather(location: str) -> dict: """Get the current weather for a location.""" # Tool implementation return {"location": location, "temperature": 72, "condition": "sunny"} # Tool schema for LLM weather_tool = { "type": "function", "function": { "name": "get_current_weather", "description": "Get the current weather in a given location", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "City name, e.g. San Francisco" } }, "required": ["location"] } } } ``` Using tools in the chat loop: ```python import json from litellm import completion response = completion( model="gpt-4", messages=messages, tools=[weather_tool], tool_choice="auto" ) # Handle tool calls if response.choices[0].message.tool_calls: for tool_call in response.choices[0].message.tool_calls: function_name = tool_call.function.name arguments = json.loads(tool_call.function.arguments) # Execute tool result = get_current_weather(**arguments) # Add tool result to messages messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result) }) ``` ### Step 2: Skills with SKILL.md Extend agent capabilities through markdown skill files. ```markdown <!-- skills/web_search.md --> # Web Search Skill You can search the internet using the `search_web` tool. ## When to Use - User asks for current information - Need to verify facts - Looking for recent news ## Example User: "What's the latest news on AI?" You: Let me search for that. [calls search_web("latest AI news")] ``` Loading skills: ```python # 02-skills/skill_loader.py import os def load_skills(skills_dir="skills"): """Load all .md files from skills directory.""" skills_content = [] for filename in os.listdir(skills_dir): if filename.endswith(".md"): with open(os.path.join(skills_dir, filename), 'r') as f: skills_content.append(f.read()) return "\n\n".join(skills_content) # Add to system prompt system_prompt = f"""You are a helpful assistant. ## Your Skills {load_skills()} """ ``` ### Step 3: Conversation Persistence Save conversations to resume later. ```python # 03-persistence/session_manager.py import json from datetime import datetime from pathlib import Path class SessionManager: def __init__(self, sessions_dir="sessions"): self.sessions_dir = Path(sessions_dir) self.sessions_dir.mkdir(exist_ok=True) def save_session(self, session_id: str, messages: list): """Save conversation history.""" session_file = self.sessions_dir / f"{session_id}.json" data = { "session_id": session_id, "updated_at": datetime.now().isoformat(), "messages": messages } with open(session_file, 'w') as f: json.dump(data, f, indent=2) def load_session(self, session_id: str) -> list: """Load conversation history.""" session_file = self.sessions_dir / f"{session_id}.json" if not session_file.exists(): return [] with open(session_file, 'r') as f: data = json.load(f) return data.get("messages", []) def list_sessions(self) -> list: """List all available sessions.""" return [f.stem for f in self.sessions_dir.glob("*.json")] ``` Usage: ```python manager = SessionManager() # Load or create session session_id = "my-conversation" messages = manager.load_session(session_id) # After each exchange manager.save_session(session_id, messages) ``` ### Step 4: Slash Commands Direct user control over agent behavior. ```python # 04-slash-commands/commands.py class CommandHandler: def __init__(self, session_manager): self.session_manager = session_manager self.commands = { '/new': self.new_session, '/load': self.load_session, '/list': self.list_sessions, '/save': self.save_session, '/clear': self.clear_session, '/help': self.show_help } def handle(self, user_input: str, current_session: str, messages: list): """Handle slash commands.""" parts = user_input.split() command = parts[0] args = parts[1:] if len(parts) > 1 else [] if command in self.commands: return self.commands[command](args, current_session, messages) return None # Not a command def new_session(self, args, current_session, messages): new_id = args[0] if args else f"session_{int(time.time())}" return {"action": "new_session", "session_id": new_id} def load_session(self, args, current_session, messages): if not args: print("Usage: /load <session_id>") return {"action": "none"} loaded = self.session_manager.load_session(args[0]) return {"action": "load_session", "session_id": args[0], "messages": loaded} ``` ### Step 5: Context Compaction Manage token limits by summarizing old messages. ```python # 05-compaction/compactor.py from litellm import completion class MessageCompactor: def __init__(self, max_messages=20): self.max_messages = max_messages def compact_if_needed(self, messages: list) -> list: """Compact messages if they exceed threshold.""" if len(messages) <= self.max_messages: return messages # Keep system message and recent messages system_msgs = [m for m in messages if m["role"] == "system"] recent_msgs = messages[-(self.max_messages - 2):] # Summarize older messages old_msgs = messages[len(system_msgs):-len(recent_msgs)] summary = self._summarize_messages(old_msgs) return system_msgs + [ {"role": "system", "content": f"Previous conversation summary:\n{summary}"} ] + recent_msgs def _summarize_messages(self, messages: list) -> str: """Generate summary of message history.""" conversation = "\n".join([ f"{m['role']}: {m['content']}" for m in messages ]) response = completion( model="gpt-4", messages=[{ "role": "user", "content": f"Summarize this conversation concisely:\n\n{conversation}" }] ) return response.choices[0].message.content ``` ### Step 6: Web Tools Give your agent internet access. ```python # 06-web-tools/web_tools.py import requests import os def search_web(query: str, num_results: int = 5) -> list: """Search the web using Serper API.""" api_key = os.getenv("SERPER_API_KEY") response = requests.post( "https://google.serper.dev/search", headers={"X-API-KEY": api_key}, json={"q": query, "num": num_results} ) results = response.json() return [ { "title": r.get("title"), "link": r.get("link"), "snippet": r.get("snippet") } for r in results.get("organic", []) ] def fetch_webpage(url: str) -> str: """Fetch and extract text from a webpage.""" from bs4 import BeautifulSoup response = requests.get(url, timeout=10) soup = BeautifulSoup(response.content, 'html.parser') # Remove script and style elements for script in soup(["script", "style"]): script.decompose() return soup.get_text(separator="\n", strip=True) ``` ## Phase 2: Event-Driven Architecture ### Step 7: Event-Driven Refactor Decouple components with an event bus. ```python # 07-event-driven/event_bus.py from typing import Callable, Dict, List from dataclasses import dataclass from enum import Enum class EventType(Enum): MESSAGE_RECEIVED = "message_received" MESSAGE_SENT = "message_sent" TOOL_CALLED = "tool_called" SESSION_CREATED = "session_created" @dataclass class Event: type: EventType data: dict source: str class EventBus: def __init__(self): self.listeners: Dict[EventType, List[Callable]] = {} def subscribe(self, event_type: EventType, handler: Callable): """Subscribe to an event type.""" if event_type not in self.listeners: self.listeners[event_type] = [] self.listeners[event_type].append(handler) def publish(self, event: Event): """Publish an event to all subscribers.""" if event.type in self.listeners: for handler in self.listeners[event.type]: handler(event) # Usage
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen