ある小さなネットショップが、カスタマーサポートを三つの AI モジュールで自動化した。顧客に返信するモジュール、注文の進み具合を整理するモジュール、返金を判断するモジュールだ。ある日、顧客から「商品が壊れていたので返金してほしい」とメールが届く。三つのモジュールが同時に起動した。サポート担当のモジュールは「返金の手配をいたしました」と返信し、進捗担当のモジュールは注文の状態を「処理中」に変えた。返金担当のモジュールは写真が足りないと判断して状態を「書類待ち」に変え、写真を送るよう求めるメールをもう一通送った。顧客は言っていることが正反対の二通のメールを受け取り、注文の状態が最後にどれになるかは、どのモジュールが最後に書き込んだかで決まる。

ここでいう「モジュール」は、ツールによって呼び名が違う。skills、agents、自動化フローなどだ。共通するのは、あるイベントが起きると、作業の一部を自動で引き受けることである。

こうした衝突にぶつかると、多くのチームがまず思いつくのは、誰の結果を優先するかを決める仲裁ルールを足すことだ。より効くのは設計に戻ることである。一つの事柄に入口は一つ、変更される項目ごとに書き込めるモジュールは一つだけにし、ほかのモジュールは提案しかできないようにする。

仲裁の規則が増え続けるわけ

仲裁ルールはもっともらしく見える。返金モジュールの判断がサポートモジュールより優先し、進捗モジュールは最後に書き込む。だがルールが増えるほど、ルール同士の例外を扱わなければならなくなる。返金モジュールの処理が終わっていなければ、サポートモジュールは待つべきか。二つのモジュールがほぼ同時に書き込んだら、どちらを先とみなすか。新しいルールの一つひとつが、本来起きるはずのなかった競争の後始末をしている。

さらによくあるのは「最後に書いたものが勝つ」というやり方だ。設計がまったく要らないからである。問題は、最後に書き込んだものが正しいとは限らないことだ。たまたま遅かっただけかもしれない。

衝突は二つの場所から生まれる

一つ目は重複した起動だ。 同じ事柄が複数の入口から入ってくる。顧客のメールで一度、サポートシステムがチケットを作ったことでもう一度、5 分ごとに未処理の案件を探す定期処理でさらにもう一度起動される。三つの入口は名前が違うが、扱っているのは同じ事柄だ。「モジュール同士のけんか」の多くは、実は同じモジュールが三回呼ばれているだけである。

二つ目は書き込む者が複数いることだ。 注文の状態という項目を、三つのモジュールすべてが変更できる。同じ項目に二つ以上のモジュールが書き込めるなら、衝突は時間の問題でしかない。

どちらも設計から生まれていて、モデルの賢さとは関係がない。Microsoft は複数 agent の連携パターンをまとめたアーキテクチャガイドで、共有の状態や外部システムへの変更を確実に調整できないなら、複数の agent を同じ作業に同時に走らせるべきではないと注意している。単一の agent とツールの組み合わせで確実にこなせるなら、まずはその単純なやり方を選ぶよう勧めてもいる。Anthropic も agent の作り方を説明した記事で、似た助言をしている。できるだけ単純な解決策を探し、結果が確かによくなるときにだけ複雑さを足す、というものだ。

広告

入口は一つ、書き込む者も一つ

だから衝突は根本から直す。順番はこうだ。

まず、一つの事柄に入口を一つだけにする。 モジュールを起動するきっかけをすべて書き出し、名前は違っても同じ事柄を扱っているものを見つけて一つにまとめる。同じイベントがもう一度送られてきたとき、システムがそれを見分けられなければならない。決済システムではこれは確立したやり方だ。Stripe はリクエストごとに一意の識別子(idempotency key、べき等キー)を付けられるようにしていて、同じリクエストが再送されると、処理をもう一度行うのではなく、最初の結果を返す。AI モジュールのイベントも同じようにできる。イベントごとに番号を付け、同じ番号は一度しか処理しない。

次に、項目ごとに書き込む者を一つにする。 変更される項目を書き出し、間違えたときの影響が大きいものに印を付ける。注文の状態、返金額、顧客に送るメールなどだ。そうした項目ごとに、書き込めるモジュールを一つだけ残す。ほかのモジュールは読んだり提案したりはできるが、直接は変更できない。

