2026 年再回看自己前几年搭过的几套 CRM,踩过的坑几乎都不在功能列表上,而在底层数据模型。同一个客户被三个销售反复跟、销售离职客户资产跟着走、官网留资谁也不知道——这些问题表面是流程问题,根子是线索、客户、联系人几张表的关系没设计对。这篇把我这几年在线索到商机这条链路上的表结构、去重、分配和埋点做法整理一遍,顺便交代一下落到云上时怎么对接,给要自己搭、或者要评审供应商方案的同行做个参考。
一、五表关系:先把骨架立住
任何 CRM 底层都绕不开五张表:Lead(线索)、Account(客户)、Contact(联系人)、Opportunity(商机)、Activity(跟进记录)。
Lead 是还没 qualify 的散客,只有联系方式和来源;Account 是已经建档的企业或个人主体;Contact 挂在 Account 下面,是具体决策人;Opportunity 是一次带金额、带阶段的销售机会,挂在 Account 下;Activity 是跟进记录,挂在前面任意一条数据上。
容易踩的反模式是把 Lead 和 Account 揉成一张表,靠 status 字段区分。前期省事,后期做转化漏斗、渠道归因就抓瞎——你算不清哪个渠道的线索真成了单,因为根本没有“线索转客户”这条事件。正规做法是 Lead 单独存,转化时把 Lead 归档(status=converted),再写一张 lead_to_account 转化记录,记下原线索 ID、来源渠道、转化时间。这样漏斗是从事实表算出来的,不是销售手填的。
关系一句话:一个 Account 对应多个 Contact、多个 Opportunity;一个 Opportunity 对应多条 Activity;Lead 转化后指向一个 Account。下面那张图画的就是这条链路。
二、两层去重:录入挡一道,离线再扫一道
线索量一上来,重复是必然的。同一个人官网留一次资、广告落地页点一次、销售手动录一次,库里就是三条。不去重,结果就是撞单和重复骚扰。
工程上一般分两道。
录入时这道:唯一键校验。以手机号、企业邮箱、微信号做联合唯一索引,写入前先查——命中已有 Lead 就走合并分支,不新建。这道挡掉大部分显式重复,代价是要处理好“同号不同人”的边界,所以合并动作默认进待确认队列,不自动落库。
入库后这道:定时模糊匹配。手机号对得上但姓名写法不一样、公司名带不带“有限公司”、同一邮箱前缀不同后缀——这些显式唯一键抓不到。做法是定时任务把新线索按规则打分:手机号完全一致记满分,企业邮箱域名一致加一档分,公司名去后缀、去空格后模糊匹配相似度再补分,超过阈值就进人工合并队列。逻辑大致是这样:
score = 0
if new.mobile == c.mobile: score += 100
if domain(new.email) == domain(c.email): score += 60
if fuzzy(new.company, c.company) >= 0.8: score += 30
if score >= 120: enqueue_for_review(new.id, c.id, score)
机器不能自动合并——合并错了比不合并更麻烦,销售会以为客户已经被别人跟了。人工确认后再物理合并,旧 Lead 软删,关联的 Activity、商机全部挂到保留的那条上。
三、自动分配引擎:规则要写,留痕更要写
小团队靠主管手动派,线索量上来就得有自动分配规则:按行业、按地区、按销售当前负载轮询,或者按来源渠道定向分给小组。
关键不在规则本身,而在分配动作必须留痕。谁、在什么时间、命中了哪条规则、把哪条线索分给了谁——写一条 assignment_log。后面撞单仲裁、算销售人均线索量、复盘规则公不公平,全靠这张日志。
一条简化的分配规则示意:
ASSIGN(lead):
pool = select_sales(region=lead.city, industry=lead.industry)
pool = filter(pool, s -> s.open_leads < s.quota)
target = min(pool, key = s -> s.open_leads)
write_log(lead.id, target.id, rule="region+load", ts=now())
轮询、负载均衡、按渠道定向这几种策略可以并存,但日志字段要统一,否则后面没法按策略复盘。
四、行为埋点:让系统比销售更早知道客户在动
传统 CRM 被动就被动在这儿——客户意图全靠销售手动填,销售一懒数据就是空的。做法是把客户在官网、小程序、报价页的行为事件埋点后回流:访问哪个产品页、下载哪份资料、打开几次报价单,每条事件带上 lead_id 或 account_id 挂回去。
这件事技术门槛不在算法,在数据通路能不能打通。官网埋点 SDK 上报,进事件网关,写入行为事件表,再按 lead_id 聚合打分。访问频次、停留时长、关键动作(反复看定价页)加权,分高的自动推给对应销售。打不通官网和系统,雷达就是瞎的。
五、商机阶段与概率:别拍脑袋
阶段别设太多。够用就四段:初步接触 → 方案报价 → 商务谈判 → 赢单/输单。每段带预计金额和成功率,月底 rollup 出来就是销售预测。阶段设一堆又没人维护,看板再漂亮也是假的。
概率可以初期拍脑袋填行业经验值,跑半年后用历史赢单/输单数据按阶段回填实际转化率,比一上来训模型靠谱。
六、落到云上这套组件怎么接
讲完模型,说一下工程上怎么落到阿里云这一套,对接很直接:
核心业务数据(五张主表)放 RDS MySQL,量级上来后切 PolarDB;分库分表先不急,单表到千万级再考虑。
客户附件、合同扫描件、营销素材这些对象文件不进数据库,全放 OSS,库里只存 object key 和元数据。
给客户发短信(验证码、通知、营销触达)走阿里云短信服务,签名和模板提前报备,业务系统只调 API,不自己养短信通道。
前面说的模糊去重、每日线索分配重算,都是定时批任务,用函数计算加定时触发器唤起,不用常驻一台机器,跑完回收。
这样切分的好处是:在线事务压力在 RDS,文件 IO 全压在 OSS,定时批处理不影响在线库主流程,短信触达也不占业务服务资源。
七、适用规模和技术局限(复盘)
最后说点实在的。这套五表模型加两层去重、规则分配,对几人到几十人销售团队、标准产品销售流程是够用的,上线两周就能跑起来。但有几个边界要清楚:
单表数据量到千万级、日增线索过万时,RDS 单库扛不住,要按渠道或按大区做分库,assignment_log 和行为事件表单独拆。
强一致场景(比如线索合并时 Activity 迁移)别靠最终一致,本地事务加补偿表兜住,别上分布式事务过度设计。
行为埋点事件量大了之后别写 MySQL,事件表走时序或列存,在线库只留聚合结果。
复杂销售流程(多级审批、报价配置、产品组合)这套轻模型撑不住,得上重一点的平台,那是另一个量级的话题。
几个常被问到的点
Q:线索和客户为什么要分开存?
A:混在一起就没有“转化”这个事件,漏斗和渠道归因都算不出来。线索是未验证的潜在客户,转化时归档并写转化记录,渠道 ROI 才闭环。
Q:模糊去重为什么要先人工确认?
A:合并错误的数据代价很高——销售会以为客户已被认领、商机归属混乱。先过人工队列,规则跑顺了再把高置信度的自动合并比例往上调。
Q:小团队有必要自己搭这套吗?
A:没有。直接用一套轻量标准化 SaaS 把这五张表和去重做掉就行,自己搭的成本主要在后续维护。但不管用谁家的,评审方案时按这几张表和两条日志(assignment_log、转化记录)去对,缺哪块心里有数。