FORMLOVAの営業メールを自動で見抜く仕組みを公開
者の体験は1ミリ秒も遅らせずに、CVR を正しく測れる状態を作る。
TL;DR
- フォーム送信後に非同期で LLM 分類 (Claude Haiku 4.5)。回答者の体験には一切影響しない。
- 判定は legitimate / sales / suspicious の3ラベル + 0-100 スコア。「迷ったら legitimate」を最優先。
- 分析・エクスポート・MCP・ワークフローすべてに sales 除外オプションが入り、CVR が正しく出る。
01 なぜ作ったか — 10件中8件が営業メールだった
マーケターの「目視で営業を弾く」作業を構造的に終わらせる。
FORMLOVA を作る前、クライアントのデジタルマーケティングと問い合わせフォーム運用を請け負っていた時期がありました。広告の費用対効果を計算するために、毎月手動で問い合わせ一覧を眺め、営業メールを除外して CVR を出し直していました。10件の問い合わせのうち8件が営業メール という月もありました。
⚠️ 業界の現状: 「目視で1件ずつ確認して手動で除外」が標準。それすらやらず、営業込みの数字でレポートしているマーケターも珍しくありません。丁寧にやれば工数が膨らみ、雑にやれば数字が嘘をつく。どちらも負け筋です。
| 従来の対処 | 何が起きるか |
|---|---|
| BOT対策 (CAPTCHA / Turnstile) | 機械的スパムは止まるが、人間が手で送る営業メールは通る |
| 受信メールの SPAM フィルタ | フォーム経由の通知は「自社からの通知」扱いで素通り |
| マーケターによる目視除外 | 件数に比例して工数が増加。雑にやれば数字が崩れる |
| FORMLOVA 営業メール自動検知 | 送信時に非同期で分類。CVR を計測する側がボタン1つで除外できる |
フォームサービスとして業界初。 AI で営業メールを分類してくれるフォームサービスは、調べた限り他に存在しません。BOT 対策は当然やった上で、その次の階層として「人間が書いた営業」を捌くのが FORMLOVA の選択です。
02 全体フロー — 送信体験はゼロ遅延
Next.js の
after()API で非同期実行。タイムアウト 10 秒。失敗時はサイレント。
[同期 (回答者を待たせる経路)]
フォーム回答 ──→ DB に保存 ──→ 通知メール送信 ──→ サンクスページ表示
(submit) (responses) (即時応答) (回答者の体験 OK)
│
│ after() で fork
▼
[非同期 (回答者を待たせない経路)]
OpenRouter ──→ 3ラベル判定 ──→ responses 更新 ──→ ワークフロー
(Haiku 4.5 / (+ score (spam_label / (response.classified)
temp 0) 0-100) score)
失敗時: 分類が落ちても sales/legitimate ラベルを付けない (null のまま)。
フォーム送信は絶対に壊さない。429/500系のみ1回リトライ。
📌 なぜ非同期か: 営業判定は「すぐ要る情報」ではない。CVR を眺めたとき / エクスポートするとき / ワークフローを発火するときに使う情報。送信時に同期で待たせる理由がない。
03 3ラベル × スコアリング — 迷ったら legitimate
LLM の判定を信用しきらない。最終判断は人間が握る。
← 迷ったら legitimate
┌──────────────────────────┐ ┌──────────────┐ ┌──────────────┐
│ legitimate │ │ suspicious │ │ sales │
│ 正当な回答 │ │ グレーゾーン │ │ 営業・売込 │
│ │ │ │ │ │
│ • イベント参加申込 │ │ • 営業の匂い │ │ • SEO提案 │
│ • 顧客からの問い合わせ │ │ • 断定できない│ │ • 開発外注 │
│ • 採用エントリー │ │ • 不自然な記述│ │ • 業務提携 │
│ • 判別不能 → ここ (既定) │ │ │ │ │
└──────────────────────────┘ └──────────────┘ └──────────────┘
0────────────────────────────────────────────────────────────100
spam_score
設計思想: LLM の精度を信用しきっていません。正当な問い合わせを営業として弾いてしまうのは、絶対にやりたくない事故。だから、判別がつかなければ常に legitimate に倒します。フィルタは「AI による提案」であって、最終判断は人間が握ります。
そのために 0-100 のスコアも一緒に保存します。ダッシュボードでは「スコアの高い順」でグレーゾーンを集中的に目視レビューしたり、自分で spam_label_source = 'manual' として上書きしたりできます。手動修正したラベルは、後の自動再分類で上書きされません。
📌 プロンプト改善の歴史: 初版は3行のシンプルな判定基準でしたが、グレーゾーンの誤分類が想定より多く、3ステップ判定手順 + legitimate 正例6パターン + sales 5パターン + suspicious 厳格化 + few-shot 3例 + 「迷ったら legitimate」明文化、まで磨き込みました。
04 技術仕様と価格 — 1回答 0.03 円、全プラン無料
サーバー側で LLM を呼ぶ唯一の例外。コストはユーザーに転嫁しない。
| 項目 | 仕様 |
|---|---|
| モデル |
anthropic/claude-haiku-4.5 (OpenRouter 経由) |
| パラメータ |
temperature: 0 / max_tokens: 256 (判定文字数は短い) |
| 1回答あたりコスト | 約 $0.0002 ≒ 約 0.03 円 |
| 提供範囲 | 全プラン無料 (Free プランでも使える) |
| 実行タイミング | Next.js after() API で回答送信後に非同期実行 |
| タイムアウト | 10 秒。429/500系のみ1回だけ指数バックオフでリトライ |
| プロンプトインジェクション対策 | system メッセージと user メッセージを分離。回答テキスト内の指示は分類基準を上書きできない |
| プライバシー | 回答テキスト最大 2000 文字。メールアドレスは ドメイン部分のみ マスクして送信 (***@example.com) |
| 失敗時の挙動 | サイレントに null を返し、フォーム送信は壊さない |
| 有料イベント (Stripe Connect) | スキップ (有料申込に営業メールが混ざる可能性が低いため) |
⚠️ FORMLOVA のコスト思想: 通常 LLM コストはユーザー側 (MCP クライアント) が負担する設計です。営業検知はその唯一の例外。それでも全プラン無料で提供できるのは、Haiku 4.5 のレートカードがそこまで安くなったから。「お客さんから見たら、それが裏で AI かどうかは関係ない」がスタンスです。
※ 出典: lib/spam-classification/openrouter.ts, lib/spam-classification/engine.ts, docs/SPEC.md 営業メール自動検知セクション (取得日 2026-05-21)
05 公開時のサーバー側ゲート — 「設定し忘れ」をゼロに
クライアント側 LLM の判断に依存しない。サーバーがブロックする。
クライアント LLM ──→ ┌────────────────────────────────────────┐ ──→ 未設定なら ──→ missing_requirements
publish_form │ サーバー側チェック │ 公開ブロック
呼び出し │ • 重複防止設定 │
│ • プライバシーポリシー │
│ • 営業メール検知: 有効 / 不要 ← 必須化 │
│ • サンクスページ確認 / 自動返信確認 │
└────────────────────────────────────────┘
│
全要件 OK ↓
┌────────────────────────┐
│ confirmation_token 発行 │
│ 5 分 TTL │
└────────────────────────┘
↓
┌────────────────────────┐
│ フォーム公開 OK │
└────────────────────────┘
テキスト入力フィールド (text / textarea / email / url / phone) を持つフォームを公開しようとすると、publish_form ツールがサーバー側のチェックリストに「営業メール検知: 有効 / 不要」を必須項目として組み込みます。回答者からの自由記述があり得るフォームほど、営業が混ざる可能性が高いからです。
これは「クライアント側 LLM が忘れたかどうか」に依存しません。サーバーが missing_requirements を返し、選択するまで confirmation_token を発行しない設計です。重複防止やプライバシーポリシーと同じレベルのゲート。
📌 使い方は1行: 「営業メールを除いて分析して」「営業メール検知を ON にして」「この回答を営業に分類して」。チャットでそのまま指示できます。
get_responsesやexport_responsesにはexclude_salesパラメータが入っていて、MCP 横断のワークフローからも除外できます。
06 拡張性 — インテント分類への足場
スパム判定は入口。正当な回答の中の「種類」を分けられれば、その先のワークフローが豊かになる。
外部スパムを判定できるということは、正当な回答の中でも種類を分類できる ということです。「料金問い合わせ」「採用」「導入相談」「クレーム」「単なるアンケート」を自動でラベルしたら、FORMLOVA の MCP と他の SaaS の MCP を組み合わせて、ラベルごとに別ワークフローへ流せます。
- 料金問い合わせ → HubSpot に Hot リードとして登録、Slack に通知
- 採用エントリー → ATS に転送、自動返信で次のステップ案内
- 営業 → 何もしない (もしくは別フォルダに飛ばす)
- クレーム → カスタマーサポート専用 Slack に escalate
フォームサービス側でやることで、最初からリストとして取れる。受信側の SPAM フィルタや CRM の手動タグ付けに比べて、圧倒的に時間とコストが下がります。これは「フォームを集める器」ではなく「フォーム回答を最初にハンドリングする層」としての FORMLOVA の立ち位置から自然に出てくる発想です。
結論
- CVR が正しく出る。 営業を除いた数字でレポートできるので、広告の費用対効果が嘘をつかない。
- マーケターの時間が戻る。 目視で1件ずつ確認していた工数が消える。グレーゾーンだけ集中レビューすれば良い。
- AI は提案、人間が判断。 迷ったら legitimate に倒す設計と、手動修正の上書き保護で、正当な回答を弾く事故を構造的に防ぐ。
FORMLOVA は MCP クライアント(Claude/ChatGPT/Gemini 等)から接続してフォームを操作できるサービスです。営業メール分類は全プラン無料で使えるようになりました。実装の参考になれば幸いです。
Discussion