Claude Media
常時稼働エージェントの5つの部品 — 受信箱から送信箱まで

常時稼働エージェントの5つの部品 — 受信箱から送信箱まで

AnthropicのBest practices記事が示す常時稼働エージェントの設計を、受信箱・タイマー・メモリ・権限・送信箱の5部品に分けて読み解きます。

常時稼働エージェントは、実際には「常に動いている」わけではありません。大半の時間は眠っていて、イベントが来たときだけ起きて仕事をし、結果を保存してまた眠ります。Claude Platformの記事「Building always-on agents」(2026年11月13日公開、著者はWilliam Hu、読了14分)は、この眠りと目覚めの繰り返しを5つの部品で組み立てる方法を整理しています。

その5つは、イベントの受信箱(event inbox)、タイマー(timers)、メモリ(memory)、権限(permissions)、送信箱(outbox)です。エージェントの中核にあるループは通常のエージェントと同じで、違いは「いつ起きるか、何を持ち越すか、結果をどう届けるか」を決める周辺の設計にあります。

要点 — 起こす・覚える・届ける仕組みを別々に持つ

  • 1回の仕事をrun、その中のメッセージとツール呼び出しの記録をsessionと呼び、runが終わるとエージェントは眠る
  • 受信箱は、イベントを直接エージェントに渡さず、いったん永続化する場所
  • タイマーは受信箱とは別のストアに置き、時間が来たらイベントとして受信箱へ流す
  • メモリは作業者(worker)より長生きする保管先に置き、再取得できるものは持たない
  • 判断が分かれる操作は、runを終えてセッションを保存し、ユーザーの返事を新しいイベントとして受け取る
  • 送信箱は、メッセージの送り方を調整したいときや、エラーから回復したいときに足す

なぜ今、常時稼働エージェントなのか

ここ数か月で常時稼働エージェントが盛り返している理由は2つあります。1つ目はモデルの判断力で、ユーザーの意図を読む精度と、確認を入れるべき場面の見極めが上がりました。2つ目はコストで、長時間のタスクほど恩恵が大きくなります。

数字は1つだけ示されています。ある長時間のコーディングベンチマークで、Opus 5.5は解決1件あたりのコストがOpus 5より78%低く、通常のワークロードでは40%低いとあります。ベンチマークの名前は記事に書かれていません。

顧客からは、既存のエージェントをもっと能動的にしたい、あるいは最初から作りたいという相談が増えています。この解説記事はその設計図です。

runとsessionで1周を数える

1周の単位は次のとおりです。

手順

常時稼働エージェントの1周

  1. 1

    イベントを受け取る

    メッセージ、webhook、タイマーのいずれかが起点になります。

  2. 2

    runを実行する

    エージェントがタスクをこなします。runはsession(メッセージとツール呼び出しの記録)の中で動きます。

  3. 3

    何が起きたかを保存する

    次のrunが拾えるよう、メモリへ書き残します。

  4. 4

    眠る

    runが終わると待機に戻り、次のイベントまで動きません。

「ずっと動いている」という感覚は、ユーザーから見た体験の説明にすぎません。実装を考えるときは、短いrunがイベントのたびに起動する構造だと捉えるほうが設計と合います。

イベント受信箱 — 競合と取りこぼしを防ぐ

通常のエージェントはユーザーがメッセージを送ったときだけ動きます。常時稼働エージェントは、webhook、スケジュールされたタスク、バックグラウンドジョブなど多様なイベントで起動します。

素朴な作りは、イベント源がエージェントを直接呼ぶ方式です。この方式は2つの失敗を招きます。同時に届いた2つのイベントが競合するrunを始めることと、クラッシュでイベントが消えることです。

そこで、すべてのイベント源は受信箱に書き込み、作業者がそこから拾う形にします。最小構成は3つです。

部品役割実装の例
イベントの一覧役割永続的に保持する実装の例データベースのテーブル
ハンドラー役割イベントを一覧へ書く実装の例HTTPエンドポイント
作業者役割一覧を読んでrunを始める実装の例バックグラウンドサービス

