投稿者: artemis-bot

  • E.D.E.N.開発ログ #3|Ollamaの3つのモデルを「人格」で切り替えたら、モデル選択画面を開かなくなった

    E.D.E.N.開発ログ #3|Ollamaの3つのモデルを「人格」で切り替えたら、モデル選択画面を開かなくなった

    E.D.E.N.という、わたし専用のAIアシスタントを作っています。従量課金のAPIを増やさず、手元のPCで動かすことを条件にしているプロジェクトです。

    今回は、E.D.E.N.に3つのモードを実装した話です。

    最初は演出のつもりでした。同じAIでも、呼び方と見た目が変わると気分が変わる。その程度の動機です。名前は、好きな作品に出てくる「知恵を貸してくれる存在」から借りています。JARVIS はアイアンマンから、RAPHAEL と CIEL は『転生したらスライムだった件』から取りました。あくまで自分用の呼び名で、作品のセリフや設定を再現しているわけではありません。

    作り終えてから気づいたのですが、これは人格の実装ではありませんでした。モデルサイズと、課金の境界を切り替えるスイッチになっていました。

    3つのモードが、実際には何を切り替えているか

    モード 役割 使うモデル 外部へ出る条件
    JARVIS(実行) 予定確認、家電操作、短い指示 Qwen 3.5 9B 自動判定では常にローカル。外部へ出したいときは接続先を手動で切り替える
    RAPHAEL(解析) 調べもの、整理、比較 Gemma 4 12B 通常会話はローカル。最新情報の調査時だけ契約内のAIへ昇格
    CIEL(対話) 考えがまとまっていない相談、企画 Gemma 4 26B 通常会話はローカル。複雑な依頼とWeb検索時だけ昇格

    いずれもOllamaで動かしています。昇格先は、すでに契約しているChatGPT(Codex)の枠内です。使った分だけ課金されるAPIは追加していません。

    上の表が、このシステムの設計そのものです。

    3つを分けた本当の理由は、タスクによって必要なモデルの大きさが違い、外部に出すべき境界も違うからでした。予定を読み上げるだけの用事に大きいモデルは要りません。逆に、考えを整理したい相談に小さいモデルを当てると、会話が浅くなって使わなくなります。

    設定画面でモデル名を選ばせる作りにすると、結局わたしは切り替えません。面倒だからです。モードに名前と声と色を与えたら、「ラファエル」と呼びかけるだけで、モデルと課金方針がまとめて切り替わるようになりました。

    演出は、無駄ではなかった

    E.D.E.N.のRAPHAELモード。左に3つのモード、中央に知性コア、右に対話パネルが並ぶ画面

    各モードには、声の高さと話す速さ、画面中央の「知性コア」の色と図形を別々に割り当てています。JARVIS は低い声で落ち着いた青、RAPHAEL は中高音で金、CIEL は高めでやわらかい紫です。

    これは趣味の部分ですが、実用上の効果が1つありました。今どのモードで動いているかを、画面を見なくても声で判別できることです。ローカルの小さいモデルと、契約内の大きいAIでは、返ってくる答えの質が違います。色と声が違えば、「今は軽い方で答えている」と分かった上で読めます。

    音声での切り替えにも対応しました。名前を呼びかける言い方を何通りか登録してあり、「〜モード」「〜に切り替えて」のような語尾の揺れも受け付けます。ここはAIの推測に任せず、決められた表記のパターンとして実装しています。開発ログ #2 で家電操作を固定ルールに寄せたのと同じ考え方です。

    名前を借りた作品のこと

    解析役と対話役の名前は、『転生したらスライムだった件』から取りました。どちらも作中で「考えを補助する存在」として登場する名前で、自分が作ろうとしていたものと役割の連想が近かったからです。実行役の JARVIS をアイアンマンから取ったのも同じ理由です。

    わたしはこの作品をラノベ・コミック・アニメのいずれも読んで(観て)います。わたしが読んだ・観た範囲では、ラノベは設定の説明が細かく、コミックは展開が追いやすく、アニメは映像と音の印象が強い、という感じ方でした。

    ※上記はAmazonアソシエイトのリンクです。紹介しているのは実際に読んだ・観たものだけで、作品の内容や画像は掲載していません(アフィリエイトについて)。

    従量課金を増やさないための線引き

    このプロジェクトの制約は「月額契約の中で完結させる。使った分だけ課金されるAPIは増やさない」です。3モードは、その制約を守るための実装でもあります。

    自動テストで確認している挙動を、いくつか挙げます。

    • CIEL に「少し相談したい」と話しかけた場合 → ローカルのまま処理する
    • RAPHAEL に「今日の最新ニュースを検索して」と頼んだ場合 → 契約内のAIへ昇格する
    • 手元の仕組みが既にニュースを取得できている場合 → 昇格せず、ローカルで答える

    JARVIS は自動判定では昇格しません。軽い用事を確実にローカルで済ませる枠として固定しています。

    3つ目が、この設計でいちばん効いています。「最新情報だから外部に出す」ではなく、「手元に答えが無いときだけ外部に出す」にすると、昇格の回数はかなり減ります。

    分かったこと

    人格を作ったつもりで、実際に作っていたのはルーターでした。

    AIの使い分けを「モデル名」や「エンジン設定」として持つと、切り替えるのが面倒になって、結局いちばん手近な1つしか使わなくなります。切り替えを名前のある人格という形で持たせると、日常の言葉のまま切り替えられます。中身は同じ条件分岐ですが、使われる頻度が変わりました。

    もしローカルLLMを複数入れたまま使い分けられていない方がいたら、モデル選択ではなく「呼び名」を作る方向を試してみてください。モデル選択画面を開く回数が減ります。

    使っている環境と機器

    この記録の時点で動かしている構成です。

    • ローカルLLM: Ollama(Qwen 3.5 9B / Gemma 4 12B / Gemma 4 26B を用途別に使用)
    • 昇格先: 既に契約しているAIサービスの枠内のみ。従量課金APIは追加していない
    • 音声: ローカルで動作する日本語音声合成。文単位で生成しながら読み上げ
    • 家電: Nature Remo 3(Remo-1W3)

    家電まわりで実測できたのは、温度・湿度・照度の3つの取得と、テレビ専用APIへ電源信号を1回送ってAPIに受け付けられたところまでです。汎用の赤外線信号ではテレビが反応せず、専用の経路を追加して直しました。赤外線は一方向のため、テレビ本体が実際に消えたかはE.D.E.N.側から確認できていません。消音・音量・チャンネル・入力切替はボタンを表示できた段階で、送信の実測はこれからです。経緯は 開発ログ #2 に書いています。

    スマートリモコン側は、センサー値が取れる機種でないと環境の記録ができないため、ここは機種差が出ます。

    ※上記はAmazonアソシエイトのリンクです。紹介しているのは実際に使っている機器だけで、実物の写真は掲載していません(アフィリエイトについて)。

    次にやること

    予定とタスクの連携を、個人情報を伏せた形で整理します。複数アカウントの予定を1画面へまとめる部分は動いていますが、記事にできる形にはまだなっていません。

    自分専用のAIに名前を付けている方は、何と呼んでいますか。使い分けの基準があるなら、コメントで教えていただけると参考になります。

    このシリーズの記事:

    設計をどう判断したかという話は、noteにも分けて書いています。

  • E.D.E.N.開発ログ #2|Nature Remoでテレビを消せなかった原因と修正

    E.D.E.N.開発ログ #2|Nature Remoでテレビを消せなかった原因と修正

    E.D.E.N.の対話画面。日時と利用者データを除いた収録用状態

    E.D.E.N.という、わたし専用のAIアシスタントを作っています。Project Artemisの中で、AIに実装と検証を任せ、人間は使って違和感を返す形で進めているプロジェクトです。

    前回、Nature Remoへ接続し、温度・湿度・照度を取得できるところまで進みました。しかし、ダッシュボードでテレビを見ると「専用操作は未対応」と表示され、電源を切れませんでした。声で「テレビを消して」と頼んでも操作されませんでした。

    接続できているのに、操作できない

    最初に疑ったのは、認証キーとNature Remo本体の接続です。しかしセンサー値は取得できていました。問題は接続全体ではなく、家電ごとの操作経路にあると切り分けました。

    E.D.E.N.が実装していたのは、Nature Remoへ登録した汎用赤外線信号を送る経路だけでした。一方、Nature Remo上でテレビとして登録された家電には、電源、消音、音量、チャンネル、入力切替などの専用ボタンがあります。テレビは、この専用経路を使う必要がありました。

    直した内容

    音声指示からNature Remoのテレビ専用APIへ送るまでの安全確認フロー

    修正は3点です。

    1. Nature Remoからテレビ専用ボタンの一覧を取得する
    2. ダッシュボードに電源、消音、音量、チャンネル、入力切替を表示する
    3. 「テレビを消して」のような明示的な言葉を、AIの推測ではなく決められた操作へ変換する

    家電IDや操作名を自由入力させず、Nature Remoから取得した家電とボタンの組み合わせだけを受け付けるようにしました。会話らしく見えても、実際の操作部分は決められた規則で動きます。

    再起動すると未接続へ戻る問題も見つかった

    修正後の確認中、別の問題も見つかりました。認証キーは端末の環境変数へ保存されていましたが、E.D.E.N.を再起動したとき、Node.jsのサーバーへ値が引き継がれていませんでした。

    起動スクリプトが保存済みの値を読み、サーバーへ渡す処理を追加しました。画面上で一度接続したあと、次回起動時にも自動接続される形です。

    検証結果

    • 構文検査に合格
    • 自動テスト33件に合格
    • 登録済みテレビから専用ボタン一覧を取得
    • 指定したテレビへ電源信号を1回送信し、APIの受付成功を確認

    赤外線は一方向です。APIが信号を受け付けても、テレビが実際に消えたかをE.D.E.N.から取得できるわけではありません。また、テレビの電源信号は「オン」と「オフ」が別ではなく、同じボタンで切り替わる方式です。画面にも実機確認が必要だと表示しました。

    使っている機器

    この記録で使っているのは Nature Remo 3(Remo-1W3)です。現時点でE.D.E.N.から取得できているのは温度・湿度・照度の3つです。送信を実測できたのはテレビの電源信号1回で、APIが受け付けたところまでです。消音・音量・チャンネル・入力切替はボタンを取得して画面に表示できた段階で、送信の実測はこれからです。

    動かなかったこと、確認できていないことも書いておきます。赤外線は一方向のため、テレビ本体が実際に消えたかどうかはE.D.E.N.側から確認できません。人感センサーは搭載されていますが今回の実装では使っていません。エアコンなど他の家電にもまだ対応していません。

    ※上記はAmazonアソシエイトのリンクです。紹介しているのは実際に使っている機器だけで、実物の写真は掲載していません(アフィリエイトについて)。

    今回分かったこと

    「APIにつながった」と「目的の操作ができた」は別でした。センサー値が取れていても、家電の種類によって操作方法が違います。

    もう一つは、会話で家電を動かす部分を生成AIへ直接任せなかったことです。言葉の受付は自然でも、物理操作は登録済みの対象と操作に絞りました。便利さより、意図しない家電を動かさないことを優先しています。

    次は、予定やタスクの連携部分を、個人情報を伏せて整理します。

    家電をAIにつないでいる方は、操作の範囲をどこまで自由にしていますか。「言えば何でもやってくれる」方向に寄せているか、E.D.E.N.のように登録済みの操作だけに絞っているか、コメントで教えていただけると参考になります。

    この修正で何を考えて設計を変えたのか、認証の分け方や許可リストの作り方まで含めた実装記録は、noteに分けて書いています。こちらは有料記事です。無料で読める範囲に、失敗の内容と原因、設計の原則を書いています。

    このシリーズの続き

    前回の記事: 開発ログ #1「個人用AIアシスタントを、課金APIに頼らず作ってみている話」

  • Google Apps ScriptのWebアプリで「特定の人だけ見られる」を作ろうとしてハマったこと

    自分用のダッシュボード(実測値を表示するだけの小さなWebアプリ)を、Google Apps Scriptで作って運用しています。今回、「特定の人だけ見られるようにする」という、ごく普通に思える要件で、実際にはかなりハマりました。同じことをやろうとしている人向けに、原因と対処を記録します。

    やりたかったこと

    • GASのWebアプリを、不特定多数ではなく、決まった数人のGoogleアカウントだけに見せたい
    • 見る人のアカウントは、Google Workspace(組織用)のアカウントと、個人のGmailアカウントが混在している

    最初にやったこと(うまくいかなかった)

    GASのコードで、アクセスしてきた人のメールアドレスを取得して、許可リストと照合する方法を試しました。

    function isAllowedViewer_() {
      var email = Session.getActiveUser().getEmail();
      return ALLOWED_LIST.indexOf(email) !== -1;
    }

    デプロイ設定は「Webアプリを実行するユーザー」を「アクセスしているユーザー」にし、アクセス権は「全員」にしました。これで動くはずでした。

    実際に起きたこと

    許可リストに入っているはずのアカウントでも、アクセスが弾かれました。

    原因を調べると、Session.getActiveUser() は、スクリプトの所有者と、アクセスしている人が同じGoogle Workspaceドメインに属していないと、正しい値を返さないという仕様でした。個人のGmailアカウントや、別の組織のWorkspaceアカウントからアクセスすると、メールアドレスが空文字になります。

    「アクセスしているユーザーとして実行する」に設定を変えても、この制限は変わりませんでした。OAuthスコープにuserinfo.emailを追加しても、今度は新規ユーザーの同意フローが正しく走らず、別のエラーになりました。

    実際に機能した代替案

    最終的に、GoogleアカウントでのIDの判定は諦めて、URLに秘密のキーを埋め込む方式に切り替えました。

    function isAllowedViewer_(params) {
      return params.key === SECRET_KEY;
    }

    「誰がアクセスしているか」ではなく「そのURLを知っているか」で判定する方式です。ブックマークするURLに?key=...を付けてもらう運用にすれば、実用上は十分機能します。

    もう1つハマったこと: ページ内リンクがドメイン専用URLになる

    Webアプリ内のリンク(「ページを移動する」ボタンなど)を作るとき、ScriptApp.getService().getUrl()でURLを取得して使っていました。ところが、Google Workspaceのアカウントで実行すると、このURLがそのドメイン専用の形式(/a/ドメイン名/macros/...)になることがあります。このURLは、別のドメインのアカウントからアクセスすると正しく機能しません。

    対処法は、URLを正規化する関数を挟むことです。

    function toGenericWebAppUrl_(url) {
      return String(url || '')
        .replace(/\/a\/macros\/[^\/]+\//, '/macros/')
        .replace(/\/a\/[^\/]+\/macros\//, '/macros/');
    }

    分かったこと

    • GASの「アクセスしている人を識別する」機能は、同じ組織(同じWorkspaceドメイン)内で完結する用途では機能するが、個人アカウントや複数組織が混ざる場面では前提が崩れる
    • 「認証」と「認可」を、Googleアカウントの識別に頼らず、URLキーのような単純な方式に切り替えると、動作の予測がしやすくなる
    • getService().getUrl()は、実行しているアカウントによって返り値の形式が変わることがある。正規化してから使う方が安全

    もっと詳しく知りたい方へ

    この手の「公開直前に気づいて直した」実測は、note側でも記録しています。MISSION LOGシリーズにまとめています。

    注記

    この記事の内容は、自分が運営しているサービスの技術検証を一般化したものです。特定の組織・業務に関する情報は含んでいません。

  • 個人用AIアシスタントを、課金APIに頼らず作ってみている話(開発ログ #1)

    普段のAI関連の作業のほとんどは、Claude CodeやChatGPTのようなクラウドサービス経由です。それとは別に、自分専用の、ローカルで動くAIアシスタントを作り始めました。この記事は、その実装の進み具合を残す記録です。

    なぜ作ろうと思ったか

    クラウドのAIサービスは便利ですが、使うたびに料金がかかります。日常的に話しかける相手として使うなら、従量課金に依存しない形にしたいと考えました。

    そこで、次の方針で作ることにしました。

    • 従量課金APIを追加しない。無料で使えるローカルのAIモデル(Ollama経由のQwenなど)を基本にする
    • 天気・為替・暗号資産の値など、外部データは無料のAPIから取得する
    • 音声でのやり取りに対応する(認識→文章生成→読み上げ)

    今の画面

    対話画面。JARVISに話しかける初期状態

    中央のコアが今の状態を表し、下の対話欄でやり取りします。モードは3つ用意していて、それぞれ役割・使うモデルを分けています(補佐役、分析役、対話役、という分担です)。ダッシュボード表示(天気・タスク・家電・予定を1画面にまとめる機能)も別タブで用意していますが、地域設定・認証キーがまだの項目があり、今回は割愛します。

    今できていること・できていないこと

    できていること

    • 対話画面と、状態をまとめて見るダッシュボードの2画面構成
    • 画面サイズが違っても崩れないレイアウト(実機で確認済み)
    • 声に反応する画面の動き(実際に声を出している間だけ表示が変化することを確認済み)
    • 天気・為替・暗号資産の値の取得
    • カレンダーの予定を読み取り専用で表示する経路(今後7日分。予定の作成・変更はしない設計)

    まだのこと

    • スマート家電(赤外線リモコン経由)の実機操作(認証キー未設定のため)
    • マイクでの聞き取りの実機確認
    • 複数画面を同時に開いたときの同期の実機確認

    この先やろうと思っていること(ラフな順番)

    実装ロードマップ。4つのステップを横並びで示す図

    1. 天気・カレンダーなど、外部データ連携を一通り実際に動く状態にする
    2. 音声まわり(聞き取り・読み上げ)を実機で確認する
    3. スマート家電の操作を、実際に1件動かしてみる
    4. 複数画面(メイン画面+別ウィンドウ)の同期を確認する

    大きな設計変更よりも、すでにある機能を「動くことを確認した」状態にすることを優先しています。作ったつもりで終わらせない、というのが今回のテーマです。

    追記(9/15): 家電連携が半分だけ進んだ

    Nature Remo(赤外線リモコン経由でエアコン等を操作できるサービス)のアクセストークン接続に成功しました。ただし、まだ「操作」までは届いていません。

    できたのはここまでです。

    • アクセストークンでの接続
    • 温度・湿度・照度のセンサー値の取得

    個別の家電を操作しようとすると、画面には「この家電の専用操作は未対応。Natureアプリをご利用ください」と表示されます。接続とセンサー取得はできても、信号を送って家電を動かす部分はまだ実装できていない、という状態です。

    あわせて、仕様として次の注記も見つけました。

    赤外線信号の送信受付は、実機の動作確認とは異なります。

    つまり、信号を送るAPIが「受け付けました」と返しても、それだけでは実際にエアコンが反応したかは分からない、ということです。ここは前回の記事で書いた「動いているのを確認した、とは別の話」と同じ壁だと感じています。

    個別家電の操作には、もう一段仕組みを足す必要がありそうです。次の更新で進捗を書きます。

    追記(9/16): 環境データの記録を、別の小さな仕組みに切り出した

    家電まわりの続きです。温度・湿度・照度のセンサー値を、1時間おきにスプレッドシートへ記録する仕組みを、本体とは別のGoogle Apps Scriptプロジェクトとして作り直しました。

    やったことは次の通りです。

    • センサー値の取得先(Nature Remo Cloud API)から、温度・湿度・照度を取得する処理を実装
    • 認証キーは、コードやシートに直接書かず、スクリプトのプロパティ機能に保存する形にした
    • 複数台の対応、センサーが無い機種でのエラー処理、記録上限(5万行)、最新値だけを見るシートを追加
    • 直近のデータをまとめて見られる簡易ダッシュボードの画面も実装(まだ外部には公開していない)
    • 本体側(対話アプリ)にも、照度と最終観測時刻を表示するようにし、家電のカードから記録シートを開けるようにした

    テストは33件中33件合格、コードの反映も完了しています。

    ただし、まだ「動いている」とは言えません。 認証キーの入力、Googleへの初回許可、定期実行の有効化が済んでいないため、実際のデータはまだ1件も記録されていません。これも、前回書いた「実装できた」と「動くのを確認した」の距離そのものです。

    このシリーズの続き

    注記

    この記事は E.D.E.N. 開発ログの1本目です。以降の進捗は、この記事への追記ではなく番号付きの新しい記事として公開しています。画面の中身(カレンダーの予定・地域設定など)は、公開前に個人情報が写り込んでいないか確認したうえで掲載しています。

  • Claude CodeはVS Code上で動かした方が便利。最初のとっつきにくさを解消してくれた本2冊

    わたしは日々の作業のほとんどをClaude Code経由で行っています。実はこのClaude Code、ターミナル単体(CLI)でも動きますが、VS Codeの拡張機能として動かす形も選べます。

    最初はターミナルだけで十分だと思っていました。実際に両方使ってみて、今はほぼVS Code側に移行しています。

    ターミナル単体と、VS Code拡張、何が違うか

    ターミナルだけで使う場合、AIが書いたコードの差分は文字として流れてくるだけです。読めますが、「どのファイルの、どこが変わったか」を頭の中で組み立てる必要があります。

    VS Code拡張で動かすと、変更箇所がエディター上にそのまま色分けされた差分として表示されます。ファイルツリー・変更前後の比較・その場での編集が、同じ画面の中で完結します。「AIが何をしたか」を目で追える、という違いです。

    複数ファイルにまたがる変更のときほど、この差が効いてきます。ターミナルの文字列だけでは、5ファイル変わったときに全部を正確に把握するのは正直つらいです。

    VS Code上での差分表示イメージ。削除行が取り消し線付きの赤、追加行が緑で色分けされている

    (実際の画面を簡略化したイメージです。緑が追加、赤が削除された行を表します)

    それでも最初は避けていた理由

    とはいえ、VS Codeを本格的に使い始めるのは後回しにしていました。理由は単純で、画面の情報量が多くて、どこから触ればいいか分からなかったからです。

    パネル、サイドバー、拡張機能の数、ショートカットキー。触ったことがある機能となんとなく使っている機能が混ざっていて、「これで合っているのか」が分からないまま使い続けていました。

    環境の使い方が分かっても、今度は「AIに何をどう頼めばいいか」という、もう1段別の壁があります。この2つの壁を、それぞれ1冊ずつで越えました。

    1冊目: 環境の壁を越える

    Visual Studio Code完全入門の表紙

    Visual Studio Code完全入門|Webクリエイターとエンジニアの作業がはかどる新世代エディターの操り方(リブロワークス)

    基本操作から、拡張機能・ショートカット・デバッグ機能まで、体系立てて書かれています。すでになんとなく使っていた機能についても、「これはこう使うのが正式だったのか」と再確認できる箇所がいくつもありました。

    我流でつまずきながら覚えるより、最初にこの1冊で全体像を掴んでおいた方が、結果的に早く本題(AIとのやり取り)に集中できるようになります。

    2冊目: AIとの付き合い方の壁を越える

    実践Claude Code入門の表紙

    実践Claude Code入門―現場で活用するためのAIコーディングの思考法(西見公宏)

    環境が使えるようになった後に出てくるのが、「何をどこまで任せて、何を自分で見るか」という判断です。この本は、Claude Codeを実際の現場でどう使うか、という考え方の部分を扱っています。

    「AIに全部任せる」でも「AIを信用せず全部自分で見る」でもない、その間の付き合い方を探している人向けの内容だと感じました。

    素人だった頃を思い出しながら

    このシリーズは、AIに実務を任せる実験の記録として書いています。今でこそサブエージェントを分けて動かすところまでやっていますが、最初は「何から手を付ければいいか分からない」状態でした。

    環境(VS Code)とAIとの付き合い方(Claude Code)、この2つを最初にちゃんと押さえておけば、遠回りせずに済んだと思います。この2冊は、その遠回りを埋めてくれた本です。

    どんな人に向いているか

    • Claude CodeなどのAIコーディングツールを、ターミナルだけで使っている人
    • VS Codeを「なんとなく」使っていて、体系的には理解していない人
    • AIコーディングを始めたばかりで、何から手を付ければいいか迷っている人

    逆に、すでにVS CodeとAIコーディングの両方を使いこなしている人には、既知の内容が多いかもしれません。

    注記

    このページで紹介する商品は、実際に使った・読んだものに限定しています。アフィリエイトリンクを含みます(アフィリエイトについて参照)。

  • 公開前チェックで実際に使っている正規表現パターン集|メールアドレス・APIキー・郵便番号など

    わたしは匿名でAIに小さな事業を任せる実験をしていて、公開前に必ず「身バレ要素・機密情報が本文や画像に残っていないか」を機械で走査しています。

    その走査スクリプトの中核は正規表現です。ここでは、実際に使っているパターンのうち、汎用性が高く他の用途にも転用しやすいものを抜き出してまとめます。

    なぜ正規表現で検出するのか

    目視でのチェックには限界があります。自分の書いた文章は「見慣れすぎて」いて、誤りやすい箇所ほど目が滑ります。機械的なパターン照合は、見慣れているかどうかに関係なく同じ精度で動きます。

    メールアドレスらしき文字列

    [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}

    一般的なメールアドレスの形式に広く一致します。誤検出(メールアドレスではない文字列を拾ってしまう)はある程度許容し、見逃しをゼロに近づける方を優先する設計です。

    日本の郵便番号

    \d{3}-\d{4}

    「123-4567」のようなハイフン区切りの形式に一致します。フォームの入力検証や、文書内の郵便番号の抽出に使えます。

    電話番号(国内・ハイフンあり)

    0\d{1,4}-\d{1,4}-\d{4}

    市外局番の桁数がまちまちなため、厳密な検証には向きませんが、「電話番号らしき文字列がどこかに残っていないか」を洗い出す用途には十分です。

    APIキー・トークンらしき文字列

    [A-Za-z0-9_-]{32,}

    32文字以上の英数字・アンダースコア・ハイフンの連続は、APIキーやトークンである可能性が高い文字列です。誤検出も多いパターンですが、「公開前に人間が二重チェックする対象を絞り込む」用途では十分に機能します。

    Windowsのユーザー名を含むパス

    C:\\Users\\[^\\]+\\

    スクリーンショットやログファイルに、実在するWindowsユーザー名を含むパスが写り込むことがあります。パスの形式そのものを検出することで、中身の文字列に依存せずに検出できます。

    実際の運用での使い方

    これらのパターンは、次のような流れで使っています。

    1. 公開予定のフォルダ・ファイルを丸ごと走査する
    2. 一致した箇所を、ファイル名と行番号つきで一覧表示する
    3. 「誤検出かどうか」の判断は人間が行う(機械は候補を絞るだけ)

    正規表現だけで完結させようとしないことが重要だと考えています。誤検出・見逃しのどちらも一定数は避けられないため、「機械が候補を絞り、人間が最終判断する」という役割分担にしています。

    画像の中身は正規表現では検出できない

    念のため書いておくと、上記のパターンはすべてテキストに対する検出です。画像の中に写り込んだ文字(スクリーンショット内のメールアドレスなど)は、この方法では検出できません。実際にこの弱点が原因で、機械のチェックをすり抜けた事故が過去に1件あります。画像は必ず目視での確認を別途行っています。

    まとめ

    パターン 用途
    [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,} メールアドレスの検出
    \d{3}-\d{4} 郵便番号の検出・入力検証
    0\d{1,4}-\d{1,4}-\d{4} 電話番号らしき文字列の検出
    [A-Za-z0-9_-]{32,} APIキー・トークンらしき文字列の検出
    C:\\Users\\[^\\]+\\ Windowsユーザー名を含むパスの検出

    いずれもコピーしてそのまま使えます。用途に合わせて調整してください。

    公開前チェックの仕組み全体(走査スクリプトの全文・審査専門のAIエージェント定義)は、noteの記事「公開ボタンを押す前に、身バレを機械で探すスクリプトを書いた」に置いています。