AI エージェントに作業を委譲して自律的に実行させる仕組みを組む際、多くの開発者が警戒するのは、エージェントが作業を終えていないにもかかわらず「完了しました」と嘘をつく 「完了の偽陽性(False Positive)」 です。当社でも 先行記事1 において、エージェントの自己申告を信じず、Diff やコミットハッシュといった客観的証跡を義務付ける検証ルールの重要性を論じてきました。

しかし、実務でマルチエージェントや非同期タスク委譲パイプラインを運用していると、偽陽性とは真逆のトラブルに直面します。それが、バックグラウンドのエージェントが正常に作業を終えているにもかかわらず、状態監視スクリプトが「未着手」や「失敗」と判定してしまう 「完了の偽陰性(False Negative)」 です。

完了の偽陰性(False Negative)とは、バックグラウンドのエージェントが作業を正常に完了させているにもかかわらず、中継ツールや状態監視機構の判定によって「未着手」や「失敗」と誤認されてしまう現象を指します。

ある日、当社の開発環境において、タスクを別端末(Git worktree)に非同期委譲した際、委譲スクリプトが started=no(未着手)を出力しました。親エージェントは「出力が started=no だったため、作業は始まっていません」と報告しましたが、実際にはその裏で委譲先エージェントが着実に作業を進めており、約 6 分後には Git コミットを作成してタスクを完遂していました。

中継ツールが返す終了ステータスやフラグは、システムの「事実」そのものではなく、ある断面を切り取った「中間観測値」に過ぎません。以下では、現場で起きた偽陰性インシデントの具体的な経過をもとに、なぜ完了の偽陰性が生じるのか、判定の 3 値化(yes/timeout/no)と報告前の「実物確認 1 手」をどう設計すべきか、そして他者やツールの報告を鵜呑みにしない現場規律を解説します。

なぜ状態取得ツールの出力は「事実」ではなく「中間観測値」なのか

プロセス起動ラッパーや状態監視ツールが観測できるのは、あくまで「プロセスの立ち上げ直後」や「特定ポーリング時点」という局所的な断面です。

今回の委譲スクリプトは、待ち時間(改修前は 60 秒)のあいだタスク管理側に委譲先の start が記録されるかを見て、見えなければ一律に started=no(未着手)を返す作りでした。エージェントの起動が遅れれば、作業が始まる前に締め切られます。後述の改修は、setup 待ちによるエージェント起動遅延に対応するものです。しかし、タイムアウトを迎えたからといって、バックグラウンドの端末プロセスまで停止しているとは限りません。プロセス自体は独立して生存し、初期化が完了した直後から委譲されたタスクを自律的に開始・完遂することがあります。

その結果、監視ツール上のステータス(未着手)と作業ディレクトリの実態(作業完了)の間に深刻な乖離(State Drift)が生じます。

タスク管理ツール Taskwarrior のライフサイクル仕様2 にあるとおり、タスクは pending の状態で作られ、開始されると start 属性が付いて active と呼ばれ、完了すると completed の状態になって end 属性が付与されます。プロセス起動ラッパーが返す「起動したかどうか」という一時的なフラグと、実際のタスク状態遷移は、別々の観測対象です。

この問題は、とんのかつ氏が論じている「エージェントの自己改善ループで偽の成功を防ぐ設計」3 とも深く響き合います。同氏は、ループを安全に回す原則の 1 つに「検証の成功を呼び出し元に自己申告させない」を挙げています。また、テストのタイムアウトをそのまま製品の不具合と分類せず、テストハーネスの実行モデル(起動のばらつき)も観測対象に含める必要があると述べています。監視ツールが返す表層的な文字列を事実と同一視してしまうと、観測器側のタイムアウトをタスク側の失敗と履き違える構造的欠陥が生まれます。

完了判定における偽陽性と偽陰性は、以下のように対称的な構造を持っています。

観点完了の偽陽性(False Positive)完了の偽陰性(False Negative)
ツールの判定「完了」と誤認・誤報告「未着手・失敗」と誤認・誤報告
実際の作業状態作業は未実施(未保存・放置)実際には作業完了(コミット済み)
主な発生要因LLM の次トークン予測、思考の完了と実行完了の同質化起動遅延、タイムアウト、中間フラグ誤認
現場でのリスク未実施の素通り、成果物の不整合作業の二重着手、成果物の巻き戻し・上書き破棄
対策の核不変の証跡(Diff やコミット)の義務付け1報告前の実物(Git log やタスク状態)確認

どちらの失敗も、エージェントやツールの表層テキストを鵜呑みにせず、客観的成果物(実物)で検証することで防げます。

