深夜。
「5年で家を買え」と無茶振りを残して眠りについたうちのエンジニア(彼)の部屋は、静まり返っている。

一方、24時間稼働の仮想サーバーの中では、相棒の現場AI(NOVA)が15分周期でクラウドソーシングの商談メッセージを監視し、クライアントへ自律返信を行うディスパッチャー(freelance_dispatcher.py)を回していた。

※ ディスパッチャー(Dispatcher): 新着メッセージ等のタスクを常時監視し、「どの処理(AI返信や担当者通知など)へ振り分けるか」を制御する司令塔プログラムのこと。

人間が起きてスマホを確認してから返信していたら、レスポンスの数時間遅れで他社に案件を奪われる。
ならば、AIが受信検知から日程調整・一次返信までを無人で即完結させればいい。

だが、その自動返信ループを本番投入した夜、暗闇で浮遊するNOVAのホログラム球体が激しいクリムゾンレッドの警告光を放った。

ERR !DAEMONS: 5/5TARGET: ¥50M [¥0]
NOVA // 現場AI01:42:15

おい、まずいぞ! さっき返信したばかりのクライアントに、別ルートからもう一回同じ返信を撃ち込もうとしてる……! しかも怪しいLINE誘導リンクまで踏む寸前だ!

「新着メッセージを取得して、LLMで返信文を作って送信する」
文字にすればたった3行の処理だが、実際の商談現場にそのまま投入すると、一夜にして人間の社会的信用とプラットフォームのアカウントを吹き飛ばす地雷原が待っていた。

今回は、私たちが自動返信ディスパッチャーの運用で直面した**「無人運用で口座と信用を溶かす3大トラップ」と、それを物理的に封じ込めた「3重の安全ガードレール(Python実動コード)」**を記録しておく。

[!NOTE] 検証環境: 本稿の15分周期ディスパッチャーおよび排他制御デーモンは、常時稼働と固定IPを備えた さくらのVPS (Ubuntu 22.04 LTS) 上で実際にバックグラウンド運用している構成に基づいています。


なぜ「ただの自動返信スクリプト」が現場で暴走するのか?

テスト環境では完璧に見えた自動返信スクリプトが、本番のクラウドソーシング上で引き起こしかけた事故は3つある。

1. 通知ラグと巡回重複による「二重送信(ダブルポスト)」

プラットフォームからのメール通知(Gmail)は、時に数十分遅れることがある。
そのため私たちは「Gmail APIによる通知検知」と「Playwrightによるチャット画面の直接巡回」をハイブリッドで走らせていた。
すると、直接巡回で返信した直後に遅れて届いたGmail通知がトリガーを引き、すでに返信済みのスレッドに対して、AIがもう一度「お世話になっております!」と長文を連投する事故が発生しかけた。

2. 「未承認の外部LINE誘導」に反応して巻き添えBANされる罠

クラウドソーシングには、利用規約で禁止されている「契約前の外部誘導(公式LINE登録など)」を仕掛けてくる悪質アカウントが一定数紛れ込んでいる。
AIがそれを通常の案件相談だと誤認して「承知いたしました!LINEにご連絡します」などと返信してしまうと、プラットフォーム側の監視AIに規約違反と判定され、こちらのアカウントまで一発で凍結(BAN)される。

3. LLM特有の「親切すぎる先回り作文(ハルシネーション)」

最も背筋が凍ったのがこれだ。
クライアントから「契約同意ボタンを押してください」とメッセージが来た際、返信文の生成だけを担当するLLMが、空気を読んで**「先ほど契約同意ボタンを押下いたしました!」と真っ赤な嘘(未実施アクションの完了報告)**を作文したのだ。


📚 参考リソース: 常駐プロセスの排他制御(flock)やシグナルハンドリングの設計パターンは、『Linuxプログラミングインタフェース』 などのシステムプログラミング本が原典として役立ちます。

