未来を形作るテクノロジーの深掘り記事。

推薦なしのフィード:アルゴリズムよりキュレーション

人の手によるキュレーションとシンプルな検索で、エンゲージメント最適化アルゴリズムに頼らない推薦なしフィードを作る方法。HackerTubeから得た教訓を紹介。

派手なサムネイルが雑然と並ぶ壁と、整然と並ぶキュレーション済みの動画タイルの棚を対比させたイラスト
注意を最大化するよう最適化されたフィードと、人の手でキュレーションされた棚の違いは、決して小さくありません。

金曜日の夜11時。疲れた状態でYouTubeを開くと、ホーム画面には叫ぶようなサムネイルやショックを受けた表情の顔が壁のように並んでいて、2019年に「好きだ」と判断された同じ3つのトピックが並んでいます。どれも見たいものではないのに、なんとなくスクロールしてしまう。インターフェースがそういう操作を前提に作られているからです。もしこの独特の疲労感に覚えがあるなら、推薦なしのフィードが急に注目されている理由がすぐに分かるはずです。そして最近、Hacker Newsのコメントでの推薦をもとに、AIエージェントを使って約2時間で組み上げたYouTubeクローンが大きな話題になりました。

問題のプロジェクトはHackerTubeです。2007年から現在までにHacker Newsのコメントで推薦された約6,500本の動画を、YouTube風のインターフェースで閲覧できるようにしたものです。アカウントもトラッキングも、自動再生の小細工もありません。状態はブラウザのローカルストレージに保存されます。データ抽出からVPSへのデプロイまで、土曜の朝のセッションでプロンプトを重ねて一気に作られました。なぜこれほどうまく機能するのかを話したいと思います。この教訓は、一つの趣味プロジェクトにとどまらず、多くの場面に当てはまるからです。このサービスがうまく機能するのは、従来の意味での推薦アルゴリズムを持たないからであり、それは自分のプロダクトに意図的に組み込める特長だと分かってきました。

推薦アルゴリズムが間違ったものを最適化してしまう理由

私は数年間ランキングシステムの開発に携わってきたので、言いにくいことをはっきり言います。目的関数こそがプロダクトそのものです。プラットフォーム規模の推薦システムは、視聴時間、クリック率、セッション長、場合によっては広告インプレッションで重み付けした滞在時間といったエンゲージメント指標で学習されます。どれも「ユーザーは満足して離脱したか」を測るものではありません。測っているのは「ユーザーが留まったか」です。両者は十分に相関しているので、良いものを作っていると思い込めてしまいます。しかし、怒りを煽る内容、刺激的な内容、すでに見尽くしたテーマの20本目の動画といった、肝心な場面で両者は食い違います。

これはグッドハートの法則が、トレンチコートを着て現れたようなものです。視聴時間が目標になった瞬間、それは品質について何も測らなくなります。さらに悪いことに、フィードバックループは閉じています。アルゴリズムがクリックされるものを形づくり、そのクリックが学習データになり、モデルはあなたについての狭い像を、ますます確信を持って描くようになるのです。HackerTubeについてのいくつかの反応で、私自身も感じていたことが指摘されていました。ヘビーユーザーが選んだ、個人化されていない動画のフィードの方が、YouTubeの深く個人化されたフィードよりも当たりの割合が高い、というものです。これは驚くことではありません。個人化は、あなたの弱い瞬間(疲れた11時に何をクリックしたか)から好みを推測します。一方、キュレーションは、人々の強い瞬間(仲間に勧めたいと思って、わざわざコメントを書いたもの)から好みを読み取るのです。

もう一つ、より見えにくい失敗パターンがあります。最適化されたフィードは、すでに知っているものをより多く見せるのが非常にうまい。しかし人がブラウズする理由の多くは、視野の拡大にあります。世界に対する自分のモデルを組み直してくれる、思いがけない発見に出会うことです。エンゲージメント最適化には、後で報われる驚きに対する勾配シグナルがありません。分かるのは、ユーザーが留まったかどうかだけです。これは私が以前AIベンチマークは実際の仕事の大半を捉えられないと書いた理由とも同じです。測定可能な指標が本当に求めているものから離れていき、そのずれは積み重なっていきます。

