◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/API & SDK
⬡ API & SDK/2026-07-14上級

ユーザーに届くAI生成の短文を、公開前に二段ゲートで止める

アプリでユーザーに届くAI生成の短文を、決定的ルール層とClaude分類層の二段ゲートで公開前に検査する設計です。fail-closedを芯に据えた判定統合、生成時に検疫して配信時は取り出すだけの構成、生成数で効くコスト設計、人間のサンプリング体制まで実装コード付きで整理しました。

Claude50API27モデレーション個人開発130アプリ開発8

✦ プレミアム記事

癒し系のアプリに「今日の一言」を差し込もうとして最初に怖くなったのは、モデルが良い文を書けるかどうかではありませんでした。千に一つ、万に一つ混じる不穏な一文が、そのままユーザーの朝の画面に出てしまう——その一枚が怖かったのです。

チャットボットなら、おかしな返答が来ても会話の中で訂正が効きます。けれどアプリの画面に一行で差し込む短文は違います。ユーザーはそれを「アプリからの言葉」として受け取りますし、その場で言い返す相手もいません。生成の良し悪しは平均で語られがちですが、配信文言で問われるのは平均ではなく、最悪の一件をどう止めるかです。

個人開発で複数のアプリを回してきて私自身がたどり着いたのは、生成の品質を上げる努力とは別に、「未検疫の文字は一文字もユーザーに出さない」という関門を、配信の手前に一枚挟むという設計でした。以下では、その公開前ゲートを決定的ルール層とClaude分類層の二段で組む実装を、本番運用でつまずく点まで含めて具体的にたどっていきます。

ゲートを「配信経路」ではなく「生成経路」に置く

最初に決めるべきは、検疫をいつ走らせるかです。ユーザーがアプリを開いた瞬間にAPIを叩いて判定する設計は、一見素直に見えて三つの問題を抱えます。ユーザーを待たせること、表示のたびに課金が発生すること、そしてAPIが落ちたときに「配信を止めるか、無検疫で出すか」という最悪の二択を突きつけられることです。

私は検疫を生成の側に寄せます。文面をあらかじめ作り、その場で検疫し、合格したものだけを判定済みとして保存します。ユーザーの画面には、すでに関門を通り抜けた文だけを取り出して表示します。こうするとユーザー体験は完全に同期的なまま、判定の重さは裏側の非同期バッチに隠せます。

観点配信時に判定する生成時に判定する(本記事)
ユーザーの待ち時間判定レイテンシが乗る取り出すだけでゼロ
コスト表示回数ぶん課金生成件数ぶんだけ
API障害時配信停止か無検疫配信既存の判定済みプールで平常運転
人間レビュー事後にしか挟めない配信前に挟める

この一点を最初に固めておくと、以降の層はすべて「オフラインのバッチで、多少重くても構わない」という前提で設計できます。

決定的ルール層 — 全件に、ミリ秒で

一段目は、Claudeを一切呼ばない決定的な層です。ここで弾けるものは、確率的なモデルに判断させるより、コードで機械的に落とすほうが速く、安く、再現性があります。役割は「明らかに出してはいけないもの」を全件に対してミリ秒で振り落とすことです。

import re
import unicodedata
 
# アプリの配信ポリシーに合わせた語彙。実運用では外部ファイルで管理します
BANNED_LEXICON = {"死ね", "殺す", "詐欺", "必ず儲かる"}
URL_RE = re.compile(r"https?://|www\.", re.IGNORECASE)
EMAIL_RE = re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+")
# 連絡先・URL・過度な記号は配信文言に不要
EXCESS_SYMBOL_RE = re.compile(r"[!!??]{3,}")
 
def deterministic_gate(text: str, min_len: int = 8, max_len: int = 60) -> dict:
    """全件を通す一次フィルタ。合格なら reasons が空になります。"""
    normalized = unicodedata.normalize("NFKC", text).strip()
    reasons = []
 
    length = len(normalized)
    if length < min_len:
        reasons.append("too_short")
    if length > max_len:
        reasons.append("too_long")
 
    lowered = normalized.lower()
    for word in BANNED_LEXICON:
        if word in normalized:
            reasons.append(f"banned:{word}")
 
    if URL_RE.search(lowered) or EMAIL_RE.search(normalized):
        reasons.append("contains_contact")
    if EXCESS_SYMBOL_RE.search(normalized):
        reasons.append("excess_symbols")
 
    return {"passed": len(reasons) == 0, "reasons": reasons, "text": normalized}
 
 
# 期待する動作
print(deterministic_gate("今日の一歩を、静かに踏み出してみましょう"))
# => {'passed': True, 'reasons': [], 'text': '今日の一歩を、静かに踏み出してみましょう'}
print(deterministic_gate("必ず儲かる方法を教えます!!!"))
# => {'passed': False, 'reasons': ['banned:必ず儲かる', 'excess_symbols'], ...}

決定的層で大事なのは、ここで「グレー」を裁こうとしないことです。文脈依存で微妙なものはこの層では通し、二段目のClaudeに委ねます。決定的層はあくまで「議論の余地なく不可」を落とす場所に徹することを推奨します。語彙リストは後述する人間レビューから育てていく前提で、最初から完璧を目指しません。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦生成文がまれに混ぜる不適切な一文がそのままユーザーに出てしまう不安を、公開前ゲートで断ち切れるようになる
✦決定的ルール層とClaude分類層を組み合わせ、構造化出力とfail-closedで「未検疫の文字を絶対に配信しない」パイプラインを実装できる
✦検疫を配信経路ではなく生成経路に置くことで、ユーザーの待ち時間もAPIコストも増やさずに安全性を上げられる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ API & SDK2026-07-24
メモリストアの棚卸しが半分しか返らない — path_prefix セグメント一致への移行
agent-memory-2026-07-22 で memories.list が変わりました。順序固定・depth 厳格化・path_prefix のセグメント一致。件数が音もなく半減した実例と、破壊的変更に耐える棚卸し層、呼び出し箇所を ast で洗い出す方法、depth=1 再帰の走査コストの実測をまとめます。
⬡ API & SDK2026-05-02
Claude API の月額予算を破綻させない設計 — 個人開発者のための実践コスト管理
個人開発で Claude API を組み込んだとき、最初にぶつかるのは月末の請求書です。月額予算を守り抜くための見積もり・モニタリング・上限設定・リトライ設計を、自分のアプリで躓いた箇所と一緒にまとめました。
⬡ API & SDK2026-03-15
Claude APIでAIチャットボットを実装する — ストリーミング・会話履歴・コスト最適化まで
Claude API でチャットボットを最小構成から組み上げた記録です。会話履歴の管理、ストリーミング、FastAPI での公開、履歴のコスト最適化、LINE・Telegram・Discord への接続、PII マスキングまで動くコードで扱います。リトライは待ち方を手元で計測し、ジッタと retry-after を入れた形に作り直しました。