做电商风控的人心里都清楚,最怕的不是那种一笔几万块的大单,而是成百上千个看起来“完全正常”的账号。它们分散在不同的群里,聊天语气像真人,下单间隔也够随机,甚至还有几笔真实消费记录。直到某个凌晨,突然所有号同时下单同一个低价商品——你才反应过来,已经被薅秃了。
问题在于,这些账号在传统风控系统里,每条都是干净的。收货地址不一样,支付方式也换着用,设备指纹甚至都做了隔离。你拿静态规则去套,一个都打不中。但如果你把这些账号放到一张关系网里去看,那些看似无关的点,其实被同一根线牵着。哪怕只有一个 IP 段、一个地址区划、甚至一句群里的闲聊,被 AI 捕捉到了,整张面具就能扯下来。
那些“干净”的号,到底在哪漏的底
现在的羊毛党团队,操作手法比大多数小公司还规范。他们养号是系统性的,每个手机号绑一个淘宝小号,每天做任务、刷信誉、偶尔买一单真实商品。表面上看,这些号彼此毫无关联,地址可能是不同的代收点,甚至分布在几个城市。但如果你把它们的“出现痕迹”全部堆在一起看,就能找到共振点。
比如说,两个淘宝小号,A 在群里发过收货地址“山东省济南市历下区”,B 在同一个群、同一个小时内提到过“备用手机号 170-****-1234”,而 170 号段的来源恰恰是同一批虚拟运营商。这种交叉信息,人工翻聊天记录永远翻不完,但模型扫一遍就能标出来。
老一套风控逻辑依赖黑名单和固定阈值。比如“同一 IP 登录超过 5 个账号”就触发警报。但羊毛党早就不这么玩了,他们用住宅 VPN,IP 段看着干净,甚至每个号单独拨号。真正的关联信息藏在聊天记录的细节里——一句“大伯家的 WiFi 今天好卡”,可能暗示了两个号共用一个宽带。这种信息,静态规则永远抓不到,必须靠能理解上下文的模型去嗅。
套话少说,风控系统得从“看单点”切换到“看网络”。不是盯着一个账号的行为,而是看一群账号之间有没有隐形的拉扯。这换的不是工具,是分析思路。
从闲聊里捞实体,再用图谱画关系网
第一步听起来很土,但绕不开:先把聊天记录弄到手。Telegram 群可以直接导出 JSON,微信稍微麻烦点,用 WechatMsg 这个开源项目能解析本地数据库,前提是拿到备份文件。不用追求实时,拉历史数据足够用。
拿到几千条消息后,直接硬搜关键词,肯定不行。“小号批发”可能写成“小昊批发”,“代挂”变成“待挂”。你写 20 个正则都追不上他们换词的速度。
我试了两套方案。本地部署 Qwen-14B(4bit 量化,8G 显存就能跑),或者调用智谱 API。本地适合高频调试,API 做定时批处理。关键不在模型大小,而在提示词怎么写。一条典型的提示词模板长这样:
你是一个刷单群聊天记录分析器。
从以下消息中提取:
1. 手机号(完整或脱敏片段皆可)
2. 淘宝昵称(出现任何类似ID都算)
3. 收货地址中的城市+区+街道
4. IP段(如 114.92.*.* 这种片段也算)
5. 黑话标签:如“小号批发”“代挂”“刷单任务”“拆单”
输出JSON数组格式,每条记录带"msg_id"和"type"。
实测下来,Qwen-14B 对“拆单”——就是把一个大额订单拆成多个小号下单——这类黑话的识别准确率能到 85% 以上。但有个坑:如果群里有人在聊“今天拆了快递”,模型会误标。所以你得在后处理里加一层过滤,把“拆快递”“拆红包”这类日常词排除。
光提取出手机号和地址还不够,得把它们串起来。我写了个简单的脚本,按时间窗口滑动:假设 24 小时内,同一个群里出现了手机号 A 和淘宝昵称 B,且 A 和昵称 C 在另一个群里也同时出现过,那 B 和 C 就有一条边。
这个逻辑听着简单,但量一上来就麻烦了。3 万条消息喂进去,提取出 400 多个实体,两两组合之后潜在关联对超过 8 万组。不能全信模型,得设置信度阈值——只有同一 IP 段、同一地址区级、且出现频次超过 3 次的三重交集,才标记为“强关联”。跑完第一轮,我盯着那张关系图看了半天。两个看起来八竿子打不着的淘宝 ID,因为共享过一个地址片段,背后其实是同一个人的小号矩阵。这就是你在订单数据里永远看不到的东西。
Neo4j 里那团亮斑,就是你要找的团伙
实体提取出来之后,得把它们放进图数据库。我选 Neo4j 而不是 Redis,因为关系一旦复杂,邻接表会炸。写了个 Python 脚本,读取上一步产出的 JSON,按“同一群聊 + 同一小时 + 同一 IP 段”三条规则建边。别小看“同一小时”这个维度,很多刷单任务只持续十分钟,抓住窗口比什么都好使。
from py2neo import Graph, Node, Relationship
graph = Graph("bolt://localhost:7687", auth=("neo4j", "******"))
for record in json_lines:
tx = graph.begin()
u1 = Node("User", uid=record["msg_id"])
addr = Node("Address", name=record["city"]+"-"+record["district"])
tx.create(u1)
tx.create(addr)
tx.create(Relationship(u1, "LIVES_AT", addr))
for peer in record["peers_in_same_hour"]:
edge = Relationship(u1, "SHARES_IP_WITH", peer)
tx.create(edge)
tx.commit()
跑完 3 万条消息,节点 4.7k,边 11.2k。浏览器一渲染,像极了夜市地图——到处都是亮斑。这时候用 Louvain 社区发现算法,把模块度增量算到 0.6,屏幕里突然跳出三个小圆点连成的三角形。它们分别挂着“山东省济南市历下区”“114.92.*.*”和“备用手机号 170-****-1234”三个标签。这不是巧合,是一个人同时掌控三个马甲。
团伙画像怎么打:哪些该封,哪些能放
图谱画出来了,社区也切开了,然后呢?总不能对着那团彩色泡泡发呆。得给每个团伙打分——哪些是“偶尔薅一把”的路人,哪些是“职业刷单手”养的小号矩阵,哪些已经踩到红线可以直接报警。我定义了一套打分维度的组合拳,不是那种拍脑袋的权重相加,权重法在风控领域就是糊弄老板的。
四个维度捏出风险骨架
团伙规模这事,小于 5 个节点,多半是亲友间互相刷一单,问题不大。可一旦超过 10 个节点,而且里头 70% 以上都是 90 天内冒出来的支付宝小号——这个比例本身就已经很不正常了。正常用户群体里,90 天内新注册的号占比连 15% 都到不了。你品品这差距。
活跃时长。刷单群有典型的时间窗口:凌晨 2 点到 5 点异常活跃的团伙,风险自动往上跳一级。正常买家谁半夜三点在群里喊“接单接单”?
刷单频率。单日交易笔数超过 50 笔,且同一收货地址出现在 3 个以上不同账户的订单里。收货地址这字段,淘宝后台其实会做模糊归一化,“北京市海淀区西三旗街道”和“北京海淀西三旗”会被映射到同一 ID,你用 API 就能拿到标准化后的地址码。
异常交易占比。我写了个小脚本,每 10 分钟拉一次团伙内所有账号的“近 7 天退款率”和“异常评价占比”,也就是买家不写文字、只给好评那种。如果退款率 > 30% 且好评率 > 95%,基本就是刷单洗分。
轻量规则引擎:YAML 比 Drools 好使
我搭了个规则引擎,直接塞进 Flask 里跑。就一个 YAML 配置文件,加载成有序链表,命中一条就停止打分。
# risk_rules.yaml
- rule_id: R001
condition: "new_account_ratio > 0.7 AND cluster_size > 10"
score: 85
label: "高危小号矩阵"
action: "封号 + 举报"
- rule_id: R002
condition: "night_active_ratio > 0.6 AND avg_daily_orders > 30"
score: 70
label: "夜间刷单窝点"
action: "降权 + 限制提现"
- rule_id: R003
condition: "refund_rate > 0.3 AND fraud_address_count > 3"
score: 60
label: "异常资金通道"
action: "冻结 72 小时人工审核"
每条规则跑完会累加一个总分,超过 80 分的直接进“红名单”,我让 Grafana 的仪表盘把那行标成深红。低于 30 分的自动忽略,连日志都不写。挑个典型的说。Louvain 切出来的一个子图,15 个节点,全是近两个月注册的闲鱼小号。收货地址集中在“广东省深圳市龙华区”同一个城中村,IP 段全部落在 113.87.*.*。这些号每天固定刷 30 笔左右,集中在下午 2 点到 4 点,商品全是几块钱的虚拟充值卡——刷单成本低,退款后资金回流快。
规则引擎一卷,R001 命中,R002 也命中,最终得分 92。系统自动把 15 个号全部限制了提现,同时把那个城中村的地址段丢进了淘宝的风控黑名单池。后续运营反馈,三天后这团伙集体失声——资金链断了,人就散了。风控画像这东西,不是搞学术论文。关键是让业务方看得懂、能拍板、敢执行。一个团伙一个标签,红黄绿三档,鼠标点进去能看到每条规则的命中详情,就够了。
落地那几天:数据合规和老生常谈的模型迭代
工具链和流程讲完了,剩下两个绕不开的雷区——数据合规和模型迭代。
先说数据。聊天记录从法律上看属于个人信息,抓取门槛其实比很多人想象的高。我身边有团队直接写脚本爬群成员的历史消息,结果被用户举报,平台封了 API 密钥。合规的做法很简单:只分析公开群聊,或者至少拿到群管理员的书面授权。《个人信息保护法》第十三条明确说了“取得个人同意”这一条。如果你爬的是需要付费加入的刷单群,用户进群时在公告里写明“聊天记录会用于风控分析”,这算一个相对干净的立场。千万别打擦边球搞“爬完再说”,一旦被追责,模型再准也没用。
模型迭代这块,实话说是最让人头疼的。羊毛党的黑话更新速度堪比互联网黑话——上半年“开车”还指代刷单,下半年“开车”已经变成了“发车任务”,中间还掺着“狗庄”“白嫖”“撸货”这种变体。我试过跑一批旧标签训练的 BERT 模型,放到新群消息里,F1 直接从 0.86 掉到 0.64。能怎么办?只能上持续微调的流水线。每季度攒 500 条最新标注数据,人工加半自动,用 LoRA 微调一次 embedding 模型和分类头。单次 Finetune 在 3090 上跑 30 分钟。数据标注也是体力活,我写了个小工具:把疑似刷单句子的 top-30 词向量拿出来,按余弦相似度排序,人只看第一遍就能标完。
说实话,能留在手边的开源工具不多,这三个是反复踩坑后才没删掉的。
- LangChain:跑流程编排,把清洗、向量化、分类、图谱写入串成 Chain,出错能定位到具体步骤,比手写 if-else 省心太多
- Neo4j:图谱存储,
Louvain算出的社区结构直接写成 Cypher 语句,查询某个团伙的历史活动轨迹,响应时间在 200ms 以内 - FastAPI:部署接口,把规则引擎和模型推理包成 POST 端点,运营那边直接挂到钉钉机器人上,消息进来秒出结论
工具换了一茬又一茬,黑话更新得比 App 版本还快,但,真正值钱的还是脑子里那根弦——什么时候该信、什么时候该怀疑,这种判断力一旦练出来,谁都拿不走。
评论