◉GEMINI LABEN
●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — deep-research-pro-preview-12-2025 は 10/23 に停止、残り6日。移行先は deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●MCP — ツール結果が 8.5万トークンに膨らんだ事例を、ADK で 310 トークンに包んで抑えた報告が出ています●FLASH — gemini-3.7-flash と 3.5-flash は新しい Flash モデルに自動で回されます(10/08)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — deep-research-pro-preview-12-2025 は 10/23 に停止、残り6日。移行先は deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●MCP — ツール結果が 8.5万トークンに膨らんだ事例を、ADK で 310 トークンに包んで抑えた報告が出ています●FLASH — gemini-3.7-flash と 3.5-flash は新しい Flash モデルに自動で回されます(10/08)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…
記事一覧/API / SDK
◈ API / SDK/2026-05-27中級

Gemini API で個人ブログの内部リンク整合性を2ヶ月チェックさせた所感

Lab 系4サイトの内部リンク整合性チェックを2ヶ月 Gemini に任せて運用した実装メモ。grep だけでは拾えなかった文脈不一致を Gemini 2.5 Flash でどう仕分けたか、運用コストとつまずいた点を書きました。

Gemini API248Gemini 2.5 Flash5個人開発121内部リンク運用自動化コンテンツ品質

Lab 系の 4 サイトを並行運用していると、記事数が増えるほど厄介になる作業が一つあります。MDX 本文に書いた内部リンクが、実在する記事を指しているかどうかの確認です。Claude Lab と Gemini Lab だけで合わせて 1,700 本近く、4 サイト合計では 3,000 本を超える記事があり、Markdown 本文の中に ~ 形式のリンクが散在しています。ビルド時にいくつかの仕組みで弾くことはできますが、それでも拾い切れない日があります。

この内部リンクの整合性チェックを、2 ヶ月ほど Gemini 2.5 Flash に任せてみました。期待した精度には届かない場面もありましたが、運用に組み込むと「自分では絶対に気づかない種類の不整合」を拾ってくれるという発見がありました。今日はその実装と、運用してみて見えてきた所感をまとめます。

なぜ Gemini に任せたか

最初は単純な grep スクリプトで充分だと思っていました。コンテンツディレクトリから /articles/(category)/(slug) 形式の文字列を全部抽出し、対応する MDX ファイルが実在するかを確認すれば終わりです。実際、それで 95% のケースは弾けます。

ところが残りの 5% に、機械的なファイル存在チェックだけでは見抜けないものが混ざります。例を 3 つ挙げます。

  1. リンク先のスラッグは実在するが、書いている文脈とまったく関連しない記事を指している
  2. アンカーテキストが「Gemini Code Assist の導入」なのに、リンク先は「Gemini for Workspace の請求設定」になっている
  3. 同じトピックを扱った記事が 3 本ある中で、最新版ではない古い記事に飛ばしている

このあたりは「文脈を読む」必要があり、grep の領分を越えます。両家の祖父が宮大工だったこともあって、組み上げたものが何十年も残るかどうかは細部の仕舞いで決まる、という感覚が体に残っています。リンクの精度は読者の信頼に直結するので、ここに時間を使うのは惜しくないと判断しました。

構成

実装は単純です。記事ごとにリンクを抽出し、リンク先記事の冒頭と現在記事の前後文脈を一緒に Gemini に渡し、関連度を JSON で返してもらいます。

import google.generativeai as genai
import re, pathlib, json
 
MODEL = "gemini-2.5-flash"
LINK_RE = re.compile(r"\[([^\]]+)\]\(/articles/([^/]+)/([^)]+)\)")
 
def collect_links(article_path: pathlib.Path):
    text = article_path.read_text(encoding="utf-8")
    return [
        (m.group(1), m.group(2), m.group(3), text)
        for m in LINK_RE.finditer(text)
    ]
 
def review_link(anchor, category, slug, body, target_excerpt):
    prompt = f"""
あなたは技術ブログのエディタです。次のリンクの妥当性を JSON で返してください。
 
アンカーテキスト: {anchor}
元記事の前後200字: {body[:200]}
リンク先記事の冒頭400字: {target_excerpt[:400]}
 
評価軸:
- relevance: 0.0〜1.0 の数値(文脈関連性)
- anchor_match: true/false(アンカーがリンク先の内容と一致するか)
- replacement_hint: 不一致なら何に置き換えるべきかの示唆(文字列、なければ空)
 
JSON だけを返してください。
"""
    model = genai.GenerativeModel(
        MODEL,
        generation_config={"response_mime_type": "application/json"},
    )
    resp = model.generate_content(prompt)
    return json.loads(resp.text)

response_mime_type="application/json" を有効にしておくと、後段の json.loads で詰まることがほとんどなくなります。最初は gemini-2.5-pro で全リンクを回していましたが、判定の質と単価のバランスを見ると Flash のほうがこの用途には合いました。Pro に再投票させるのは relevance が 0.3〜0.7 のグレーゾーンに入った 5% 程度に絞り、明確な不一致は Flash で即決しています。