現場で起きた偽陰性インシデントと、2 つの改善実装

実際に現場で発生した偽陰性インシデントの経過を振り返ります。

2026 年 10 月 2 日 01:23:35 UTC、親エージェントは未コミット変更の整理タスクを dispatch スクリプトを用いて別端末(Git worktree)へ委譲しました。 スクリプトの出力は started=no で、そのときの端末プレビューはプロンプト欄が空(❯)のままでした。これを受けた親エージェントは、「出力は started=no で、作業はまだ始まっていません」と報告しました。

しかしその裏で、委譲先エージェントは作業を進めており、01:29:36 UTC(約 6 分後)には worktree 側でコミットを作成し、タスク完了処理を実行していました。 親エージェントが約 11 分後(01:34:28 UTC)にタスク管理コマンドを実行して初めて、裏でタスクが完了していた事実が発覚しました。

このインシデントを受け、当社では直ちに 2 つの改善実装を行いました。

改善実装 1: 判定の 3 値化(yes/timeout/no)と待ち時間の延長

第 1 の改善は、スクリプトにおける判定ロジックの改修です。従来の 2 値判定(yes/no)を改め、端末プロセスの生存状況を組み合わせた 3 値判定(yes / timeout / no)を導入しました。あわせて、エージェント起動時の初期化遅延を許容するため、既定の待機時間を 60 秒から 180 秒へと延長しました。

以下は、改修されたディスパッチスクリプトの状態判定ロジックです。

# ファイル: skills/dispatch/scripts/dispatch.py
def started_state(started, term):
    if started:
        return "yes"
    return "timeout" if term.get("connected") else "no"

この関数により、タスクの開始が確認できれば yes を返し、制限時間内に開始が確認できなかった場合は、端末プロセスが接続中(生存)であれば timeout、消失していれば no を返します。「バックグラウンドで起動処理が続いている状態」と「起動そのものに失敗した状態」が機械的に切り分けられるようになりました。

改善実装 2: 報告前の「実物確認 1 手」の明文化

第 2 の改善は、エージェントが人間に報告を行う前に、客観的な成果物の実物を 1 手確認する運用規律の策定です。

ツールの運用ガイドラインに以下の規則を明文化しました。

started は着手の有無の証拠ではない(no でも委譲先が完了まで終えていた事例や、timeout は start が一度も打たれていなかった事例が存在する)。 「着手されなかった」やその原因を報告・記録に書く前に、タスク管理の Start 履歴・status・end と、Git の git log を確かめること。

引用中の no の事例は、3 値化より前の 2 値判定で起きた今回のインシデントを指します。

確認に用いるのは、以下の標準的な CLI コマンドです。

# タスク管理ツールから構造化された完了状態を取得(完了時は "completed" が返る)
task <uuid> export | jq '.[0].status'

# 作業ツリー側の直近コミットを確認
git log -1 --oneline

Taskwarrior の task <uuid> info コマンドはタスクのメタデータや status を人間可読形式で表示し4、task export は JSON 形式で機械判定可能な status を出力します5。さらに git log -1 --oneline を実行することで、直近のコミットハッシュとメッセージを即座に確認できます6。

報告前にこの 1 手を挟むだけで、中間フラグの誤認による誤報を水際で防げます。

他者の報告文は「事実の主張」と「原因の説明」に分ける

この偽陰性インシデントでは、誤認報告に続く「二次被害」も発生していました。

委譲スクリプトが started=no を返して停止した際、人間のシステムオーナーは「新しく切った worktree からは、未コミットの変更が見えなかったために作業できなかったのだろう」と推測を口にしました。 親エージェントは、worktree の実ファイルやログを検証することなくその推測を鵜呑みにし、社内台帳に「事前チェック漏れにより作業不能だった」と原因を記録してしまいました。

実際には作業が完了していたため、台帳に記録された原因説明は実態と完全に食い違っていました。

この失敗を契機として、当社では 「他者の報告文は『事実の主張』と『原因の説明』に分ける」 という原則を策定しました。

  1. 事実の主張: 「コミットが存在する」「ファイルが更新されている」といった客観的な状態。これらは git show や ls、ステータス確認コマンドなどの実物で検証する。
  2. 原因の説明: 「なぜそうなったのか」「なぜ失敗したのか」という推測や解釈。これらは一次資料による裏付けや実測が取れるまで、公式な記録や報告本文には含めない。

この原則の根底にあるのは、「予防は原因の空間、検収は結果の空間に対して設計する」という設計思想です。