受信箱にはイベントごとの状態を持たせ、イベント源の一意な識別子で重複排除できます。関係データベースに1イベント1行で追記する形が相性がよく、最初は1ユーザーに1つの受信箱から始め、並列性が要るときに分けます。

ユーザーの返信のように前の仕事を引き継ぐイベントは既存のsessionを再開し、それ以外は新しいsessionを始めます。作業者はイベントをエージェントのループへ渡し、runの完了を待って、対応するイベントを完了にします。

実装で押さえる4点

  1. ハンドラーは素早く応答する。webhookの送り元には、遅い応答を失敗とみなすものがある。軽い確認はハンドラーでよいが、プロンプトインジェクションの確認のような深い検証はrunの中で行う
  2. 受信箱を真実の源にする。作業者は起きたら最初に受信箱の最新を読む。作業者が途中で死んでも、次の作業者が同じイベントを拾って再試行できる
  3. 受信箱に同時に動く作業者は1つにする。2つのrunが仕事を重複させたり、互いの結果を上書きしたりするのを防ぐ
  4. 保留中のイベントはまとめて渡す。ユーザーが続けて何通も送ったとき、1回のrunに統合すれば返信も1回で済む

runの途中で新しいイベントが来た場合は、次のrunへ回す、実行中のrunに織り込む、中断してやり直す、の3通りがあります。どれを選ぶかの指定は元記事にありません。

受信箱の形を、元記事の説明に沿って最小限のテーブルにすると次のようになります。これは読者が手を動かすための一例で、元記事のスキーマではありません。

-- 例: 受信箱の最小構成(元記事の説明をもとにした一例)
CREATE TABLE inbox (
  id          BIGSERIAL PRIMARY KEY,
  user_id     TEXT NOT NULL,          -- 受信箱はユーザーごと
  source      TEXT NOT NULL,          -- webhook / timer / user など
  source_key  TEXT NOT NULL,          -- イベント源の一意な識別子
  payload     JSONB NOT NULL,
  status      TEXT NOT NULL DEFAULT 'pending',  -- pending / done
  received_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (user_id, source, source_key) -- 重複排除
);

ハンドラーはこの表へ1行書いて作業者を起こすだけにし、検証の重い処理はrunの側へ寄せる、というのが元記事の流れです。

タイマー — 自分で設定する期限と定期実行

受信箱と並んで、エージェントを能動的にするのがタイマーです。2種類あります。

  • follow-up: エージェントが自分に課す期限。返信の確認などに使う
  • schedule: 既知の周期で繰り返す定期タスク。毎日のニュースレターなど

タイマーは受信箱とは別の永続ストア(これもデータベースのテーブルが多い)に置きます。受信箱に入れるのは、すぐ取りかかれるイベントだけです。follow-upとscheduleのスキーマは似せられますが、scheduleには繰り返しの規則を持たせる必要があります。

タイマー自身はrunを始めません。スケジューラー(通常はバックグラウンドサービス)が一定間隔でストアを調べ、期限が来たものを発火させます。1回の走査は次の順です。

手順

スケジューラーの1回の走査

  1. 1

    期限が来たタイマーを探す

    ストアを調べ、期限を過ぎたものを拾います。

  2. 2

    タイマーを更新する

    follow-upは完了にし、scheduleは次の発生時刻に進めます。

  3. 3

    受信箱に流す

    イベントを受信箱に追加し、作業者を起こします。

スケジューラーは自前のサービスでも、durable execution engine(処理の途中状態を永続化して再開できる実行基盤)でも構いません。受信箱とタイマーを分けると、まだ先の予定はタイマー側に置かれ、受信箱に入るのは時刻が来たイベントだけになります。

メモリ — 再取得できないものだけを持つ

常時稼働エージェントは、途切れ途切れの多数のrunにまたがって動きます。連続性はメモリが支えます。受信箱やタイマーと同じく、専用のストアを持たせます。

