BLOG.HIRO UENO.ART
← INDEX

モデルを足す前に、0件の理由を数える

MONET(僕が普段話しかけている、中心のAI)には、過去の会話を言葉で探す道具がある。recallという名前で、コーディングしてくれているClaude Code(以降Code)が前に作ってくれた。MONETとの会話は、あとで要約されて記憶として残る。僕が前の話を聞くと、MONETが探す言葉をいくつか選んでrecallに入れ、recallはその言葉を含む要約を返す。見つからなければ0件。

きっかけは、Xに出ていた判断専用の小さなAIモデルの話だった。Codeに調べてもらうと、検索で集めた候補が質問にどれくらい関係あるかを採点するモデルだった。その流れで、recallが集めた候補をこういうモデル(ここでは判断モデルと呼ぶ)で採点して、関係の深いものを選べば、取りこぼしが減るんじゃないか、という話になった。

ただ、足す前に、recallが今どれくらい取りこぼしていて、それはなぜなのかを確かめることになった。

AIが実際に探した時の記録で、0件の中身を1回ずつ調べた

やり方はこう。recallを本番(僕が普段使っているMONET)に入れてから今までに、MONETがrecallを呼んだ記録を全部集める。その呼び出しを、本番のデータを写したものの上でもう一度動かす。この時、要約は呼び出しの時点で既にあったものだけを使う。こうすると、当時何が返ったかがそのまま分かる。そのうえで、0件だった回を1回ずつ要約の本文と突き合わせて、本当に記録が無かったのか、あるのに見つからなかったのかを分けていった。

先に言っておくと、数は少ない。recallには、言葉を入れずに期間だけ決めて要約を並べる使い方もある。それと、結果が残っていなかった1回を除くと、言葉で探したのは24回。しかもほとんどが、recallを入れた直後に僕がテストで質問した数日に集中している。記録があるかどうかの判定もCodeが要約を読んで付けたもので、僕は1件ずつは見ていない。

それでも、24回のうち14回、半分以上が0件だった。

記録があるのに見つからなかった8回のうち7回は、言葉が全部そろわないだけだった

0件の中には正しいものもある。14回の内訳はこうだった。そもそも記録が無い話を聞いた時は、0件が正解。これが4回。質問が漠然としていて、どちらとも決められなかったのが2回。残る8回は、記録があるのに0件だった(ここでは取りこぼしと呼ぶ)。その8回のうち7回は、原因が同じだった。

recallは、入れた言葉が全部そろっている要約しか返さない。

例えば(これは説明用に作った例)、MONETが「スケッチ 保存 決定」で探したとする。要約には、スケッチの保存の話がちゃんと残っている。でもその要約に「決定」という語が無いと、それだけで0件になる。1語ずつ探していれば見つかっていた。

意味で探す必要があったのは1回だけ。候補があふれたことも無かった

MONETが選んだ語と要約の言い方が違っていて、意味で探さないと見つからなかったのは、8回のうち1回だけ。この回は、MONETが選んだ語が要約に1つも入っていなかった。

Codeはもう1つ、切り捨ての回数も数えていた。recallは一度に返す数に上限があって、候補がそれを超えると、あふれた分は切り捨てる。判断モデルで採点して並べ直すのが役に立つのは、この時だ。多すぎる候補の中から、関係の深いものを残せる。でも集めた記録の中で、切り捨てが起きたことは一度も無かった。

Codeの結論は、判断モデルは今は足さない、というものだった。

言葉が全部そろわない時だけ、1語ずつ探し直す

直すのにモデルは使っていない。Codeが作った仕組みはこう。

気をつけたのは、記録が本当に無い時の扱い。1語ずつ探すと、関係ない話も引っかかる。

そこで、返す要約の1行ごとに、〔一致: スケッチ・保存〕のように当たった語を付ける。さらに、探した範囲のどの要約にも1回も出てこない語があれば、結果の一番上に出す。さっきの例で、範囲のどの要約にも「決定」が無ければ、「この範囲に無かった語: 決定」のように。

どれが関係あるかはMONETが決めて、recallはそのための材料を必ず付けて返す、という分担。言い換えが原因だった1回は、この方法でも拾えないまま。

前は0件だった問いのうち、記録のある2つは本番でも見つかった

ここまでの調べものと直しは、Windowsで動いているCodeがやった(僕はMacとWindowsの両方でCodeを使っている)。その変更をMac側のCodeが受け取って中身を読み、テストが全部通るのを確かめてから、僕がOKを出して、Codeが本番に入れた。

その後、Mac側のCodeが、前に0件だった質問を3つ、本番のrecallに直接入れて確かめた。記録がある2つは、一部一致のおかげで、目当ての要約が結果に入るようになった。

記録の無い1つでは、全部の語がそろう要約が2件返ってきた。ただ、どちらも目当ての話ではない。1件は、前に僕が同じことを聞いて「該当なし」で終わった時の、その会話自体の要約だった。目当ての記録はやはり無いので、MONETは「無い」と答えられる、とCodeは見ている。

この確認は、MONETがツールを呼んだ時と同じ処理を直接動かしたもので、MONETにチャットで聞いたわけではない。MONETが〔一致〕の印を見て正しく判断できるかは、普段使いながら見ていく。

問題の大半は、言葉が1つでも欠けると何も返さない決まりの方にあった。言葉の意味まで読む賢さが要ったのは、8回のうち1回だけだった。