Les agents OpenClaw : guide complet
Comprendre les agents OpenClaw : composants, types, cycle de vie, création et orchestration. Guide technique avec code Python et exemples concrets.
Les agents OpenClaw : guide complet
Un agent OpenClaw est une unité autonome capable d'accomplir un objectif défini en enchaînant des skills, en prenant des décisions conditionnelles et en gérant ses propres erreurs. Comprendre ce que sont les agents OpenClaw, comment ils sont structurés et comment les créer est le point de départ de tout déploiement. Ce guide couvre l'architecture interne, les types d'agents disponibles, le cycle de vie et la création d'un premier agent fonctionnel, avec des exemples de code Python commentés.
Qu'est-ce qu'un agent OpenClaw ?
Un agent OpenClaw est un programme Python qui orchestre des skills dans un ordre logique pour accomplir une tâche de bout en bout. Il ne s'agit pas d'un simple script séquentiel : l'agent peut interrompre son exécution si une condition n'est pas remplie, réessayer une étape en cas d'échec, ou adapter son comportement en fonction des données reçues à chaque étape.
La différence avec un script classique est dans la gestion de l'état. Un agent maintient une mémoire de contexte partagée entre tous ses skills. Quand le skill A produit un résultat, le skill B peut l'utiliser directement sans qu'il soit nécessaire de le passer manuellement entre les fonctions. Cette mémoire persistante rend les workflows multi-étapes fiables et inspectables.
Un agent OpenClaw est défini par :
- un nom et une configuration (modèle LLM, nombre de retries, backend mémoire) ;
- une liste de skills enregistrés dans un ordre d'exécution logique ;
- une mémoire de contexte initialisée à l'entrée et enrichie à chaque étape ;
- des règles de sortie : continuer, arrêter, ou réessayer.
Pour aller plus loin sur la philosophie du framework, consultez le guide complet OpenClaw.
Les composants d'un agent
AgentConfig
AgentConfig définit le comportement global de l'agent : quel LLM utiliser, combien de fois réessayer en cas d'échec, quel backend utiliser pour stocker la mémoire.
from openclaw import AgentConfig
config = AgentConfig(
name="mon-agent",
model="gpt-4o", # LLM utilisé par les skills qui en ont besoin
max_retries=3, # Nombre de tentatives avant abandon
memory_backend="local", # "local", "redis", "sqlite"
log_level="INFO", # Niveau de verbosité des logs
timeout=120, # Timeout global en secondes
)
Skill
Un skill est une classe Python qui hérite de Skill. Elle implémente une méthode run(context: dict) -> SkillResult. Chaque skill reçoit le contexte courant, effectue une action, et retourne un résultat qui enrichit ce contexte.
from openclaw import Skill, SkillResult
class MonSkill(Skill):
name = "mon_skill"
def run(self, context: dict) -> SkillResult:
# Lire des données du contexte
input_data = context.get("input_data")
# Effectuer une action
result = process(input_data)
# Retourner succès ou arrêt
if result:
return SkillResult.success({**context, "output": result})
else:
return SkillResult.stop(reason="Traitement impossible")
AgentMemory
La mémoire est le contexte partagé entre tous les skills. Elle est initialisée avec les données d'entrée et enrichie à chaque étape. Chaque skill peut lire tout ce qui a été produit par les skills précédents.
# Initialisation de la mémoire à l'entrée
initial_context = {
"keyword": "agent ia python",
"lang": "fr",
"user_id": "42",
}
result = agent.run(initial_context)
SkillResult
SkillResult communique à l'agent ce qu'il doit faire après l'exécution d'un skill :
SkillResult.success(data) # Continuer avec les données enrichies
SkillResult.stop(reason) # Arrêter le pipeline (log + exit propre)
SkillResult.retry(reason) # Réessayer ce skill (jusqu'à max_retries)
SkillResult.error(exception) # Erreur inattendue (log + exit avec code erreur)
Les types d'agents
OpenClaw supporte plusieurs patterns d'agents selon la complexité du workflow :
Agent séquentiel
Le type le plus simple. Chaque skill s'exécute dans l'ordre, l'un après l'autre.
agent = Agent(config)
agent.register_skill(SkillA())
agent.register_skill(SkillB())
agent.register_skill(SkillC())
agent.run(context)
# Exécution : A → B → C
Adapté pour : pipelines de traitement de données, génération de contenu, rapports automatiques.
Agent conditionnel
Les skills s'exécutent selon des conditions évaluées sur le contexte courant.
from openclaw import ConditionalSkill
agent.register_skill(ConditionalSkill(
condition=lambda ctx: ctx.get("volume", 0) > 500,
skill=WriterSkill(),
fallback=LogSkill(message="Volume insuffisant"),
))
Adapté pour : workflows avec critères de qualité, filtrages métier, traitement sélectif.
Agent boucle
Répète un ensemble de skills sur une liste d'entrées.
from openclaw import LoopAgent
agent = LoopAgent(config, items_key="keywords")
agent.register_skill(SerpSkill())
agent.register_skill(WriterSkill())
agent.run({"keywords": ["kw1", "kw2", "kw3"]})
# Exécute le pipeline complet pour chaque mot-clé
Adapté pour : traitement par lot (mots-clés, URLs, leads, produits).
Agent orchestré (multi-agents)
Un agent principal délègue des sous-tâches à des agents spécialisés. Chaque sous-agent est autonome et retourne un résultat à l'orchestrateur.
from openclaw import OrchestratorAgent
orchestrator = OrchestratorAgent(config)
orchestrator.register_sub_agent("seo", seo_agent)
orchestrator.register_sub_agent("social", social_agent)
orchestrator.register_sub_agent("email", email_agent)
orchestrator.run({"article_id": "123"})
# L'orchestrateur délègue en parallèle ou en séquence selon config
Adapté pour : workflows complexes impliquant des domaines différents, pipelines avec parallélisation.
Cycle de vie d'un agent
┌─────────────────────────────────────────────────────────┐
│ CYCLE DE VIE AGENT │
│ │
│ ┌──────────┐ │
│ │ INIT │ ← AgentConfig + Skills enregistrés │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ START │ ← context = données d'entrée │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ SkillResult.retry ┌──────────┐ │
│ │ SKILL │──────────────────────▶│ RETRY │ │
│ │ RUN │◀──────────────────────└──────────┘ │
│ └────┬─────┘ (max_retries atteint → STOP) │
│ │ │
│ ├── SkillResult.stop ──▶ ┌──────────┐ │
│ │ │ STOP │ → log │
│ │ └──────────┘ │
│ │ │
│ ├── SkillResult.error ─▶ ┌──────────┐ │
│ │ │ ERROR │ → log+exit │
│ │ └──────────┘ │
│ │ │
│ ▼ SkillResult.success │
│ ┌──────────┐ │
│ │ NEXT │ ← context enrichi avec output du skill │
│ │ SKILL │ │
│ └────┬─────┘ │
│ │ (dernier skill atteint) │
│ ▼ │
│ ┌──────────┐ │
│ │ DONE │ → retourne AgentResult final │
│ └──────────┘ │
└─────────────────────────────────────────────────────────┘
Chaque transition est loggée. Le résultat final (AgentResult) contient le contexte final, le statut global, la liste des skills exécutés et les éventuelles erreurs rencontrées.
Créer son premier agent
Voici un agent minimal fonctionnel qui récupère le contenu d'une URL et en extrait les titres H2.
Installation
pip install openclaw beautifulsoup4 httpx
Code complet
# first_agent.py
from openclaw import Agent, AgentConfig, Skill, SkillResult
from bs4 import BeautifulSoup
import httpx
# --- Skill 1 : fetch ---
class FetchSkill(Skill):
name = "fetch_url"
def run(self, context: dict) -> SkillResult:
url = context.get("url")
if not url:
return SkillResult.stop(reason="Aucune URL fournie")
try:
response = httpx.get(url, timeout=10, follow_redirects=True)
response.raise_for_status()
return SkillResult.success({**context, "html": response.text})
except httpx.HTTPError as e:
return SkillResult.retry(reason=f"Erreur HTTP : {e}")
# --- Skill 2 : parse ---
class ParseH2Skill(Skill):
name = "parse_h2"
def run(self, context: dict) -> SkillResult:
html = context.get("html", "")
soup = BeautifulSoup(html, "html.parser")
h2s = [h.get_text(strip=True) for h in soup.find_all("h2")]
if not h2s:
return SkillResult.stop(reason="Aucun H2 trouvé sur la page")
return SkillResult.success({**context, "h2_titles": h2s})
# --- Configuration ---
config = AgentConfig(
name="h2-extractor",
model="gpt-4o",
max_retries=2,
memory_backend="local",
log_level="INFO",
)
# --- Création et exécution ---
agent = Agent(config)
agent.register_skill(FetchSkill())
agent.register_skill(ParseH2Skill())
result = agent.run({"url": "https://example.com/article"})
if result.success:
print("H2 trouvés :", result.data["h2_titles"])
else:
print("Arrêt :", result.reason)
Cet agent de 40 lignes est autonome : il gère les erreurs HTTP, réessaie automatiquement, et s'arrête proprement si la page ne contient pas de H2.
Pour explorer les skills disponibles dans la bibliothèque standard OpenClaw, voir le guide des skills OpenClaw.
Agents simples vs agents orchestrés
| Critère | Agent simple | Agent orchestré |
|---|---|---|
| Nombre de skills | 2–6 | Illimité (via sous-agents) |
| Parallélisation | Non | Oui (sous-agents en parallèle) |
| Complexité code | Faible | Élevée |
| Débogage | Facile | Plus complexe |
| Cas d'usage | Pipeline linéaire | Workflow multi-domaines |
| Exemple | Audit SERP + rédaction | SEO + social + email |
Recommandation : commencez toujours par un agent simple. Ajoutez un orchestrateur uniquement quand un pipeline linéaire atteint ses limites (trop de skills, besoin de parallélisation, domaines métier trop différents).
Un agent simple bien conçu couvre 80 % des cas d'usage courants. La complexité supplémentaire d'un orchestrateur n'est justifiée que si elle apporte un gain mesurable (temps d'exécution, capacité de traitement).
Exemple concret : agent de veille
Objectif : surveiller les 5 principaux concurrents sur un mot-clé et envoyer un rapport email hebdomadaire si un concurrent publie un nouvel article.
# veille_agent.py
from openclaw import Agent, AgentConfig, Skill, SkillResult, LoopAgent
import httpx
import smtplib
from email.mime.text import MIMEText
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
class CheckNewArticlesSkill(Skill):
name = "check_new_articles"
def run(self, context: dict) -> SkillResult:
competitor_url = context.get("competitor_url")
response = httpx.get(competitor_url, timeout=10, follow_redirects=True)
soup = BeautifulSoup(response.text, "html.parser")
# Chercher des articles publiés dans les 7 derniers jours
# (logique simplifiée — adapter aux balises du site concurrent)
articles = soup.find_all("article")
new_articles = []
for article in articles:
date_tag = article.find("time")
if date_tag and date_tag.get("datetime"):
pub_date = datetime.fromisoformat(date_tag["datetime"][:10])
if pub_date >= datetime.now() - timedelta(days=7):
title = article.find("h2") or article.find("h3")
link = article.find("a")
if title and link:
new_articles.append({
"title": title.get_text(strip=True),
"url": link.get("href"),
"date": str(pub_date.date()),
})
if not new_articles:
return SkillResult.stop(reason="Aucun nouvel article cette semaine")
existing = context.get("new_articles", [])
return SkillResult.success({
**context,
"new_articles": existing + [
{"source": competitor_url, **a} for a in new_articles
],
})
class EmailReportSkill(Skill):
name = "email_report"
def __init__(self, smtp_config: dict, recipient: str):
self.smtp_config = smtp_config
self.recipient = recipient
def run(self, context: dict) -> SkillResult:
articles = context.get("new_articles", [])
if not articles:
return SkillResult.stop(reason="Rien à envoyer")
body = "Nouveaux articles concurrents cette semaine :\n\n"
for a in articles:
body += f"- [{a['title']}]({a['url']}) — {a['source']} ({a['date']})\n"
msg = MIMEText(body)
msg["Subject"] = f"Veille concurrentielle — {datetime.now().strftime('%d/%m/%Y')}"
msg["From"] = self.smtp_config["from"]
msg["To"] = self.recipient
with smtplib.SMTP(self.smtp_config["host"], self.smtp_config["port"]) as server:
server.starttls()
server.login(self.smtp_config["user"], self.smtp_config["password"])
server.send_message(msg)
return SkillResult.success({**context, "email_sent": True})
# --- Configuration et exécution ---
config = AgentConfig(name="veille-agent", model="gpt-4o", max_retries=2, memory_backend="local")
smtp_cfg = {"host": "smtp.gmail.com", "port": 587, "from": "vous@email.com",
"user": "vous@email.com", "password": "APP_PASSWORD"}
competitors = [
"https://concurrent1.fr/blog/",
"https://concurrent2.fr/articles/",
"https://concurrent3.fr/ressources/",
]
# Agent boucle : exécute CheckNewArticlesSkill pour chaque concurrent
loop_agent = LoopAgent(config, items_key="competitor_urls")
loop_agent.register_skill(CheckNewArticlesSkill())
# Exécuter la veille
result = loop_agent.run({"competitor_urls": competitors})
# Envoyer le rapport si des articles ont été trouvés
if result.success and result.data.get("new_articles"):
report_agent = Agent(config)
report_agent.register_skill(EmailReportSkill(smtp_cfg, "destinataire@email.com"))
report_agent.run(result.data)
Cet agent de veille tourne en cron hebdomadaire (via Vercel Cron ou un scheduler Linux). Il envoie un rapport uniquement quand des nouveaux articles sont détectés — pas de bruit inutile dans la boîte mail.
Pour voir un agent plus complexe en production, consultez le guide Créer un agent SEO avec OpenClaw.
Bonnes pratiques
Nommer les skills de façon descriptive. L'attribut name du skill apparaît dans les logs. fetch_url est utile au débogage ; skill_1 ne l'est pas.
Toujours retourner un SkillResult explicite. Ne jamais laisser une méthode run retourner None ou lever une exception non gérée. L'agent doit savoir quoi faire à chaque sortie possible.
Garder les skills petits et focalisés. Un skill fait une chose. Si un skill dépasse 50 lignes, il fait probablement deux choses différentes — découpez-le. Cela facilite les tests unitaires et la réutilisation.
Tester chaque skill isolément avant de l'intégrer dans un agent. Passez-lui un contexte minimal et vérifiez que SkillResult.success, SkillResult.stop et SkillResult.retry se déclenchent dans les bons cas.
Logger les métriques importantes dans le contexte. Durée d'exécution, coût API, nombre d'items traités — ajoutez ces données dans le contexte à chaque skill. Le AgentResult final contiendra alors un historique complet inspectable.
Définir une stratégie de retry différenciée. Certaines erreurs méritent un retry (timeout réseau), d'autres non (volume insuffisant, contenu inexistant). Utilisez SkillResult.retry uniquement pour les erreurs transitoires.
Conclusion
Un agent OpenClaw est la combinaison d'une configuration, de skills modulaires et d'une mémoire partagée. Sa puissance réside dans la clarté de cette architecture : chaque composant est indépendant, testable et remplaçable. La progression naturelle est de démarrer par un agent séquentiel simple, de valider son comportement sur des cas réels, puis d'augmenter la complexité uniquement si le besoin le justifie. La maîtrise des agents OpenClaw commence par cette discipline de conception — simple d'abord, complexe seulement si nécessaire.
Restez informé sur les agents IA
Nouveaux tutoriels, comparatifs et guides pratiques directement dans votre boîte mail.
