完成品はこちら → 例えツッコミジェネレーター
🤩 例えツッコミに魅せられて...
マリアナ海溝よりも深いよ!
例えツッコミは、特定の共通点から、ある物事と別の物事を結びつけて指摘する手法だ。
冒頭の発言は、例えツッコミの名手、くりぃむしちゅー上田氏のものである。
くりぃむしちゅーファンの僕としては、上田氏のような例えツッコミへの憧れを持っているが、簡単には真似できない。
例えツッコミを成立させるには、独自の切り口を養うことはもちろん、前提となる膨大な知識が必要だからだ。
そこで、AIネイティブDBの Convex を使った「例えツッコミ生成アプリ」を作ることで、擬似的に上田氏の例えツッコミ力を、無料枠の範囲で簡単に再現してみたい。
この記事は、僕が大好きな Convex の紹介記事です。
📝 前提・実装方針
例えツッコミは、ある要素と別の要素の類似点を指摘する作業である。
無料枠でこの要件を実現するなら、シンプルにコサイン類似度のベクトル検索をするのが良いだろう。
検索するデータセットは、知識の宝庫である Wikipedia を活用したい。
ざっくり実装イメージとしては、
- ユーザーが文章を入力
- その文章を意味ベクトルに変換(Embedding)
- ベクトル化済みのWikipedia記事データベースと類似度比較
- スコアが高いものを、「例え先」としてユーザーにツッコむ!
という流れになる。
アーキテクチャは以下のようなイメージ。
フロントエンド - Next.js + Vercel
普段の業務でも利用しているので、今回は拘らずにスピード重視で実装する。
2025年12月22日現在、Vercelの無料プラン(Hobby)は「非商用の個人用途向け」です。
商用利用はPro/Enterpriseが必要です。
詳細は、公式のFair use Guidelinesをご参照ください。
バックエンド - Convex
Convexの Vector Search が今回の主役。
Embedding済みのベクトルデータを高速でベクトル検索できる機能がデフォルトで備わっている。
この機能を駆使して、類似度の高いWikipedia記事を「例え先」として引っ張ってこられるようにしたい。
Convexにはこのほかにも、
- リアルタイム同期が標準装備
- 強整合性(自動トランザクション)
- 認証・ストレージ・関数が一体化
など便利な機能が多数あるが、今回は Vector Search にフォーカスしたい。
無料枠だと、ストレージ・Vector index・クエリ回数制限があります。
本格的にアプリをリリースする場合は注意が必要です。
参考→Plans & pricing
外部API - Hugging Face
Wikipediaの記事データセットを探していたら、
Upstash/wikipedia-2024-06-bge-m3 を見つけたのでこちらを採用する。
BGE-M3でEmbeddingされたデータセットであるため、ユーザー入力も 同一の
- モデル(BGE-M3)
- 次元数
- 正規化設定
でEmbeddingすることで、同一ベクトル空間上での類似度比較が可能になる。
ユーザー入力文をBGE-M3でEmbeddingする部分は、Hugging Faceの推論API(無料枠)を利用する。
Hugging FaceのAPIは無料枠だとRate Limitがあります。
また、商用利用時にはモデル・エンドポイントごとにライセンス確認が必須です。
🌊 マリアナ海溝への道
1. 記事データの収集
まずは、Convex DB にWikipediaのEmbedding済みのデータを入れるところから。
Hugging Faceの datasetsを使って、Upstash/wikipedia-2024-06-bge-m3からデータを収集してくる。
dataset = load_dataset(
"Upstash/wikipedia-2024-06-bge-m3",
"ja",
split="train",
streaming=True,
)
この結果を整形してjsonlとして保存しておく。
記事全量を取り込むとConvexの無料枠の容量をオーバーしてしまうので、適度な分量に抑えておく。
2. DBにインポート
Convexでは、schema.tsにORM的に型定義をするだけで、勝手にDBのテーブルが生成される。
今回であれば、以下のような定義を書いて、deployコマンドを実行するだけで、開発環境にこの内容のテーブルが自動生成される。🚀
そこにimportコマンドを実行してあげれば、バックエンドの準備は完了だ。
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
wikiArticles: defineTable({
docId: v.string(),
title: v.string(),
text: v.string(),
url: v.string(),
embedding: v.array(v.float64()),
})
.index("by_docId", ["docId"])
.vectorIndex("by_embedding", {
vectorField: "embedding",
dimensions: 1024, // BGE-M3は1024次元
}),
});
# Convexの開発環境へのデプロイ
bunx convex dev
# wikiArticlesテーブルへのインポート
bunx convex import --table wikiArticles ./wiki_bge_m3_data.jsonl
3. ツッコミ精度の向上
この状態でフロントエンドを適当に作って試してみたところ、何を入力しても「曽祢まさこ」さんが出てくるようになってしまった。
どうやら、この記事の「作品リスト」の項目が多種多様なため、どの単語に対してもスコアが高くなってしまうようだ。
そこで、今回の検証ではノイズになる作品リストなどを排除するために、改行率が5%以下のデータのみを採用するようにした。
def is_quality_text(text: str) -> bool:
"""例えツッコミの材料にふさわしい良質なデータかを判断する"""
if len(text) < 50:
return False
newline_ratio = text.count("\n") / len(text)
return newline_ratio <= 0.05 # 5%以下の改行率なら良質なデータ
新しいデータセットをDBに再度importし、改めて同じ文章を入力すると...
トランプの「スペードの女王」へ辿り着けるようになった。
その平民出身の主人公ゲルマンは、大金を求めて人知の限りを尽くすが、愛と友情とを知らぬままナポレオンのごとき野望を持てあまし、二つの固着観念のせめぎあいのなかで(ヴィノグラードフ)ついには発狂して全てを失ってしまう。
うん。これは間違いなく悲劇だ...😭
4. 完成
さらに見た目をポップに整えて、冒頭の「深いなぁ」を入力してあげると...
無事にくりぃむしちゅー上田氏の例えツッコミをConvex Vector Searchで再現することができた!🎉㊗️🥳
まとめ
Convex の Vector Search を使って、Wikipedia(Embedding済みデータ)から“例え先”を引っ張る「例えツッコミジェネレーター」を、無料枠の範囲で試作してみた。
LLMを使わなくても、Embedding + 検索だけで「それっぽい知識の引き当て」は意外とできることが分かった。
改行の多いデータを省いたのと同じように、データセットの精査や、スコアの付け方を工夫すれば、より精度の高い例えツッコミができるようになるだろう。
この記事が、Convexを触ってみるきっかけになれば嬉しい。
この記事は、朝日新聞社の文章校正AI Typoless を使ってチェックされています。
APIプランもあるので、文章チェックの課題をシステムで解決したい方はぜひお試しください!
毎月2万文字まで無料でお使いいただけます!🙌✨




