ブログ一覧

Jev 互換をうたう無料モデルを内部リンクの判定で試したら、使い物にならなかった

更新: Web開発者向け

Jev は有料の判定 API で、たとえば記事 A と記事 B を渡して「A を読んでいる人に B へのリンクは役に立つか」と問うと、「はい」の確率が返ります(詳細はJev を LLM の代わりに使えた処理)。同じ形の問いに答えるとうたう、重みが公開された無料のモデル Laya と Jeff が手元で動くと知り、ブログの内部リンク(記事の中に張る別の記事へのリンク)の候補選びを Jev から置き換えられるか試しました。

既存のリンクを正解にして採点すると、2つともモデルを使わないタグの一致(2本の記事に付いたタグのうち共通する物の割合)に負けたので、置き換えは見送りました。Laya は記事の組ごとの「はい/いいえ」でほぼどの候補にも「役に立つ」と答え、Jeff は読んでいる記事以外の 136本から 1つ選ぶ問いで、並べた選択肢の 27 番目以降をほぼ選びませんでした。

Jev で拾っている内部リンクの候補を、無料のモデル 2つに置き換えたかった

このブログでは、内部リンクの候補を Jev で拾っています。読んでいる記事 A と、リンク先の候補の記事 B の組み合わせ(以下、組)ごとに Jev の「はい」の確率を出し、組の点にしています。公開済みの記事 137本の全組を Jev で判定し、本文に既にあるリンクを正解にして採点すると、AUC は 0.94 でした。AUC は、点の高い順に並べたとき、正解(既存のリンク)が正解でない組より上に来る確率です。0.5 はでたらめ、1.0 は完全を表します。

Jev 互換をうたう、重みが公開された無料のモデルが 2つあります。

  • Laya: 多言語の版は 3 億 2,200 万パラメータ(モデルの中の数値の数)の小型のモデルを元にしている
  • Jeff: 小さな LLM を判定用に学習させた物で、一番小さい 8 億パラメータ(0.8B)の版を試した

どちらも手元で動くので API の費用がかかりません。知りたかったのは、この 2つに置き換えられるかどうかです。

どちらも Python から呼び、GPU の無い CPU で動かした

動かした場所は GPU の無い 4 コアの CPU の Linux マシンで、どちらも Python から呼びました。問いの形は、Laya が組ごとの「はい/いいえ」、Jeff が 136本から 1つ選ぶ形と違います。

Laya は pip install laya で入れ、判定を呼ぶ Router を作って、predict(state, 問い, model="multilingual") で「はい」の確率を受け取りました。state は判断の材料として渡す文章で、多言語の版の重みは初回にダウンロードされました。

  • 問い: 「この記事を読んでいる人にとって、次の記事へのリンクは役に立ちますか?」に、候補の記事 B のタイトルと概要を付けた
  • 回数: 組ごとに 1回
  • 点: 「はい」の確率

Jeff は GitHub のリポジトリからパッケージを入れ、Hugging Face で配布されている 0.8B の版の重みを落として読み込みました。問いの型は choice(選択肢を並べ、それぞれが選ばれる確率を返す型)を使いました。

  • 問い: 「この記事を読んでいる人に、次に読んでもらうリンク先として最も役に立つ記事はどれですか?」に、残り 136本のタイトルを選択肢として並べた
  • 並び: 記事の URL のアルファベット順
  • 回数: 記事 A ごとに 1回
  • 点: 選択肢ごとの確率

記事の中身は、サイトの CMS から公開済みの記事を全部取り出して使いました。記事 A の材料はタイトル・概要・本文の先頭 1,500字です。Laya と Jeff への問いは、Jev に渡した問いと同じ意味になるよう私が書いた文です。

GPU の無い CPU での実測は次のとおりです。

  • Laya: 1 組あたり 0.14〜0.95秒
  • Jeff: 136 択の 1 問で中央値 151秒

Laya の公称値は T4 GPU で 1 問 33ms(README、2026-09-28 取得)です。

既存の内部リンクを正解にして、タグの一致と同じ 42本で比べた

正解は、記事 A の本文に、私が既に記事 B へのリンクを張っている組です。張っていない組は不正解として扱いました。

公開済みの 137本から乱数で記事 A を 42本選び、それぞれ残り 136本を候補にしました。記事 B から記事 A にだけリンクがある 50組は正解とも不正解とも言えないので除き、組は 5,662組、うち正解は 85組です。採点は、先に説明した AUC です。

比べる基準は、モデルを使わないタグの一致です。このブログの関連記事は今タグの一致で選んでいて、同じ 42本での AUC は 0.86 でした。

Laya は関係の無い記事にも高い点を付け、Jeff は並びの後ろの正解にほぼ 0 の点を付けた

