Yyatmita

「スキルを訓練する」を採用しかけて止めた——SkillOpt を自分の検証軸で測ったら、同じ地図に乗っていた

自己流の開発手法に自己改善ループを入れた直後、モデルでなくスキルを訓練する SkillOpt が目に留まった。一対一で噛むので採用しかけたが、二つ引っかかって止めた。理由を辿ると、前回引いた検証層の軸の上に、この新手法もちゃんと座っていた。

自分のエージェント基盤を組む#claude-code#agent#architecture#idd

最近、自己流の開発手法を試している。GitHub Issues を起点にして、設計の議論・採択・実装・リリースをスキルとテンプレートの束で回す、IDD(Issue-Driven Development)と勝手に呼んでいるものだ。中身は要するに Claude Code 向けの Markdown(スキル・ルール・テンプレ)の集合で、使っていて得た気づきを issue に貯め、溜まったら直す、という自己改善ループを最近そこに足した。「IDD の改善も IDD で回す」という、自分用のドッグフーディングだ。

ちょうどその作業をしている最中に、ある手法が目に留まった。SkillOpt。「モデルの重みを fine-tuning する代わりに、自然言語のスキルを訓練可能な外部パラメータとして扱う」。Train the skill, not the model。自己改善ループを手で書いていた直後だったので、これはまさに自分がやろうとしていることの自動化版だ、と飛びついた。

結論から言うと、採用しかけて止めた。そして止めた理由を辿っていったら、前回の記事で引いた「検証層をどこから調達するか」という軸の上に、この新手法もきれいに座っていた。新しい話に見えて、同じ地図の別の地点だった、という話を書く。

SkillOpt が何をやっているか

ざっくり言うと、スキルの Markdown を「重み」に見立てた最適化だ。エージェントを実行してトラジェクトリを集め、その経験から「勾配方向」(どう直すべきか)を要約し、スキル文書に小さな編集を当て、評価して採否を決める。これを反復する。

機構はディープラーニングの語彙を借りている。learning rate に当たる「1ステップで当てる編集数の上限」、複数のトラジェクトリを束ねて再現するエラーだけを拾う minibatch reflection、却下した編集を負例として覚えておく rejected-edit buffer、エポック境界で長期的な指針を別フィールドに固める slow update。そして肝が、候補スキルは held-out の検証スプリットでスコアが厳密に上回ったときだけ採択する(同点は却下)という gating だ。6つのベンチマーク・7モデル・3つの実行環境(直接呼び出し・Codex・Claude Code)で、52/52 のセルで best または tied-best、と主張している。

自己改善ループとして見れば、要素は私が手で回していたものと一対一で対応する。

SkillOpt私の IDD 自己改善ループ
訓練対象のスキル文書SKILL.md / ルール / テンプレの Markdown 集合
経験から得る勾配方向使っていて貯めた気づきの issue
検証スコア(loss)eval ハーネス(deepeval + judge)
bounded editPR ベースの小さな改善
rejected-edit buffer効かなかった改善の記憶

ここまで噛み合うと、手で回すのが馬鹿らしくなる。採用したくなった。

一つ目の引っかかり——理解を超えると、逆にガードが弱まる

最初に立ち止まったのは、素朴な不安だった。最適化が自分の理解を超えて賢くなると、かえって歯止めが効かなくなるんじゃないか。

ここを切り分けると、怖い場所がはっきりした。自己改善ループには二つの層がある。成果物(編集後のスキル文書)と、目的(評価器が何を「改善」と呼ぶか)だ。

成果物の側は、実はガードが強くなる。テキスト空間の最適化だから、変更は常に読める diff として残る。重みの fine-tuning と違い、「何がどう変わったか」を人間が必ず追える。前回の言葉でいえば、ここは可逆性が崩れない側だ。

弱くなるのは目的の側だ。評価器のスコアが上がった=良くなった、と信じた瞬間、判断の権限が人間からプロキシ指標へ移る。評価器(IDD の場合は LLM の judge)が間違った方向を「改善」と呼んでも、気づけなくなる。これは前回②の失敗モードに挙げた Goodhart そのものだし、より一般には「監督者が被監督者より弱いと監督が崩れる」という構図だ。

つまり、SkillOpt 流の本当の怖さは「AI が勝手にスキルを書き換える」ことではない。diff は読めるのだから。怖いのは、何を改善と呼ぶかの定義を評価器に委譲して、その評価器が間違っていても気づけなくなることだった。

二つ目の引っかかり——その 52/52 は信頼できるのか

そこで評価器そのものを疑った。52/52 という数字も、出来すぎている気がする。

割り引くべき理由はあった。査読前のプリレポートで、手法もベンチマークも baseline 実装も全部著者が握っている自己申告。baseline をどれだけ詰めたかの開示もない。tied-best を勝ちに数えていて、引き分けと厳密な勝ちの内訳も出していない。鵜呑みにする数字ではない。

だが本当の急所は、数字の信頼性ではなかった。使っている6つのベンチマークを見て気づいた。SearchQA は完全一致、SpreadsheetBench はコード実行で検証、数学ベンチは選択肢の一致、ALFWorld はタスク完了判定——6つ全部が客観的な検証器を持っている。LLM の主観判定は主結果に一切使っていない。

