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

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

正解率はそのままで、別の案件が壊れる

TT Labで続きを見る

目標

ノードを包んで、どこで何をしたかを帳簿に残し、ゴールデンセットで正解率と間違えた件のリストを出します。ルールを直した2つ目のバージョンと比べて、新しく壊れたものと新しく直ったものを名前で分け、コストと経路の変化まで測ります。

なぜ重要なのか

エージェントを直したあとに、「良くなったか」をスコア1つで尋ねることがよくあります。ところが、スコアが同じでも、中で1つが直って1つが壊れていたなら、それは良くなったのではなく、変わったのです。スコアは個数で、私たちが知る必要があるのは、名前です。 観測は、ノードを1枚包めば済みます。このとき、重要な選択が1つあります。時間も測っておきますが、判定には使いません。同じコード・同じ入力でも、時間はマシンと負荷によって変わり、時間で判定するリグレッション検査は、ぶれて、結局オフにされます。判定には、回数とサイズを使います。 ゴールデンセットは小さくてよいですが、毎回同じものである必要があります。そして、今間違える件を残しておいてこそ、直したときに直ったものが見えます。全部当たるゴールデンセットは、何も見つけられません。 品質がそのままでも、コストと経路はリグレッションすることがあります。ノードの呼び出し回数は、同じ入力でいつも同じ値なので、リグレッション指標として使え、足跡が変わったなら、答えが同じに見えても別の動作です。 採点ツールは、書かれた説明を信用しません。書かれたモジュールを実際に読み込んで、任意の問い合わせで動かしてみて、ゴールデンセットの判定と2つのバージョンの差を、採点ツールが別に計算した値と突き合わせます。

ステップ

  1. /root/work/ageval/evalkit.pyにLABELS・ANSWER・classify_v1・State・5つのノード(normalize・refund・shipping・other・finish)・ROUTE・build_graph(version="v1")・run_one(text, version="v1")を作成してください。
  2. PROFILE・reset_profile()・instrument(name, fn)を追加して、build_graphがすべてのノードを包んで追加するようにしてください。
  3. hotspots(texts, version="v1")を追加して、ノードごとの呼び出し回数と、最も忙しいノードを出すようにしてください。
  4. GOLDENとevaluate(version="v1")を追加して、正解率と間違えた件のリストを出すようにしてください。
  5. classify_v2とcompare(old="v1", new="v2")を追加して、新しく壊れた件と新しく直った件を分けるようにしてください。
  6. cost_delta(old="v1", new="v2")を追加して、ノードの呼び出し回数の変化を測るようにしてください。
  7. path_changes(old="v1", new="v2")を追加して、足跡が変わった件を探すようにしてください。
  8. 測ったことを記録してください(保存先: /root/work/ageval/eval_report.json、/root/work/ageval/eval_report.md)。

参考

問い合わせをブランチに送る

/root/work/ageval/evalkit.pyにLABELS・ANSWER・classify_v1・State・5つのノード・ROUTE・build_graph(version="v1")・run_one(text, version="v1")を作成してください。

normalizeが作ったcleanを見て分類します。条件関数はラベルを返し、ROUTEがどのノードへ行くかを決めます。ラベル名とノード名を同じにしないのは、パスマップの役割をはっきり見せるためです。version引数は、今は"v1"だけを受け付けます。

ノードを包んで帳簿を残す

PROFILE・reset_profile()・instrument(name, fn)を追加して、build_graphが5つのノードをすべて包んで追加するようにしてください。帳簿にはcalls・written・msを残します。

包む関数は、元のノードを呼び出して、その結果をそのまま返しながら、横に数値を書きます。writtenは、そのノードが返したディクショナリのキーの数です。時間も一緒に測っておきますが、判定には使わないことをコメントとして書いておいてください。なぜそうなのかが、このステップの核心です。

どのノードが最も忙しいか

hotspots(texts, version="v1")を追加して、{"calls": {...}, "total_calls": 정수, "busiest": 문자열, "timed": [...]}(プレースホルダーは整数と文字列です)を出すようにしてください。呼び出すたびに、帳簿を新しく広げます。

帳簿を空にしないと、前の実行の数値が混ざって、何を測っているのかわからなくなります。busiestは、呼び出し回数が最も多いノードで、同点なら名前の昇順で分けて、毎回同じ答えが出るようにしてください。timedは、時間が記録されたノードの名前のリストです。

手で正解を付けた6件

GOLDENの6組とevaluate(version="v1")を追加して、{"total", "correct", "accuracy", "wrong"}を出すようにしてください。wrongにはtext・gold・gotを入れます。

ゴールデンセットは小さくてよいですが、毎回同じものである必要があります。そして、今間違える件を残しておいてこそ、直したときに直ったものが見えます。全部当たるゴールデンセットは、何も見つけられません。正解率だけを出さず、間違えた件の名前も一緒に出してください。

スコアは同じなのに、別の件が間違う

classify_v2とcompare(old="v1", new="v2")を追加してください。答えは{"old_accuracy", "new_accuracy", "newly_broken", "newly_fixed"}で、2つのリストはソートします。

classify_v2は、"반품"(韓国語で「返品」を意味する語です)を返金として見るようにしつつ、検査の順序を変えたバージョンです。2つのバージョンの正解率を先に測って、その数値だけで判断できるかを問いかけてください。旧バージョンで合っていたものが新バージョンで間違う件と、その反対を、それぞれ集めると、スコアが隠していたものが見えます。

品質が同じでもコストは変わる

cost_delta(old="v1", new="v2")を追加して、{"old_calls", "new_calls", "delta"}を出すようにしてください。ゴールデンセット全体を1回ずつ動かしたあとのノードの呼び出し回数です。

呼び出し回数は、同じ入力でいつも同じ値なので、リグレッション指標として使えます。時間と違う点が、それです。前のステップで作ったhotspotsをそのまま使えば済みます。このグラフでは、どのブランチへ行ってもノード数が同じですが、それならdeltaが何を語っているのかも、考えてみてください。

同じ答えが別の道で出た

path_changes(old="v1", new="v2")を追加して、足跡が変わった件だけを、[{"text", "old", "new"}, ...]としてtextの昇順で出すようにしてください。

ラベルが同じでも、通ってきたノードが違えば、別の動作です。今は答えが同じに見えても、次の変更で違う方向に分かれます。足跡が同じ件は入れないでください。リストが短いと、人が見ます。

何を出すかを判断する

/root/work/ageval/eval_report.jsonにold_accuracy・new_accuracy・newly_broken・newly_fixed・cost・path_changes・busiest・total_callsを、/root/work/ageval/eval_report.mdに## 어디서 무엇을 했는지 어떻게 기록했나 ## 점수만 보면 놓치는 것 ## 비용과 경로도 회귀한다 ## 다음에 무엇을 하겠는가の4つの節を書いてください(4つの見出しは、順に韓国語で「どこで何をしたかをどう記録したか」「スコアだけを見ると見逃すもの」「コストと経路もリグレッションする」「次に何をするか」を意味します)。

costはcost_deltaの答えをそのまま、path_changesは、変わった件の個数です。busiest・total_callsは、ゴールデンセット全体をv1で動かしたときの値です。4番目の節には、この結果を見てどちらのバージョンを出すかについての、自分の判断を書いてください。正解は1つではありません。