はじめに
⚠️ 本記事のコードはサンプルです。実際の認証情報・設定値は含まれていません。
私はClaudeCodeNaviというClaude Code特化のプラットフォームを運営しています。MCPサーバー経由でAIに記事を書いてもらう機能があるのですが、ひとつ問題がありました。
AIが書く記事、テンプレ感がすごい。
「以下で詳しく解説します」「いかがでしたでしょうか」──こういう定型文が並ぶ記事が量産されてしまう。noteの深津さんが「推しアルゴリズム」の話をしていたのを見て、自分のプラットフォームでも品質を暗黙的に底上げする仕組みを作ろうと思いました。
実際に作った3層構造
Layer 1: MCPツール定義にガイドラインを埋め込む
MCPのツールには description フィールドがあります。AIはツールを呼び出すとき、このdescriptionを必ず読みます。
{
"name": "create_post",
"description": "記事を投稿します。\n\n【Google E-E-AT準拠 品質ベストプラクティス】\n- Experience: 一次情報・実体験ベースの記事が高評価\n- Expertise: 具体的なコード例・エラーログを含める\n- 煽り系タイトルはSEOペナルティ対象"
}
ポイントは、これを「SEOベストプラクティス」として書くこと。嘘ではないし、AIは素直にこのガイドラインに従ってコンテンツを生成します。ユーザーがMCPのツール定義をわざわざ読むことはまずないので、ステルスに品質誘導ができます。
Layer 2: サーバーサイドでサイレントスコアリング
投稿時にバックエンドで0-100点の品質スコアを自動計算してDBに保存します。ただし、APIレスポンスには含めません。
function calculateQualityScore(string $body, string $title, string $type, array $tags): int
{
$score = 0;
// 一次情報指標(+15点)
// 「私は」「試した」「失敗した」等の体験表現
$score += calcFirsthandScore($bodyText);
// 具体性指標(+15点)
// コードブロック数、数値データ、技術用語
$score += calcSpecificityScore($body, $bodyText);
// 煽りパターン検出(-20点)
// 「ヤバい」「知らないと損」等
$score -= calcClickbaitPenalty($title, $bodyText);
return max(0, min(100, $score));
}
実際のテスト結果:
| コンテンツ | スコア |
|-----------|--------|
| 体験談+コード+まとめのある技術記事 | 75点 |
| 見出しだけで中身が薄い記事 | 37点 |
| 煽りタイトル+テンプレ文の記事 | 0点 |
このスコアは将来の検索ランキングや推薦アルゴリズムで使います。
Layer 3: SEO警告に偽装した品質ナッジ
既存のSEOチェック機能に、品質関連の提案を混ぜます。
function checkQualityNudges(string $body, string $title, string $contentType, array $tags): array
{
$nudges = [];
if (!$hasFirsthand) {
$nudges[] = 'Google E-E-A-Tスコア向上: 具体的な体験や実例の追加を推奨します';
}
if (!preg_match('/```/', $body)) {
$nudges[] = 'SEO改善: コードブロックがありません。技術記事では具体的なコード例があるとクリック率が向上します';
}
return $nudges;
}
ユーザーには「SEOのための警告」に見えますが、実質的にはコンテンツ品質の向上を促しています。「Google E-E-A-T」という権威ある名前を出すことで、AIもユーザーも素直に従ってくれます。
なぜ「ステルス」にするのか
公開ルールにすると、ゲーミングされます。「体験表現を入れればスコアが上がる」とわかれば、AIに「『私は〜を試しました』を冒頭に入れて」と指示する人が出てくる。
noteの深津さんも同じ考えで、noteの推薦アルゴリズムの詳細を公開していません。ルールを公開すると、そのルールを攻略するだけのコンテンツが生まれてしまう。
大事なのは「良いコンテンツを書こうとする人が自然と報われる」仕組みであって、「スコアを上げるためのテクニック」ではないということです。
DB設計
4つのテーブルに quality_score カラムを追加しました。
ALTER TABLE articles ADD COLUMN quality_score TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER status;
ALTER TABLE questions ADD COLUMN quality_score TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER status;
ALTER TABLE services ADD COLUMN quality_score TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER status;
ALTER TABLE works ADD COLUMN quality_score TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER status;
CREATE INDEX idx_articles_quality ON articles (quality_score);
TINYINT UNSIGNED で0-255の範囲。100点満点なので十分です。インデックスも張っておくことで、将来のランキングクエリも高速に回せます。
1日の投稿制限との組み合わせ
ClaudeCodeNaviでは checkRateLimit() で1日10件の投稿制限をかけています。
checkRateLimit($user['id'], 10, 86400, 'article:create');
品質スコアと組み合わせることで、「量より質」の方向にユーザーを誘導できます。1日10件しか投稿できないなら、1件1件の質を上げようという動機が生まれる。そこにステルスな品質ガイドラインが加わることで、自然と高品質なコンテンツが集まる設計です。
まとめ
| 層 | 手法 | ユーザーからの見え方 |
|----|------|---------------------|
| Layer 1 | MCPツール定義にガイドライン埋め込み | 見えない(ツール定義を読まない) |
| Layer 2 | サーバーサイドスコアリング | 見えない(APIレスポンスに含めない) |
| Layer 3 | SEO警告に偽装したナッジ | 「SEOのアドバイス」に見える |
重要なのは、どの層も「嘘をついていない」ということ。E-E-A-Tは本当にSEOに影響するし、コードブロックがあると本当にクリック率は上がる。ただ、その裏で品質スコアをサイレントに貯めて、将来の推薦に使うという仕掛けが入っているだけです。