un tronc
Claude Code

Workers AIでブログをベクトル検索して比較

こんにちは!アントロンのNaokoです。

前に読んだブログや記事に、悩みのヒントが書いてあった気がする。でも、検索しても見つからない。そんなことはありませんか?

私は、読んできた記事を、自分の悩みをふだんの言葉で質問して探せるようにしたくて、この仕組みを作りました。

文章をベクトル(文章を表す数値の並び)にするのは Cloudflare Workers AI の bge-m3、検索結果から答えをまとめるのは Claude Code(AI に作業を頼めるアプリ)です。

アントロンBLOGの公開済み記事で2つの質問を試すと、検索方法によって上位に出る文章が変わりました。ただし、この比較だけで、どの検索方法が優れているかまでは決められません。

使った構成と実装条件、検索の比較、答え方の実演を紹介します。

言葉の一致だけでなく、文章の近さで探す

今回作ったキーワード検索は、質問から取り出した言葉が文章に入っているかで探します。質問と記事で言い方が違うと、その言葉では見つけられません。

そこで、記事と質問をそれぞれベクトルにして、意味が近い文章を上から並べるベクトル検索も使いました。

記事をチャンク(記事を区切った短い文章)に分け、ベクトルを保存します。見つけた文章をもとに AI が答える RAG の仕組みです。検索結果はチャンク単位で数えています。

私1人で使うので、検索サーバーは置かなかった

使うのは私1人だけで、公開する用途でもありません。検索サーバーは置かず、チャンクとベクトルをファイルに保存し、自分の PC で読み込んで探します。

使ったものは次のとおりです。

  • Cloudflare のアカウント
  • wrangler(Cloudflare の開発用ツール)
  • Python と NumPy(数値計算のライブラリ)
  • Claude Code

やったこと1:文章をベクトルにする Worker を動かす

Cloudflare Workers AI(Cloudflare 上で AI のモデルを呼べるサービス)の @cf/baai/bge-m3 を使いました。

文章を受け取り、ベクトルを返す Worker(小さなプログラム)を、Claude Code に書いてもらいました。

export default {
  async fetch(request, env) {
    if (request.method !== 'POST') return new Response('POST only', { status: 405 });
    const { texts } = await request.json();
    if (!Array.isArray(texts) || texts.length === 0) return Response.json({ error: 'texts が空' }, { status: 400 });
    const r = await env.AI.run('@cf/baai/bge-m3', { text: texts });
    return Response.json({ vectors: r.data, shape: r.shape });
  },
};

この Worker は本番に上げず、自分の PC で wrangler dev(開発用コマンド)を使って動かしています。設定ファイル wrangler.toml の該当部分は次のとおりです。

[ai]
binding = "AI"
remote = true

[dev]
port = 8799

remote = true により、AI の処理は Cloudflare 側で動きます。ベクトルにする文章は Cloudflare に送られ、Workers AI の利用量に入ります。

開発時の動作は Cloudflare Docs の開発・テストの案内、料金は Workers AI の料金(Cloudflare Docs)で確認できます。利用量の考え方は、Workers AIの無料枠は1日何回?にも書きました。

手元で wrangler dev を動かし、文章をベクトルにする Worker が http://127.0.0.1:8799 で待っている画面

やったこと2:記事を分けて、ベクトルを保存する

チャンクを作る Python のスクリプトも、Claude Code に書いてもらいました。実装条件は次のとおりです。

  • 記事の行の切れ目で、400〜700字くらいを目安に分ける
  • 前のチャンクの最後の2行を、次のチャンクの頭にも入れる
  • ベクトルにするときは、記事のタイトルをチャンクの頭に付ける
  • チャンクの本文は元の記事の行のまま残し、日付・タイトル・URL・行番号も持つ

Worker には32件ずつ送ります。返ってきたベクトルは長さを1にそろえる正規化をしてから保存します。質問のベクトルも同じ処理で正規化し、保存したベクトルとの内積で近さを計算します。

アントロンBLOGの公開済み記事38本は、291チャンクになりました。保存したファイルは、チャンクの一覧 chunks.jsonl と、ベクトルの vectors.npy です。

やったこと3:2つの質問を3通りで比較した

2026年10月12日、同じ質問を次の3通りで探し、上位5チャンクを比較しました。

  • キーワード検索:漢字・カタカナ・英数字は2文字以上、ひらがなは3文字以上のつながりを質問から取り出し、本文に含まれる語で順位を付ける
  • ベクトル検索:質問と各チャンクのベクトルの近さで順位を付ける
  • ハイブリッド検索:両方式の上位20件を使い、RRF(順位を点にして足し合わせる方法)で並べ直す。各順位の点は 1 ÷(60+順位)