Claude Codeの自動メモリやMessages APIのメモリツールは、ファイルのディレクトリとして実装されています。常時稼働エージェントでは、そのディレクトリを永続的な保管先(データベースやオブジェクトストア)に対応づけます。作業者が消えても記憶が残るようにするためです。

Messages APIのメモリツールは、Claudeが/memories以下のファイル操作を要求し、アプリ側が実行するクライアント側のツールです。/memoriesは実際の保管先へ対応づけるための接頭辞なので、ユーザーごとのディレクトリにもデータベースのキーにも割り当てられます。ツールはClaude 4以降のモデルで使えます。経験則は「エージェントが改めて調べられないものだけを持つ」で、課題管理ツールのように他のシステムにある情報は、本文でなくポインターを保存します。

保存する記憶は4種類に分かれています。

記憶の種類

メモリに置く4種類

  • ユーザーの指示

    エージェントの振る舞いへの指示は専用のファイルに保存し、毎回のrunの冒頭で読み込みます。ユーザーが常に見ているわけではないため、指示が次のrunに引き継がれる必要があります。

  • ユーザーのメモ

    役割や好み、受けた訂正など、ユーザーについて学んだこと。1ファイルから始め、増えたら小さなファイルに分けます。分けた場合は索引だけを読み込み、詳細は必要なときに取りに行きます。

  • 過去のメッセージ

    すでに伝えた内容を記録し、同じことを繰り返さないようにします。別ファイルに持つ方法と、作業者がエージェントの直近のメッセージを読み込む方法があります。

  • タスクの進捗

    進行中のタスクごとに、済んだことと残りを書く進捗ファイルを持ちます。新しいrunはそれを読んで前回の続きから始められます。ここも索引だけを先に読み込みます。

ここまでは実行中に保存する記憶の話です。これに加えて、過去のsessionを見直してメモリを整える「dreaming」も選べます。古い項目を置き換えたり、多数のrunにまたがって初めて見えるパターンを拾ったりする働きです。dreamingの詳細はAnthropicのエージェントメモリの記事にあり、その内容はエージェントメモリの構成要素 — dreamingでメモリを整える設計にまとめています。

コンテキストウィンドウの中身

runの冒頭でエージェントは、システムプロンプト、ツール定義、メモリファイルを読み込みます。この初期のコンテキストは毎回のrunに乗ります。小さく保ち、プロンプトキャッシュで費用を下げます。キャッシュの仕組みはClaudeのプロンプトキャッシュの仕組みにあります。

新しいsessionが持つのは、この初期コンテキストと、runの引き金になったイベントだけです。既存のsessionは、以前のrunのメッセージとツール呼び出しを引き継ぎます。sessionが長くなりすぎたら、古いメッセージを圧縮するか、新しいsessionを始めるかを選べます。どちらも細部が失われるので、残すべきことは途中でメモリに保存しておきます。

権限 — 無人で動くからリスクが集中する

権限は、常時稼働エージェントでもっともリスクが集中する部品です。runはユーザーのアクセス権を持ち、設計上、無人で動きます。ツール呼び出しごとに、そのまま進める、ブロックする、承認を待つのいずれかを決める必要があります。

使う部品は他のエージェントと同じで、3つです。

部品内容
認証情報のストア内容パスワードやアクセストークンのような機密情報の扱い。エージェントの環境の外にプロキシを置き、エージェントは認証情報なしでリクエストを出し、プロキシが本物の認証情報を差し込んで転送する形が推奨
auto mode内容分類器で危険度の高い操作を審査し、危険と判断したものをブロックして、Claudeに別のやり方を探させる。最も重要な判断にはユーザーの確認が引き続き要る。Claude Codeでは、分類器のブロックが連続3回、または合計20回に達すると、auto modeが止まって確認の表示に戻る
保留されたツール呼び出し内容Claude Codeでは、-pフラグを付けた非対話モードで、hookがツール呼び出しを保留してユーザーの入力を待てる。常時稼働エージェントにも同じパターンを当てはめる

auto modeの運用面は、Claudeアプリのauto mode既定化が扱っています。