コーパスとしての人によるキュレーション:Hacker Newsのコメントを掘り起こす

では、推薦なしのフィードは在庫をどこから得るのでしょうか。HackerTubeの答えは巧妙です。すでに存在する高品質なシグナル、つまり20年分のHacker Newsのコメントを再利用しているからです。パイプラインは単純に説明できます。公開されているHNのコメントをすべてダウンロードします(公式APIやコミュニティのデータセットで入手可能です)。YouTubeのリンクを含むコメントに絞り込むと、約40,000件になります。次に、安価なLLMで各コメントを処理し、一つの問いに答えさせます。この人は本当にこの動画を推薦しているのか、それともスパム、通りすがりのリンク、あるいは動画を馬鹿にするために引用しているのか。このフィルタリングによって、約150のトピッククラスタにまたがる約6,500本の動画にコーパスが絞り込まれます。

ここで真似する価値のある設計上の選択が二つあります。第一に、この分類ステップは、LLMが得意とする限定された判断タスクそのものです。短い根拠を添えた「はい・いいえ」の判定を、わずかなコストで大規模に適用できます。これは制約付きデコーディングでLLMを高速な意思決定モデルにするのと同じパターンです。モデルに生成させるのではなく、フィルタリングさせるのです。第二に、このコーパスには組み込みの品質の下限があります。そこに含まれる動画はすべて、くだらない投稿を下票する読者の前で、人間が文章で推薦したものです。これはクリックではなく評判に根ざしているため、どのエンゲージメントモデルにも再現できないフィルタリングの仕組みです。

コメントでの推薦は、人が自分の評判を賭けている行為です。クリックは反射にすぎません。前者をもとにしたフィードが違う手触りになるのは、実際に別物だからです。

時間の次元も重要です。これらの推薦は2007年から現在までにわたるので、コーパスはその時々にアルゴリズムが押し上げているものではなく、長く価値を保つコンテンツ、つまり講義、深い技術トーク、長尺のインタビューが中心になります。人々に愛された細部の一つが、長尺動画のための「Longs」カテゴリです。YouTubeでは、90分のトークはおすすめシステムがセッションに対して取るリスクです。HackerTubeでは、それが特長になります。隣に「これでコンパイラの見方が変わった」と書いた人がいるからです。

コメントの泡の流れを絞り込み、小さな動画タイルの山にまとめるファネルのイラスト
4万件のコメントが入り、6,500本の推薦済み動画が出てくる。このファネルこそがプロダクトなのです。

シンプルな検索がスマートなランキングに勝つ

推薦システムに携わったことがある人には異端に聞こえるかもしれませんが、ここが核心です。コーパスが小さくて質が良ければ、ランキングはほとんど重要ではなくなります。6,000本の動画は多くありません。二塔型の埋め込みモデルや再ランキングのカスケードは必要なく、必要なのはトピックタグ、新しさ、そしてクライアント側で動く軽量な個人化処理だけです。HackerTubeの「For You」は、ローカルストレージのセッション状態、つまりそのブラウザで見た動画とスキップした動画をもとに動きます。アカウントもサーバー側のプロファイルもありません。これは制約ではなく、アーキテクチャ上の判断です。ユーザーの行動を保存しなければ、それに対して最適化したくなる誘惑そのものが消え、悪いインセンティブの一群を丸ごと排除できるのです。

もし自分のコミュニティが推薦する論文、カンファレンストーク、ブログ記事などのフィードを自作したいなら、ランキングロジックは数十行で書けます。その形はこうなります。

import math
import time
def score(video, session, now=None):
now = now or time.time()
s = 0.0
# Corpus quality signal: how many distinct humans vouched for it
s += math.log1p(video["recommenders"])
# Gentle recency so the feed isn't frozen in 2014
age_days = max((now - video["recommended_at"]) / 86400, 1)
s += 0.5 / math.log1p(age_days)
# Session-level taste: topics the user finished vs. skipped,
# stored in localStorage — never leaves the browser
for topic in video["topics"]:
s += 1.5 * session["finished"].get(topic, 0)
s -= 1.0 * session["skipped"].get(topic, 0)
# Already watched? Push it down hard, don't hide it
if video["id"] in session["seen"]:
s -= 5.0
return s
def for_you_feed(videos, session, limit=24):
return sorted(videos, key=lambda v: score(v, session), reverse=True)[:limit]

