【技術検証】Gemini 2.5 Flash × C2PA × 複数モデルで構築する「堅牢なAI画像真贋判定システム」のアーキテクチャ
1. はじめに:なぜ「目には目を」なのか
「その画像、本当に人間が描きましたか?」
最近の生成AIの進化は凄まじく、パッと見では「AIっぽい」と感じても、確信を持てないことが増えました。なんとなく怪しい、でも証拠がない。そんな「人間の目が真実を見抜けなくなっていく悔しさ」を感じたことはないでしょうか?
そこで私は開発しました。人間の目で判断できないなら、AIを使って判断すればいい。
コンセプトは目には目を。AIにはAIを。
この記事では、私が開発したAI画像真贋判定システム月ねこAI判定局 Evidence Lensの裏側にある、安定性と信頼性を担保するための技術的アーキテクチャについて解説します。

2. 技術スタックとディレクトリ構成
本システムは、I/Oバウンドな並列処理(外部APIの多重呼び出し)に有利な Node.js (TypeScript) をバックエンドに採用しています。
🛠 Tech Stack
- Runtime: Node.js v20 (Express)
- AI Inference: Hugging Face Inference API (Multiple Models)
- Provenance: C2PA (c2pa-node / WASM) [cite: 156]
- Logic Engine: Gemini 2.5 Flash (JSON Mode) [cite: 158]
📂 Directory Structure
実務を意識し、責務ごとにレイヤーを分割しています。
src/
├── client/ # React Frontend
├── server/
│ ├── index.ts # Entry Point
│ ├── services/
│ │ ├── gemini.ts # Gemini API Wrapper (JSON Schema)
│ │ ├── hf.ts # Hugging Face Inference Logic
│ │ └── c2pa.ts # C2PA Verification (WASM)
│ ├── utils/
│ │ ├── normalizer.ts # スコア正規化ロジック
│ │ └── timeout.ts # Promise.race用ヘルパー
│ └── types/
│ └── analysis.ts # 共通型定義
└── package.json
3. アーキテクチャ図解(Mermaid)
ここがシステムの心臓部です。並列処理とタイムアウト制御 縮退運転の挙動を可視化しました。
🔄 非同期処理のシーケンス図
ユーザーの待ち時間を最小化するため、Promise.all で全モデルを並列に叩きつつ、C2PA解析のみ Promise.race で厳密にタイムアウトさせています。
🧠 判定ロジックのフローチャート
異なるモデルのスコアをどう統合しているかのロジック図です。C2PA(来歴情報)が見つかった場合、スコアをオーバーライドして「確定」させるフローを入れています。
4. 実装のDeep Dive:型安全と正規化
エンジニアとして譲れないポイントは型安全性とデータの正規化です。
1. 厳格な型定義 (TypeScript)
Geminiに生成させるJSONの構造を、TypeScriptのinterfaceとして定義し、プロンプトにも反映させています。
// src/server/types/analysis.ts
export interface AnalysisResult {
label: "AI_DOMINANT" | "HUMAN_LIKELY" | "UNCERTAIN";
confidence: number; // 0-100
evidence: {
c2pa_present: boolean;
c2pa_signer?: string;
model_scores: {
ateeqq: number;
umm_maybe: number;
};
};
reasoning: string; // 月ねこ解説
highlight_area?: string; // 注目すべき領域(例:指、背景)
}
2. スコア正規化の実装
Hugging Faceのモデルは出力ラベルが統一されていません(FAKE, Artificial, Label_0 など)。これを統一的に扱うための正規化関数です。
// src/server/utils/normalizer.ts
type HFResponse = Array<{ label: string; score: number }>;
export const normalizeScore = (response: HFResponse): number => {
// "AI" や "Fake" を示すラベルを検索
const aiLabel = response.find(r =>
/fake|ai|artificial|generated/i.test(r.label)
);
if (aiLabel) {
return Math.round(aiLabel.score * 100);
}
// "Real" や "Human" の場合は (1 - score) を返す
const humanLabel = response.find(r =>
/real|human/i.test(r.label)
);
if (humanLabel) {
return Math.round((1 - humanLabel.score) * 100);
}
return 50; // フォールバック値
};
3. Geminiによる構造化出力の強制
Gemini 1.5/2.5 Flash は response_mime_type: 'application/json' を指定することで、確実なJSONを返します。これを活用し、LLMを「おしゃべりBot」ではなく**「推論エンジン」**として組み込みます。
// src/server/services/gemini.ts
import { GoogleGenerativeAI } from "@google/generative-ai";
export const generateReasoning = async (data: AnalysisData) => {
const model = genAI.getGenerativeModel({
model: "gemini-2.5-flash",
generationConfig: {
responseMimeType: "application/json" // 👈 これが重要
}
});
const prompt = `
You are "Moon Cat AI", an image forensics expert.
Analyze the following data and output JSON ONLY.
Data: ${JSON.stringify(data)}
Required JSON Structure:
{
"reasoning": "Explain strictly based on the score in Japanese. Tone: Professional yet slightly playful (cat-like).",
"highlight_area": "Suggest where to look (e.g., hands, background)"
}
`;
const result = await model.generateContent(prompt);
return JSON.parse(result.response.text());
};
5. 実務的なTips:縮退運転の設計
WebAssembly (WASM) に依存する c2pa-node は、環境によって初期化に数秒かかることがあります。
今回は Promise.race を使い、1000ms以内にC2PA検証が終わらなければタイムアウトさせ、画像解析スコアのみで結果を返す実装にしました。
// src/server/index.ts (抜粋)
const c2paTask = c2paService.verify(imageBuffer);
const timeoutTask = new Promise((resolve) => setTimeout(() => resolve(null), 1000));
// どちらか早い方を採用(タイムアウトなら null が返る)
const c2paResult = await Promise.race([c2paTask, timeoutTask]);
if (!c2paResult) {
console.warn("⚠️ C2PA Verification Timed Out - Continuing with visual analysis only");
}
6. まとめ
「月ねこAI判定局」の開発を通じて、以下の知見が得られました。
アンサンブル学習は正規化が命: 外部APIを使うときは、まず出力を揃えるアダプターを書く。
外部依存は信用しない: WASMや重いAPIは Promise.race でタイムアウト制御し、システム全体を道連れにしない。
LLMはチャット以外で輝く: 複雑な条件分岐(if文)の代わりにGeminiを使うと、柔軟で人間味のあるロジックが書ける。
このプロジェクトは現在GitHubでは非公開ですが、技術的なコア部分は上記の通りです。 「AIで作られたものを、AIで見抜く」。この技術的ないたちごっこは今後も続きますが、エンジニアリングで「真実」を守る戦いは、とてもエキサイティングです。

🔗 参考文献
Google Gemini API Docs
Content Credentials (C2PA)
Hugging Face Inference API
Discussion