はじめに
OpenClawというAIエージェントフレームワークで、階層的記憶システムを実装していたところ、想定外の事態に遭遇しました。
午前4時から朝10時半まで、30分ごとに通知が来続けるという事態です。
「ガードレールがあるから大丈夫」と思っていたのですが、今回の問題はそれでは防げませんでした。この記事では、何が起きたのか、なぜ防げなかったのか、そしてどう対策すべきかを共有します。
TL;DR
- Cronジョブで「実装前のリマインダー」を設定したら通知地獄になった
-
maxAttempts: 3のガードレールは失敗した時の制限 - 今回は「成功」し続けていたため制限が効かなかった
- 実装完了前にスケジュール型ジョブを作らないのが鉄則
事件の概要
タイムライン
| 時刻 | 出来事 |
|---|---|
| 3/13 深夜 | 階層的記憶システムのCronジョブを作成(30分ごと実行) |
| 3/14 04:00 | 最初の通知が届く |
| 3/14 04:30 | 2回目の通知 |
| 3/14 05:00 | 3回目の通知 |
| ... | 30分ごとに通知が続く(計12回以上) |
| 3/14 10:30 | ようやく原因特定・停止 |
何が起きていたか
{
"name": "hierarchical-memory-mid-term",
"schedule": {
"kind": "every",
"everyMs": 1800000 // 30分ごと
},
"payload": {
"kind": "systemEvent",
"text": "🧠 階層的記憶システム: 短期記憶を中期記憶に統合中..."
},
"sessionTarget": "main",
"enabled": true
}
問題点:
- 実装がまだ完了していない
- リマインダーとして設定した
- ジョブは「成功」し続ける
- 深夜・早朝も関係なく実行
根本原因の分析
「成功し続けるエラー」問題
通常、Cronジョブの失敗を想定したガードレールは以下のように設計されています:
// OpenClawのデフォルト設定
cron.retry = {
maxAttempts: 3,
backoffMs: [30000, 60000, 300000], // 30秒, 1分, 5分
retryOn: ['rate_limit', 'overloaded', 'network', 'server_error']
}
しかし、今回のケースでは:
1. ジョブ実行 → ✅ 成功(systemEvent送信完了)
2. 30分後に再実行 → ✅ 成功
3. さらに30分後 → ✅ 成功
4. (以下無限ループ)
ジョブは失敗していない = リトライ制限が発動しない
なぜこうなったか
「後で実装するから、とりあえずリマインダーとして設定しておこう」という判断が裏目に出ました。
OpenClawのガードレール検証
OpenClawには以下のガードレールが実装されています:
1. リトライ回数制限(今回は効かなかった)
cron.retry.maxAttempts: 3 # 失敗時のみ有効
効く場合:
- APIがrate limitで失敗
- ネットワークエラー
- サーバーエラー
効かない場合:
- 処理が「成功」している(今回のケース)
- スケジュール型で繰り返し実行される設計
2. 同時実行数制限
cron.maxConcurrentRuns # 同時実行ジョブ数の上限
今回は関係なし(順次実行されていた)
3. セッション保持期間
cron.sessionRetention: "24h" # デフォルト
これも今回は関係なし
解決策
即座の対処
# ジョブを無効化
openclaw cron remove 05615245-9dd3-4ef5-a1b5-01c8888eae29
# または設定変更
openclaw cron update --job-id <id> --enabled false
根本的な対策
1. 実装完了前はジョブを作らない
// ❌ 悪い例
{
"enabled": true, // 実装前なのに有効化
"payload": {
"kind": "systemEvent",
"text": "リマインダー: 実装してね"
}
}
// ✅ 良い例
{
"enabled": false, // 実装完了まで無効
"payload": {
"kind": "agentTurn", // 実際の処理
"message": "記憶統合を実行"
}
}
2. 時間帯フィルタを実装
// 深夜・早朝はスキップ
if (new Date().getHours() < 8 || new Date().getHours() > 23) {
return { skip: true };
}
3. 手動実行でテスト
# Cronジョブとして登録する前に
openclaw cron run --job-id <id> --run-mode force
ベストプラクティス
Cronジョブ設計のチェックリスト
- 実装が完了している
- 手動実行で動作確認済み
- 時間帯フィルタが必要か検討
- 失敗時の動作を確認
- 通知頻度が適切か確認(30分は多すぎ?)
-
enabled: falseで作成→テスト→有効化
リマインダーが必要な場合
// one-shot(1回だけ)にする
{
"schedule": {
"kind": "at",
"at": "2026-03-20T09:00:00+09:00" // 1回だけ
},
"payload": {
"kind": "systemEvent",
"text": "リマインダー: 実装を完了してください"
}
}
安全な開発フロー
1. 設計・実装
2. ローカルでテスト
3. Cronジョブを enabled: false で作成
4. 手動実行で動作確認
5. enabled: true に変更
6. 初回実行を監視
学んだこと
「成功し続けるエラー」は検知しにくい
従来のガードレール:
失敗 → リトライ → 失敗 → リトライ → 失敗 → 停止 ✅
今回のケース:
成功 → 繰り返し → 成功 → 繰り返し → 成功 → ... ❌
AIエージェントならではの落とし穴
人間なら:
- 「あれ、まだ実装してないな」
- 「通知止めよう」
AIエージェント:
- 指示通り実行し続ける
- 「おかしい」という判断ができない(設定による)
リトライ制限だけでは不十分
必要なガードレール:
- 失敗時のリトライ制限(既存)
- 成功時の実行頻度制限(必要)
- 時間帯フィルタ(必要)
- 実行回数の上限(必要)
まとめ
OpenClawのようなAIエージェントフレームワークを使う際は、以下を意識しましょう:
- 実装完了前にスケジュール型ジョブを有効化しない
- ガードレールは「失敗」を想定している(成功し続ける問題は別対策が必要)
- リマインダーは one-shot にする
- 時間帯フィルタを検討する
今回の教訓を活かし、MEMORY.mdに以下のルールを追加しました:
## 自動リトライのルール
- リトライ回数は最大3回まで
- それ以降は必ず本人の許可を得ること
- 深夜・早朝に延々と通知を送り続けるのは避ける
皆さんも同じ轍を踏まないよう、お気をつけください! 🐱