そこにないものに注目してください。滞在時間の特徴量も、エンゲージメントの速度も、ユーザーの限界点を探る探索と活用のバンディットもありません。個人化のシグナルは明示的です(完走とスキップという、そのセッションでのユーザー自身の行動によるもの)。そして有界です(それぞれ数点程度で、コーパスの品質の項によってたやすく上書きされます)。アルゴリズムは後押しはできても、閉じ込めることはできません。この非対称性こそが、一つのスコアリング関数に込められた哲学全体です。

サムネイルの判断も触れておく価値があります。インターフェースの最適化を取り除く、分かりやすい例だからです。YouTubeのクリエイターはサムネイルをA/Bテストで擦り切れるまで試すので、サムネイルそのものが敵対的な成果物になってしまいました。HackerTubeはアップロードされたサムネイルを無視し、代わりに動画の50%地点のフレームを使います。これは一行の変更で、クリックベイトの軍拡競争を丸ごと取り除きます。プレビューが示すのは、クリエイターがクリックさせたいと思うものではなく、動画の実際の中身なのです。

アカウントもトラッキングもないフィードの設計

状態をクライアントに移すことは、プライバシーの姿勢だけでなく、コスト構造と法的な責任範囲も変えます。ユーザーアカウントがなければ、認証システムもパスワードリセットもGDPRの開示請求対応も、行動プロファイルに対する情報漏えいの責任も発生しません。バックエンドは静的ファイルサーバーと、せいぜい小さなAPIが一つあるだけです。サイト全体をビルド成果物にできます。アーキテクチャがユーザーデータを蓄積できないなら、ダークパターンの多くは、単にポリシー違反になるのではなく、物理的に不可能になります。こうした保証は、どんなプライバシーポリシーよりも信頼できると私は思います。

正直なトレードオフもあります。ローカルの状態は一時的で、デバイスに紐づきます。ブラウザのデータを消せばフィードはリセットされ、デバイスをまたいだ継続性もありません。リラックスして見るタイプの動画サイトであれば、これで問題ありません。むしろ、ときどきリセットされるのは健全でさえあると私は考えています。ユーザーが長期的なコレクションを作るような用途では、エクスポートとインポートの逃げ道が必要になります。そしてそれが、このプロジェクトで最も先を見越した判断へと、ちょうどつながっていきます。

データがインターフェースになる:フォークできるコーパスを公開する

HackerTubeで私が本当に新しいと感じるのは、UIではありません。サイトの背後にあるデータセット全体が、AIエージェント向けに特別に書かれたDATA.mdを含むzipとしてダウンロードできることです。このファイルには、ファイル同士の関係、注意点、サンプルのレコード、新しいメタデータの取得方法が書かれています。想定されているワークフローは、そのzipをコーディングエージェントに渡して「自分のトピックに関するトークを毎週メールで送るものを作って」や「これ用のターミナルクライアントを作って」と頼むことです。プロダクトはウェブサイトではありません。プロダクトはキュレーションされたコーパスであり、ウェブサイトはその参照用のレンダラーにすぎないのです。

これは今後もっと増えると思うパターンです。この20年、標準的なアドバイスは「APIを公開せよ」でした。しかしAPIは、クエリの門番としてあなたを留めます。そして保守をやめた瞬間に腐ります。ポータブルでエージェントが読めるデータセットは、その関係を逆転させます。一度、よく文書化された形で公開すれば、あとは数千の個人化されたフロントエンドが勝手に育ちます。これはスモールウェブの精神と通じるものがあります。プラットフォームが何を見せるかを決めるのではなく、人々が気に入ったものへのリンクを積み重ねて作る発見の仕組みです。それを、最初の利用者が言語モデルかもしれない世界向けに更新したものです。

