ワークフロー

メッセージ生成

Sales Claw が「この会社だけに書いた」文面を生成する仕組みを、実装ファイルレベルで解説します。

1. アーキテクチャ概要

Sales Claw のメッセージ生成は「機械処理で事実を抽出」「AI で文面を起こす」を 明確に分離した 2 段構成です。事実は parallel-analysis.cjs が HTTP フェッチで集め、 文面は CLI エージェント (Claude / Codex / Gemini) がプロンプトに基づいて生成します。

  • Phase A (並列・MCP 不使用) — 各社の公式サイトを HTTP で fetch し、事業領域・注力分野・ ギャップ・サイト抜粋を抽出。AI 推論はここでは行わず純粋なパース処理。
  • Phase A.5 (CLI 文面生成) — Phase A の analysis から buildMessagePrompt(analysis)が CLI 用プロンプトを構築。CLI がそれを受けて 1 社ずつ本文を最終化。
  • Phase B (順次・MCP Playwright) — 生成した本文を実ブラウザのフォームに入力し、 スクリーンショットを撮ってユーザーの承認待ちに登録。

AI を呼ぶのは Phase A.5 のみで、しかも「プロンプトが完全に固まった状態」で呼ぶため、出力の 再現性とコストコントロールが効きます。フェールセーフ用に buildCustomMessage(analysis)のテンプレート生成も常に裏で動いており、CLI が失敗した場合のフォールバックとして機能します。

2. 2 フェーズ生成パイプライン

┌────────────── Phase A (並列, haiku 推奨) ──────────────┐
│ parallel-analysis.cjs                                  │
│   ├─ fetchSite(companyUrl)       … HTML + テキスト抽出 │
│   ├─ analyzeBusiness(text)       … 事業領域・キーワード│
│   ├─ findKeyPages(html)          … ニュース・採用 etc. │
│   └─ extractFormCandidates(html) … 問い合わせ導線     │
│ → analysis = { businessAreas, gaps, focusAreas,        │
│                excerpts, formUrl?, ... }               │
└────────────────────────────────────────────────────────┘
                       │
                       ▼
┌────────────── Phase A.5 (sonnet 推奨) ─────────────────┐
│ message-builder.cjs                                    │
│   buildMessagePrompt(analysis) ───► CLI に渡すテキスト │
│   CLI (Claude/Codex/Gemini)    ───► 最終本文を生成    │
│   buildCustomMessage(analysis) ───► フォールバック    │
└────────────────────────────────────────────────────────┘
                       │
                       ▼
┌────────────── Phase B (順次, sonnet) ──────────────────┐
│ MCP Playwright で実ブラウザにフォーム入力              │
│ → スクショ → awaiting_approval ログ                    │
└────────────────────────────────────────────────────────┘

3. analysis オブジェクトの構造

parallel-analysis.cjs が返す analysis オブジェクトは、Phase A.5 の唯一の入力です。 プロンプトに何が渡るかを理解すると、設定の効き方が読みやすくなります。

type Analysis = {
  // ── 基本情報 ───────────────────────────────
  companyName: string;            // 会社名 (ターゲットリストから)
  companyUrl?: string;            // 公式サイト URL (空ならフォーム探索が走る)
  formUrl?: string;               // 既知のフォーム URL

  // ── 事業領域の抽出結果 ─────────────────────
  businessAreas: string[];        // 例: ["CMS構築", "EC構築", "DX支援"]
  focusAreas: string[];           // 例: ["Sitecore", "Adobe Experience Manager"]
  keywords: string[];             // テキスト頻出語のトップ N

  // ── ギャップ分析 ──────────────────────────
  // 設定の valuePropositions.strengths と相手企業の業務領域から
  // 「相手にとって価値が出そうな」テーマを抽出
  gaps: Array<{
    strength: string;             // 自社の強み (settings.json 由来)
    rationale: string;            // なぜ相手に刺さりそうか
    confidence: 'high' | 'mid' | 'low';
  }>;

  // ── サイト抜粋 (生のテキスト引用) ──────────
  excerpts: Array<{
    page: 'top' | 'service' | 'about' | 'news' | 'recruit';
    text: string;                 // ~200 文字程度の生テキスト
  }>;

  // ── サンプル/コンプライアンス情報 ──────────
  isSalesNg: boolean;             // 営業 NG 文言の検出
  hasContactForm: boolean;        // 問い合わせフォームの存在
  captchaDetected?: 'recaptcha-v2' | 'recaptcha-v3' | 'hcaptcha' | 'turnstile';
};

