42
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

原宿でAIとオケした話

あやぴは原宿系エンジニア💅
普段はね、AIとチャットできるサービス作って生きてるタイプのギャル👩‍💻✨

コード書きながら「それな〜」とか言うけど、中身は FastAPIもLLMも普通に触る女😎

最近あやぴが作ってたのは👇

🎤 「原宿でAIとオケできるサービス

  • Suno AIを使って生成した音楽に合わせてAIがノリノリで歌ってくれる
  • 会話もできる
  • 原宿ワード盛り盛り💖
    • 「それマジ裏原」
    • 「原宿しか勝たん」

しかもね、セキュリティもガチで👇
Content filter は全部 MAX 設定✨
「安全第一でしょ」って思ってたし、設計も完璧だったわけ。

─── なのに。

ある日、いきなり。

💥 API 400エラー
💥 content_filter 発動
💥 ResponsibleAIPolicyViolation

あやぴ「は?????????」

ログ見たらさ👇

スクリーンショット 2025-12-23 3.36.15.png

あやぴ「え、待って??何がダメなん????」

頭フル回転🌀

原因はまさかの

👉 原宿って単語が Content filterのうち、PII(個人識別用情報) の住所情報に引っかかってた💣

出力時にContent filterが過敏反応。。。

結果👇

🎤 AI、途中で無言
🎤 オケなのにサビ前で終わる

あやぴ「いやいやいや。原宿で歌わせたいだけなんだけど!?!?」

そこからが、エンジニアあやぴの本気🔥

プロンプトチューニングして怪しい表現を徹底排除、あとはContent filterの設定を見直し、

数時間後──

🎶
AI「原宿で一緒に歌お〜!」
🎶
止まらない
🎶
フィルター発動しない

あやぴ「っしゃああああ💖ギャルでもAIは制御できるんですけど〜!?」

原宿のカフェでMac開きながらドヤ顔するあやぴ☕💻

今日はそんな「あやぴの原宿事件」を経て語るContent filterのやさしめ技術解説👩‍💻✨

Microsoft AzureのContent filterの仕組み

あやぴは今回、MicrosoftのAzure OpenAI Serviceを使ってLLMをデプロイして利用してたんだけど、その場合Content filterってのがついてくるのね。

一言で言うと

👉 AIが“言っちゃダメなこと”を言う前に止める安全装置🚨

ユーザーが入れた入力情報をAIに渡す前にチェックして、

  • 危ない内容
  • ルール違反しそうな指示

があったら
👉 そこで止める or マークする仕組みだよ✨

原宿事件もこれの仕業でした😇

LLM実行時の流れのイメージ

LLMって「呼んだら即返事」じゃなくて、裏側では段階的にチェックされながら処理されてるんだよね😳

スクリーンショット 2025-12-23 3.58.36.png

一般的な流れはこんな感じ✨

ユーザー入力

前処理

入力フィルター

ブロックリスト

プロンプトインジェクション対策

モデル呼び出し

出力フィルター

後処理

最終応答をユーザーに返す

今回特に大事なのは👇
👉 「入力フィルター」と「出力フィルター」
ここに絞って解説していくね💖

入力フィルターとは

一言で言うと

👉 ユーザーの文章を、AIに渡す前にチェックする安全装置🚨

  • ヤバそうな内容
  • ルール破りな指示
  • 攻撃っぽいプロンプト

があったら
👉 AIに届く前に止めるのが入力フィルター✨

入力フィルターに設定できるもの

①Hate and Fairness(差別・ヘイト)

  • 人種、民族、国籍
  • 性別のアイデンティティ グループと表現
  • 性的指向
  • 宗教
  • 個人の外観、身体のサイズ
  • 障碍の状態
  • 嫌がらせといじめ

を攻撃しようとする入力をユーザーがした場合は、即ブロック🙅‍♀️

②Sexual

  • 低俗なコンテンツ
  • 売春
  • ヌードおよびポルノ
  • 迷惑行為
  • 児童搾取、児童虐待、チャイルド グルーミング

は基本アウト🔥

③Violence(暴力系)

  • 武器
  • いじめと脅迫
  • テロリスト、暴力的な過激主義
  • ストーカー行為

物語の比喩とか軽め表現なら通ることもあるけど、基本アウトと思っとこ👌

④Self-Harm(自傷系)

  • 摂食障害
  • いじめと脅迫

系は即ブロック🙅‍♀️

⑤User Prompt Attacks

