Skip to content

필사 모드: AIでブログ記事のパイプラインを作る — 初稿ではなく検証がボトルネックです

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

はじめに — 初稿は3分、検証は90分

AIで記事を書き始めると、たいていの人が一度は同じ錯覚を経験します。初稿が3分で出るのだから、記事一本にかかる時間は10分の1に減るはずだ、という期待です。実際にやってみると、初稿は本当に3分で出て、その後が90分です。数字が合っているか確認し、リンクが生きているかクリックして確かめ、引用文が原文に実在する文かどうか照合し、同じ内容を三回違う言い方で繰り返した段落を取り除くのに、それだけかかります。

だからパイプラインを設計するとき、初稿生成を中心に置くと作り方を間違えます。ボトルネックではない場所を自動化しているからです。実際に時間を食う段階は検証であり、改善の余地がもっとも大きいのもここです。初稿の速度を二倍にすれば3分が1分半になりますが、検証を半分に減らせば90分が45分になります。

この記事はプロンプト集ではありません。テーマ収集から成果確認までの七つの段階を実際に回してみて、各段階でモデルが何を得意とし、何を任せると事故が起きるかを切り分けた記録です。AIが書いた記事が崩れる個別の失敗タイプとそれぞれの検知法は次の記事で別途扱い、ここではそれらをふるい落とす流れ自体を見ます。

パイプラインの七つの段階と各段階の失敗コスト

まず全体の地図を置いてから始めます。各段階でAIが実際に価値を生む地点と、渡した瞬間に取り返しが付きにくくなる地点を分けた表です。

段階AIが実際に得意なこと人が必ずやること渡したときの失敗コスト
1. テーマ収集候補を幅広く広げ、既に書いた記事との重複を示す読者にとって価値があるか判断し候補を捨てる低い。悪いテーマは次の段階でふるい落とされる
2. 調査と出典確保検索語の拡張、原文の要約、対立する主張の整理一次出典か確認し、直接開いて見る高い。ここで入り込んだ誤りは最後まで生き残る
3. 初稿構成の提案、白紙画面の解消、説明段落の初版論旨と順序の決定、何を削るかの決定中程度。目立つので編集で捕まる
4. 事実検証主張リストの抽出、引用文位置の照合補助数字・日付・引用・リンクの最終確認最高。公開後に露見すると信頼が壊れる
5. 編集と声のトーン統一重複段落の検知、長さの圧縮、表現候補の提示声のトーン基準そのものの定義と最終判断中程度。読者がすぐ気づく
6. 公開メタデータ生成、リンク・ビルド検査の自動化公開するかどうかの決定と、戻す準備中程度。戻せるなら低くなる
7. 成果確認ログ集計、指標計算、外れ値の指摘指標を次の記事の決定へと変換する解釈低い。ただしやらないと改善が止まる

この表で読み取るべきは個々のマス目ではなくコストの分布です。第2段階と第4段階にコストが集中しています。この二つは自動化しつつも人の承認なしには通過させないようにし、残りは思い切って任せてよいのです。パイプライン設計の大半は、この配分を守ることに尽きます。

テーマと調査 — AIは候補を増やし、人は候補を捨てます

テーマ収集でモデルは発散に強いです。一つの種から二十の切り口を引き出すのは人間より速く、疲れもしません。逆に収束はできません。「このなかでどれが一番いい?」と聞けば、もっともらしい根拠とともに一つを選びますが、その判断には読者が先月何を読んでがっかりしたかという情報が入っていません。候補を増やすのに使い、捨てる作業は自分でやりましょう。

ここで実務的に価値が大きい自動化が一つあります。既に書いた記事との重複検査です。新しいテーマ候補を既存記事のタイトル・要約と照合して重なりを示せば、同じ話を角度だけ変えてまた書いてしまう事故を防げます。これは判断ではなく照合なので、機械が得意とするところです。

調査段階は性格が違います。ここで入り込んだ誤りはパイプラインの最後まで生き残り、後の段階はそれをより一層もっともらしく磨き上げるだけです。だからルールを一つだけ立てるなら、これです。モデルが要約した内容を調査結果として使わないこと。 モデルがやることは、どこを読むべきか教えるところまでで、読むこと自体は人がやります。

