Managed Agentsのアウトカム評価イベントを3段階で追う
Managed Agentsのアウトカム評価はstart/ongoing/endの3イベントで進みます。運用中に何を監視すればよいか、成果物の取得方法までを扱います。
Managed Agentsでアウトカム(達成すべき成果物の定義)を設定したセッションは、進捗をspan.outcome_evaluation_*という専用のイベント群でストリームに流します。イベントはstart・ongoing・endの3種類だけで、構造は単純です。実装側が決めるのは、どの値を見て次の動きを選ぶかです。3種類それぞれの意味と、ポーリング・Webhookでの追い方、成果物の取り出し方を扱います。
アウトカム評価だけが専用イベントを持つ理由
アウトカム指向のセッションでは、通常のagent.*イベント(メッセージやツール呼び出し)と、評価専用のspan.outcome_evaluation_*イベントが同じストリームに混在します。前者はエージェントがアウトカムに向けて何をしているかを示し、後者はグレーダー(採点役)が何周目の評価をしているか、どう判定したかを示します。
span.outcome_evaluation_*はアウトカム指向のセッションでだけ発生します。アウトカムを設定していない通常のセッションには、評価という概念自体がありません。
アウトカムの進行中でも、user.messageを送ってエージェントの作業を方向づけられます。必須ではなく、エージェントは成功するか反復回数を使い切るまで自律的に作業を続けます。
アウトカムの数字
max_iterations の既定値
3回
省略可。上限は20回
同時に持てるアウトカム
1つ
次のアウトカムは直前の終了後に送る
評価イベントの種類
3種
start / ongoing / end
イベントのoutcome_idはどこから来るか
アウトカムはuser.define_outcomeイベントで始めます。descriptionに作らせたいもの、rubricに採点基準、max_iterationsに反復の上限を渡します。ルーブリックはテキストで直接渡すか、Files APIにアップロードしてfile_idで渡します。複数のセッションで使い回すなら後者が向きます。
{
"type": "user.define_outcome",
"description": "Build a DCF model for Costco in .xlsx",
"rubric": { "type": "file", "file_id": "file_01..." },
"max_iterations": 5
}このイベントは受信時にそのまま返され、processed_atとoutcome_idが付きます。以降の評価イベントはすべてこのoutcome_idを持つので、監視側はIDで突き合わせるだけで、どの評価がどのアウトカムのものか分かります。送った時点でエージェントは作業を始めるため、追加のユーザーメッセージは要りません。
採点するグレーダーは、メインのエージェントとは別のコンテキストウィンドウで動きます。エージェントの実装上の選択に引きずられずに、成果物をルーブリックと照らします。
start — 評価サイクルの開始を示す
グレーダーが1周分の評価を始めるとspan.outcome_evaluation_startが発火します。
{
"type": "span.outcome_evaluation_start",
"id": "sevt_01def...",
"outcome_id": "outc_01a...",
"iteration": 0,
"processed_at": "2026-03-25T14:01:45Z"
}iterationは0始まりの改訂カウンターです。0が最初の評価、1が最初の改訂後の再評価になります。この番号を記録しておけば、あとから「何回目の改訂で合格したか」を追えます。
ongoing — グレーダーが動作中であることのハートビート
span.outcome_evaluation_ongoingは、グレーダーが動いている間に送られるハートビートです。
{
"type": "span.outcome_evaluation_ongoing",
"id": "sevt_01ghi...",
"outcome_id": "outc_01a...",
"iteration": 0,
"processed_at": "2026-03-25T14:02:10Z"
}グレーダーの内部推論は非公開です。動いていることは分かっても、何を考えているかは分かりません。進捗インジケーターを出したいUIなら、このイベントの受信をトリガーにできます。一方で、イベントの中身から採点の途中経過を読み取ることはできません。
ハートビートなので、評価が長引けば複数回届き得ます。1周に1回だけ来る前提で数えないでください。
end — 評価サイクルの結果で次の動きが決まる
span.outcome_evaluation_endは、グレーダーが1周分の評価を終えたとき、またはアウトカムが有効な間にセッションが割り込まれたときに発火します。resultの値が次に起きることを決めます。
| result | 次に起きること | 監視側の対応 |
|---|---|---|
satisfied | 次に起きることセッションがidleへ遷移 | 監視側の対応成果物の取得に進む |
needs_revision | 次に起きることエージェントが新しい反復を開始 | 監視側の対応待機を続ける |
max_iterations_reached | 次に起きること最終の確認ターンのあとidleへ。以降の評価は走らない | 監視側の対応未達成のまま終了。成果物とexplanationを人が見る |
failed | 次に起きることidleへ遷移 | 監視側の対応ルーブリックが成果物に当てはまっていない。descriptionとの矛盾が一例 |
interrupted | 次に起きること割り込み時に発火。評価の開始前ならoutcome_evaluation_start_idは空文字 | 監視側の対応新しいアウトカムを定義できる |
リファレンスでは、needs_revisionだけが「次の周が続く」結果で、残る4つは終端として扱われています。待機を続けるか手を打つかは、この区別で分岐できます。
{
"type": "span.outcome_evaluation_end",
"id": "sevt_01jkl...",
"outcome_evaluation_start_id": "sevt_01def...",
"outcome_id": "outc_01a...",
"result": "satisfied",
"explanation": "All 12 criteria met: revenue projections use 5 years of historical data, WACC assumptions are stated, sensitivity table is included...",
"iteration": 0,
"usage": {
"input_tokens": 2400,
"output_tokens": 350,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 1800
},
"processed_at": "2026-03-25T14:03:00Z"
}explanationには、どの基準を満たしどの基準を満たさなかったかが書かれます。needs_revisionのとき、この説明の内容が次の反復でエージェントに戻ります。usageにはトークン数が入るので、iterationごとに集計すれば、反復の多いセッションのコストを後から見積もる目安になります。
割り込みで止める
user.interruptを送ると、現在のアウトカムへの作業が止まり、span.outcome_evaluation_endのresultがinterruptedになります。続けて新しいuser.define_outcomeを送れるので、方針が違っていたアウトカムを途中で差し替えるときの経路です。
イベントが流れる順序と、評価ループの中身
ストリームではagent.*とspan.outcome_evaluation_*が交互に並びます。1周は次の流れで進み、needs_revisionなら先頭へ戻ります。
評価ループの1周
- 1
エージェントが作業する
agent.*イベントで成果物づくりが流れます。 - 2
start が出る
iterationは初回が0です。 - 3
ongoing が出続ける
グレーダーが動いている間、ハートビートが届きます。
- 4
end が出る
resultがneeds_revisionなら、explanationを受けたエージェントが1へ戻ります。satisfiedならセッションがidleになります。
span.outcome_evaluation_*だけを取り出す監視コードは、タイプの接頭辞で絞れます。
jq -r 'select(.type | startswith("span.outcome_evaluation_")) | "\(.type) iteration=\(.iteration // "-")"'エージェントの動きと採点の経過を1本のタイムラインに描きたいときは、processed_atでソートします。
ストリームかポーリングか
イベントストリームを常時開けない構成では、GET /v1/sessions/{session_id}でoutcome_evaluations[].resultを読む方法があります。評価が終わるまではpending・running・evaluatingのいずれかが返ります。
session=$(curl -fsSL "https://api.anthropic.com/v1/sessions/$session_id" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01")
jq -r '.outcome_evaluations[] | "\(.outcome_id): \(.result)"' <<<"$session"
# outc_01a...: satisfied画面にリアルタイムの進捗を出すならストリーム、バッチで結果だけ回収するならポーリングが向きます。ポーリングで読む例はresultだけで、ongoingは届かない点に注意してください。
Webhookで監視する場合は、イベントの粒度が違う
Webhookでも評価の終了は追えます。ただしストリームの3種類が丸ごと届くわけではありません。
ストリームとWebhookの違い
ストリーム
start・ongoing・endの3種類が届き、endにはresultとexplanationとusageが載ります。セッションの待機状態はsession.status_idleです。
Webhook
評価に関するイベントはsession.outcome_evaluation_endedだけで、1周分の評価が終わるたびに届きます。セッションの待機状態はsession.status_idledで、名前が違います。
WebhookのイベントはtypeとIDだけを運び、中身は受け取ったあとに自分でGETして取ります。つまりresultやexplanationはペイロードに入っておらず、受信後にセッションを取得してoutcome_evaluationsを読む作りになります。
配信の性質も、評価の追跡に効きます。
- 順序が保証されない:
session.status_idledがsession.outcome_evaluation_endedより先に届くことがあります。到着順でなく、取得したセッションの状態で判断します - 重複する: 同じイベントが複数回届き得て、
event.idが同じなら再送です。重複排除に使えます - 欠落し得る: 配信は最大3回までの試行で、すべて失敗するとイベントは破棄されます。通知もありません。取りこぼしが困る用途では、定期的にセッションを取得して照合します
- 遡れない: 購読していない間に出たイベントは、あとから購読しても配信されません。評価を始める前に購読を済ませます
監査ログや完了通知のように、あとから参照できれば足りる用途ならWebhook、途中経過の描画が要るならストリームという分担になります。
成果物の取得 — Files APIからscope_idで絞り込む
エージェントはサンドボックス内の/mnt/session/outputs/に出力ファイルを書きます。取得するには、Files APIをセッションIDのscope_idで絞ってリスト化し、IDでダウンロードします。
# このセッションが生成したファイルを一覧取得
files=$(curl -fsSL "https://api.anthropic.com/v1/files?scope_id=$session_id" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01")
jq -r '.data[] | "\(.id) \(.filename)"' <<<"$files"
# ファイルをダウンロード
file_id=$(jq -r '.data[0].id // empty' <<<"$files")
if [[ -n $file_id ]]; then
curl -fsSL "https://api.anthropic.com/v1/files/$file_id/content" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-o /tmp/output.txt
fiscope_idで絞るリスト取得にはmanaged-agents-2026-04-01のベータヘッダーが必須です。ファイルは書き込み完了の少し後にリストへ現れ、セッションがidleになってから数秒かかることもあります。期待したファイルが見えないときは、少し待って取り直します。リストに現れた時点で、そのファイルのアップロードは完了しています。
サンドボックスの状態が保たれるのは、作成から30日間です。この期間は活動しても延びず、過ぎると状態は戻せません。長く残したい成果物は、期間内に/mnt/session/outputs/へ書かせて取り出しておきます。
satisfiedの後にセッションをどう使うか
satisfiedでidleになったセッションは、そこで終わりではありません。通常の会話セッションとして続けることも、新しいuser.define_outcomeを送って次のアウトカムへつなげることもできます。前のアウトカムの履歴は残るので、たとえば「さっきのDCFモデルを踏まえて感応度分析シートを足して」という続きの依頼を送れます。
アウトカムは同時に1つしか持てません。次のアウトカムを送るのは、前のアウトカムの終端のspan.outcome_evaluation_endが出たあとです。
反復が続くときに見るもの
needs_revisionが続くセッションでは、iterationごとのusageとexplanationを並べると状況が読めます。反復のたびにトークンが積み上がるのに、explanationの指摘がほぼ同じなら、ルーブリックの基準が成果物に対して合っていない可能性があります。max_iterationsの既定は3回、上限は20回なので、大きめに設定した場合ほど、上限に届く前に自前のしきい値で人に知らせる仕組みが効きます。
ルーブリックの設計とは別の話
ここで扱ったのは、評価が走っているときに何が起きるかを追う側の話です。何を基準に採点させるかはManaged AgentsのRubricでアウトカムを定義する方法が扱っています。アウトカム以外のメッセージやツール呼び出しをリアルタイムに追う手順は、Managed Agentsのセッションイベントストリームを実装するにあります。
セッション・ハーネス・サンドボックスの分離という基盤の設計は、Agent SDKのManaged Agentsの設計思想で解説しています。
まとめ
監視コードに入れる分岐は、endのresultがneeds_revisionか終端かの区別と、終端ごとの扱いです。Webhookだけで運用するなら、イベント名と中身の取り方がストリームと違い、順序も保証されないので、通知を受けたらセッションを取得し直す作りにします。