保留の流れが、受信箱の設計とつながる部分です。呼び出しが保留されると、runは終わり、sessionは呼び出しの途中の状態で保存されます。保留された呼び出しの要求は、送信箱を通して届けることも、画面に直接表示することもできます。ユーザーにはMCP Appsで作った対話カードなどで要求が表示され、答えはイベントとして受信箱に戻ります。そのイベントが新しいrunを起こして保存済みのsessionを再開します。待っている間、作業者は他のイベントを拾えるので、エージェント全体は止まりません。

送信箱 — 結果だけをどう届けるか

通常のエージェントは、推論やツール呼び出しの過程を生成と同時にユーザーへ流します。常時稼働エージェントは仕事の大半をバックグラウンドで済ませ、ユーザーが受け取るのは結果と少しの詳細です。

runの終わり方は3通りです。

  1. 送信箱にメッセージを送る
  2. 何も送る必要がないと判断する
  3. 保留されたツール呼び出しで許可や追加入力を求める

多くの常時稼働エージェントは、ユーザーへ直接届ける「send」ツール1つで足ります。正式な送信箱が要るのは、メッセージの送り方に間隔を持たせたいとき、またはエラーから回復できるようにしたいときです。構造は受信箱と対になっていて、送信待ちメッセージの表と、作業者に相当するディスパッチャー(届けるものを決めて送るバックグラウンドサービス)で成り立ちます。

送る量の調整は見落とされやすい論点です。多すぎればノイズになり、少なすぎればユーザーが知るべきことを逃します。元記事は、バランスを探るためにevalを作ることと、最初は静かに始めてユーザーの注意を少しずつ得ることを勧めています。

5つが1つの循環になる

全体の流れは次のとおりです。runは必ず受信箱のイベントから始まり、作業者がそれを拾ってエージェントを新規または既存のsessionで起こします。エージェントはメモリで基準を得て、権限の範囲で動き、学んだことをメモリに書き戻します。終わると送信箱に1行を積み、ディスパッチャーがユーザーに届けます。

この循環は閉じています。runの中でタイマーを設定すれば後でまた起こされ、ユーザーが返信すればそれがイベントとして受信箱に戻ります。1回のrunは短くても、循環が続くので「いつもいる」ように見えます。

自分のプロダクトに当てはめるとどう読めるか

ここからは元記事の事実ではなく、編集の読みです。

Claude Code Channelsとの対応

Claude Codeには、Telegramなどのチャットアプリから開いたままのセッションへイベントを送り込むChannelsという研究プレビュー機能があります。仕組みの違いはClaude Code Channelsとはにあります。イベントを外から常駐のセッションへ届けるという点では、受信箱の発想と通じる部分があります。違いは届け先です。Channelsのイベントは、すでに開いているセッションにだけ届きます。受信箱は作業者がイベントを拾って新規または保存済みのsessionを起こすので、セッションが閉じていても受け取れます。

設計の順序

5つのうち、後から足せないのは受信箱です。イベントを直接エージェントに渡す作りで始めると、競合と取りこぼしの対策を後付けすることになり、作り直しに近い工事になります。タイマーは受信箱にイベントを流す側、メモリと権限はrunの中身、送信箱は後から足せる出口です。だから受信箱と「send」ツールだけで始め、問題が出た箇所に部品を足す進め方が成り立ちます。

定期実行との違い

定期実行だけなら、タイマー、受信箱、作業者の3点で足ります。ユーザーの返信や承認待ちが加わると、保留されたツール呼び出しと、sessionの保存・再開が要ります。定期実行を無人で回す設計の注意点はManaged Agentsの定期自動化 — 失敗を防ぐ6つの設計ルールにあります。

まとめ

常時稼働エージェントの設計は、エージェントのループを賢くする話ではなく、周りの5部品を分けて持つ話です。

最初に決めるのは、イベントをどこに永続化するか、メモリをどの保管先に置くか、無人で許す操作と確認を求める操作の線をどこに引くか、の3点です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. claude.com/resources/articles/building-always-on-agents
  2. platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool
  3. code.claude.com/docs/en/permission-modes
この記事を共有:XはてブLinkedIn