最後に、競争をリレーに変える。 ネットショップの例に戻ると、返金モジュールを主モジュールにし、判断して注文の状態を書き込み、メールを送るかどうかも決めさせる。サポートモジュールと進捗モジュールは、見えた情報を返金モジュールに渡すだけにする。顧客に届くメールは一通になり、注文の状態の出どころも一つになる。

仲裁にも役割はあるが、例外にだけ使う

当面どうしても切り分けられない場面はある。古いシステムが変更しにくい、あるいは二つの部署が同じ項目の別の部分をそれぞれ担当している、といった場合だ。そこでは仲裁がまだ必要だが、例外として扱う。優先順位をはっきり書き、判断できないときは止めて人に渡し、仲裁を使うたびに記録を残す。仲裁が使われた回数こそ、設計がまだ直っていない場所を示している。

このやり方にもコストがある。書き込む者を一つにするということは、主モジュールがつまずいたとき、ほかのモジュールが自動で補えないということだ。だから主モジュールの失敗は検知でき、人に回せるようにしておく。ほかのモジュールに慌てて肩代わりさせてはいけない。

次の一歩として、いちばんよく問題を起こすイベントを一つ選び、二つ問うてみてほしい。このイベントはいくつの入口から入ってくるか。変更する項目ごとに、書き込めるモジュールはいくつあるか。答えがどちらも「一つ」なら、そのイベントに仲裁はほとんど要らない。AI モジュールを外部から導入しているなら、導入前に確かめるべき層がもう一つある。AI agent の拡張機能はスキャンを通っても入れてはいけない。危険は動き出した後に現れるも参考になる。処理が途中で失敗したときの後始末については、自動化が途中で止まったら、やり直す前に何がもう起きたかを確かめるを参考にしてほしい。

AI 整理カード

イベントの入口と書き込む者を AI と洗い出す このプロンプトは、どのイベントが複数のモジュールを起動させるかを確認し、入口と項目ごとの書き込む者を書き出したうえで、一つの主モジュールが書き込む形への切り替え方を提案する。

私の自動化フローでは、あるイベントが複数の AI モジュール(skills、agents、自動化フローなど)を同時に起動させ、よく衝突が起きる。
判断方法はこの記事による:https://boosterminiclass.com/ja/posts/ai-agent-skill-conflict-prevention/
記事の見方はこうだ。衝突は主に二つの場所から生まれる。同じ事柄が複数の入口から入ってくること、そして同じ項目に複数のモジュールが書き込めることだ。直し方は、一つの事柄に入口を一つ、重要な項目ごとに書き込む者を一つにし、ほかのモジュールは提案だけにすること。仲裁は切り分けられない例外にだけ残す。

まず私に 3 つ質問してほしい:
1. それはどのイベントで、どのモジュールを起動させ、それぞれ何をするか;
2. そのイベントはどこから入ってくるか(メールの受信、チケットの作成、定期スキャンなど)。同じ事柄が複数回起動されることはあるか;
3. これらのモジュールはどの項目や外部への動作(注文の状態、金額、メール送信など)を変更するか。それぞれ、いま何個のモジュールが直接書き込めるか。

私の回答をもとに、次を出力してほしい:
- 入口の一覧:実は同じ事柄を扱っている入口はどれか、どうまとめるか、重複したイベントをどう見分けるか;
- 書き込む者の一覧:重要な項目ごとのいまの書き込む者と、残すべき一つの書き込む者;
- リレー型にした後の流れ:主モジュールはどれか、ほかのモジュールは何を渡すか;
- それでも切り分けられず、仲裁や人の判断が必要な例外。
私が触れていない機能がシステムにあると仮定しないこと。情報が足りなければ、まず私に質問してほしい。

提案は出発点にすぎない。どのモジュールを書き込む者にするかは、そのフローに責任を持つ人が決める。

広告

Share

このミニクラスを共有

このミニクラスが仕事の詰まりをほどく助けになったら、AI の使い方を考えている人にも共有してください。

参考資料