4. buildMessagePrompt の出力構造

buildMessagePrompt(analysis) は、以下のセクションを順番に持つテキストプロンプトを返します。 CLI はこのプロンプトを「そのまま」受け取って本文を生成します。

# CONTEXT
- 会社名 / 公式 URL / 既知のフォーム URL
- 事業領域 / 注力分野 (analysis.businessAreas, focusAreas)
- 自社プロフィール (companyProfile)

# APPROACH OBJECTIVE
${messageTemplates.approachObjective}
(例: "CMS 構築・リニューアルの相談窓口として認知してもらう")

# APPROACH GUARDRAILS
${messageTemplates.approachGuardrails}
(例: "価格や競合比較は書かない。相手の課題を決めつけない")

# GAP ANALYSIS
- analysis.gaps から confidence:high のみ最大 3 件
- 「自社の強み × 相手の業務領域」のペアごとに rationale を提示

# SITE EXCERPTS
- analysis.excerpts のうち最も関連度の高い 1-2 件
- 「貴社の◯◯事業を拝見し…」という導入の根拠

# CONSTRAINTS
- 400〜600 文字
- 自社紹介から入らない、相手の事業から入る
- テンプレート感を排除する
- Compliance Footer は自動付与されるので本文には含めない

# OUTPUT
プレーンテキストの問い合わせ本文のみ (Markdown 禁止)

ポイントは APPROACH OBJECTIVEAPPROACH GUARDRAILS がそのまま CLI の 制約として反映されることです。設定で「やりたいこと」「やってはいけないこと」を 1〜2 行ずつ書くだけで、 全社共通の文体ガイドが効くようになります。

5. メッセージ作成 8 原則

これらは approachObjective / approachGuardrails 経由で CLI に伝わります。

  1. 相手の事業から入る — 自社紹介は最後にする。書き出しは「貴社の◯◯事業を拝見し」
  2. この会社だけに書いた感を出す — analysis.excerpts から 1 件は必ず引用する
  3. 尖った強みに集中 — 全部伝えようとしない。gaps から high 1〜2 件のみ
  4. Win-Win は匂わせ程度 — 「お互いに〜」は使わない、相手のメリットだけを書く
  5. 実績は控えめに — 企業名より数字 (「190 件超」のような表現)
  6. 相手の課題を決めつけない — 「〜とお見受けします」「もしご検討の余地があれば」
  7. 提供価値を前面に — 「相手に何ができるか」を先に書き、相談を促すクロージング
  8. コンパクトに — 400〜600 文字、読了 1〜2 分。改行多めで視認性確保

6. 設定リファレンス

data/settings.json の以下のキーが直接プロンプトに作用します。 ダッシュボードの Settings タブ から GUI でも編集可能です。

{
  "companyProfile": {
    "companyName": "株式会社サンプル",
    "contactName": "中澤 圭志",
    "email": "contact@example.com",
    "phone": "070-XXXX-XXXX"
  },
  "messageTemplates": {
    "approachObjective": "CMS 構築・リニューアルの相談窓口として認知してもらう",
    "approachGuardrails": "価格や競合比較は書かない。相手の課題を決めつけない",
    "tone": "professional",
    "signature": "{name}\n{company}\nTEL: {phone}"
  },
  "valuePropositions": {
    "strengths": [
      "Sitecore 国内導入実績 No.1",
      "CMS 構築 190 件超",
      "Adobe Experience Manager 連携"
    ],
    "successPatterns": [
      "金融 SI の社内 DX 部門と CMS 刷新を共同推進",
      "製造業のグローバル CMS 統合"
    ],
    "industryProfiles": {
      "manufacturing": "製造業向けテンプレ…",
      "saas": "SaaS 向けテンプレ…"
    }
  },
  "preferences": {
    "complianceFooter": true,
    "minBodyChars": 400,
    "maxBodyChars": 600
  }
}
  • valuePropositions.strengths — ギャップ分析の素材。3〜8 件が経験上ベスト。
  • valuePropositions.successPatterns — 「直接の自慢」ではなく「協業の文脈」として CLI が間接的に引用。
  • valuePropositions.industryProfiles — フォールバック生成時の業種別テンプレ。
  • preferences.minBodyChars / maxBodyChars — 字数レンジ。範囲外は再生成 or トリム。

