コンテンツにスキップ

ナイトエンジン — AI 社員が空いている間に片づける

一日じゅう人と話していた AI 社員の記憶は散らかります。同じ事実が五通りの言い回しで書き込まれ、一つの手順が三つの会話にまたがって断片的に学習され、誰も戻ってこなかった宿題が残ります。ナイトエンジンは、アイドル時間にそれを整理するバックグラウンドの処理です。ついでに翌日のための下読みも少しします。

**既定はオフで、agent ごとの有効化が必要です。モデル呼び出しには追加のグローバルスイッチも必要です。**このページが存在する理由は単純で、これまで運用者がどこを開けばよいか知る手段がまったくなかったからです。


1 回の「ナイトパス」で、1 つの agent に対して 4 つのサブパスを実行します。

パス 名称 LLM 必要? 生成物
N1 スリープタイム計算 はい agent の現在のコンテキストを先に推論し、次回の起動用にキャッシュ
N2 先読みプリフェッチ はい 履歴+記憶から次のニーズを予測し、根拠を先に収集
N3 スキーマ帰納 いいえ エピソード記憶に繰り返し現れるパターンをスキーマ項目へ昇格
N4 再現性ゲート付き統合 いいえ 意味的に再現する知識だけが統合対象。書き込み前にカバレッジ/保存性/忠実性の検査を通し、失敗時はロールバック

N3 と N4 は決定論的でコストはゼロです。N1 と N2 はその agent のユーティリティモデル(既定は haiku 級)を呼び、支出上限の対象になるのもこの 2 つだけです。

参考文献:スリープタイム計算(arXiv:2504.13171)、ProAct(arXiv:2605.25971)、DCPM スキーマ帰納(arXiv:2606.09483)、RecMem(arXiv:2605.16045)+ TRUSTMEM(arXiv:2606.25161)。


スイッチは 2 つ、どちらも必須です。これは意図的な設計で、グローバル側は運用者の予算判断、agent 側は「どの社員に適用するか」の判断にあたります。

1. グローバル — ~/.duduclaw/config.toml:

[night]
# LLM を使うサブパス(N1/N2)が実際にモデルを呼ぶことを許可する。
# キーが無い・false・型が違う場合はすべて無効。このつまみは「オン」方向にしか効かない。
llm_enabled = true

llm_enabled = false(既定)でもスケジューラは動きますが、N1/N2 はモデルを受け取れず、ログを残してスキップします。N3/N4 は影響を受けません(そもそもモデルを必要としません)。

2. agent ごと — ~/.duduclaw/agents/<id>/agent.toml:

[night_engine]
enabled = true # この agent のマスタースイッチ。既定 false
idle_threshold_minutes = 90 # ユーザー操作がこれだけ無ければアイドル扱い
max_pass_cost_cents = 20 # 1 パスあたりの上限。到達したら N1/N2 を打ち切る
max_passes_per_day = 8 # サーキットブレーカー。agent ごと、ローリング 24 時間
sleep_time = true # N1
prefetch = true # N2
schema_induction = true # N3(決定論的)
recurrence_consolidation = true # N4(決定論的)
schema_min_support = 3 # N3: スキーマ化に必要な出現回数
recurrence_threshold = 3 # N4: 統合を起動する再現回数
context_window = 40 # N1/N2: 1 パスで見る直近の記憶/ターン数

このブロックはその agent 自身の agent.toml からのみ読み込まれます。config.toml にグローバルな [night_engine] フォールバックはありません(レジストリは各 agent の設定をそのまま読み、グローバル既定値を重ねません)。したがって [night_engine] を書いていない agent には上記の組み込み既定値(enabled = false)が適用されます。複数の社員で有効化するには、それぞれの agent.toml に enabled = true を書きます。


  • パスごとの支出上限。 max_pass_cost_cents は N1/N2 の呼び出し前に確認され、呼び出し後に推定コストが記録されます。上限に達すると残りの LLM サブパスはスキップされ、N3/N4 は続行します。
  • 日次サーキットブレーカー。 max_passes_per_day は agent ごとのローリング 24 時間のパス数を制限します。状態は永続化されるため、クラッシュループでカウンタがリセットされることはありません。ブレーカーファイルが壊れていた場合は新規状態から開始します(フェイルセーフ)。
  • アイドル時のみ。 idle_threshold_minutes の間ユーザー操作が無い場合にのみ起動します。一度も活動していない agent もアイドル扱いです。
  • 記憶の内容はデータとして扱う。 2 つのナイトプロンプトはいずれも記憶断片を <data> ブロックで囲み、その中の指示には決して従わないよう明示します。記憶の行はチャネル由来であり、攻撃者が書き込める経路があるためです。
  • 書き込みは既存のゲートを通る。 N3/N4 の統合書き込みは共有の記憶エンジン構築点を使うため、[memory] novelty_gate は他の gateway 内部書き込み経路と同様にここでも効きます。

ナイトパスのログは duduclaw_gateway::night_engine ターゲットから出ます。完了時は night pass complete と実行されたサブパスが記録され、スキップ時は理由(例:night pass skipped: daily circuit breaker open)が出ます。agent がアイドルでないときは何も出ません。

パスが洞察や先読み資料をキャッシュした場合、スキーマを生成した場合、統合結果を保存した場合、または検証に失敗した統合を復元した場合、ダッシュボードの Activity Feed に night_engine.pass_complete が 1 件追加されます。要約には実際の成果と件数が表示されます。成果のないパスやスキップされたパスは追加されません。フィードへの書き込みはベストエフォートで、失敗はログに記録され、ナイトエンジンは続行します。

ターミナルウィンドウ
# systemd
journalctl -u duduclaw -f | grep night
# フォアグラウンド実行
RUST_LOG=duduclaw_gateway::night_engine=debug duduclaw run

何も出ない場合は、その agent が本当にアイドルか、2 つのスイッチが両方オンか、その日の max_passes_per_day を使い切っていないかを確認してください。