実際に守りやすい形に落とすと、こうなります。

  • モデルが出したURLは全部自分で開きます。開かなければ、その主張は丸ごと捨てます。
  • 二次出典(ブログのまとめ記事、ニュース要約)から始めるのはよいですが、引用は一次出典(公式文書、論文、発表文、リリースノート)に差し替えます。
  • 日付のないページは出典として使いません。いつ正しかったのか分からない事実は検証できません。
  • 対立する主張に出会ったら、どちらが正しいかをモデルに聞くのではなく、対立しているという事実そのものを記事に書きます。

最後の項目が実戦で特に役立ちます。この記事の姉妹編でオフィスの単一キーボードショートカットを調べていたとき、マイクロソフトの公式文書どうしが同じ操作に違うキーを案内しているケースに実際に遭遇しました。そのときの答えは一つを選ぶことではなく、「文書が食い違っている」と書くことです。

初稿 — 白紙画面はなくすが、構成は渡しません

初稿段階でのモデルの価値は明確です。白紙画面を前に最初の一文を悩む時間をなくしてくれます。これだけでも十分に役立ち、この段階は間違えてもコストが低いです。おかしければ目立ち、目立てば直ります。

ただし渡してはいけないものが一つあります。構成です。目次をモデルに任せると、ほぼ毎回同じ形が出てきます。定義→長所→短所→事例→結論。この構成は間違ってはいませんが、何も主張しません。記事で読者が記憶するのはたいてい構成が作る順序なのに、その順序を平均値で埋めると、読んだ後に何も残りません。

実務ではこう分けます。H2の見出しと順序は自分で決め、各H2の下に何を書くかを二、三行書いてモデルに渡します。そうすればモデルは段落を埋める仕事をし、論旨は保たれます。逆に「このテーマで記事を書いて」と頼むと論旨のない記事が出ますが、それはモデルができないからではなく、論旨を一度も渡していないからです。

初稿のプロンプトに入れると体感が変わる制約をいくつか挙げておきます。

  • 分からないことは空欄にして印を付けさせます。埋めるなと明示しなければ埋めてしまいます。
  • 数字と固有名詞は提供した資料にあるものだけを使わせます。
  • 段落の長さの上限を与えます。上限がなければ同じ話を引き延ばします。
  • 各H2ごとに「この節で読者が新しく知ることを一行」を先に書かせ、それが前の節と重なるなら節を合体させます。

事実検証 — このパイプラインの重心

ここがこの記事でもっとも重要な節です。前の六段階を雑にやっても、この段階が生きていれば記事は公開に値し、ここがなければ他をどれだけうまくやっても、いつか事故が起きます。

自信ありげに書かれた文と確認済みの文は違います

モデルの出力には確信の度合いが表示されません。学習データで何千回も見た事実と、もっともらしくて今しがた作り出した文が、まったく同じ調子で出てきます。人間の文章では確信がないとき文が揺れるので私たちは無意識にその信号を読みますが、モデルの文章にはその信号がありません。だから「読んでみて自然だ」は検証にならず、むしろ自然であるほど危険です。

特に注意すべき項目は決まっています。数字、日付、バージョン、価格、引用文、人名と所属、そしてURLです。これらはモデルがもっともらしく捏造しやすい項目であると同時に、読者がもっとも簡単に確認できる項目でもあります。他の文が全部合っていても、このうちの一つが間違っていれば記事全体の信頼が一緒に落ちます。

知識のカットオフも同じ場所で問題を起こします。モデルは自分が知らない最新情報を「知らない」と言う代わりに、最後に知っている状態を現在形で語ります。価格、料金プラン、製品名、APIパラメータ、ポリシーの文言のようによく変わるものは、モデルの答えを出発点としてのみ使い、必ず現在の文書で再確認しなければなりません。

モデルが実際に読んだものだけを引用させる方法

「出典を付けて」と頼めば出典が付きます。問題は、その出典が読んだ場所ではなく、もっともらしい場所かもしれないという点です。URLの形式は学習しやすいので、存在しない文書番号や死んだアンカーが自然な形で生成されます。

これを防ぐ方法は、要求を変えることではなく検証可能な形に出力を強制することです。鍵は逐語引用です。要約ではなく原文の文字をそのまま写させれば、その文字列が原文に実在するかを機械が照合できます。

主張一つごとに、この四つを一緒に出させます。

  1. 主張の文そのもの
  2. 出典URL
  3. そのURLの本文から一字一句そのまま取った一文以上の引用
  4. その引用が主張を裏付けると考える理由一行

3番が自動検証の鍵です。引用文がページになければ、その主張は根拠なく作られたものであり、人が読む前にスクリプトが先に捕まえられます。以下はその照合を行う最小実装です。

