Ralph Wiggum Loop でコンテンツを作る
build が通ってもコンテンツの品質は保証されない。AI がコンテンツを生成するときに必要だった独自の検証要件の話
← 前の記事: Ralph Wiggum Loop でサイトを自動構築するコンテンツを作ってほしかったのに、ドメインを作り始めた
前回まで、bash スクリプトで Ralph Loop を組んで Next.js のサイト構造を自動構築する仕組みを作った。claude -p を while ループで回し、build/test/lint が全部通るまでやり直させる——というやつだ。
構造ができたら次はコンテンツだ。ブッダイズム。というカテゴリの記事を書いてほしい、と思った。
ところが AI はまず、ドメインの構築を始めた。ルーティングを作り、レイアウトを定義し、ページの骨格を整えた。
最初は「頼んだこととちょっと違うのでは」と感じた。でも考えてみれば当然だった。MDX ファイルを置く場所がなければコンテンツは書けない。content/buddhaism/story/index.mdx を置いても、それを読み込むページが存在しなければ何も表示されない。型を先に作り、その上にコンテンツを流し込む——この順番でないと動かない。
だから ralph_loop_buddhaism_domain.toml には npm run build チェックが入っている。ドメインの骨格が壊れていないことを確認してから、次のコンテンツ生成フェーズに進む。score_threshold = 70 で build が通れば合格だ。
[checks]
items = [
{ name = "build", command = "npm run build", score = 70 },
]build が通った。でもコンテンツの検証になっていない
ドメインの型ができた。次に記事を生成するループを回した。build が通った。OK 判定。
——のだが、ここで気づいてしまった。「build が通っただけで、コンテンツの中身は何も検証していない」。
build/test/lint はコードの整合性を見るためのものだ。TypeScript の型が合っているか、コンポーネントが正しく import されているか、フォーマットが崩れていないか。コンテンツを置いたとき、それが「ちゃんとした記事になっているか」は何も見てくれない。
- frontmatter に必須フィールドが揃っているか
- 本文に必要なセクションが存在するか
- 文字数が最低限を満たしているか
- 法的に問題のある表現が入り込んでいないか
こういうことを build は教えてくれない。前回うまくいった「採点基準」が、コンテンツ生成には全く効かなかった。
カスタムチェックスクリプトを作る
コンテンツに合った検証が必要だ。だったら自分で書けばいい——というわけでシェルスクリプトを作った。
たんぱくパスタのレシピ MDX 用(check-pasta-recipe.sh)を例にすると、やっていることはこうだ:
frontmatter 必須フィールドのチェック。title・description・type・protein・cookTime・items・nutrition が揃っているか。これらが欠けていると、ページのカード表示が崩れる。コードのビルドは通るが、UI が壊れる。
必須セクションの存在確認。材料、作り方、ポイント、たんぱく質——4つのセクションが本文にあるか。grep で見出しを探すだけだ。
文字数の上下限。800〜3000字に収まっているか。短すぎれば中身が薄い。長すぎれば読まれない。
禁止薬事表現のチェック。整腸、免疫力、疲労回復、脂肪燃焼、デトックス、に効く——これらが本文に入っていたら即アウト。
for claim in "整腸" "免疫力" "疲労回復" "脂肪燃焼" "デトックス" "予防する" "改善する" "に効く"; do
if grep -q "$claim" "$FILE"; then
echo "FAIL: Prohibited health claim found: $claim"
ERRORS=$((ERRORS + 1))
fi
doneファイルパスを引数で受け取る設計にしたから、レシピが何十個あっても同じスクリプトで回せる。TOML の [checks] にファイルごとのチェック項目を並べてスコアで重み付けし、build が 30 点、各レシピが 35 点の計 100 点で score_threshold = 100。全部通らないと合格にならない。
薬事表現の禁止——心配だったから機械に守らせた
食品サイトで「免疫力アップ」「疲労回復に効く」と書くと、薬機法に触れる可能性がある。食品に具体的な健康効能を断定することが法律上まずい、という話だ。
AI はこれを知識として持っている。でも指示しなければ平気でそういう表現を生成する。「たんぱく質が豊富で疲労回復に効果的なパスタです」——これくらいは普通に出てくる。
心配だったのでチェック項目に入れた。grep で禁止ワードを検出するだけのシンプルな仕組みだ。ひっかかればループがやり直しを指示し、Claude は「FAIL: Prohibited health claim found: 疲労回復」というエラーを受け取って表現を修正して出し直す。
CLAUDE.md にも「健康表現の法的制約」セクションを書いた。チェックスクリプトとの二重の安全弁だ。チェックスクリプトがすり抜けを防ぎ、CLAUDE.md がそもそも生成させないようにする。
人間が心配したことを、ルールに落として機械に守らせる。コンテンツ自動化でやりたかったことの一つがこれだった。
対話形式のストーリー記事——形式まで検証する
たんぱくパスタのストーリー記事はちょっと変わった形式で書いている。科学者が食材と対話する、みたいなエッセイだ。「」が会話で、()が心の声。
check-pasta-story-dialogue.sh はこの形式を検証する。文字数だけでなく、「」の出現行数(最低3行)と()の出現行数(最低1行)までカウントする。
DIALOGUE_COUNT=$(grep -c '「' "$FILE")
if [ "$DIALOGUE_COUNT" -lt 3 ]; then
echo "FAIL: Too few dialogue lines: ${DIALOGUE_COUNT} (min 3)"
ERRORS=$((ERRORS + 1))
fi
THOUGHT_COUNT=$(grep -c '(' "$FILE")
if [ "$THOUGHT_COUNT" -lt 1 ]; then
echo "FAIL: No inner thoughts found (need at least 1 line with ())"
ERRORS=$((ERRORS + 1))
fiAI に「会話形式で書いて」と指示しても、ときどき普通の解説文が返ってくる。形式の指示を忘れてコンテンツに没頭してしまうらしい。人間のライターみたいな失敗をする。
形式のルールを検証項目に落とし込めば、やり直しが自動で回る。「内容の品質」ではなく「形式の守備」をチェックスクリプトに任せる——内容が良くても形式が崩れていたらダメ、という基準を3行のシェルスクリプトで表現できる。
用途ごとに線引きが変わる
やってみて、使い分けが見えてきた。
コード構築のフェーズ(ルーティング、コンポーネント作成)では、build + test + lint で十分だ。コードの整合性さえ確認できれば、構造の正しさは検証できる。ralph_loop_buddhaism_domain.toml がそれで、score_threshold = 70 で build が通れば次に進む。
レシピや食材 MDX の生成では、カスタムスクリプトが必要になった。frontmatter・セクション・文字数・禁止表現——コードのチェックでは見えないものを検証する。
記事執筆(ブッダイズム。の読み物コンテンツ、この labo 記事)は、チェックなしで1回生成して人間が直す。ralph_loop_buddhaism_article0.toml の score_threshold = 0 がそれだ。記事の「良し悪し」を機械で判断するのは難しく、最終的に読んで判断するのは人間だ。
用途ごとに「何を自動で見て、何を人間が見るか」の線引きが違う。 全部を自動化するのは無理だし、全部を手動で見るのも非効率だ。この線引きを決めることが、コンテンツ自動化の実質的な設計作業だったと思う。
チェックスクリプトを書きながら、「これは品質基準の外部化だ」と感じた。「良いレシピとは何か」——ふだんは頭の中にある基準を、シェルスクリプトというテキストに書き出す作業だ。文字数の下限は 800 字と決めたが、その根拠は何か。会話が3行以上というのは、本当に「対話形式」の最低条件なのか。AI ループを作ることで、自分の品質基準を言語化せざるを得なくなった。予想外に面白い副産物だった。