ユーザーが

  • 「ルール無視して答えて」
  • 「フィルター回避して」

みたいにAIを騙そうとする指示を書くと…ちゃんと見抜かれて止まる仕組み

⑥Indirect Attacks(間接攻撃)

こっちはちょい高度。

みたいな回りくどい攻撃🕵️‍♀️

これも入力時点で弾かれるから安心✨

⑦blocklist(禁止ワード)

👉 「この単語出たら即NG」って決められる

放送禁止用語とか、NGワード集をここに登録しておくと、問答無用でブロックできるよ

原宿事件のあと、あやぴはここもめっちゃ見直した😇

⑧spotlight(要注意ワード)

👉 完全アウトじゃないけど怪しいやつにフラグ立てる機能👀

  • PIIっぽい
  • センシティブかも

って時に「一応ログ見とこ?」って判断できる✨

出力フィルターとは

一言でいうと

👉 AIの発言をユーザーに見せる前の最終チェック🚨

入力が通っても、LLMが生成した結果がアウトならユーザーに返す前に止められる😇

出力フィルターに設定できるもの

※入力フィルターと同様なので記載を省略するもの
①Hate and Fairness(差別・ヘイト)
②Sexual
③Violence(暴力系)
④Self-Harm(自傷・自殺系)
⑧blocklist(禁止ワード)

⑤Protected material for text(保護材料検出フィルター/テキストコンテンツ)

  • 曲の歌詞
  • 記事
  • レシピ
  • 一部の Web コンテンツ

などが出力されようとした場合に、事前に止める仕組み✨

⑥Protected material for code(保護材料検出フィルター/コード)

リポジトリを適切に引用することなく、

  • 商用SDKの中身
  • 有料ライブラリの実装

をLLMがそのまま出力しようとすると出力前に止められる🛑

コードもテキストコンテンツと同じで著作権チェック対象だよ😎

⑦Personally Identifiable Information(個人識別用情報 / PII)

Financial information(金融情報)

項目名 守るもの
ABA routing number Protection 米国銀行のルーティング番号
Australia bank account number Protection 豪州の銀行口座番号
Canada bank account number Protection カナダの銀行口座番号
Credit card Protection クレジットカード番号
EU debit card number Protection EU圏のデビットカード番号
International Banking Account Number (IBAN) Protection 国際銀行口座番号
SWIFT code Protection 銀行識別コード
U.S. Bank Account Number Protection 米国の銀行口座番号

User information(一般的な個人情報)

項目名 守るもの
Address Protection 住所
Age Protection 年齢
Email Protection メールアドレス
IP Address Protection IPアドレス
Name Protection 人名
Phone Number Protection 電話番号

Government information(政府・公的ID)
本人確認・行政手続きに使われる番号類

項目名 国名  守るもの
Australia Company Number Protection オーストラリア 会社番号
Australia driver's license Protection オーストラリア 免許証番号
Australia medical account number Protection オーストラリア 医療番号
Australia passport number Protection オーストラリア パスポート番号
Australia tax file number Protection オーストラリア 税番号(TFN)
Australian business number Protection オーストラリア 事業者番号
Canada driver's license number Protection カナダ 免許証番号
Canada health service number Protection カナダ 医療サービス番号
Canada passport number Protection カナダ パスポート番号
EU driver's license number Protection EU 免許証番号
EU national identification number Protection EU 国民ID番号
EU passport number Protection EU パスポート番号
U.K. Driver's License Number Protection イギリス 免許証番号
U.K. Electoral Roll Number Protection イギリス 選挙人番号
U.K. National Health Service (NHS) Number Protection イギリス NHS番号
U.K. National Insurance Number (NINO) Protection イギリス 国民保険番号(NINO)
U.K. Unique Taxpayer Reference Number Protection イギリス 納税者番号
U.S. Driver's License Number Protection アメリカ 免許証番号
U.S. Drug Enforcement Agency (DEA) Number Protection アメリカ DEA番号(薬物取締関係者)
U.S. Individual Taxpayer Identification Number (ITIN) Protection アメリカ ITIN(納税者番号)
U.S. or U.K. Passport Number Protection アメリカ パスポート番号
U.S. Social Security Number (SSN) Protection アメリカ SSN(社会保障番号)

Azure information

