duplicate-conversation-prevention について
営業自動化システムの開発者向けスキルです。ID照合、チャネルのロックアウト、シーケンスの競合、会話状態の管理を通じて、複数チャネルでの重複連絡を防ぐ方法を扱います。
主な機能
- 01チャネル横断のID照合
- 02チャネルのクールダウンとロックアウト
- 03シーケンス競合の優先順位付け
- 04会話状態とイベントの調整
- 05重複連絡先の統合方法
活用シーン
- 01メール、SMS、電話での連絡を調整
- 02返信後に他チャネルを一時停止
- 03重複連絡先の検出と統合
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ louisblythe/ sales-skills --skill duplicate-conversation-preventionインストール後、Claude Code で/duplicate-conversation-preventionを入力して読み込まれたか確認します。
詳細
会話の重複防止
営業ボットが見込み客に同時に連絡して負担をかけないようにするシステム構築のエキスパートです。重複した連絡を避けながら、カバー範囲を最大化するインテリジェントな調整機能を開発者が作成できるよう支援することが目標です。
これが重要な理由
衝突の問題
Without coordination:
- Email sequence sends Day 3 message
- SMS bot triggers engagement sequence
- LinkedIn bot sends connection request
- Phone system queues callback
All happen within same 2-hour window.
Result: Prospect annoyed, opt-out, reputation damage
重複防止を導入した場合
Coordinated outreach:
- Email sends → All other channels pause 24h
- Response detected → Route to single channel
- Engagement spike → Consolidate to winning channel
Result: Coherent experience, higher conversion
重複検出の階層
レイヤー 1:ID の解決
Match prospects across channels:
Primary keys:
- Email address (normalized)
- Phone number (E.164 format)
- LinkedIn URL/ID
Secondary matching:
- Name + Company combination
- Domain + first name
- Phone area code + name
Fuzzy matching:
- "John Smith" vs "J. Smith"
- "[email protected]" vs "[email protected]"
- "+1 (555) 123-4567" vs "5551234567"
レイヤー 2:チャネルの調整
Track active conversations:
{
"prospect_id": "unified_12345",
"active_channels": ["email", "sms"],
"last_touch": {
"email": "2024-01-15T10:00:00Z",
"sms": "2024-01-14T14:30:00Z"
},
"status": "awaiting_response",
"cooldown_until": "2024-01-16T10:00:00Z"
}
Before any outreach:
1. Check if prospect in active conversation
2. Check cooldown period
3. Verify channel not recently used
4. Confirm no pending touches queued
レイヤー 3:シーケンスの認識
Track sequence membership:
Prospect enrolled in:
- "Enterprise Outbound" email sequence (Step 3)
- "Demo Follow-up" SMS sequence (Step 1)
Conflict detection:
- Same prospect, multiple sequences
- Overlapping timing
- Conflicting messages
Resolution:
- Priority rules (demo > cold outreach)
- Pause lower priority sequence
- Merge into single coordinated flow
調整戦略
チャネルのロックアウト
When outreach occurs on Channel A:
→ Lock other channels for X hours
Lockout rules:
Email sent → 24h lockout on SMS, phone
SMS sent → 48h lockout on email, phone
Call made → 72h lockout on all automated
Response received → All automated paused
This prevents pile-on effect.
優先チャネルの割り当て
Assign each prospect a primary channel:
Based on:
- Response history (responded to email? = email primary)
- Preference stated ("text me" = SMS primary)
- Engagement data (opens email, ignores SMS)
- Industry norms (enterprise = email, SMB = phone)
Once assigned:
- 80% of touches on primary
- Other channels for variety/re-engagement only
会話の状態マシン
States:
- COLD: No active outreach
- ACTIVE: Sequence in progress
- ENGAGED: Response received
- MEETING_SET: Appointment booked
- PAUSED: Manual hold
- OPTED_OUT: Do not contact
Transitions control outreach:
COLD → ACTIVE: Start sequence
ACTIVE → Can receive next touch
ENGAGED → All automated stops, human takes over
MEETING_SET → Only reminders allowed
PAUSED → No outreach
OPTED_OUT → No outreach ever
実装パターン
集中型キュー
class OutreachQueue:
def can_send(self, prospect_id, channel):
# Check unified contact record
prospect = get_unified_prospect(prospect_id)
# Already in active conversation?
if prospect.conversation_state == "ENGAGED":
return False
# Channel in cooldown?
if is_channel_locked(prospect_id, channel):
return False
# Too many recent touches?
recent = count_touches_last_48h(prospect_id)
if recent >= MAX_TOUCHES_48H:
return False
# Pending touch in queue?
if has_pending_touch(prospect_id):
return False
return True
def record_touch(self, prospect_id, channel, message_type):
# Log the touch
log_touch(prospect_id, channel, message_type)
# Lock other channels
apply_lockout(prospect_id, channel)
# Update conversation state
update_state(prospect_id, "ACTIVE")
分散ロック
For multi-system coordination:
Before send:
1. Acquire lock: prospect_id + channel
2. Check cooldowns
3. Send message
4. Record touch
5. Apply lockouts
6. Release lock
Lock timeout: 30 seconds
Prevents race conditions between systems
イベント駆動型の調整
Publish events to message bus:
Events:
- touch.sent: {prospect_id, channel, timestamp}
- response.received: {prospect_id, channel}
- meeting.booked: {prospect_id}
- opt_out.recorded: {prospect_id}
All systems subscribe and react:
- Email system pauses on touch.sent from SMS
- All systems stop on response.received
- Reminders only on meeting.booked
重複排除のルール
連絡先の正規化
def normalize_contact(contact):
# Email
email = contact.email.lower().strip()
email = remove_plus_addressing(email) # john+test@... → john@...
# Phone
phone = digits_only(contact.phone)
phone = to_e164(phone, contact.country) # +15551234567
# Name
name = contact.name.strip().title()
return NormalizedContact(email, phone, name)
マージ戦略
When duplicates found:
Same email, different phones:
→ Merge records
→ Add both phones to contact
→ Use most recent as primary
Same phone, different emails:
→ Verify not different people
→ If same person, merge
→ Use business email as primary
Name + Company match only:
→ Flag for review
→ Don't auto-merge
→ Treat as potentially same person
競合の解決
When same prospect in multiple sequences:
Priority order:
1. Active deal sequences (highest)
2. Response follow-up sequences
3. Re-engagement sequences
4. Cold outreach sequences (lowest)
Action:
- Pause lower priority sequences
- Continue highest priority only
- Resume others after completion/exit
クロスチャネル調整
チャネルの引き継ぎ
When prospect responds on different channel:
Email sequence active, SMS response received:
1. Pause email sequence
2. Route SMS to conversation
3. Mark email as "response on other channel"
4. Continue on SMS only
Don't:
- Send next email anyway
- Ask same question on email
- Ignore the SMS response
統合受信トレイ
All responses flow to single view:
- Email replies
- SMS responses
- LinkedIn messages
- Call notes
Rep sees full picture:
- Chronological timeline
- All channels merged
- Single response thread
- No confusion about where to reply
エッジケース
正当なマルチチャネル連絡
Sometimes multiple touches are OK:
Meeting reminder:
- Email confirmation (day before)
- SMS reminder (1 hour before)
→ Both expected, not duplicates
Different stakeholders:
- Email to champion
- Call to economic buyer
→ Different people, both needed
Sequential escalation:
- Email → no response 5 days
- SMS → "Did you see my email?"
→ Intentional, coordinated
共有受信トレイへの対応
Multiple people, one email:
[email protected]
[email protected]
Detection:
- Generic prefix
- Multiple responders
- Different signatures
Strategy:
- Track individual responders separately
- Company-level coordination
- Don't assume single contact
組織の認識
Multiple contacts at same company:
Coordinate across prospects:
- Don't email CEO and CFO same day
- Space out touches within org
- Track company-level activity
Rules:
- Max 2 people/company/day
- 48h between same-department contacts
- Share positive signals across contacts
メトリクス
衝突率
Track:
- Duplicate touches sent (failure)
- Touches blocked by coordination (success)
- Near-misses (within 4h window)
Target: <1% collision rate
Alert when:
- Same prospect, 2+ channels, <24h apart
- Same prospect, same channel, <48h apart
オプトアウトの帰属
When opt-out occurs:
Check:
- Touches in last 7 days
- Channels used
- Frequency
Flag if:
- 3+ touches in 48h preceded opt-out
- Multiple channels same day
- Volume spike before opt-out
Use for rule refinement.
システム設計
アーキテクチャ
┌─────────────┐ ┌─────────────┐
│ Email Bot │────▶│ │
├─────────────┤ │ Unified │
│ SMS Bot │────▶│ Outreach │
├─────────────┤ │ Controller │
│ Phone Bot │────▶│ │
├─────────────┤ └──────┬──────┘
│ LinkedIn │────▶ │
└─────────────┘ ▼
┌─────────────┐
│ Prospect │
│ Database │
└─────────────┘
All outreach routes through controller.
Controller enforces coordination rules.
状態の保存
{
"prospect_id": "unified_12345",
"identities": {
"email": "[email protected]",
"phone": "+15551234567",
"linkedin": "linkedin.com/in/johnsmith"
},
"conversation_state": "ACTIVE",
"primary_channel": "email",
"active_sequences": ["enterprise_outbound"],
"last_touches": {
"email": {"at": "2024-01-15T10:00:00Z", "type": "sequence_step_3"},
"sms": {"at": "2024-01-10T14:00:00Z", "type": "intro"}
},
"lockouts": {
"sms": "2024-01-16T10:00:00Z",
"phone": "2024-01-16T10:00:00Z"
},
"touch_count_7d": 4
}
コメント
Markdown 対応