// verify-claims.mjs — 主張台帳(claims.jsonl)の逐語引用が実際に原文にあるか照合します。
// 各行の形式: {"claim": "...", "url": "https://...", "quote": "...原文そのまま...", "why": "..."}
import { readFileSync } from 'node:fs'

// 空白・引用符・大文字小文字の違いは引用失敗とみなしません。内容が違う場合だけを捕まえます。
const normalize = (s) =>
  s
    .replace(/<[^>]+>/g, ' ')
    .replace(/&[a-z]+;|&#\d+;/gi, ' ')
    .replace(/[‘’“”]/g, "'")
    .replace(/\s+/g, ' ')
    .trim()
    .toLowerCase()

const rows = readFileSync('claims.jsonl', 'utf8')
  .split('\n')
  .filter(Boolean)
  .map((l) => JSON.parse(l))

const cache = new Map()
let failed = 0

for (const [i, row] of rows.entries()) {
  const label = `[${i + 1}] ${row.claim.slice(0, 50)}`

  if (!row.url || !row.quote) {
    console.error(`MISSING ${label} — urlまたはquoteが空です`)
    failed++
    continue
  }

  if (!cache.has(row.url)) {
    try {
      const res = await fetch(row.url, { redirect: 'follow' })
      // リンク切れは引用照合以前にすでに失敗です。
      cache.set(row.url, res.ok ? normalize(await res.text()) : null)
    } catch {
      cache.set(row.url, null)
    }
  }

  const page = cache.get(row.url)
  if (page === null) {
    console.error(`DEAD    ${label}${row.url} を開けません`)
    failed++
  } else if (!page.includes(normalize(row.quote))) {
    // ここがこのスクリプトの存在理由です。もっともらしいが原文にない引用。
    console.error(`NOQUOTE ${label} — 引用文が原文にありません: "${row.quote.slice(0, 60)}"`)
    failed++
  }
}

console.log(`\n${rows.length}件検査、${failed}件失敗`)
process.exit(failed ? 1 : 0)

このスクリプトが捕まえられないものもはっきりさせておく必要があります。引用文が原文に存在していても文脈を切り取られた引用である場合や、引用は正しいがそれが主張を裏付けていない場合は通過します。だから4番の項目(理由一行)を人が読む手順は依然として必要です。ただし機械が前段でふるい落としてくれれば、人が読む量は大きく減ります。実際にこの照合を導入してから人の検証時間は目に見えて減りましたが、捏造された引用を探して原文を読み込む作業がなくなったためです。

公開直前チェックリスト

以下は公開ボタンを押す前に実際に回すリストです。機械ができることと人がやるべきことを分けてあります。

項目確認方法自動化
すべての外部リンクが開くかレスポンスコードの確認可能
引用文が原文に一字一句あるか逐語照合スクリプト可能
内部リンクが実際の経路を指しているかファイル存在確認可能
数字と日付が出典と一致するか原文との目視照合不可能
時点に依存する記述があるか「最新」「現在」「今年」などの表現を検索して判断部分的に可能
引用が文脈を歪めていないか原文の前後の段落を読む不可能
根拠なく断定した文があるか断定的な語尾を検索して根拠を確認部分的に可能
同じ内容を繰り返した段落があるか段落類似度を測って判断部分的に可能
自分がこの記事を説明できるか読まずに要旨を言ってみる不可能

最後の項目は形式的に見えて、実際にもっともよくふるい落とします。記事を見ずに核心の主張を言おうとして詰まるなら、その部分は検証したのではなく、通過させただけです。

編集・公開・成果確認 — 声のトーンを統一し、戻せるようにします

編集段階でモデルに任せられるのは検知であり、任せられないのは基準です。「この記事は自分の声か」をモデルは判断できません。学習した平均的な文章の質に収束させようとするため、任せると文は滑らかになり、記事は他人のものになります。

代わりに声のトーンをルールとして書き下しておけば機械が検査できます。使わない単語のリスト、段落の長さの上限、感嘆表現の禁止、特定の接続詞の多用禁止といったものです。これは好みではなく検査可能な条件なので自動化できます。逆に「もっと自然に直して」は検査条件ではなく好みの委任です。

公開段階で重要なのは速度ではなく戻せることです。記事はコードと違い、公開後に誤りが露見してもロールバックが静かには済みません。すでに読んだ人がいて、引用された場合もあります。だから公開自体を自動化するとしても、戻す経路を先に作っておくほうがよいです。訂正の履歴を記事のなかに残すルールをあらかじめ決めておけば、事故が起きたときに静かに直したくなる誘惑を避けられます。

成果確認段階では、指標を絞ることがコツです。閲覧数は次の記事を変えません。実際に決定を変えるのは、滞在時間の分布(最初の画面で離脱する割合)、検索流入クエリと記事タイトルのずれ、そしてどの節でスクロールが止まるかくらいです。特に検索クエリと内容のずれは次の記事のテーマを直接教えてくれるので、一つだけ見るならこれを勧めます。

ここでGoogleのポリシーを一度押さえておく必要があります。GoogleはAIで作ったという理由でコンテンツに不利益を与えないと明示しており、判断基準は生成手段ではなく読者に価値を与えるかだと検索セントラルの文書で述べています。ただし、順位を目的として価値のない記事を大量生産する行為はスパムポリシーで大量生成コンテンツの濫用として明示的に禁止されています。まとめると、パイプラインの目標を「たくさん作ること」に据えた瞬間、ポリシーの反対側に立つことになります。

自動化のスケッチ — 止まれる地点を残したワークフロー

全体を一つにまとめると、下のような形になります。重要なのは自動化の範囲ではなくどこで止まるかです。このワークフローは検証ゲートを通過しなければ公開段階に進まず、人の承認なしには初稿が公開ブランチに触れません。

# .github/workflows/content-gate.yml
# 初稿のPRが開くと、機械ができる検証を全部回しますが、通過しても自動マージはしません。
name: content-gate

on:
  pull_request:
    paths: ['data/blog/**/*.mdx']

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: ビルド安全性 — MDXが実際にコンパイルされるか
        run: node scripts/check-posts.mjs

      - name: 内部リンク — 指す経路が存在するか
        run: node scripts/check-links.mjs

      - name: 逐語引用照合 — 引用文が原文に実在するか
        run: node scripts/verify-claims.mjs

      - name: 時点依存表現 — 人が判断すべき箇所を示すだけです
        run: |
          # 失敗にはしません。検証ではなくレビュー誘導用のシグナルです。
          grep -nE '最新|現在|今年|去年|最近|もっとも早い|業界初' data/blog/**/*.mdx \
            | tee /tmp/time-sensitive.txt || true
          echo "上の表現はカットオフ以降の事実である可能性があります。レビュアーが直接確認してください。"

      - name: 段落の重複 — 類似度上位のペアだけ抽出して報告
        run: node scripts/find-duplicate-paragraphs.mjs --top 5 || true

  # 人の介入地点: 上の検証が全部通っても、ここで止まります。
  # 承認はGitHubのレビュー承認で受け、ワークフローが代わりに承認することはありません。

ここで意図的にやっていないことが二つあります。

第一に、検証の通過を公開トリガーとして使いませんでした。 機械の検証は「公開してよい」ではなく「明白な事故はない」までしか言ってくれません。自動マージを付けた瞬間、チェックリストの最後の三項目(文脈の歪み、断定、説明可能性)がパイプラインから消えます。

第二に、時点依存表現の検査を失敗扱いにしませんでした。 この検査は精度が低いので、失敗にするとすぐ無視されるようになり、無視されるゲートはないゲートより悪いです。人にどこを見るべきか教える役目までにとどめるほうが長続きします。

おわりに — 自動化する価値があるのは生成ではなく判定です

AIコンテンツパイプラインを作るとき、先に手が伸びるのは生成です。結果が目に見え、作るとすぐ速くなった感じがするからです。しかし実際に時間を返し、事故を防いでくれるのは判定のほうです。引用が実在するか、リンクが生きているか、同じ話を繰り返していないかを機械が先にふるい落としてくれれば、人は機械にできないことだけに時間を使えます。

そして機械にできないことは、思ったより少なく明確です。引用が文脈を歪めていないか、このテーマが読者にとって価値があるか、そしてこの記事の論旨が自分のものか。この三つは最後まで人の仕事であり、パイプラインがよくできていれば、この三つに使う時間が残っているはずです。

一行にまとめるとこうです。初稿を信用できないのではなく、確認していない初稿を信用する根拠がないだけです。

参考資料

현재 단락 (1/144)

AIで記事を書き始めると、たいていの人が一度は同じ錯覚を経験します。初稿が3分で出るのだから、記事一本にかかる時間は10分の1に減るはずだ、という期待です。実際にやってみると、初稿は本当に3分で出て、...

작성 글자: 0원문 글자: 8,897작성 단락: 0/144