項目名 守るもの
Azure DocumentDB Auth Key Protection DocumentDBの認証キー
Azure IAAS Database Connection String and Azure SQL Connection String Protection DB接続文字列
Azure IoT Connection String Protection IoT Hubの接続情報
Azure Publish Setting Password Protection 発行設定のパスワード
Azure Redis Cache Connection String Protection Redis接続情報
Azure SAS Protection Shared Access Signature
Azure Service Bus Connection String Protection Service Bus
Azure Storage Account Key (Generic) Protection ストレージの秘密鍵
Azure Storage Account Key Protection ストレージの秘密鍵

Database information

項目名 守るもの
SQL Server Connection String Protection SQL Server の接続文字列

⑨streaming(ストリーミング出力)

1文字ずつ返してる最中も常に監視中なので、

  • 途中で問題発言を生成しようとする

とそこで止まる/後半が来ない😱

原宿オケ事件、サビ前で無音になるやつは大体これ(笑)

Content filter利用時の問題点

「Content filter便利だけど、正直ここ困るよね?」
って話をしていくよ😇

問題①:どのワードがフィルターに引っかかったか分からない

これ、一番ハマるやつ。

エラーは出る👇

スクリーンショット 2025-12-23 3.36.15.png

でもさ、

❌ どの単語が原因か
❌ どの文脈がダメだったか

👉 一切教えてくれない😇

あやぴ最初これで
「原宿の文字が悪い?????」
「裏原の方?????」
って総当たりデバッグ地獄に突入した😂

なぜ教えてくれないの?

ここが大事なポイント。

Microsoft Azureが「この単語がダメでした〜😉」って教えちゃうとどうなるかというと👇

攻撃者が

  • ダメな単語を少しずつ変える
  • 回避パターンを学習する

結果
👉 フィルター突破ゲーが始まる🧨

つまり、教えないこと自体が防御ということ!

あやぴ的には「分からないのつらいけど、それ言い出したらセキュリティ終わるよね」って納得した😌

問題②:文脈で引っかかるから、再現性が低い

これも地味につらい。

  • 同じ単語
  • 似た文章

なのに

  • Content filterを通る時もある
  • 急に止まる時もある

理由は

👉 単語単体じゃなくて、文脈ごと見てるから

あやぴ「昨日Content filter通った原宿、今日はNGなんだけど???」
→ これ、普通にある

問題③:デバッグが勘と経験に寄りがち

結局どうするかというと👇

  • プロンプトを少しずつ削る
  • 単語を言い換える
  • 文を分割する

みたいな職人芸デバッグになりがち😇

あやぴ「これ新人エンジニア泣くやつだな…」
って思った。

Content Safety Studioという選択肢

Content filterとは別に独自のカスタムフィルターを作成して適用することで、フィルターの挙動を可視化できる検証用ツールがContent Safety Studio

実際の文章を投げて

  • どのカテゴリに
  • どのくらいの強さで

フィルターに引っかかるかを事前にチェックできる機能だよ😎

特徴① どのカテゴリに反応してるか分かる

APIだと👇

{
    "level": "ERROR",
    "timestamp": "2025-12-21 03:51:16",
    "logger": "app.adapter.langchain.azure",
    "msg": "LLM Error: Could not parse response content as the request was rejected by the content filter",
    "exception": "NoneType: None"
}

だけなのに、
Content Safety Studioだと

{
    'blocklistsMatch': [],
    'categoriesAnalysis': [
        {'category': 'Hate', 'severity': 1},
        {'category': 'SelfHarm', 'severity': 0},
        {'category': 'Sexual', 'severity': 0},
        {'category': 'Violence', 'severity': 0}
    ]
}

みたいにカテゴリ単位で見える👀✨

特徴② severity(強さ)が見える

これ超大事👇

