「なんかAIっぽい文章だね」と言われた日
先月、業務で使う提案書のドラフトをChatGPTに書かせて、軽く手直しして提出した。そしたらクライアントから「これAIで書きました?」と聞かれた。バレた。
正直ショックだった。自分なりに修正したつもりだったのに。それ以来「AI臭い文章とは何か」をずっと考えていて、パターンを分析してリライトツールを作ることにした。
AI臭さの正体を分解する
ChatGPTが生成する日本語テキストには、人間が書くとまず使わない表現パターンがある。自分が200本くらいの出力を分析して見つけた特徴をまとめる。
構文パターン
- 「〜することが重要です」「〜が不可欠です」の多用
- 「まず〜、次に〜、最後に〜」の三段構成
- 「〜について詳しく見ていきましょう」という誘導表現
- 段落の冒頭が「また、」「さらに、」「加えて、」で始まる率が異常に高い
語彙パターン
- 「多角的」「包括的」「網羅的」の3連コンボ
- 「革新的」「画期的」という大げさな形容詞
- 「〜を活用して」「〜を踏まえて」の頻出
- 「いかがでしたでしょうか」で締める
構造パターン
- 各セクションの文字数が均一すぎる
- 箇条書きが3〜5個でキレイに揃う
- 結論が「まとめ」で始まり、内容の復唱で終わる
人間の文章はもっとムラがある。長い段落の後に一行だけの段落が来たり、話が横道に逸れたりする。AIの文章はそういう「ノイズ」がないから、逆に不自然に見える。
リライトのアルゴリズム設計
AI臭さを消すアプローチはいくつかある。
- パターン検出 → 置換: 定型表現を検出して、より自然な表現に置き換える
- 構造の揺らぎ挿入: 段落の長さを不均一にする、接続詞を間引く
- 口語表現の注入: 書き言葉すぎる部分にカジュアルな表現を混ぜる
全部を自動でやるのは品質が安定しないので、ツールとしては「検出してハイライト→ユーザーが選んで置換」というセミオート方式にした。
実装
パターン検出エンジン
まず、AI臭い表現をパターンとして定義する。正規表現だけだと限界があるので、形態素解析も組み合わせた。
interface AiPattern {
id: string;
category: "phrase" | "structure" | "vocabulary";
pattern: RegExp;
description: string;
severity: "high" | "medium" | "low";
suggestions: string[];
}
const AI_PATTERNS: AiPattern[] = [
{
id: "important-desu",
category: "phrase",
pattern: /することが(重要|不可欠|大切|必要不可欠)です/g,
description: "AIが多用する「〜することが重要です」構文",
severity: "high",
suggestions: ["した方がいい", "しないと困る", "がカギになる"],
},
{
id: "lets-look",
category: "phrase",
pattern: /について(詳しく|具体的に)見ていきましょう/g,
description: "読者を誘導する定型表現",
severity: "high",
suggestions: ["の話をする", "を掘り下げる", "に触れておく"],
},
{
id: "moreover-chain",
category: "structure",
pattern: /^(また、|さらに、|加えて、|その上、)/gm,
description: "段落頭の接続詞連鎖",
severity: "medium",
suggestions: ["(削除して直接始める)", "ちなみに", "で、"],
},
{
id: "comprehensive",
category: "vocabulary",
pattern: /(多角的|包括的|網羅的|革新的|画期的)(な|に)/g,
description: "AIが好む大げさな形容詞",
severity: "high",
suggestions: ["幅広い", "全体的な", "新しい", "面白い"],
},
{
id: "utilizing",
category: "vocabulary",
pattern: /を活用(して|し|する)/g,
description: "「活用」の過剰使用",
severity: "medium",
suggestions: ["を使って", "でやって", "を入れて"],
},
{
id: "how-was-it",
category: "phrase",
pattern: /いかがでし(た|ょう)でしょうか/g,
description: "AI記事の定番締め",
severity: "high",
suggestions: ["(削除)", "参考になれば嬉しい"],
},
];
これだけだとまだ甘いんだけど、パターンは随時追加していく設計。ユーザーがカスタムパターンを登録できる機能も入れた。
検出結果のスコアリング
テキスト全体のAI臭さを0〜100のスコアで出す。パターンの出現頻度と深刻度を掛け合わせて算出する。
interface DetectionResult {
patternId: string;
match: string;
index: number;
length: number;
severity: "high" | "medium" | "low";
}
function detectAiPatterns(text: string): DetectionResult[] {
const results: DetectionResult[] = [];
for (const pattern of AI_PATTERNS) {
// RegExpのlastIndexをリセット
pattern.pattern.lastIndex = 0;
let match: RegExpExecArray | null;
while ((match = pattern.pattern.exec(text)) !== null) {
results.push({
patternId: pattern.id,
match: match[0],
index: match.index,
length: match[0].length,
severity: pattern.severity,
});
}
}
return results;
}
function calcAiScore(text: string, detections: DetectionResult[]): number {
if (text.length === 0) return 0;
const SEVERITY_WEIGHT = { high: 3, medium: 2, low: 1 };
const rawScore = detections.reduce(
(sum, d) => sum + SEVERITY_WEIGHT[d.severity], 0
);
// テキストの長さで正規化(1000文字あたり)
const normalized = (rawScore / text.length) * 1000;
// 0-100にクランプ
return Math.min(Math.round(normalized * 5), 100);
}
スコアが50以上だと「かなりAI臭い」、30以下なら「人間っぽい」という目安にしている。自分の体感だと、ChatGPTの素の出力は大体60〜80くらいのスコアが出る。
置換ロジック
検出したパターンに対して、候補の中からランダムに選んで置換する。毎回同じ置換だとそれはそれで不自然なので。
function applyRewrite(
text: string,
detections: DetectionResult[],
mode: "auto" | "suggest" = "suggest"
): { rewritten: string; changes: Array<{ from: string; to: string }> } {
const changes: Array<{ from: string; to: string }> = [];
// indexの降順でソート(後ろから置換しないとindexがずれる)
const sorted = [...detections].sort((a, b) => b.index - a.index);
let result = text;
for (const detection of sorted) {
const pattern = AI_PATTERNS.find(p => p.id === detection.patternId);
if (!pattern || pattern.suggestions.length === 0) continue;
if (mode === "auto") {
// ランダムに候補を選択
const suggestion = pattern.suggestions[
Math.floor(Math.random() * pattern.suggestions.length)
];
if (suggestion === "(削除)" || suggestion === "(削除して直接始める)") {
result = result.slice(0, detection.index)
+ result.slice(detection.index + detection.length);
changes.push({ from: detection.match, to: "" });
} else {
result = result.slice(0, detection.index)
+ suggestion
+ result.slice(detection.index + detection.length);
changes.push({ from: detection.match, to: suggestion });
}
}
}
return { rewritten: result, changes };
}
後ろから置換するのは地味だけど大事なポイント。前から置換するとインデックスがずれてバグる。文字列操作あるある。
実際に使ってみた結果
ChatGPTに「フリーランスのメリットとデメリット」という記事を書かせて、このツールに通してみた。
- 素の出力: AIスコア 72
- リライト後: AIスコア 18
具体的には「〜することが重要です」が4箇所、「包括的な」が2箇所、段落頭の「また、」が6箇所検出された。これらを置換・削除するだけで、かなり人間っぽくなった。
ただし限界もある。AI臭さの原因は表面的な表現だけじゃなくて、論理展開の「きれいすぎる」構造にもある。メリット3つ・デメリット3つがバランスよく並んでる時点で、読む人が読めばAIだとわかる。このへんは自動化が難しい。
作ってみて学んだこと
AI臭さの本質は「予測可能性」だと思う。次に何が来るか予想できる文章はAI臭い。人間の文章は良い意味で予測を裏切る。急に個人的なエピソードが入ったり、話が脱線したりする。
このツールはあくまで「表面的なAI臭さ」を消すもので、文章の構造レベルの不自然さは人間が直す必要がある。とはいえ、定型表現を機械的に潰すだけでもかなり効果がある。
ツールは text.mildsolt.jp で公開中。テキストを貼り付けるとAIスコアが出て、検出箇所をハイライト表示する。置換候補もワンクリックで適用できる。
ChatGPTを業務で使ってる人は、提出前に一回通してみると安心感が違う。「AIで書きました?」と聞かれる回数は確実に減る。
まとめ
- AI臭さの正体は定型表現・均一な構造・大げさな語彙
- パターンマッチングだけでもスコア72→18まで改善できる
- ただし論理構造の不自然さは人間が直すしかない
- text.mildsolt.jp で無料公開中
AIの出力をそのまま使う時代は終わった。「AIに書かせて、人間が仕上げる」のが現実的なワークフローだと思う。そのとき、仕上げの手間を減らしてくれるツールがあると捗る。