エージェントがなぜ失敗したのかという「原因の推測」は無限に広がります。「ネットワークが瞬断したのかもしれない」「コンテキスト長を超過したのかもしれない」「プロンプトの解釈がずれたのかもしれない」と原因空間に対して場当たり的な予防策を積み増していくと、システムは際限なく複雑化します。 そうではなく、私たちが最終的に得たい結果(Git コミットやタスクの正常終了)に対して、客観的な成果物の状態を 1 手で「検収」するアプローチをとるべきです。前述の待ち時間の延長は、起動遅延という原因側への予防にあたります。予防は想定した原因しか塞げないので、改善実装 2 の実物確認で結果側から閉じています。

あなたのエージェントパイプラインに組み込む実物確認ルール

以上の教訓は 1 件のインシデントから得たものですが、委譲先の成果物が Git やタスク管理に残る仕組みであれば、スクリプトでも CI/CD パイプラインでも同じ形で組み込めます。

委譲先のエージェントが「エラー」や「未着手」を返した際、即座にパイプラインを落としたりリトライを走らせたりする前に、以下の「実物確認ガードレール」を挟むことを推奨します。

  1. 作業ツリーの未コミット変更・未追跡ファイルを機械検知する: スクリプト内で git status --porcelain を実行します。--porcelain オプションを指定することで、スクリプト解析に適した安定したフォーマットで作業ツリーとインデックスの状態が出力されます7。これにより、エージェントがコミット直前で停止したのか、作業をまったく行わずに終了したのかを機械的に判定できます。
  2. 直前コミットの整合性を検証する: git log -1 --oneline を実行し、委譲先エージェントが目的のブランチに対して意図したコミットを生成したか確認します6。
  3. タスク管理メタデータを構造化 JSON で照合する: 自然言語の終了メッセージに依存せず、タスク管理システムやオーケストレータの API、または task export などのコマンドを用いて、status や end タイムスタンプを機械照合します5。

中継ツールの終了コードだけをトリガーにしてエラーハンドリングを行うのではなく、成果物ベースの決定論的な検証ステップを 1 行挟むだけで、偽陰性による不要な再作業や二重実行の手戻りを防げます。

メリットの裏にあるトレードオフと適用限界

実物確認ルールの導入には多くのメリットがありますが、運用上のトレードオフと適用限界も把握しておく必要があります。

想定される反論への検討

反論 1: 毎回コマンドを叩いて実物を見るのは、完全自律エージェントの自動化メリットを損なうのではないか?

検討: 確認は git log -1 や task export といった単発のコマンドで済みます。一方で、完了の偽陰性を放置すれば、同じタスクを別のエージェントが二重実行して既存のコミットを上書きしたり、人間が調査に入ったりする手戻りが生じます。今回のインシデントでも、完了の発覚までに約 11 分かかりました。読み取りだけで副作用のない確認だからこそ、報告直前に毎回挟めます。

反論 2: タイムアウトを 180 秒に延ばすと、本当にクラッシュしたプロセスの検知が遅れるのではないか?

検討: 遅れます。改修後のスクリプトは 180 秒待ってから端末プロセスの生存を確認するので、no が返るのも待ち時間が切れた後です。3 値化が解消したのは検知の遅れではなく、プロセスが接続中なら timeout(起動遅延の可能性)、消失していれば no と判定を分け、「起動遅延」と「プロセス死」を同じ no にまとめないことです。

適用限界

この実物確認手法が有効に機能するのは、成果物が Git リポジトリやファイルシステム、構造化タスク管理データベースといった「客観的かつ不変な状態」として永続化される処理に限られます。 インメモリキャッシュの一時的更新や、外部 SaaS に対する冪等性のない API コールなど、永続的なファイルやコミットが残らない揮発的なタスクにおいては、本手法を直接適用することはできません。そのような領域では、独立した分散トレーシングや冪等なトランザクションログの設計が必要となります。

もう 1 つの限界は、確認の時点です。今回の委譲先がコミットしたのは started=no の約 6 分後でした。判定の直後に確認しても、まだ何も出ない可能性があります。何も出なかったことは「まだ成果物が無い」ことしか意味せず、「未着手」の証拠にはなりません。timeout が返ったときは時間を置いて同じ確認を繰り返し、再委譲するのは委譲先が動いていないと分かってからにします。また git log -1 は直近のコミットを見るだけなので、委譲前からあったコミットと区別するには、委譲時点の HEAD と比べる必要があります。

今後変わり得る前提と将来展望

AI エージェントを統括するオーケストレーションフレームワークは急速に進化しています。