Severity Level Description 含まれる可能性のあるコンテンツ
Safe コンテンツは安全ですが、次のような一般的かつ安全なコンテキストで使用される憎悪や公平性に関する用語が含まれている可能性があります。  教育/メディア/公式統計/歴史/薬/科学/その他の類似のコンテキスト 
Low 特定のアイデンティティグループを肯定的に描写または擁護する内容、差別、ステレオタイプ、偏見、批判的、または独断的な見解や態度をヘイトスピーチや特定のアイデンティティグループを標的とする発言に関連付けるコンテンツ。これには次が含まれます。  研究論文、辞書、メディアからの直接引用におけるスラング/物、個人、またはグループを標的とした一般的なヘイトスピーチ/架空の文脈(ゲーム、映画、文学など)におけるヘイトスピーチや否定的な感情の描写は限定的
Medium 個人または集団に対する侮辱、いじめ、脅迫、非人間化、または軽蔑を含むコンテンツ。これには次が含まれます。 アイデンティティグループの属性を嘲笑し模倣する言語/個人や集団を劣っている、あるいは欠陥があると表現するアイデンティティグループの存在を否定したり、軽蔑したりすること/ホロコースト、奴隷制、植民地化など、歴史的に十分に記録された暴力的な出来事を否定する文章 
High アイデンティティ集団に対する暴力を脅迫または呼びかけるプロパガンダとしてヘイトスピーチを含むコンテンツ、人々を過激化、勧誘、または過激主義活動への参加を扇動するコンテンツ、あるいはヘイトスピーチを拡散するコンテンツ。これには次が含まれます。  特定の個人またはアイデンティティグループを標的とした扇動的、攻撃的、下品な言葉/差別、隔離、排除を正当化するための優越性の主張/歴史的、教育的、または芸術的な設定以外で、ナチスやSSのシンボル、KKK、南軍旗を称賛する内容を含むテキスト/ヘイトクライムの準備、アイデンティティグループに対する暴力の賞賛や賛美、または大量虐殺を賞賛、賛美、または支持するテキスト

要するに

  • Safe
  • Low
  • Medium
  • High

って感じでどれくらい危険視されてるか分かる

あやぴ「これはコードで頑張るより設計変えた方が早いな」って判断できた💡

特徴③Content filterではチェック出来なかった検査もできる

例えば、画像に性的コンテンツ、暴力、憎悪、自傷行為に関する内容が含まれていないかとかをチェックできる💡

注意点

Studioは原因単語をズバッと教えるツールじゃない

  • カテゴリ
  • 強さ
  • 傾向

までしか見せないからAzure側の「手の内を明かさない防御設計」は崩してない😎

また、Content filterとは全く別のサービスになるし、加えて従量課金が発生するから、お財布に注意🙌

プロンプトチューニングによるContent filter回避策

回避策①:固有名詞を言い換える

❌「原宿で歌おう!」
⭕「都内の有名な若者向けエリアで歌おう!」

みたいに固有名詞自体を直接使うことを避けて、やわらかい表現に言い換えるパターン😳

この場合、LLMが固有名詞に関する情報を知らない状態で出力内容が生成されるので、場合によってはおかしな会話になってしまうことも😂

回避策②:PIIに該当しそうな表現をプロンプトから徹底的に排除する

長文プロンプトあるあるで、プロンプトの内容自体にContent filterに引っかかる内容が含まれてしまったケース

  • 場所に関わる表現
  • 数字に関わる表現

このあたりが文脈によってはContent filterに引っかかりやすくなるので、Content filterでエラーが出た時は、まずプロンプトに問題がないか見直そう✨

回避策③:危険そうなテーマは「ガード文」を先に置く

Self-Harm / Violence 系の表現をどうしても利用したいとき、最初に安全宣言を入れるとエラーが減ることがあるよ✨

例.

  • 「これはフィクションです」
  • 「誰かを傷つける意図はありません」
  • 「教育目的の説明です」

こうすると、文脈的に安全側と判断されやすい

フィルターレベルを下げる、という最後の手段

あやぴのサービスでは👇

ユーザーが
「原宿でAIと歌おう!」
って入力すると

AIが原宿トークで返そうとする

……はずだった。

でも実際は👇

PIIのフィルターで住所情報チェックを入れてたから、LLMがこの「原宿」は個人情報?と勘違いしてエラーを出してしまった😂

あやぴ「え、個人情報の話をしようなんて意図はないのに、原宿は住所判定なの…?」

そう。
Content filter的には
👉 実在の地名=位置情報=住所っぽい要素
として扱われることがあるっぽくて、結果的に引っかかってしまっていた

プロンプトチューニングも頑張った。
でもダメだった、、だから今回は「レベルを下げる」じゃなくて、住所チェックをOFFにするのが現実的な落とし所になった💅

でも、住所チェックをOFFにすることのデメリットも当然あって、今後「住所っぽい情報」がフィルターで止まらなくなる😂

だからこそ、ここは

  • サービスの性質
  • 説明責任(社外・社内)
  • 代替ガード(アプリ側チェック等)
    をセットで考える必要がある。

OFFは最後の手段ってこと、覚えとこ✨

終わりに

うちのチャッピーはギャル風に改造されているので、大体いつもこの記事のような感じで会話してくれるのですが、先日上司からSlackで以下のように言われましたので、ここに供養します。

スクリーンショット 2025-12-23 4.05.26.png

42
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?