エージェント向けのドキュメント作成は、それ自体が新しく生まれつつある技術です。人間は流し読みしますが、エージェントは文字通りすべてを隅々まで読み、人間なら推測できる暗黙の前提でつまずきます。良いDATA.mdは、単位、null許容性、エンコーディングの癖、失敗パターンを冒頭で明示します。データセットを公開するなら、これはもはや最低限の要件です。エージェントが一度で動くフォークを作るか、スキーマを幻覚で作り出すかの違いになるからです。

一つのアーカイブ箱から、多くの異なるデバイスや形式へと枝分かれするイラスト
コーパスは一度公開すれば、あとは百のフロントエンドが花開く。

キュレーションされたフィードの正直な限界

誇大広告よりも実用性を重視すると約束したので、鋭いエッジも挙げておきます。まず、キュレーションされたコーパスは、キュレーターの偏りを引き継ぎます。Hacker Newsは特定の層と特定の好みを持つ集団です。その結果は「100%純粋なギーク向けコンテンツ」であり、ターゲットの読者にとっては楽しいものですが、そうでない人には存在すら見えません。このアプローチは「すべての人」向けにはスケールしませんし、そうしようともしていません。これは公共施設ではなく、行きつけの酒場のようなものです。

  • 陳腐化:凍結されたスナップショットは時間とともに劣化します。抽出パイプラインを再実行する定期ジョブが必要で、さもなければフィードはいつの間にか博物館になってしまいます。
  • プラットフォームへの依存:動画は今もYouTube上にあります。削除、地域制限、利用規約の変更は、コーパスを足元から腐らせます。リンク切れを追跡しなければ、信頼を失います。
  • 人口統計的な固定化:推薦する人が、好みの範囲を決めてしまいます。コミュニティサイトなら問題ありませんが、中立的な発見の仕組みとして売り出すなら、深刻な偏りの問題になります。
  • 新しさの天井:まったく新しい優れたコンテンツには、まだ推薦がありません。キュレーションされたフィードは、新しいものを体系的に十分に扱えません。これはまさに、エンゲージメント・アルゴリズムが埋めている隙間であり、良くも悪くも、です。

この最後の点こそ、このアプローチについて私を正直に保ってくれるものです。エンゲージメント型のフィードとキュレーション型のフィードは敵同士ではなく、異なる時間軸に最適化されています。キュレーションは、何が価値を証明したかを教えてくれます。エンゲージメントランキングは、最良の状態では、いずれ価値になるかもしれないものを浮かび上がらせます。YouTubeの推薦システムの健全な姿は、HackerTubeのコーパスに、小さく、はっきりとラベルを付けた「新しくて未検証」のレーンを加えたものに近いはずです。悲劇は、推薦アルゴリズムが存在することではありません。ビジネスモデルが、それをインターフェースの全体にすることを求めてしまうことなのです。

自分で作るべきとき

この2時間という制作時間こそが、もう一つの物語です。このプロジェクトは5年前には、この速度では実現できませんでした。どの一つのステップが難しいからではなく、抽出、フィルタリング、メタデータの拡充、UI、デプロイ、ハードニングといった、細かい作業が40ほどもあるからです。計画全体をコンテキストに保持できるエージェントがあれば、それはひと続きのプロンプトのセッションに圧縮されます。つまり、プラットフォームのフィードに対するニッチでキュレーションされた代替品を作る障壁は、「やる気のある一人が土曜の朝を使う」程度にまで下がったのです。

そこで私の結論です。はっきり言います。フィードを持つプロダクトを運営しているなら、社内のナレッジベース、コミュニティフォーラム、コンテンツ製品のいずれであっても、アルゴリズム版を作る前に、キュレーション版をプロトタイプすべきです。まずは人間が明示的に行った推薦から始め、安価なLLMのパスでフィルタリングし、スタンドアップで説明できるほど単純なスコアリング関数でランキングし、可能な限りクライアント側に状態を保ちましょう。そうすれば、自分が抱えているのが在庫の問題なのか、ランキングの問題なのかが分かります。私の経験では、ほぼ必ず在庫の問題です。エンゲージメント最適化されたフィードは、指標を最大化するための道具です。キュレーションされたフィードは、人を尊重するための道具です。先に後者を作り、前者に手を伸ばすのは、それが誰のために、なぜ存在すべきかを正確に説明できるときだけにしましょう。