骚扰电话识别与处置:特征计算、规则引擎到模型评分的落地链路
当一通骚扰电话拨打进来时用户侧能看到的是“疑似骚扰”或“陌生号码”这几个字但放在通信风控、企业通话平台或客服系统里要处理的问题远不是挂断那么简单。系统必须在通话前判断要不要拦截通话中判断话术和意图通话后判断要不要进灰名单还要尽量避免把正常号码误伤成“骚扰”否则就会引发用户投诉和业务损失。这篇文章就围绕“骚扰电话识别与处置”讲一条可以落地的处理链路从呼叫事件接入、特征计算、规则引擎、模型评分到批量任务、实时接口、验证指标和常见排查。适合通信领域的技术开发、风控工程师、客服质检负责人以及准备做号码治理或通话安全的产品经理阅读。最值得关注的不是某一个算法而是整条链路里那些容易翻车的位置特征没对齐、阈值拍脑袋、批量任务没有幂等、模型上线没有影子期每一处都可能让方案从“能用”变成“不敢用”。1. 先说结论骚扰电话识别不是单点功能而是一条完整链路很多团队第一次接这类需求时容易把它理解成“找一个号码黑名单库命中就拦截”。这个理解不完整。实际生产环境里骚扰电话的形式一直在变号码可以变更、伪装、通过不同线路外呼单靠静态黑名单无法覆盖新增和变体。所以我更建议把问题定义成当一次呼叫开始之后系统能否在有限时间内基于可获取的数据判断该呼叫属于“正常业务呼叫”还是“疑似骚扰”并触发合适的处置动作。这里的核心不只是一个模型而是一条由数据接入、特征计算、判定策略、处置动作、日志回流组成的闭路。如果只问“骚扰电话识别准不准”不如先问“系统能不能在一通电话发起后的几百毫秒内把该算的特征都算完”。实时性、稳定性、可解释性往往比单一准确率更重要。这决定了你后面的技术选型规则引擎能不能兜底模型该不该上实时接口该用多高的超时批量任务要不要做断点续跑。1.1 一通骚扰电话从呼叫开始会发生什么按时间线来说一次呼叫会经历这几个关键节点。第一个节点是呼叫事件产生。无论是运营商侧、企业通信平台还是客服系统都会在呼叫发生时生成一条呼叫记录至少包含主叫号码、被叫号码、发起时间、呼叫标识。这个节点最重要的是“有没有事件”和“能不能实时拿到事件”。第二个节点是基础信息补全。系统会根据主叫号码查询历史标签、号码归属地、近期呼叫频次也会查询被叫号码是否在此之前被其他人标记过。这里的风险在于号码字段不一致导致的漏算比如有的记录带国家码有的记录不带归一化没做好后面所有特征都会偏。第三个节点是行为特征计算。这一层会统计短时间呼叫次数、呼叫不同被叫数量、平均通话时长、接通率、集中呼叫时段、号码生命周期等。骚扰号码通常在某个时间窗内高频外呼且大量呼叫无法接通这些行为特征会比静态标签更敏感。第四个节点是内容特征提取。在合规和授权前提下可以做通话文本转写或关键词抽取判断是否包含“贷款”“中奖”“退款”“转账”“验证码”等高风险词再看是否存在重复话术。内容层能发现行为层看不出的长尾骚扰。第五个节点是判定与处置。规则和模型输出风险分系统根据分数映射到不同动作直接拦截、来电标记、转接提示、生成告警工单、进入人工复核队列。处置动作不是越多越好而是要能解释清楚“为什么这条呼叫被判了高风险”。第六个节点是数据回流。用户标记、客户投诉、复核结果、通话录音抽检结果都要回到样本和特征库用于下一轮规则调整和模型训练。没有回流系统会慢慢失效。这条链路你可以在小规模环境里先简化但不能砍掉任何一个断点。比如只做规则、不做回流时间久了规则会被绕过只做模型、不保留规则兜底模型上线初期出现异常时容易失控。1.2 适合谁看以及最值得关注的三件事如果你是第一次做这类系统下面三件事最值得先记住。第一先把“跑通”和“调准”分开。不要一开始就追求把所有骚扰电话都识别出来而是先用一条真实话单走通“输入 - 特征 - 判定 - 输出”的最小链路。链路通了再逐步增加特征和策略。第二不要把误报当成小事。拦截十个骚扰电话当然有效但每误伤一个正常客户电话都可能造成真实投诉。做风控一定要同时看“拦截数量”和“误报数量”只看命中量会让你盲目调高敏感度。第三默认配置只适合学习和演示。生产环境里号码伪装、批量外呼、分段更换号码、不同时段活跃等行为都会让简单规则失灵。你需要在设计规则和模型时保留“可解释”“可回滚”“可观测”三个能力。2. 先理清系统链路从呼叫事件到处置动作要经过哪几步在写代码之前先画一遍系统数据流。这一步花半小时后面能省很多排查时间。我一般会把链路分成四段接入层、特征层、决策层、处置层。接入层负责接收呼叫事件或话单特征层负责把原始记录计算成特征向量决策层运行规则和模型处置层执行拦截、标记、告警、复核等动作。每一段之间通过明确的输入输出协议连接日志要带上同一呼叫ID方便回溯。2.1 呼叫事件接入与数据字段在合规前提下系统至少需要拿到以下字段。字段含义在风控中的用途呼叫 ID一次呼叫的唯一标识贯穿日志、特征、处置全链路主叫号码发起呼叫的号码号码身份识别、历史关联被叫号码接收呼叫的号码判断被叫侧反馈和标记记录呼叫时间呼叫发起时间戳频次、时段、时间窗计算接通状态是否接通接通率、空号判断通话时长接通后的持续时长区分机器空放和真实对话挂断原因主动挂断、超时、拒绝等判断用户反感程度用户标记被叫方是否标记骚扰回流标签和样本来源来源线路走运营商、SIP 线路还是客服平台识别批量外呼、线路切换有一点要特别提醒原始字段里没有“骚扰标签”它不是数据自带属性而是系统计算出来的结果。所以接入层的首要任务是保证字段准确性和完整性尤其是主叫号码归一化。号码不统一后面所有频次类特征都是错的。另外涉及录音、转写、用户号码等数据时必须遵循相应授权和合规要求。我在实际项目中见过因录音文件权限没收敛导致复核流程出问题的情况所以建议在接入层就把数据分级和权限控制做清楚不要在后期补救。2.2 特征计算号码、频次、时间分布、内容骚扰电话识别的特征不是越多越好而是要看“计算代价和区分度”。我一般把它们分成四类。第一类叫静态属性特征。包括号码号段、归属地、注册时长、历史标签。这类特征稳定但容易被绕过因为骚扰号码也会养号。第二类是行为特征。重点看主叫号码在特定时间窗内的外呼次数、呼叫不同被叫数量、接通率、平均通话时长、振铃时间、夜间呼叫占比。高频次、低接通、短通话是批量骚扰最明显的信号。第三类是关系特征。一个号码可能不单独行动多个号码可能共用线路、设备标识、呼叫模板。通过号码聚类或共现关系可以发现单一号码看不出的团伙特征。第四类是内容特征。在授权前提下对通话进行文本转写后统计关键词命中次数、话术雷同度、重复模板。内容特征对“金融诈骗”“冒充客服”这类强意图骚扰特别有效。特征计算层最容易踩的坑是时间窗口不统一。比如规则里写“一小时内呼叫超过20次”但代码里用的是自然小时的开始时间不是滑动窗口那么跨小时边界的高频呼叫就可能漏掉。建议规范成统一的滑动时间窗口并且把所有特征的窗口参数放在配置中心方便后续调整。2.3 判定与处置拦截、标记、告警、复核判定层不是只有一个阈值而是把规则、模型、名单组合起来输出一个风险等级和处置动作。我常用的风险等级是高、中、低、正常。高风险直接拦截或来电侧提示中风险在用户端展示“疑似骚扰”标签低风险记录日志然后放行正常呼叫不受影响。对于高风险和中风险还要生成一条供人工复核的记录方便后续抽检。处置动作要注意一致性。同一个呼叫不能同时被拦截又放行处置状态也要记录清楚。如果系统做了拦截但用户手机侧因为保护逻辑没有正常展示提示那会引发“被拦截了为什么还能打进来”的困扰。所以处置层需要一个确认回执机制至少要让处置结果可查。3. 规则引擎先行用最小可运行方案把链路跑通第一次做骚扰电话识别我强烈建议不要直接上模型。先把规则引擎跑通用规则确认数据质量和处置链路没问题再考虑模型加码。原因有两个规则可解释出问题时能立刻定位规则迭代快业务人员也能参与。3.1 规则设计的核心维度规则设计不用复杂但维度要覆盖到频次、行为、内容和反馈。频次维度可以设置“1小时内主叫呼叫超过20个不同被叫”这类规则行为维度可以设置“接通率低于30%且平均通话时长低于10秒”内容维度可以设置“命中高风险关键词”反馈维度可以设置“累计被标记次数超过阈值”。每条规则命中后累加风险分总分超过阈值则进入高风险处置。这里要注意规则之间的相互影响。比如“呼叫次数多”和“接通率低”高度相关如果两条规则同时加权会给同一批次话单重复计分。建议先做规则相关性分析把强相关规则合并再给不同维度配置不同的权重上限。3.2 单条呼叫判定示例下面给一个特征计算的示意代码目的是说明链路不是生产实现。# 示意代码单条呼叫风险评分 def calculate_risk_score(call, history): score 0 # 1 小时窗口内不同被叫数量 callee_count history.count_distinct_callee(call.caller, window_minutes60) if callee_count 20: score 40 # 接通率 connect_rate history.get_connect_rate(call.caller, window_minutes60) if connect_rate 0.3: score 30 # 平均通话时长 avg_duration history.get_avg_duration(call.caller, window_minutes60) if avg_duration 10: score 20 # 被叫侧用户标记数 if history.get_mark_count(call.caller) 5: score 10 return score这段示意里每个阈值都是可配置的。实际生产里history 数据通常来自 Redis 或 ClickHouse 这类存储查询时要避免对每条话单实时全量扫描。我一般会把主叫号码的频次特征做成增量计数器放在缓存里减少重复计算。3.3 规则阈值怎么定为什么不能只看准确率很多团队在定阈值时习惯直接看“准确率”但准确率在骚扰电话场景里经常骗人。假设线上10000通呼叫只有200通是骚扰电话。如果系统把全部呼叫都判为正常准确率也有98%。但这套系统没有任何实际作用。所以你至少要同时关注误报率、漏报率、处置准确率这几个指标。指标含义怎么观察准确率全部判定中正确的比例看混淆矩阵整体误报率正常呼叫被误判为骚扰的比例用户投诉、复核抽样漏报率骚扰呼叫没有被判出的比例用户后续标记、升级投诉处置准确率被拦截样本中真的属于骚扰的比例人工复核确认调阈值时不要只看一版结果。我会先保存一批已经标注好的历史话单规则调整后在同一批话单上做回放对比新旧结果再决定是否上线。这种回放机制比“上线跑几天再看效果”要安全很多。4. 模型识别阶段处理规则覆盖不到的长尾规则的好处是稳定可解释坏处是覆盖不了长尾。骚扰号码会不断变换行为模式新出现的模式在规则库里可能没有对应规则。这个阶段可以引入模型但要注意引入方式。4.1 模型解决什么问题模型主要解决“规则没覆盖到的新模式”和“多特征非线性组合”两类问题。比如一个号码单看频次不高但如果它同时满足“夜间活跃”“归属地异常”“被叫用户多数在短时间内挂断”“话术中出现诱导性关键词”规则很难用简单阈值表达模型可以通过特征组合给出更高分。但模型不能完全替代规则。我的建议是规则和模型并行最终用一个分值融合策略。规则分值侧重稳定可解释因素模型分值侧重长尾识别。融合后超过阈值再进处置流程。4.2 样本、特征、训练先聊样本。正样本可以来自用户标记、客户投诉、人工复核确认的骚扰号码负样本可以选择已确认正常的外呼号码和日常通话记录。样本数量不足时不要急着上复杂模型先用规则生成候选再人工标一部分保证正负样本都够。再聊特征。训练特征要和线上特征保持一致否则会出现离线评估很好、线上效果很差的问题。最典型的坑是离线用了未来信息比如用了“通话结束后的录音结果”去预测“通话开始时是否拦截”这属于特征泄露必须避免。模型选择上第一版用 XGBoost 或 LightGBM 这类梯度提升树模型就够了。它们对表格特征友好训练快还方便查看特征重要性。不要一上来就上深度模型除非你有大规模文本或音频特征需要处理。4.3 影子模式上线前先陪跑模型上线前最好的方式不是直接拦截而是先开影子模式。影子模式的意思是模型已经在实时接口里运行并打分但它的分数不会影响处置动作只会记录到日志和存储里。影子模式跑一段时间后你可以对比“线上规则处置结果”和“模型建议结果”看模型新增命中哪些样本、是否包含大量误报、分数分布是否稳定。确认模型在历史回放和影子模式里都表现稳定后再切小流量比如让模型管理10%的呼叫处置剩余继续走规则观察几天再逐步放大。我见过不少项目因为没做影子模式模型直接上线后误报率升高导致正常业务收到大量拦截投诉最后只能紧急回滚。这类事故完全可以靠影子模式避免。5. 落地实现批量任务、接口与并发控制当方案从验证走向落地时你会面对两类任务一类是离线批量处理比如每天跑一遍全量话单生成号码画像另一类是实时接口比如呼叫发生时在线打分。两者的实现方式差别很大不要混在一起设计。5.1 单条呼叫处理示例先把单条处理逻辑写好因为后续的批量任务和实时接口都会复用这部分。下面是一个简化的处理流程# 示意代码单条话单处理 def process_call(call): features feature_service.build_features(call) rule_score rule_engine.score(features) model_score model_service.predict(features) final_score fusion_score(rule_score, model_score) if final_score high_risk_threshold: return {call_id: call.call_id, risk_level: high, action: block} elif final_score medium_risk_threshold: return {call_id: call.call_id, risk_level: medium, action: mark} else: return {call_id: call.call_id, risk_level: low, action: allow}这里的关键是特征服务和模型服务要独立便于后续扩展。单条跑通后才能继续做批量和接口。5.2 批量处理与队列设计批量话单处理时最忌讳一次性把全部数据加载到内存然后循环处理。如果一天有几十万通话每条还涉及历史特征查询很容易把内存和数据库连接打满。更稳的方式是分批读取、逐批处理、增量写入。比如每批读取1000条话单处理完后写入结果表再读取下一批。如果某一条失败了记录失败原因不要中断整批任务。输出文件或结果表要带上批次标识和时间戳方便定位。处理任务要有幂等性同一批话单因为异常重跑时不会产生重复结果或覆盖错误。简单做法是结果表以“呼叫ID 任务批次”作为唯一键重复写入时使用更新语义。5.3 接口化和并发控制实时接口的核心约束是超时和并发。骚扰电话识别必须在呼叫接续时间内返回结果通常不能超过几百毫秒。如果特征服务查询很慢就需要做缓存或预计算而不是强行增加下游数据库压力。并发控制上我不建议一开始就把接口实例开到很大。先跑单实例压测观察响应时间、内存、下游连接数再决定扩几个实例。有一个好习惯接口接入方要设置熔断和降级。当评分服务响应超时或异常时默认放行呼叫避免因为风控系统故障影响正常通信。对比项离线批量处理实时接口触发方式定时任务或手动触发呼叫事件触发响应要求分钟级或小时级毫秒级数据量大批量全量扫描单条或小批量失败处理可以重跑、断点续跑必须熔断、降级资源占用峰值高需要控制并发稳定低延迟需要压测6. 验证标准我用什么指标判断系统真的可用功能上线不等于方案可用。你要有一套验证标准能回答“它到底行不行”以及“某一版改动是变好还是变坏”。6.1 准确率、误报率、召回率我建议建立一套固定的评估样本集样本来源包括历史已确认的骚扰话单、正常外呼话单、线上新产生的用户投诉和标记。每次改动后都在这套样本集上跑一遍输出混淆矩阵。具体看三个数召回率要高说明多数骚扰都被识别出来了精度要高说明被判为骚扰的确实有问题误报率要低说明正常呼叫没有被错误拦截。三者不能只看一个否则容易顾此失彼。另外要关注“处置准确率”。这个指标是人工复核被拦截样本后计算出来的能够反映线上实际效果。如果被系统拦截的样本里有相当一部分人工复核后认为不是骚扰说明策略过度激进。6.2 延迟、吞吐、资源占用识别系统是典型的数据链路系统除了算法效果还要看运行性能。实时接口建议统计 p50、p95、p99 延迟。p99 延迟过高的系统在呼叫峰值时段容易引发超时。批量任务要看单批处理耗时、总任务耗时、内存峰值。资源占用要关注特征服务所在数据库的连接数这个位置最容易成为瓶颈。如果发现开通了识别能力后系统整体内存上涨明显先排查是不是特征缓存没有设置过期时间或者批量任务一次性加载了过多话单。6.3 从日志回看和复盘我每周会做一次抽样复盘从本周被拦截的样本里抽一批从本周被放行但后来被用户标记的样本里抽一批分别看特征分数和判定原因。复盘的价值在于发现规则和模型没注意到的模式。比如某个时间段突然出现大量高分散步号码或者某个被叫群体频繁投诉说明可能有新的骚扰话术或线路变化。复盘结果要记录成文档并转化为规则更新任务或样本补充计划。7. 常见排查链路和边界提醒最后讲一些实际排查时我会优先看的点。这些经验不限于一种技术方案通常能帮你在出问题时快速缩小范围。7.1 排查顺序当你发现漏报增多、误报增多、接口超时或批量任务失败时先别急着改模型按照下面的顺序排查。第一步看输入数据。主叫号码是否归一化时间戳是否统一是否包含重复呼叫ID文件编码是否异常。数据问题会导致特征计算和判定结果一起漂移。第二步看特征计算。取一条已知风险话单手动核对特征值是否和预期一致。比如一小时窗口内号码呼叫次数是否正确接通率统计是否排除无效呼叫。第三步看判定策略。确认最近有没有调整过阈值、规则权重或模型版本。策略变更后没有回放验证是线上指标突然变化的常见原因。第四步看处置链路。被拦截或标记的记录是否真正写入日志处置结果有没有被后续流程覆盖工单是否正常生成。这里最容易出现“模型判定正确但处置没生效”的问题。第五步看资源占用。如果接口变慢先看特征库的连接数和响应时间再看评分服务所在进程的CPU和内存不要一上来怀疑模型文件损坏。7.2 边界提醒要明白任何骚扰电话识别方案都有边界过度期待会踩坑。号码可能被伪冒所以不要只依赖主叫号码。用户标记有滞后性新号码要累积到一定量才会被识别。规则和模型都会有失效期需要持续回流和更新。低配环境能跑通批量小样本不代表能在高并发实时场景稳定运行。支持模型不等于所有类型骚扰都覆盖不同话术、线路、用户群可能需要单独调优。数据合规是底线。涉及用户号码、通话记录、录音内容时必须在授权范围内使用并做好权限控制和数据脱敏。这些不是可选项而是上线前必须落实的基础设施。7.3 最后几个落地建议如果让我给一个实施顺序我会建议这样走先把单条话单评分跑通再开放批量任务最后接实时接口。能单条跑稳说明基础链路没问题能批量处理说明边界和容错到位能实时接口说明性能和降级策略可靠。每一步之间都加验证不要跨步。参数调整时每次只改一个变量。比如先调频次阈值不动权重再调权重不动模型。否则出问题后很难定位原因。上线前留好回滚方案。规则引擎和模型要能快速开关最好有配置中心统一管理。真正落地时最该盯住的不是准确率数字而是输入数据质量、特征一致性和处置动作可观测性。这三个地方不出问题系统就不会失控。
