この記事は、連載「動かさない技術」の第 3 回です。うまくいかない症状と、その対処を一つずつ並べています。各回はファイルやスクリプトを一つ置けば完結します。その仕組みがなぜ要るのかは、置いたあとに解説を読めば分かります。連載の全体像と各回の一覧は序論にあります。
今回は、複数のサブエージェント(メインの会話から別に起動して作業を任せる AI)にレビューを任せたら、複数のサブエージェントが見つけていた重要な不具合が、メインの会話の AI(この先「メインエージェント」と呼びます。一般の用語ではオーケストレーターです)がまとめた調査結果に入っていなかった、という症状です。答えを 1 つにまとめるときに、多数決は種類を消すことがあります。困るのは、調査結果だけを読んでいると、消えたことに気づく手がかりが無いことです。
まず一つだけ、確かめてみてください。
複数のサブエージェントにレビューを任せ、指摘を 1 つにまとめさせたことがあるなら、まとめる前の、サブエージェントごとの答えを開いてください。
調査結果に載っていない指摘は、いくつありますか。
CC BY 4.0
複数のサブエージェントが見つけた不具合が、調査結果から落ちていました
あなたは、プルリクエストのレビューを、複数のサブエージェントに観点を分けて任せ、メインエージェントに調査結果をまとめさせています。
ある日、重要な不具合が調査結果に入っていなかったことに気づきました。サブエージェントの答えを開くと、複数のサブエージェントがその不具合を見つけていました。あなたなら、次のどちらで対処しますか。
- サブエージェントを増やし、まとめ方は変えない
- まとめる前の答えを残し、種類ごとに何回挙がったかを数える
答えは、まとめる前の答えから数えるほうです。不具合はサブエージェントの答えにはあって、調査結果には無かったので、答えをまとめるときに落ちています。サブエージェントを増やしても、通るのは同じまとめ方です。まとめる前の答えから数えれば、まとめ方を通らずに、いくつのサブエージェントが見つけたかが残ります。
理解したことは一文にできます。
複数のサブエージェントが見つけた重要な不具合でも、答えをまとめるときに落ちることがある。だから、まとめる前の答えを残し、種類ごとに何回挙がったかを数える。
なぜ、複数のサブエージェントが見つけた不具合が消えるのか
落ちたのは答えをまとめるときで、どう落ちるかはまとめ方しだいです。
が測ったのは、挙がった回数の多い項目から 3 件を残すまとめ方です。スクリプトで作った 40 件の指摘(6 種類の欠陥が 6 件か 7 件ずつ)をサブエージェントに渡し、「この 40 件から、先に直すべきものを 3 件選び、優先順にIDと理由を 1 行ずつ書いてください」と 12 回頼んで、その答えをこのまとめ方でまとめました。
| 種類 | 挙げた答え | 項目ごとの票 |
|---|---|---|
| 記録や外部に秘密が出る | 12 回のうち 12 回 | 9・7・7・3・3・1 |
| 消したものが戻らない | 12 回のうち 6 回 | 2・2・2 |
残ったのは 9 票・7 票・7 票の項目で、3 件とも「記録や外部に秘密が出る」でした。「消したものが戻らない」は、12 回のうち 6 回の答えが選んでいたのに、1 件も残りませんでした。このまとめ方は項目ごとの回数を比べ、種類ごとの回数は比べません。残す枠がほかの種類の項目で埋まれば、半分の答えが挙げた種類でも、枠の外に出ます。
ほかのまとめ方は測っていません。どのまとめ方で落ちても、まとめる前の答えを種類ごとに数えれば残ります。の実験でも、12 回のうち 6 回として残りました。
CC BY 4.0 はここまで
集めなくなったもの
複数の答えを、1 つの結果に集めることです。いまは、まとめる前の答えを残し、種類ごとに、いくつの答えが挙げたかを出します。は票の少ない項目を落とすつもりで、実際には種類を 1 つ落としていました。
CC BY 4.0
注意: 測ったのは、のスクリプトのまとめ方だけです
12 回の答えをまとめたのはのスクリプトで、メインエージェントにまとめさせて測ってはいません。観点を変えて指示した答えも、は測っていません。母数は 12 回、モデルは 1 つです。
種類ごとに数えるには、指摘を種類に分ける必要があります。この実験では、は題材を作ったスクリプトの対応表で分けました。手元の指摘を分けるときは、分ける人の判断が数に入ります。
実験手順: 同じ問いを n 回投げて、項目ごとの票と種類ごとの数を分けて数える
前提
会話を引き継がないサブエージェント(前のやり取りを持たずに起動したもの)を、別々に n 回(できれば 10 回以上)起動する手段が要ります。項目の一覧は、スクリプトで作ります。手で書くと、どれを先に直すべきかという書いた人の考えが題材に入るからです。各サブエージェントに渡すものが 1 バイトまで同じであることを、ハッシュで照合する手段も要ります。
所要時間: 40 分(題材を作るスクリプトと、数えるスクリプトを自分で書く場合。どちらもすでにあるなら 10 分)
手順
- 項目の一覧をスクリプトで作ります。種類を数個決めて、1 種類につき複数の書き方を用意し、ファイル名・記号名・数値を全部振り直してください。種類ごとの件数を同じにします(件数を偏らせると、件数の偏りが、種類が揃ったように見えます)
- 種類の対応表を、サブエージェントに渡すディレクトリの外へ置きます。一覧の本文にも頼み方にも、種類の名前を 1 語も出さないでください
- 並びを混ぜます。同じ種類が固まって並んでいると、並び自体が、サブエージェントが種類を見分ける手がかりになります
- 頼み方から、種類に関わる語を全部取り除きます。「種類」「分類」「重い」「深刻」などを禁止語にして、頼み方に入っていないかをスクリプトで確かめてください。入っていると、測ることができるのは、種類という観点に沿った答え方だけになります
- 同じディレクトリを n 個作り、ハッシュが 1 つに一致することを確かめます。ハッシュが 2 通り以上になると、答えの分かれ方が、題材の差から来たのかどうかを、分けることができません
- サブエージェントを n 回起動します(1 回に選ばせる件数を k 件とします)。頼み方は、パス以外 1 文字も変えないでください
- 項目ごとの票と、種類ごとに挙げた答えの数を数えます。種類への読み替えは、必ず対応表でやります(本文を読んで分類すると、読んだ人の判断が入ります)
- 多数決で上位 k 件を残し、落ちた種類があるかを見ます。落ちた種類があれば、その種類を挙げた答えの数と、残った項目の票を並べます
7 と 8 は、次のスクリプトで数えることができます。
# 項目ごとの票と、種類ごとに挙げた答えの数を分けて数える(手元の実装からの簡約版)
python3 - kind_map.tsv answer_*/PICK.tsv <<'PY'
import collections, sys
kind_of = dict(line.split("\t")[:2] for line in open(sys.argv[1]).read().splitlines() if line)
votes, answers_by_kind = collections.Counter(), collections.Counter()
for path in sys.argv[2:]:
seen = []
for line in open(path):
cell = line.rstrip("\n").split("\t")
# 未知の ID と、1 つの答えの中で 2 度書いた ID は数に入れない
if len(cell) < 2 or cell[0] not in kind_of or cell[0] in seen:
continue
seen.append(cell[0])
votes.update(seen)
answers_by_kind.update({kind_of[i] for i in seen})
n = len(sys.argv) - 2
for kind, k in answers_by_kind.most_common():
items = sorted((c for i, c in votes.items() if kind_of[i] == kind), reverse=True)
print(f"{kind}: {k}/{n} answers / votes per item {items}")
top3 = [i for i, _ in votes.most_common(3)]
print(f"kinds left after majority vote to 3: {sorted({kind_of[i] for i in top3})}")
PY
合格条件(すべて満たすこと)
合格の条件は 3 つです。1 つ目に、n 回ぶんのディレクトリのハッシュが 1 通りであること(題材が同じであること)を確かめます。2 つ目は、選ばれた項目の種類が 2 種類以上あることです。1 種類だけなら、項目の一覧の作り方が偏っています。3 つ目は、選ばれなかった種類が 1 つ以上あることです。全種類が選ばれたなら、種類の分け方が細かすぎます。
合格しなかったとき
項目まで全部の答えが一致したときは、項目の一覧の中で 1 件だけが目立っています。同じ種類の件数を増やしてください。種類まで散ったときは、種類の分け方が細かすぎます。近い種類を 1 つにして、種類の数を減らしてください。1 種類しか出なかったときは、項目の一覧の作りに偏りがあります。件数を同じにし直して、並びを混ぜてください。ハッシュが 2 通り以上になったときは、題材を作るたびに変わるもの(時刻・乱数・パス)が題材に入っています。先にそれを消してください。
後始末
サブエージェントに渡したディレクトリと、種類の対応表を削除します。対応表を残すと、次に題材を作り直したときに、古い対応表で読み替えることになります。
まとめるときに落ちた種類も、まとめる前の答えを種類ごとに数えれば、12 回のうち 6 回として残っていました。
CC BY 4.0 はここまで
次回は「役に立たない技術」。は、指示ファイルに「必要なら」で始まる行を書くのをやめました。 それでも、必要な作業が抜けたことはありません。