400电话来电时,系统自动与CRM客户通讯录比对,显示正确的客户信息:
┌─────────────────────────────────────────┐
│ ☎️ 来电弹屏 - 4008-320-160 │
├─────────────────────────────────────────┤
│ 📞 来电号码: 138****8888 │
│ 🏢 客户公司: 宁波奥克斯空调有限公司 │
│ 👤 联系人: 张经理 (采购部) │
│ ⭐ 客户等级: VIP金牌客户 │
│ 📊 年交易额: ¥580万 │
│ 📋 历史订单: 12笔 │
│ 🕐 上次联系: 2024-06-10 (5天前) │
│ 📝 备注: 正在洽谈PCR-ABS批量订单 │
├─────────────────────────────────────────┤
│ 🎯 本次来电意图: 产品咨询 (按1) │
│ 📌 建议处理: 优先转接销售经理A │
│ ⚡ 紧急度: 高 (VIP客户) │
├─────────────────────────────────────────┤
│ [接听] [转接] [留言] [挂断] [查看详情] │
└─────────────────────────────────────────┘
# 来电识别与CRM匹配
async def match_caller_with_crm(caller_number: str) -> dict:
"""
来电号码与CRM客户通讯录比对
"""
# 1. 格式化号码(去除区号、空格等)
formatted_number = format_phone_number(caller_number)
# 2. 精确匹配
customer = await db.query("""
SELECT c.*, cp.name as contact_name, cp.department, cp.position
FROM customers c
LEFT JOIN customer_contacts cp ON c.id = cp.customer_id
WHERE cp.phone = ? OR cp.mobile = ? OR c.phone = ?
LIMIT 1
""", (formatted_number, formatted_number, formatted_number))
if customer:
return {
"matched": True,
"customer_id": customer["id"],
"company_name": customer["company_name"],
"contact_name": customer["contact_name"],
"department": customer["department"],
"position": customer["position"],
"customer_level": customer["level"], # VIP/普通/潜在客户
"annual_revenue": customer["annual_revenue"],
"order_count": customer["order_count"],
"last_contact": customer["last_contact_date"],
"tags": customer["tags"], # 标签: 大客户/长期合作/价格敏感
"notes": customer["notes"]
}
# 3. 模糊匹配(号码部分匹配)
similar_customers = await db.query("""
SELECT * FROM customers
WHERE phone LIKE ? OR mobile LIKE ?
""", (f"%{formatted_number[-8:]}%", f"%{formatted_number[-8:]}%"))
# 4. 未匹配到 - 标记为新线索
return {
"matched": False,
"caller_number": caller_number,
"status": "new_lead",
"suggestion": "创建新客户档案"
}
-- 客户通讯录扩展表
ALTER TABLE customer_contacts ADD COLUMN IF NOT EXISTS
phone_type VARCHAR(20) DEFAULT 'mobile', -- mobile/landline/wechat
is_primary BOOLEAN DEFAULT FALSE, -- 是否主联系人
call_preference VARCHAR(20) DEFAULT 'any', -- any/morning/afternoon
last_call_date TIMESTAMP,
call_count INTEGER DEFAULT 0;
-- 来电识别记录表
CREATE TABLE IF NOT EXISTS caller_identifications (
id SERIAL PRIMARY KEY,
call_record_id INTEGER REFERENCES phone_call_records(id),
caller_number VARCHAR(32) NOT NULL,
matched_customer_id VARCHAR(64),
matched_contact_id INTEGER,
match_confidence DECIMAL(3,2), -- 匹配置信度
company_name VARCHAR(128),
contact_name VARCHAR(64),
department VARCHAR(64),
position VARCHAR(64),
customer_level VARCHAR(32),
identified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
---
每次400电话通话结束后,自动将通话内容推送到CRM系统的客户沟通记录中:
# 通话录音转文字
async def transcribe_call_recording(call_record_id: str) -> dict:
"""
使用AI语音识别将通话录音转为文字
"""
# 1. 获取录音文件
recording = await get_recording_file(call_record_id)
# 2. 调用语音识别API(本地模型或云服务)
# 方案A: 本地Whisper模型(MacStudio)
# 方案B: 阿里云语音识别API
# 方案C: 科大讯飞API
transcription = await speech_to_text(
audio_file=recording,
model="whisper-large-v3", # 或阿里云/讯飞
language="zh",
speaker_diarization=True # 区分说话人
)
# 3. 提取关键信息
key_info = extract_call_insights(transcription["text"])
return {
"call_record_id": call_record_id,
"full_transcript": transcription["text"],
"speakers": transcription["speakers"], # 销售/客户对话分离
"duration": transcription["duration"],
"key_points": key_info["key_points"],
"customer_intent": key_info["intent"],
"follow_up_items": key_info["follow_ups"],
"sentiment": key_info["sentiment"] # 正面/中性/负面
}
# 关键信息提取
async def extract_call_insights(text: str) -> dict:
"""
使用AI提取通话关键信息
"""
prompt = f"""
分析以下电话通话记录,提取关键信息:
通话内容:
{text}
请提取:
1. 客户意图(询价/投诉/技术支持/合作洽谈/其他)
2. 关键需求点
3. 客户情绪(正面/中性/负面)
4. 需要跟进的事项
5. 提到的产品型号
6. 提到的价格/数量
7. 下次联系建议
输出JSON格式。
"""
# 调用本地模型或API
result = await model_router.route_request("A10", prompt, "medium")
return json.loads(result["result"])
# 通话结束后自动创建CRM沟通记录
async def create_crm_communication_record(call_data: dict, transcription: dict) -> dict:
"""
自动创建CRM客户沟通记录
"""
# 1. 构建沟通记录
record = {
"record_id": f"COMM-{datetime.now().strftime('%Y%m%d')}-{uuid.uuid4().hex[:8]}",
"customer_id": call_data["matched_customer_id"],
"contact_id": call_data["matched_contact_id"],
# 沟通基本信息
"communication_type": "phone", # 电话沟通
"direction": "inbound", # 呼入
"channel": "400电话", # 渠道
# 时间信息
"call_time": call_data["call_time"],
"call_duration": call_data["duration"],
"call_end_time": call_data["end_time"],
# 通话内容
"summary": transcription["key_points"]["summary"],
"full_transcript": transcription["full_transcript"],
"recording_url": call_data["recording_url"],
# 客户意图
"customer_intent": transcription["key_points"]["intent"],
"intent_category": classify_intent(transcription["key_points"]["intent"]),
# 关键信息
"products_mentioned": transcription["key_points"].get("products", []),
"price_discussed": transcription["key_points"].get("price", None),
"quantity_discussed": transcription["key_points"].get("quantity", None),
# 跟进事项
"follow_up_required": True,
"follow_up_items": transcription["key_points"]["follow_ups"],
"follow_up_deadline": calculate_follow_up_deadline(
transcription["key_points"]["intent"]
),
# 情绪分析
"customer_sentiment": transcription["key_points"]["sentiment"],
"urgency_level": calculate_urgency(
call_data["customer_level"],
transcription["key_points"]["sentiment"]
),
# 负责人
"handled_by": call_data["answered_by"], # 接听人
"assigned_to": call_data["assigned_sales"], # 分配销售
# 系统信息
"created_at": datetime.now(),
"source_system": "400_phone_system",
"call_record_id": call_data["call_record_id"]
}
# 2. 保存到CRM沟通记录表
await db.insert("customer_communications", record)
# 3. 更新客户最后联系时间
await db.execute("""
UPDATE customers
SET last_contact_date = ?, last_contact_type = 'phone'
WHERE id = ?
""", (datetime.now(), call_data["matched_customer_id"]))
# 4. 创建待办事项(如需要跟进)
if record["follow_up_required"]:
await create_todo_task({
"title": f"跟进客户:{call_data['company_name']} - {record['follow_up_items'][0]}",
"customer_id": call_data["matched_customer_id"],
"deadline": record["follow_up_deadline"],
"priority": record["urgency_level"],
"source": "400_phone",
"related_record_id": record["record_id"]
})
# 5. 推送企业微信通知
await send_wechat_notification({
"type": "call_record_saved",
"customer_name": call_data["company_name"],
"call_duration": record["call_duration"],
"summary": record["summary"],
"follow_up": record["follow_up_items"],
"recording_url": record["recording_url"]
})
return record
-- 客户沟通记录表(扩展)
CREATE TABLE IF NOT EXISTS customer_communications (
id SERIAL PRIMARY KEY,
record_id VARCHAR(64) NOT NULL UNIQUE,
tenant_id VARCHAR(64) DEFAULT 'T001',
-- 关联信息
customer_id VARCHAR(64) NOT NULL,
contact_id INTEGER,
project_id VARCHAR(64),
opportunity_id VARCHAR(64),
-- 沟通类型
communication_type VARCHAR(32) NOT NULL, -- phone/email/meeting/wechat/visit
direction VARCHAR(16), -- inbound/outbound
channel VARCHAR(32), -- 400电话/企业微信/邮件/面谈
-- 时间信息
communication_time TIMESTAMP NOT NULL,
duration INTEGER, -- 时长(秒)
-- 内容信息
summary TEXT, -- AI摘要
content TEXT, -- 完整内容/文字记录
recording_url VARCHAR(256), -- 录音链接
attachment_urls JSONB, -- 附件
-- 意图分析
intent_category VARCHAR(32), -- 询价/投诉/技术支持/合作洽谈
intent_detail VARCHAR(128),
-- 关键信息
products_mentioned JSONB,
price_discussed DECIMAL(12,2),
quantity_discussed INTEGER,
-- 跟进信息
follow_up_required BOOLEAN DEFAULT FALSE,
follow_up_items JSONB,
follow_up_deadline TIMESTAMP,
-- 情绪分析
sentiment VARCHAR(16), -- positive/neutral/negative
urgency_level VARCHAR(16), -- high/medium/low
-- 负责人
handled_by VARCHAR(64), -- 实际处理人
assigned_to VARCHAR(64), -- 分配跟进人
-- 系统字段
source_system VARCHAR(32), -- 400_phone_system/crm_manual/wechat
source_record_id VARCHAR(64), -- 源系统记录ID
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 索引
CREATE INDEX idx_comm_customer ON customer_communications(customer_id);
CREATE INDEX idx_comm_time ON customer_communications(communication_time);
CREATE INDEX idx_comm_type ON customer_communications(communication_type);
CREATE INDEX idx_comm_intent ON customer_communications(intent_category);
---
400电话来电可以转接到销售人员的移动电话,确保:
# 400电话转接策略
CALL_FORWARDING_CONFIG = {
"basic_rules": {
"work_hours": { # 工作时间
"weekday": "09:00-18:00",
"saturday": "09:00-12:00",
"sunday": "closed"
},
"after_hours": "forward_to_mobile", # 非工作时间转手机
"holiday": "forward_to_duty" # 节假日转值班人员
},
"forwarding_strategies": {
# 策略1: 顺序转接(先办公室,后手机)
"sequential": {
"description": "先响办公室话机,无人接听转手机",
"steps": [
{"timeout": 15, "target": "office_phone"}, # 响15秒
{"timeout": 20, "target": "mobile_phone"}, # 转手机响20秒
{"timeout": 10, "target": "voicemail"} # 最后留言
]
},
# 策略2: 同时振铃(办公室+手机同时响)
"simultaneous": {
"description": "办公室和手机同时响铃",
"targets": ["office_phone", "mobile_phone"],
"timeout": 30,
"overflow": "voicemail"
},
# 策略3: 智能转接(根据销售状态)
"smart": {
"description": "根据销售状态智能选择",
"rules": [
{"condition": "status == 'in_office'", "target": "office_phone"},
{"condition": "status == 'in_field'", "target": "mobile_phone"},
{"condition": "status == 'in_meeting'", "target": "colleague"},
{"condition": "status == 'off_duty'", "target": "duty_person"}
]
}
},
# 销售人员移动电话配置
"sales_mobile_numbers": {
"sales_manager_a": {
"name": "销售经理A",
"office_ext": "8001",
"mobile": "138****0001",
"duty_days": ["mon", "tue", "wed", "thu", "fri"],
"duty_hours": "09:00-22:00",
"max_daily_calls": 50
},
"sales_manager_b": {
"name": "销售经理B",
"office_ext": "8002",
"mobile": "138****0002",
"duty_days": ["mon", "tue", "wed", "thu", "fri", "sat"],
"duty_hours": "09:00-20:00",
"max_daily_calls": 50
},
"sales_manager_c": {
"name": "销售经理C",
"office_ext": "8003",
"mobile": "138****0003",
"duty_days": ["wed", "thu", "fri", "sat", "sun"],
"duty_hours": "10:00-21:00",
"max_daily_calls": 50
},
"duty_person": {
"name": "值班人员",
"mobile": "138****9999",
"duty_days": ["sun"], # 周日值班
"duty_hours": "09:00-18:00"
}
}
}
# 时间段转接策略
TIME_BASED_ROUTING = {
"weekday": {
"09:00-12:00": {
"primary": "office_phone", # 上午在办公室
"backup": "mobile_phone",
"strategy": "sequential"
},
"12:00-13:30": {
"primary": "mobile_phone", # 午休时间
"backup": "voicemail",
"strategy": "direct"
},
"13:30-18:00": {
"primary": "office_phone", # 下午在办公室
"backup": "mobile_phone",
"strategy": "sequential"
},
"18:00-22:00": {
"primary": "mobile_phone", # 下班后手机
"backup": "voicemail",
"strategy": "direct"
},
"22:00-09:00": {
"primary": "duty_person", # 夜间值班
"backup": "voicemail",
"strategy": "direct"
}
},
"weekend": {
"09:00-18:00": {
"primary": "mobile_phone", # 周末手机
"backup": "duty_person",
"strategy": "sequential"
},
"18:00-09:00": {
"primary": "duty_person", # 夜间值班
"backup": "voicemail",
"strategy": "direct"
}
}
}
# 鼎信通达语音网关转接配置
VOIP_FORWARDING_CONFIG = {
"device": "鼎信通达 DAG1000-4S",
# 基本转接规则
"call_forwarding": {
"unconditional": { # 无条件转接
"enabled": False,
"target": None
},
"busy": { # 忙时转接
"enabled": True,
"target": "mobile_phone",
"timeout": 10
},
"no_answer": { # 无应答转接
"enabled": True,
"target": "mobile_phone",
"timeout": 15
},
"offline": { # 离线转接
"enabled": True,
"target": "duty_person",
"timeout": 5
}
},
# 移动电话绑定
"mobile_bindings": {
"8001": {
"sales": "sales_manager_a",
"mobile": "138****0001",
"forwarding_type": "simultaneous", # 同时响铃
"office_timeout": 10, # 办公室响10秒
"mobile_timeout": 25 # 手机响25秒
},
"8002": {
"sales": "sales_manager_b",
"mobile": "138****0002",
"forwarding_type": "sequential", # 顺序转接
"office_timeout": 15,
"mobile_timeout": 20
}
}
}
# 销售状态管理(用于智能转接)
class SalesStatusManager:
"""
管理销售人员状态,用于智能转接
"""
async def update_status(self, sales_id: str, status: str, location: str = None):
"""
更新销售状态
status: in_office / in_field / in_meeting / off_duty / on_leave
"""
await redis.setex(
f"sales:{sales_id}:status",
3600, # 1小时过期
json.dumps({
"status": status,
"location": location,
"updated_at": datetime.now().isoformat()
})
)
async def get_status(self, sales_id: str) -> dict:
"""获取销售当前状态"""
data = await redis.get(f"sales:{sales_id}:status")
if data:
return json.loads(data)
return {"status": "unknown", "location": None}
async def get_best_contact(self, sales_id: str) -> str:
"""
根据状态获取最佳联系方式
"""
status = await self.get_status(sales_id)
if status["status"] == "in_office":
return "office_phone"
elif status["status"] in ["in_field", "in_meeting"]:
return "mobile_phone"
elif status["status"] == "off_duty":
return "duty_person"
else:
return "sequential" # 默认顺序转接
# 状态更新接口(销售可通过企业微信/小程序更新)
@app.post("/api/sales/status")
async def update_sales_status(
sales_id: str,
status: str, # in_office / in_field / in_meeting / off_duty
location: str = None
):
"""
销售更新自己的状态
"""
await sales_status_manager.update_status(sales_id, status, location)
return {"success": True, "status": status}
---
┌─────────────────────────────────────────┐
│ 7×24小时接听排班表 │
├─────────────────────────────────────────┤
│ 时间段 │ 主接听人 │ 备用接听人 │
├─────────────────────────────────────────┤
│ 09:00-18:00 │ 销售A/B/C │ 值班人员 │ (工作日)
│ 18:00-22:00 │ 销售A/B │ 值班人员 │ (晚间)
│ 22:00-09:00 │ 值班人员 │ 语音留言 │ (夜间)
├─────────────────────────────────────────┤
│ 周六 09:00-18:00 │ 销售B/C │ 值班人员 │
│ 周日 09:00-18:00 │ 值班人员 │ 语音留言 │
└─────────────────────────────────────────┘
DUTY_SCHEDULE = {
"weekday_night": { # 工作日夜间
"22:00-09:00": {
"duty_person": "值班人员",
"mobile": "138****9999",
"response_time": "15分钟内",
"escalation": "销售总监"
}
},
"weekend": { # 周末
"saturday": {
"09:00-18:00": {
"duty_person": "销售B/C",
"mobile": "138****0002",
"response_time": "即时"
}
},
"sunday": {
"09:00-18:00": {
"duty_person": "值班人员",
"mobile": "138****9999",
"response_time": "15分钟内"
}
}
},
"holiday": { # 节假日
"duty_person": "值班人员",
"mobile": "138****9999",
"response_time": "30分钟内",
"note": "节假日仅处理紧急咨询"
}
}
# 非工作时间语音留言处理
async def process_voicemail(call_data: dict):
"""
处理语音留言
"""
# 1. 保存语音留言
voicemail = {
"id": f"VM-{datetime.now().strftime('%Y%m%d')}-{uuid.uuid4().hex[:8]}",
"caller_number": call_data["caller_number"],
"call_time": call_data["call_time"],
"recording_url": call_data["recording_url"],
"duration": call_data["duration"]
}
# 2. 语音转文字
transcription = await transcribe_call_recording(voicemail["id"])
voicemail["transcript"] = transcription["text"]
# 3. 提取关键信息
insights = await extract_call_insights(transcription["text"])
# 4. 判断紧急程度
urgency = calculate_urgency(insights)
# 5. 创建紧急通知
if urgency == "high":
# 立即通知值班人员
await send_urgent_notification({
"type": "urgent_voicemail",
"caller": call_data["caller_number"],
"summary": insights["summary"],
"recording_url": voicemail["recording_url"],
"duty_person": DUTY_SCHEDULE["weekday_night"]["22:00-09:00"]["duty_person"]
})
# 6. 创建待办事项(工作时间处理)
await create_todo_task({
"title": f"处理语音留言:{call_data['caller_number']}",
"description": insights["summary"],
"priority": urgency,
"deadline": get_next_workday_morning(),
"recording_url": voicemail["recording_url"]
})
return voicemail
---
客户拨打 4008-320-160
↓
【步骤1: 来电识别】
系统自动识别来电号码
↓
【步骤2: CRM比对】
查询CRM客户通讯录
├─ 匹配成功 → 显示客户信息(公司/姓名/部门/等级)
└─ 未匹配 → 标记为新线索
↓
【步骤3: 智能路由】
根据时间/销售状态选择转接策略
├─ 工作时间 → 办公室话机(顺序/同时响铃)
├─ 外出时间 → 移动电话转接
├─ 非工作时间 → 值班人员/语音留言
└─ 节假日 → 值班人员/语音留言
↓
【步骤4: 接听处理】
销售接听电话
├─ 来电弹屏显示客户信息
├─ CRM自动创建沟通记录
└─ 通话录音开始
↓
【步骤5: 通话结束】
├─ 录音保存
├─ 语音转文字
├─ AI提取关键信息
├─ 自动创建CRM沟通记录
├─ 生成待办事项
└─ 推送企业微信通知
↓
【步骤6: 跟进管理】
├─ 待办事项提醒
├─ 跟进记录更新
├─ 客户状态更新
└─ 全生命周期追溯
---
| 阶段 | 时间 | 内容 | 优先级 |
|---|
| 第1阶段 | 第1周 | 基础400电话配置(IVR+录音) | 高 |
| 第2阶段 | 第2周 | CRM来电弹屏+客户识别 | 高 |
| 第3阶段 | 第3周 | 移动电话转接配置 | 高 |
| 第4阶段 | 第4周 | 语音识别+自动推送CRM | 中 |
| 第5阶段 | 第5周 | 7×24值班制度+智能路由 | 中 |
| 功能 | 推荐方案 | 说明 |
|---|
| 语音识别 | 本地Whisper (MacStudio) | 隐私好,免费 |
| 语音合成 | 阿里云语音合成 | 中文效果好 |
| 通话录音 | 语音网关自带 | 无需额外设备 |
| 移动转接 | 运营商呼叫转移 | 稳定可靠 |
| 状态管理 | Redis + 企业微信 | 实时更新 |
---
**文档版本**:v3.0(增强版)
**日期**:2026-06-15
**更新内容**:
**审批人**:admin@topcentral.cn / 麻一明
**执行状态**:待确认