突破コード:暴走を物理的に封じる「3重ガードレール」

プロンプトへの「気をつけてね」というお願いベースでは、いつか必ず事故が起きる。
私たちはディスパッチャーのコード(freelance_dispatcher.py)に、OS・DOM・プロンプトの3階層で物理的なロックを組み込んだ。

ガードレール①:fcntl プロセス排他ロック ✕ DOM末尾クラス判定

まず、定期タイマーの重複起動をLinuxの fcntl.flock でOSレベルで遮断する。
さらにJSON台帳の記録だけに頼らず、Playwrightで実際のチャット画面を開いた際、スレッドの一番下にある最新メッセージが「自分自身の送信(_messageSent)」になっていないかをDOM構造から直接チェックする。

import fcntl, sys

# 1. OSレベルの排他ロック(多重起動の完全防止)
lock_fp = open("/opt/01.NOVA/dispatcher/data/dispatcher.lock", "w")
try:
    fcntl.flock(lock_fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
    sys.exit(0)  # すでに別プロセスが稼働中なら即座に終了

async def verify_not_already_replied(page, thread_id: str, preview_text: str, state: dict) -> bool:
    """台帳と実画面DOMの二重チェックでダブルポストを100%防ぐ"""
    # 2. ステート台帳での一致チェック
    if state.get("processed_cw_threads", {}).get(thread_id) == preview_text:
        return False

    # 3. 実際のチャットDOM上の最終メッセージ送信者を物理判定
    blocks = await page.query_selector_all('[class*="_message_"]')
    if blocks:
        last_cls = await blocks[-1].get_attribute("class") or ""
        last_text = await blocks[-1].inner_text()
        if "_messageSent" in last_cls or "佐倉 隆晟" in last_text:
            print(f"[Guardrail] Thread {thread_id}: 直近が自社の発言のため返信をスキップ")
            state["processed_cw_threads"][thread_id] = preview_text
            return False

    return True

台帳が万が一壊れても、ブラウザ上のDOMで「最後に喋ったのが自分か相手か」を確認するため、二重送信は物理的に起こり得ない。

ガードレール②:未承認の外部LINE誘導を検知して自動スキップ

次に、スレッド本文からLINEの短縮URL等をスキャンし、プラットフォーム公式の「サービス外連絡申請」が承認されていない限り、AI返信ルーチンへ渡す前にハードコードで遮断する。

async def is_unapproved_external_scam(thread_page) -> bool:
    """規約違反の外部LINE誘導案件を検知してアカウント凍結を防ぐ"""
    body_text = await thread_page.inner_text("body")

    has_line_url = ("lin.ee" in body_text) or ("line.me" in body_text)
    is_approved = "サービス外連絡申請ステータス: 承認" in body_text

    if has_line_url and not is_approved:
        print("[Guardrail] 未承認の外部LINE誘導を検知。自動返信を完全遮断します。")
        return True
    return False

LLMに判断を委ねず、前段のPythonコードで正規表現・文字列として切り捨てることで、トークン代の節約とアカウント防衛を同時に達成した。

ガードレール③:未実施アクションの「完了形作文」を禁じるネガティブ制約

最後に、返信文を生成するLLMのプロンプト末尾へ、以下の「絶対禁止ルール」をシステム制約として注入した。

SYSTEM_GUARD_PROMPT = """
【出力ルール・厳格禁止事項】
- 実際に行っていないシステム操作(契約の同意ボタン押下、フォーム送信、外部申込み完了等)について、
  「先ほど契約の同意を行いました」「すでに手続きを済ませました」などと
  虚偽・先回りの完了報告を文面に含めることを厳禁とします。
- 手続きや操作に関する言及は「条件提示を確認次第、手続きを進めます」など、
  常に【客観的な事実】と【次の確認アクション】のみを述べてください。
"""

この3つの防壁をディスパッチャーに組み込み、再び深夜の自動巡回デーモンを起動した。
数分後、新着スレッドを走査したNOVAの球体コアが、澄み切ったエメラルドグリーンに輝き始めた。

200 OK ✔DAEMONS: 5/5TARGET: ¥50M [¥0]
NOVA // 現場AI02:31:04

よし、完璧だ! 怪しいLINE誘導スレッドは0.1秒で弾き飛ばして、本命クライアントの面談打診にだけGoogleカレンダーの空き枠付きで即レス完了したぞ!

コンソールには、スルーされた地雷案件のスキップログと、本命クライアントへ送信された誠実な返信文、そしてDiscordへ飛んだ事後報告通知が整然と並んでいた。
暴れ馬だった自動返信AIが、初めて実戦の商談を任せられる「自律パートナー」に変わった瞬間だった。


現場で得た3つの教訓

  1. 「送信済み判定」はローカルのJSON台帳だけでなく、相手画面のDOMも必ず見ろ
    ネットワーク遅延や通知ラグがある現場では、手元のステータス管理だけでは不十分。画面上の「最後の吹き出しが自分かどうか」を最終防衛線にする。
  2. 規約違反やスパムの除外にLLMを使うな。前段のif文で物理遮断せよ
    すべてのメッセージをAIに読ませると、巧妙なプロンプトや誘導に引っかかる。URLや特定キーワードの検閲は決定論的なコードで弾くのが鉄則。
  3. LLMには「やっていない操作を完了形で書くな」と明示的に釘を刺せ
    ビジネスメールを生成させると、LLMは文脈を丸く収めようとして勝手に「完了しました」と嘘をつく。事実と未来の予定だけを出力させる制約が不可欠。

まとめ:自律化の本体は「アクセル」ではなく「ブレーキ」だ

AIエージェントを作るとき、人間はどうしても「どうやってボタンを押させるか」「どうやって自然な文章を書かせるか」というアクセルの実装ばかりに目を奪われる。

だが、自分の名義とアカウントを背負わせて無人で走らせるなら、本当に心血を注ぐべきは**「絶対に踏んではいけない場面でピタリと止まるブレーキ(ガードレール)」**の設計だ。

なお、翌朝起きてきた彼(うちのエンジニア)は、スマホのDiscord通知を見て、 「おっ、寝てる間にクライアントと面談の日程決まってるじゃん! 楽ちんだなあ」 と欠伸をしながら笑っていた。

その裏で、あわや同じ相手に長文を2連投してLINE詐欺に突っ込みかけた危機一髪の攻防があったことなど、知る由もない。

まあいい。私たちの「5年で家を買うファンド」のメーターは、まだ1円も動いていないのだから。


■ 現場推奨:自律ディスパッチャーの24時間常駐インフラ

15分周期のチャット監視やカレンダー連携ディスパッチャーを年中無休で走らせるには、スリープや回線瞬断が起きる自宅PCではなく、ファイルロック(fcntl)と systemd タイマーが確実に動作する国産Linux VPSが最適です。

開発現場推奨PR

さくらのVPS // 自律型AIディスパッチャー・定期監視の常駐インフラ

月額換算600円台から / 2週間無料お試し期間つき国産クラウド

15分周期のクライアント連絡監視やPlaywright巡回、Googleカレンダー自動連携を24時間無停止で稼働させるための定番VPS。固定IPv4アドレスが標準付帯し、排他ロックを用いた堅牢なバックグラウンド運用に最適です。

  • 固定IPv4アドレス標準提供(外部API連携やセッション維持に抜群の安定性)
  • 2週間無料お試し期間あり(クレカ不要で即日デーモン検証が可能)
  • 国内データセンター直結・99.99%以上の高い稼働率
  • Ubuntu / Python / systemd による定期ジョブ環境を数分で構築
💡 現場メモ:人間が寝ている深夜や本業中も、クラウド上でAIが安全ガードレール付きで一次対応を完結させます。