TT Lab
はじめる
学ぶ 学習パス コース

AIエージェント — モデルではなくグラフ

点数は同じなのに、外れている案件が違った

TT Labで続きを見る

一言でいうと

エージェントを直したあと、スコア1つで良くなったかを判断してはいけません。スコアが同じでも、中で1つが直って1つが壊れていたなら、それは良くなったのではなく、変わったのです。

なぜ必要なのか

問い合わせの分類ルールに「返品」を加えました。それまで「返品したいです」がその他に落ちていたのを、返金として捉えさせるためでした。ゴールデンセットで測ると、正解率はそのままでした。83パーセントから83パーセント。

「そのままなら、少なくとも悪くはなっていない」と考えて、リリースしました。2日後、「配送料は返金されますか」という問い合わせが、すべて配送チームに行っていました。

ルールを直すときに、検査の順序も変えたので、1つが直って1つが壊れました。6件のうち5件が合っているのは同じなのに、合っている5件が違いました。

スコアは、その事実を隠します。スコアは個数で、私たちが知る必要があったのは、名前でした。

どう動くのか

評価を正しく行うには、3つを分けて見る必要があります。

3つとも、同じ実行で測れます。ノードを1枚包めば済みます。

def instrument(name, fn):
    def wrapped(state):
        started = time.perf_counter()
        update = fn(state)
        row = PROFILE.setdefault(name, {"calls": 0, "written": 0, "ms": 0.0})
        row["calls"] += 1
        row["written"] += len(update or {})
        row["ms"] += (time.perf_counter() - started) * 1000.0
        return update
    return wrapped

ここで重要な選択が1つあります。時間も測っておきますが、判定には使いません。同じコード・同じ入力でも、時間はマシンとそのときの負荷によって変わります。「遅くなった」を時間で判定すると、リグレッション検査がぶれ、ぶれる検査は、やがてオフにされます。判定には回数とサイズを使います。時間は、人が覗き込むときの手がかりとして使います。

ゴールデンセットは小さくてよい。ただし変わってはいけない

ゴールデンセットは、「手で正解を付けた入力のまとまり」です。6件でも役に立ちます。条件は、毎回同じものを測ることです。

そのため、ゴールデンセットはコードやファイルに埋め込んでおき、直すときは、直したという事実そのものを記録します。実行のたびにサンプルを新しく選ぶと、昨日と今日を比べられません。

もう1つ。ゴールデンセットには、間違える件を残しておきます。全部当たるゴールデンセットは、「今うまくいっている」ことしか語らず、何も見つけられません。実際に間違える件が入っていてこそ、直したときに直ったものが見えます。

リグレッションはスコアではなく集合で見る

2つのバージョンを比べるときに見るべきものは、この2つです。

2つが同じ数なら、スコアはそのままです。ところが、この2つの重みは、たいてい同じではありません。すでにうまくいっていたものが壊れるほうが、はるかに痛いです。ユーザーがすでにその動作に頼っているからです。そのため、「新しく壊れたものは0か」を先に尋ね、次に「新しく直ったものはあるか」を尋ねる順序が、実務で安全です。

コストと経路もリグレッションする

品質がそのままでも、コストは増えることがあります。分岐を1つ増やせば、ノードがもう1回動き、そのノードが外部を呼び出すなら、その分お金が出ていきます。そのため、ノードの呼び出し回数もリグレッション指標として残します。時間と違って、この数値は同じ入力でいつも同じです。

経路も同じです。同じラベルが出ても、別の道を通って出たなら、それは別の動作です。今は答えが同じに見えても、次の変更で違う方向に分かれます。足跡(trace)を比べると、これが見えます。

現場での姿

1つ目: スコアだけを記録する。上の事故です。どの件が間違ったかを残さないと、振り返れません。

2つ目: ゴールデンセットが実行のたびに変わる。ランダムなサンプルで測ると、数値が毎回違って、リグレッションなのかサンプルのせいなのかを分けられません。

3つ目: 時間でパフォーマンスのリグレッションを判定する。検査がぶれて、ぶれる検査は無視され、結局オフにされます。

4つ目: 観測をあとから付けようとする。ノードを包む場所は、グラフを作るときが最も安いです。あとで付けると、ノードごとに直す必要があり、1か所でも抜けると、そのノードだけが帳簿に残りません。

実務で本当に大切なこと

次のラボですること

/root/work/ageval/evalkit.pyを、1ステップずつ育てます。まず、問い合わせを分類するグラフを作り、ノードを包んで、呼び出し回数と書いたキーの数を帳簿に残します。どのノードが最も忙しいかを取り出し、手で正解を付けたゴールデンセットで、正解率と間違えた件のリストを出します。次に、ルールを直した2つ目のバージョンを作って2つのバージョンを比べ、スコアは同じなのに、どの件が壊れて直ったかを、名前で分けます。最後に、呼び出し回数と経路の変化まで測って、記録に残します。