判定結果は YAML ログとして書き出し、サイトごとの _link_review/YYYY-MM-DD.yml に貯めています。同じ URL を翌日にもう一度回すような無駄を避けるため、過去 7 日間に判定済みのリンクはスキップする仕掛けを足しました。

2ヶ月運用して見えたこと

毎晩 02:30 JST にバッチで走らせ、当日 push された記事の内部リンクだけを対象にしています。4 サイト合算で 1 日あたりおよそ 60〜80 リンク。token 単価で見るとひと月 1,000 円前後で済んでいます。個人開発の運用費としては許容範囲です。

明確な誤判定もありました。Gemini は同義語に厳しすぎる傾向があり、「Function Calling」と「ツール呼び出し」を別物として扱ってしまう日があります。閾値を緩めると今度はノイズが増える。このバランス調整は今も手で詰めている最中です。

一方で、想定以上の収穫もありました。たとえば「公式ドキュメントへの外部リンクが古いバージョンの URL を指している」というケースを、内部リンクのチェック中に副次的に拾ってくれたことがあります。プロンプトには「内部リンクの妥当性を見て」としか書いていないのですが、リンク先の冒頭を読み込んだ際に「このページは古いと注釈が出ています」と Gemini が返してきました。これは grep ではまず気づけません。

もう一つ、自分の記事の癖を Gemini に客観視してもらえた点も収穫でした。「同じ記事で『個人開発』『個人事業』『インディーデベロッパー』を混在させている」「アンカーテキストにスラッグそのまま使っている箇所がある」といった指摘が、レビュー結果のメタコメントとして時折出てきます。指示していないのに拾ってくれる、というのは Pro よりも Flash の方が頻度が高かったように感じます。

自分の運用に取り入れるなら

同じ仕組みを試したい場合、いきなり全記事に流すのではなく、まず直近 1 ヶ月の記事に絞ることをお勧めします。古い記事までスコープを広げると、過去の自分が書いた文体や用語の揺れに引っ張られて、Gemini の判定が安定しません。

もう一つ大事だと感じたのは、判定結果を「自動修正」ではなく「レビュー候補リスト」として書き出すことです。テキストの差し替えは最終的に人の目で確認した方が安全で、特に技術用語の精度を保ちたいブログでは差し戻しの判断は自分でやる方がしっくり来ます。私は朝のコーヒーを淹れている数分で前夜のレビュー候補リストに目を通し、明らかな不一致だけその場で修正する運用に落ち着きました。

コスト管理の面では、gemini-2.5-flash-lite も一度試しました。単価は確かに安いのですが、文脈関連性の判定がブレやすく、relevance のスコアが 0.5 付近に偏る傾向が出ました。リンク整合性チェックのように「白黒つけたい」用途では、Flash で固定したほうが結果的に運用が楽でした。

次に取り組むこと

次は同じパイプラインを Crashlytics のクラッシュレポート分類に流用しようと考えています。Claude in Chrome で取得した日次レポートを Gemini に投げて、影響範囲と緊急度を分類させる仕組みです。2014 年から個人でアプリを出してきて、何度かクラッシュ対応が後手に回った苦い経験があるので、ここは自動化の優先度が高い領域だと感じています。

リンク整合性チェックは目立たない作業ですが、地味に効きます。読者がリンクをクリックして「期待した内容と違う」と感じる回数が少しでも減れば、それは結果的に検索エンジンが評価する滞在時間にも返ってくるはずです。同じような運用をされている方の参考になれば嬉しいです。最後までお読みいただきありがとうございました。

シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

◈ API / SDK2026-05-06
Gemini 2.5 Flash を1ヶ月使い続けた個人開発者の正直レポート — 費用・速度・品質の実態
Gemini 2.5 Flash を個人開発で1ヶ月使い続けた実測レポートです。実際にかかった API 費用、速度の揺れ幅、品質が足りないと判断した2つの場面、Flash と Pro の切り替え判断フレームワーク、コスト上限アラートの設定まで数字で示します。
◈ API / SDK2026-09-29
『F6号』と『A4くらい』が同じ列に並ぶ作品台帳を、Gemini の読み取りと号数表の換算で cm に揃えるまで
作家さんの作品台帳に『F6号』『41×31.8cm』『A4くらい』が混ざっていました。Gemini API には読み取りだけを頼み、換算は号数表、向きは画像で決める小さな道具を、動くコードとともに一本ずつ組み立てます。
◈ API / SDK2026-09-11
文字起こしの固有名詞が直らないとき、カスタム語彙に何を入れて何を諦めるか
gemini-3.5-transcribe の custom_vocabulary は最大1,000語ですが、枠を埋めることが目的ではありません。誤認ログの正解と出力の対から、枠を渡す語だけを選び直す60行のスクリプトと、その判断基準をまとめます。