7. Good / Bad の対比例

同じ analysis から、原則を守った場合と守らなかった場合の差を示します。

❌ Bad — 自社紹介から入る・テンプレ感

株式会社サンプルの中澤と申します。 弊社は Sitecore 国内導入実績 No.1 の CMS ベンダーで、190 件超の構築実績がございます。 御社の事業に弊社のサービスは必ずお役に立てます。ぜひお打ち合わせの機会をいただけませんでしょうか。

✅ Good — 相手の事業から入る・引用付き

貴社のグローバル製造拠点向けの CMS 統合の取り組みを拝見し、ご連絡いたしました。 特に「多言語サイトの運用負荷削減」をテーマに掲げられている点が印象に残っています。 私どもは Sitecore を中心に CMS 構築を 190 件ほどお手伝いしており、 製造業のグローバル統合 CMS のプロジェクトでは、地域ごとの編集権限と 公開フローの分離をテンプレ化したことで、運用工数を 4〜6 割削減できた事例があります。 もし「グローバル CMS 統合」のテーマでヒアリングや事例共有の場をお取りいただけそうでしたら、 30 分ほどのオンライン打ち合わせでも構いません。お気軽にご検討ください。

8. AI CLI ごとの特性

CLI強み注意点推奨用途
Claude Code日本語の文章品質、トーン制御、長文の構成API コストは中〜高 (sonnet 4.6 / 4.7)BtoB 営業文面、品質最優先
Codex CLI低コスト、構造化指示への素直な追従感情面・抑揚は Claude より弱い大量送信、テンプレ強め運用
Gemini CLIGoogle 検索連携、グラウンディング日本語表現に個性が出やすい (要 guardrails)業界調査込みで文面化したい時

AI CLI セットアップのページで、それぞれのインストールと API キー 設定の手順を解説しています。

9. フォールバック動作

CLI 呼び出しが以下のいずれかになった場合、buildCustomMessage(analysis) のテンプレ生成に自動フォールバックします。

  • CLI のプロセス起動に失敗 (PATH 不在 / 認証エラー)
  • 30 秒以内に応答が無い (タイムアウト)
  • 生成された本文が minBodyChars を下回る / maxBodyChars を上回り、リライトも失敗
  • 本文に placeholder 文言 (例: 「【URL 不在のため CLI 本体が最終化します】」) が残っている

フォールバック時は valuePropositions.industryProfiles の業種別テンプレが選択され、{companyName} / {strengths} / {contactName} 等の 変数が埋め込まれます。テンプレ感は強くなりますが、最低限の品質は保たれます。

10. Compliance Footer

preferences.complianceFooter: true (デフォルト) の場合、特定電子メール法第 4 条の 4 要件 (送信元会社名・氏名・連絡先メール・オプトアウト案内) が 本文中に揃っているかを src/compliance.cjs がチェックします。

不足要素のみ自動追記される実装になっており、以下のような文末ブロックが必要に応じて生成されます:

────────────────────────────
株式会社サンプル  中澤 圭志
TEL: 070-XXXX-XXXX
Email: contact@example.com
今後のご連絡が不要な場合は、お手数ですが本メールへのご返信にてお知らせください。

API: POST /api/compliance/check でも単体検証が可能で、レスポンスに { status: 'ok' | 'warn' | 'fail', missing: [...] } が返ります。

11. トラブルシューティング

症状原因の典型対処
生成本文がテンプレ感強いanalysis.excerpts が空 / 短すぎる公式サイトのトップ/サービスページが薄いケース。companyUrl を見直し、必要なら「会社名 + 公式」検索で代替 URL を探す
「弊社は」「弊社の強みは」で始まるapproachGuardrails に「自社紹介から始めない」を入れていないguardrails に明文化し、CLI モデルを sonnet 以上に
文字数オーバーmaxBodyChars 未設定 or 大きすぎる500〜700 が経験的に最適。Claude/Codex とも 1000 を超えると冗長化しやすい
署名が二重に入るCLI が本文末尾に署名 + Compliance Footer も自動追記guardrails に「署名は付けない (Compliance Footer 自動付与)」を追記
422 で awaiting_approval が拒否されるdetails.sentMessage が欠如 or 30 文字未満1.2.100+ の API ガード仕様。フォーム本文欄に実入力した文字列を sentMessage として渡す

12. 関連ドキュメント