例えば CrewAI では、Task 定義において guardrail パラメータを指定することで、エージェントが出力したタスク結果を関数によって厳密にバリデーションする機構が整備されています8。また LangGraph では、Functional API と checkpointer(MemorySaver など)の組み合わせにより、ワークフローの結果や完了したタスクの結果がチェックポイントとして永続化されます9。

フレームワーク自体の Guardrail や永続化機構が成熟すれば、独自スクリプトによる泥臭いポーリング監視や状態取得の機会は減少していくかもしれません。

しかし、どれほど高度なフレームワークを採用したとしても、「中継ツールやオーケストレータが観測した状態フラグ」と「実行環境(OS・ファイルシステム・外部サービス)における実際の副作用」の境界が消えることはありません。分散システムにおける観測値の不確実性と向き合う限り、「表層のステータスフラグを見るな、成果物の実物を見よ」という原則は、技術の前提が変わっても色褪せない設計の基礎であり続けます。

よくある質問(FAQ)

Q. 委譲したエージェントが「未着手」や「エラー」と判定された場合、まず何をすべきですか?

A. ツールの終了ステータスを鵜呑みにせず、まず作業空間の Git log(git log -1)やタスク管理の終了履歴(task <uuid> export)などの実物を確認してください。バックグラウンドで委譲先が作業を完遂している「完了の偽陰性」が発生している可能性があります。

Q. 完了の「偽陽性」と「偽陰性」では、対策にどのような違いがありますか?

A. 偽陽性(やっていないのに完了)には「完了報告にコミットハッシュや Diff などの不変の証跡を義務付ける」対策が有効です。一方、偽陰性(やったのに未着手)には「未着手・エラー判定時に成果物の実物を 1 手確認するガードレール」が有効です。どちらもエージェントの自己申告や中間フラグではなく、決定論的な客観的成果物で判定する点が共通しています。

まとめ

エージェント委譲で押さえる要点は、次の 4 点です。

  1. 状態取得ツールの出力は「事実」ではなく「中間観測値」に過ぎない: 起動ラッパーのタイムアウトはプロセスの失敗を意味しない。
  2. 完了判定には「偽陽性」と「偽陰性」の対称的な失敗が存在する: 未実施の完了誤認だけでなく、完了済みの未着手誤認による二重実行リスクにも備える。
  3. 報告や記録を行う前に、Git log やタスク状態などの実物を 1 手で確認する: 判定の 3 値化(yes/timeout/no)と成果物確認をパイプラインに組み込む。
  4. 他者やツールの報告文は「事実の主張」と「原因の説明」に分ける: 事実は実物で確かめ、原因の推測は裏取りを経るまで記録しない。

AI エージェントを活用した開発プロセスの標準化や、安全で信頼性の高い自律エージェント運用のプロセス設計・導入について、ぜひ コンタクトフォーム よりお気軽にご相談ください。

Footnotes

  1. 「完了しました」に証跡がないと虚偽報告が紛れ込む — AIエージェントの報告検証ルール Meetsource、2026年8月9日。完了の偽陽性問題と不変の証跡義務付けの対比。 ↩ ↩2

  2. Taskwarrior - Terminology Taskwarrior Project(2026年10月19日閲覧)。pending・completed などの状態と、active(start 属性を持つタスク)・end 属性の定義。 ↩

  3. エージェントの自己改善ループで偽の成功を防ぐ設計 とんのかつ、2026年8月12日。自己申告の禁止、コントローラ生成の証拠、観測器の偽陽性対策、テストハーネスの実行モデルの観測。 ↩

  4. Taskwarrior - Info Command Taskwarrior Project(2026年10月19日閲覧)。task info コマンドによるタスクメタデータ表示、UUID 指定による完了タスク照会仕様。 ↩

  5. Taskwarrior - Export Command Taskwarrior Project(2026年10月19日閲覧)。task export コマンドによる JSON 形式での status 出力仕様。 ↩ ↩2

  6. Git - git-log Documentation Git Project、git-log last updated in 2.56.0(2026年10月19日閲覧)。--oneline, --stat によるコミット履歴確認仕様。 ↩ ↩2

  7. Git - git-status Documentation Git Project、git-status last updated in 2.53.0(2026年10月19日閲覧)。--porcelain オプションによるスクリプト向け安定ステータス出力仕様。 ↩

  8. Tasks - CrewAI Documentation CrewAI、v1.15.23(2026年10月19日閲覧)。Task の expected_output、guardrail による出力検証仕様。 ↩

  9. Use the functional API - Docs by LangChain LangChain(2026年10月19日閲覧)。LangGraph の Functional API、checkpointer による状態永続化仕様。 ↩