質問

キーワード検索

ベクトル検索

ハイブリッド検索

AIに毎日の作業を任せたい

Claude Code の定期実行、Instagram のストーリーズ、Workers AI の無料枠の記事のチャンク

5件とも AI 導入の記事のチャンク

AI 導入の記事が2件、Workers AI の無料枠の記事が3件

ブログを書いてもSNSで知らせ忘れる

1位は Facebook への自動投稿。2位以下にスクリーンショットのぼかしや AdSense の記事

上位3件は Facebook への自動投稿と Instagram のストーリーズ。4・5位はスクリーンショットのぼかし

1〜3位は Facebook への自動投稿、スクリーンショットのぼかし、Instagram のストーリーズ。4位は Contact Form 7、5位は Facebook への自動投稿

アントロンBLOGの公開済み記事で、同じ質問をキーワード検索・ベクトル検索・両方を合わせたもので探した上位を並べた画面

1問目のキーワード検索1位は、定期実行の記事の99〜102行でした。そこには次の相談案内が含まれています。

> AI に毎日の作業を任せる仕組みづくりのご相談は、お問い合わせフォームからどうぞ。

一方、ベクトル検索4位のチャンクには、次の行がありました。

> ステップ1:任せる仕事を1つだけ選ぶ

AI導入の記事の8〜21行で、任せる仕事を選ぶ条件が続きます。つまり、キーワード検索でも質問に近い言葉は見つかっていますが、相談案内と仕事を選ぶ説明では、読める内容が違います。記事名や順位だけでなく、返された本文を見る必要があります。

また、ベクトル検索の5件は、5つの別の記事ではありません。同じ記事のチャンクです。ハイブリッド検索では別の記事も入りましたが、それだけで答えの質が上がったとは判断できません。

2問目は、Facebookへの自動投稿の記事が、どの方式でも1位でした。そのチャンクには、次の行があります。

> 記事を書いても、SNSで知らせるのを忘れる

今回のキーワード検索が取り出した語は、1問目が AI・毎日・作業・せたい、2問目が ブログ・いても・SNS でした。単語の途中で切れた語も含まれています。

この簡易的な語の取り出し方と2問の結果を、キーワード検索全般の評価には広げられません。今回確認できたのは、同じ資料と質問でも、方式によって上位のチャンクが変わることです。

やったこと4:引用・出典・AI のまとめを分ける

Claude Code のスキル(決まった手順をまとめたファイル)には、検索順位だけで答えを決めず、候補の全文を読んで選ぶ手順を書きました。

ベクトル検索とキーワード検索から上位10件ずつを渡します。キーワードは、質問の言葉と、書いた人が同じことを書くときの言葉を2組に分けて探すようにしています。

答え方にも、次の決まりを書きました。

  • 引用はチャンクの連続した行をそのまま写し、1文字も変えない
  • 引用の下に日付・タイトル・URL を付ける
  • 最後に まとめ(Claude) を1行付け、引用にあることだけをつなぐ
  • 答えが見つからなければ 見つからなかった と書き、探した言葉を添える

AI が言い換えた文を、書いた人の言葉として読んでしまうのを避けるためです。

下の実演では、アントロンBLOGのデータを渡し、比較の上位から質問に合うチャンクを1つ選ぶ短い指示を使いました。画面には、AI 導入の記事の8〜21行の引用、日付・タイトル・URL、AI のまとめが返っています。

この実演は、上位10件ずつを渡してキーワードを2組に分けるスキル全体の検証ではありません。

アントロンBLOGのチャンクを Claude Code に渡して「AIに毎日の作業を任せたい」と質問し、引用・出典(日付・タイトル・URL)・まとめ(Claude)の1行で答えが返った画面

人の文章を使うときの扱い

ふだん探している記事には、購入した有料の記事も含まれます。記事や検索結果を公開せず、自分の用途で使っています。

ただし、ベクトル化する文章は Cloudflare に送られます。自分だけで使うことと、外部に送らないことは別です。

答えは引用と出典で受け取り、元の記事を開いて確かめる方針です。

探せなかった悩みを1つ書き出す

前に読んだはずなのに見つからなかった悩みを、1つ書き出してみてください。今回の比較では、質問の語の取り出し方と、検索された本文の両方を見ることが判断材料になりました。

自分の記事や資料を探す仕組みについてのご相談は、お問い合わせフォームからどうぞ。

最後まで読んでくださりありがとうございました!

コメント