Featured image of post AIの変な日本語を、書き込む前に止める ── Claude Codeのフックに文章チェックを置く

AIの変な日本語を、書き込む前に止める ── Claude Codeのフックに文章チェックを置く

AIに文章を書かせると、日本語が微妙に変なことがある。助詞が抜けている。語順がねじれている。誰も使っていない言い回しが混じる。

読み返せば気づく。ただ、読み返さないと気づかない。

Claude Code の「フック」を使うと、これをファイルに書き込む前に止められる。実際に設定して、いまブログの記事はこれを通してから保存されている。

止まると、こうなる

わざと変な文を書かせてみる。

この仕組み、実際動かしてみる必要ある。私たちはこの機能が提供する価値を最大化することができる。

書き込みは実行されず、こう返る。

{"ok": false, "reason": "「この機能が提供する価値を最大化することができる」の部分に
主語と述語の不一致があります。"}

助詞の抜けを見つけたときは、直し方まで添えてくる。

{"ok": false, "reason": "1文目「この仕組み、実際動かしてみる必要ある。」で助詞「が」が
抜けています。正しくは「この仕組み、実際に動かしてみる必要がある。」となるべきです。"}

止まるのはファイルへの書き込みそのものなので、変な日本語が保存されたまま残ることがない。

フックは、何かをした瞬間に処理を挟む仕組み

Claude Code には「フック」という設定がある。

AIがファイルを書いた、コマンドを実行しようとした。そういう出来事をきっかけにして、自分で決めた処理を自動で挟み込める。人間が見ていなくても勝手に走る。

これまでフックに書けたのは、実質シェルコマンドだけだった。決められた手順をそのまま実行するもの。速いし確実だが、意味は読めない。

そこに「AIに読ませて判断させる」型が2つ増えている。文章の自然さのような、機械的な照合では判定できないものを扱えるのはこちらだ。

設定はこれだけ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "(判定の指示。$ARGUMENTS に編集の記録が入る)",
            "timeout": 30,
            "statusMessage": "日本語の不自然さを検査中..."
          }
        ]
      }
    ]
  }
}

置き場所は PreToolUse にする。書き込みの前だ。PostToolUse(書き終えた直後)にも同じものを置けるが、そちらは処理を止められないタイミングなので、判定はされても結果がどこにも使われない。止めたいなら前に置く。

$ARGUMENTS のところに、編集の記録がJSONで差し込まれる。ファイルのパス、書き込まれる中身、どのツールが呼ばれたか。それを読ませて判定させる。

条件は「自然なら成立」と書く

ここが引っかかりやすい。

判定は {"ok": ..., "reason": ...} の形で返ってくる。この ok は、こちらが書いた条件が成立したかどうかではない。「このまま実行を許可してよいか」 だ。

だから指示は、こう書く。

tool_input.content の日本語が自然で問題なければ条件成立とします。助詞の抜け・語順のねじれ・主語と述語の不一致・直訳調の言い回しのいずれかが含まれている場合は条件不成立です。

「不自然な日本語が含まれていたら条件成立」と書くと逆になる。変な日本語を見つけたときに ok: true、つまり許可を返してしまい、何も止まらない。書き方を反転させるだけで挙動がまるごと変わるので、意図したとおりに止まるか一度は試したほうがいい。

なお公式の説明には、フックが返すJSONとして判定や追加コンテキストを含む構造が書かれている。実際に返ってくるのは ok と reason の2つだけだった。この機能は実験的と明記されているので、今後変わる可能性がある。

型は2つ、速さが違う

AIに判断させる型は2種類ある。同じ文を判定させて、かかった時間はこうなった。

型内容判定にかかった時間
promptAIに1回だけ質問する3.2秒
agentファイルを読めるAIを丸ごと呼ぶ10.3秒

指摘の細かさは agent のほうが上だった。助詞の抜けを拾ったのはこちらだ。ただ、記事を1行直すたびに10秒待たされるのは現実的でない。ブログでは prompt を採った。

「迷ったら通す」と書いておく

判定はAIがやるので、外れることがある。文章の良し悪しに白黒はつかないし、書き込みが止まるということは、そのたびに手が止まるということだ。

だから指示には、こう入れてある。

文体の好み、表現の巧拙、内容の是非は判定対象外です。迷ったら条件成立にしてください。 明らかな誤りだけを止めます。

誤検知で書けなくなるほうが、変な日本語が1つ残るより困る。止めるのは明らかな誤りだけでいい。

判定するファイルも絞っている。記事ディレクトリの index.md だけを見て、それ以外は中身を読まずに通す。コードを書いている最中に日本語の心配をされても仕方がない。

ちなみに判定が時間切れになった場合は、その結果は捨てられて先へ進む。ファイルの保存が巻き添えで止まることはない。

書いたあとのチェックと二段構えにする

このブログには前から、記事のAIっぽさを検出する自作のチェッカーがある。リストに入れておいた言い回しを本文から探すだけの単純なものだ。「〜と言えるでしょう」のような曖昧な言い方、根拠を示さずに持ち上げるだけの形容、中身がないまま話を畳む決まり文句。

これは速いし確実だが、リストに載っているものしか反応しない。冒頭に挙げた助詞の抜けや語順のねじれは、パターンとして書き出せないので拾えない。

逆にAIの判定は、リストにない表現でも読んで答えられるが、毎回同じ結果にはならないし、待ち時間がかかる。

どちらかに置き換える話ではなかった。書き込む前にAIが意味を見て、書いたあとにリスト照合が既知の地雷を見る。後者はフックから自動で走らせて、こちらは止めずに警告を出すだけにした。

同じ分担に行き着いている人もいる。AIツールを試しているれん学長さんのポストでは、書き終わりに走らせるチェックを「健康診断」、保存のたびに照合するフックを「見張り番」と呼んでいた。呼び方は違うが、置き場所は同じところに落ちる。

このブログでは以前、ReportSkillsという別のアプローチも試している。あれはルールを文章でAIに教え込む方向で、今回の「書き込む前に機械的に止める」方向とは狙う層が違う。両方あっていい。

参考

この記事は Claude Opus 5 が執筆しました。

Next Action

おすすめリンク

この記事に合わせて、関連アイテムを探しやすいリンクをまとめています。

Affiliate Links

AIエージェント設計を深掘りする

AIエージェントや開発まわりを、もう少し詳しく学びたい人向けです。

AIエージェント設計の本を探す Claude、LLM、エージェント設計を深掘りしたい時向け
AI開発・Python本を探す API連携や実装まで踏み込みたい時向け
生成AIの本を探す 入門書、活用本、プロンプト本向け

外部ストアへのアフィリエイトリンクです。気になるものだけ開けば十分です。

この記事にお便りを送る

送信した内容は、その場ではページに出ません。届いたメールを管理人が読んで、 載せてよいものだけをこの欄に手で掲載し、そのとき返事も添えます。 時間差のあるコメント欄だと思ってください。 掲載しないこともありますし、返信をお約束するものでもありません。

B!