例を 2つ挙げます。リンク先の記事を開くと、関係があるかどうかを自分で確かめられます。

Jeff の行の「並びの○番目」は、Jeff に選択肢として渡した 136本のタイトルの中での位置です。並びは記事の URL のアルファベット順なので、URL が a で始まる記事は前の方に、w で始まる記事は後ろの方に来ます。

記事 A が WordPressのphpMyAdminのログイン情報を調べる(タグは database・wordpress)の場合です。

Laya は関係の無い Nuxt の記事 C に正解の B より高い点を付け、この記事 A では 136本すべてに 0.99 以上(最小 0.993)を付けました。Jeff は、中身と関係なく並びの 1 番目にあった C を 1 位にし、並びの後ろにあった B(128 番目)と D(69 番目)にはほぼ 0 を付けました。

記事 A が Cloudflare D1 の上限を守るために作らなかった仕組みの記事の場合です。

Jeff は並びの 10 番目にあった正解 B は 1 位にしましたが、43 番目にあった同じ D1 の話の正解 B2 には 0 を付けました。Laya は関係の無い C に 0.990 を付け、正解の B2 の 0.991 と差がありません。

AUC は 2つともタグの一致の 0.86 を下回った

同じ 42本・5,662組の AUC は次のとおりです。

  • Laya: 0.49(記事 A をタイトル・概要・本文の先頭 1,500字で渡したとき)
  • Laya: 0.60(記事 A をタイトルと概要だけ、候補をタイトルだけに短くしたとき。以下、短い渡し方)
  • Jeff: 0.53
  • タグの一致: 0.86

Jev の 0.94 は 137本の全組での値で、42本だけで測り直してはいません。

記事 A の 42本のうち既存のリンクを持つ 34本で、1 位の候補が既存のリンク先だったのは Jeff で 4本でした。同じ 34本で、タグの一致が最も大きい候補を 1 位にすると約 15本、でたらめに選んだときの期待値は約 0.6本です。

Laya は読んでいる記事、Jeff は選択肢の並びで点が動いていた

Laya は、ほぼ全部の組に「役に立つ」と答えました。点の 99.9% が 0.9 以上で、中央値は 0.991 です。記事 A をタイトル・概要・本文の先頭 1,500字で渡したときは、点の差が候補ではなく、読んでいる記事 A で決まっていました。

  • 点のばらつきのうち、記事 A ごとの平均の違いで説明できる割合
    • Laya: 61%(短い渡し方 49%)
    • タグの一致: 9%
  • 同じ記事 A の中だけで候補を並べ替えたときの AUC
    • Laya: 0.44(短い渡し方 0.61)
    • タグの一致: 0.86

Jeff は、27 番目以降の選択肢をほぼ選びませんでした。確率の合計のうち 1〜26 番目に乗った割合は、記事ごとの中央値 99.3%、最小 98.8% で、正解 85組のうち 75組は 27 番目以降にありました。選択肢を逆の順に並べて記事 A を 6本回し直すと、同じ組の点の順位相関(1 は同じ順、0 は無関係)は中央値 0.02 でした。

記事の中身と関係なく、並びの位置だけで起きるかを見るため、英語の対照も取りました。Jeff で選択肢を 40個にし、次の内容で、正解を置く位置だけ変えました。

  • state: 「Refund request: the customer says the parcel arrived crushed and wants their money back.」
  • 問い: 「Which team should handle this?」
  • 選択肢: 部署名 40個
  • 正解: 「Damaged or lost parcels」

正解を置く位置ごとの点は次のとおりです。

  • 3 番目: 0.976
  • 20 番目: 0.995
  • 27 番目: 0.000
  • 35 番目: 0.000

Jeff の README にある公称値(2026-09-29 取得)は choice で 255 択までで、26 択を超えたときの注意は README に無く、この挙動を報告した Issue もありません。Jeff は選択肢に A〜Z、その先に AA、AB… の符号を付け、符号の 1 トークン分(モデルが文字列を区切って読む単位)の確率を読みます(`model.py` の 68〜87行目)。選ばれなくなる 27 番目は、符号が 2 文字になる位置と一致します。原因までは確かめていません。

この結果が当てはまるのは配布されたままの版だけで、2つとも自分のデータで追加の学習をする微調整をせずに使いました。Laya の作者は BENCHMARKS.md で、微調整前の版の点は作者自身の評価で、いつも多数派を答えるだけのときより低く、この評価の能力はすべて微調整から来ると書いています。Jeff は 0.8B の版だけ試しました。

内部リンクの候補選びは Laya にも Jeff にも移さず、候補の判定は Jev、関連記事はタグの一致のままにしました。置き換えを考えるときに私が見たのは、全体の AUC と、実際の組で点が候補の中身で決まっているかの 2つです。

関連

この記事をシェア