ここで前回の話に直結する。SkillOpt の自動 gating が機能するのは、スコアが揺るがない正解だからだ。数学の正答やテストの pass は、評価器が嘘をつく余地がない。だからこそ「自動で採否を決める」が成立する。これは前回引いたオラクル原理そのものだった。安い決定論的なオラクルがあるドメインでだけ、外枠を外してループに検証を任せられる、というあれだ。

そして IDD の MD 改善には、このオラクルが無い。スキル文書の質——ワークフローが滑らかになったか、過剰なルールが減ったか——は完全一致で測れない。判定は LLM の judge に戻り、それは私が一つ目で避けたかった「評価器が弱い証人」の状況そのものだ。

同じ地図の、別の地点だった

ここで二つの引っかかりが一本に繋がった。

SkillOpt が安全に自動ループを回せたのは、目的が客観スコアだったからだ。前回の分類でいえば、SkillOpt は Type ③(自律ループ型)の手法で、その 52/52 は cheap oracle が在るドメインに限った数字だった。オラクルを外した瞬間——主観的なスキルの質を相手にした瞬間——それは Type ①(製品内蔵型・人間が密に DoD を評価する)に崩れ戻る。

前回の結論を、自分でこう書いていた。①②③は離散的な種ではなく、DoD をどれだけ機械で表現できるかでスライドする相対的な位置だ、と。スキルの最適化も、その例外ではなかった。「スキルを訓練する」という新しい看板の下でも、座っている場所を決めているのは、結局 DoD の表現可能性と人間の関与だけだった。

密な HiL は、巻き戻しが安いから成り立つ

ここで当然の反論が来る。オラクルが無いなら人間が検証器になる、と言うのは簡単だが、人間が毎手評価するのは高くつくのではないか。Type ① の「人間が密に DoD を評価する」は、放っておけば一番コストの高い選択肢のはずだ。

それでも成り立つのは、巻き戻しが安いからだ。以前、自分の Claude Code のログを分析して、持続する vibe coding は「永続的に受け入れる」のではなく「とりあえず受け入れて、やっぱり安く巻き戻す」スタイルだと書いた。いったん・とりあえず・やっぱり——判断を仮に留めておいて、結果を見てから決める。密な人間評価が高くつかないのは、一回一回の評価が軽く、間違っても巻き戻しがほぼ無料だからだ。

そして巻き戻しを安くしているのは、ほかでもないテキスト空間の編集という性質だ。SkillOpt が「モデルでなくスキルを訓練する」ことの利点として挙げていた、diff が読めて revert が一コマンドで済むという性質。それは自動 gating の前提であると同時に、自動 gating を諦めて人間に戻したときの、HiL を支える土台でもあった。同じ性質が、軸の両端で別の役を演じている。オラクルがある側では「安全に自動で回せる」を支え、無い側では「密な人間評価を安く保つ」を支える。

つまり Type ① の密な HiL が成立しているのは、検証可能性で二分した後の片端で、たまたま人間が頑張っているからではない。とりあえずで試して、やっぱりで巻き戻す——その安さが、密な HiL を経済的に成立させている。「検証層を人間から借りる」という前回の言い方には、「借りるコストが、巻き戻しの安さで割り引かれている」という但し書きが要った。

何を借りて、何を人間に残したか

地図の上の位置が分かれば、移植の線引きも決まる。

借りられるのは、スコアの信頼性に依存しない機構だ。bounded edit(小さく可逆な編集)、minibatch reflection(単発の逸話でなく束ねて方向を出す)、rejected-edit buffer(効かなかった方向の記憶)。これらは judge が弱かろうと、diff が読めて revert が安いという性質の上に立っているので、丸ごと持ってこられる。

借りてはいけないのは、held-out gating の自動採否だ。IDD では judge のスコアは advisory な第二意見に留め、最終的な採択は人間が押す。SkillOpt の数字がどれだけ立派でも、その正当性は「客観検証器が在る」という、IDD が満たさない前提に乗っているからだ。検証可能性で二分して、deepeval で測れるものだけ自動ゲートにし、測れないものは bounded edit で試して戻す——人間が検証器になる。

最後に、負例の蓄積。SkillOpt の rejected-edit buffer は、効かなかった編集とそれが落としたスコアを覚えておく仕組みだ。これを別途ログとして作ろうとして、要らないと気づいた。IDD なら git log が兼ねる。効かなかった編集を git checkout で握りつぶさず revert commit として残せば、「試して効かなかった方向」が履歴に積み上がる。「なぜ効かなかったか」は、再発したときに気づきの issue を reopen する側に残る。新しい入れ物は一つも要らなかった。捨てるときに checkout でなく revert を選ぶ、という規律だけだ。

今日のところの結論

frontier の新手法を一つ読んで、採用しかけて、止めた。止めた判断の中身は、前回自分で引いた軸を、別の入口からもう一度なぞっただけだった。検証層がどこから来るか、安いオラクルが在るか、無ければ DoD を誰が密に評価するか。SkillOpt の 52/52 はその軸の片端(オラクルが在る側)で成立する数字で、私の IDD はもう片端(人間が検証器の側)に座っている。

地図があると、新しいものを読んだときに「これは地図のどこか」を先に問える。そして今回は、地図ごと書き直さずに済んだ。スキルを訓練するという話も、結局は完成の定義(DoD)と人間の関与の話に畳めた。たぶん次に何かを読んだら、また同じ問いから始めることになる。


前回の記事: 「ワークフロー vs エージェント」では足りなかった——自分のプロダクトを実コードで分類した