V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
samray
V2EX  ›  分享创造

产品上线半月的故障、挑战与优化之路

  •  
  •   samray ·
    ramsayleung · 8 小时 16 分钟前 · 449 次点击

    博客原文: 基于贝叶斯算法的 Telegram 广告拦截机器人(二):上线半月的故障、挑战与优化之路


    1 引言

    半个月前,我发布了一个基于贝叶斯算法的 Telegram 广告拦截机器人 @BayesSpamSniperBot (https://t.me/BayesSpamSniperBot)

    项目地址:https://github.com/ramsayleung/bayes_spam_sniper

    系列文章:

    尽管项目代码开源,但我始终以产品思维运营它。上线半个月以来,经历了故障、用户反馈与持续优化,现将这段经历分享出来。

    2 上线即故障

    没想到我的产品的第一个线上故障来得这么快,发布的时候直接不可用,把正常消息都给删了,用户在各种途径都向我反馈:

    故障的原因是我当时一直在收集垃圾广告的数据,太专注于垃圾广告数据,而忽略了收集的正常数据, 导致垃圾广告数据过多,消息都被认为是垃圾广告,被误删了。

    通过补充大量正常消息数据,重新平衡训练集,模型逐渐恢复正常识别能力。

    3 挑战

    3.1 邮件与即时消息的差异

    我在《基于贝叶斯算法的 Telegram 广告拦截机器人(一):从问题到产品》里面提到过:

    常见的 Telegram 广告机器人是大多是基于关键字的,通过匹配关键字进行文本拦截,非常容易被发垃圾广告的人绕过。

    这不禁让我想起了保罗.格雷厄姆在《黑客与画家》一书在 2002 年介绍的情况:

    当时电子邮件兴起,也有非常多的垃圾邮件,常见的垃圾广告拦截方式是关键字匹配+邮件地址黑名单,但是既低效也容易被绕过。

    保罗.格雷厄姆就创造性地使用贝叶斯算法(Bayes Theorem)实现了一个广告拦截器, 效果竟然出奇地好。

    但产品上线之后,我发现聊天软件消息和 Email 虽然都是文字,还是有很大差别的:

    Email 大多时候都是长文的,内容较长,并且大多情况,一封邮件上下文本身也很完整,就有较多的内容,较高的准确度来判断是否是广告。

    而 Telegram, 微信这类的即时聊天软件,聊天消息大多都不长,可能把内容分成多条消息来发,就没有完整的上下文,比如:

    换 U

    找我

    单条消息很较难准确判断是否是广告,所以对即时消息做广告拦截本身就更难, 「短文本+无上下文」是 NLP 中的经典难题,也是本项目最大的技术挑战。

    3.2 漏删与误删

    漏删与误删是广告拦截中不可避免的矛盾权衡。

    若想提高拦截率(召回率),就需降低置信度阈值,将更多疑似广告的消息拦截,但这也会增加误删正常消息的风险。

    反之,若想避免误删(提高精确率),则必须提高置信度阈值,但这又会导致更多广告被漏掉。

    在即时消息短小、上下文缺失的特性下,想同时实现零误删和零漏删几乎是不可能的。

    权衡之下,我选择优先保证用户体验: 宁可漏删,不可误删

    因为漏掉的广告,群友可以举报或由管理员手动删除;但误删的正常消息却无法恢复,对用户的伤害更大。

    因此,我将拦截阈值设置为 95%,即仅当模型有极高把握(>95%概率)判定为广告时才会删除。

    这虽然会放过一些疑似广告,但最大程度地保障了正常聊天不被误删。

    4 优化之路

    4.1 自动删除消息

    产品上线之后,很快就有用户来试用了,然后其中一个用户就提了一个非常好的优化建议。

    这个警告的消息不会自动删除,如果有很多人在群里发广告,那么群里就会有一堆这样的消息,也算是对群消息的污染。

    所以用户建议:

    可以发这个提醒,但在几分钟后也把这个提醒消息删除掉

    我觉得这是个非常好的优化体验,因为就把这个功能给加上了,提醒消息本身会在 5 分钟后自动删除。

    倾听用户的声音是非常重要的,他们可能就会从他们的角度提出非常好的建议。

    但是不要盲目听从用户的建议,比如也有用户建议:

    我觉得还应该有以下功能.

    1. 恢复消息, 恢复用户. (让管理员恢复误删的消息和用户)
    2. 主动投喂正常消息. (让管理员主动投喂一些消息. 比如, 群里面昨天 的消息, 随便选一些正常的, 投喂给机器人)

    恢复消息这个功能没有太大必要,并且也不实用,因为恢复消息这个功能本身就很微妙,是直接恢复被删除的消息呢,还是重新发一条新消息?

    如:

    • 2025-09-09 10:01:00 张三: 我今天吃了鸡翅
    • 2025-09-09 10:02:00 李四:鸡翅有啥好的(被误删消息)
    • 2025-09-09 10:03:00 王五:人家就喜欢吃,你管得着嘛

    如果是直接恢复被删除的消息,当前时间是 2025-09-09 11:00:00 ,把消息恢复之后,还有人会手动刷历史消息,查找旧消息么?

    Telegram 客户端不一定支持会跳转被恢复的旧消息,这意味着,你恢复误删的消息,也没人看得到。

    假如是重新发一条新消息 鸡翅有啥好的, 因为缺失了上下文,群里的人反而会疑惑,你在说什么。

    解决误删问题本质是提高拦截的准确率,而非考虑如何恢复被误删消息,准确率提高了,误删就会减少, 自然就不需要考虑如何恢复消息,用户体验还会更好.

    而主动投喂消息这个想法有点理所当然了。

    没有任何群管理员有意愿帮忙训练这个机器人,对用户而言,他们只想要一个好用的广告拦截机器人,至于怎么开发,训练出来的,用户并不在乎。

    所以用户不会有意愿和动力来优化这个机器人,不好用就再换一个好了,更何况,逐条消息收集的效率实在太慢太慢了, 所以我后面想出了一个比手工收集数据提效至少 100 倍的主意。

    4.2 过滤重复消息

    发现人难免会有误区,总会以为别人会和自己一样,之前看到发垃圾广告的人的时候,总会觉得他们是正常的用户手工发。

    但是最近几天发现了一些规律,有用户把同一条消息反复发,不同的群还是发同样的内容 即使是复制粘贴也难免会多个或者少个空格,然后消息被删了还一直发同样的内容。

    此外,还有一些群,内容的聊天内容都是广告,我还很奇怪,大家都在发广告,正常用户不都跑了嘛?

    此时,我才意识到,发消息的都是机器人。

    所以我加了个优化,计算消息内容的 hash 值,保存到数据库,并为这个字段建立索引。

    后面检测消息的时候,先根据 hash 值查询,检查是否存在已有的消息,如果消息已经存在且已经被标记成广告或者正常消息,那么就无需再使用模型检测,可以直接返回之前的检测结果。

    这样既提高了准确度,也优化了性能,也减少了人工干预的成本。

    同一个用户如果在同一个群发了三条广告,那么就会自动被封禁掉,也就是相同的广告只要发三条,就会马上被自动封禁掉。

    4.3 自动收集数据

    使用机器学习算法来实现一个类似的垃圾广告过滤器并不难,困难的持续收集高质量的训练数据,训练数据是非常宝贵的,毕竟数据才是核心资产。

    而对于我这个产品来说,最难的是冷启动时的训练数据问题:

    因为没有训练数据,模型就不准确,模型不好用就不会有人使用,自然也无法通过用户来收集垃圾广告数据,就无法良性循环, 存在一个鸡生蛋,还是蛋生鸡的问题。

    所以冷启动时,我是手动加了非常多的 Telegram 大群,然后人工在里面收集垃圾广告.

    但是这个效率实在是太低了,我收集了快一周才只有几百条数据, 一个是我无法一直盯着各个群,另外是这种 20w 的大群,一般都会有几个管理员,会手工删除广告,一会没有看垃圾广告数据就会被删掉了。

    这样手工收集数据实在在太痛苦了,我就在想有没有什么办法自动收集数据呢?

    我本来想的是直接把我的机器人拉到这些大群里面,即使没有管理员权限无法删除消息,也可以收集数据嘛,后面才意识到 Telegram 有个规定,只有群管理员才有权限加机器人,因为我不是管理员,所以自动没有权限添加机器人。

    但是 telegram 的客户端是开源的,他们提供了 tdlib [^1]这个跨平台的 C++ 库便于社区构建第三方的 Telegram 客户端,那么我自然可以使用这个库来登录我自己的账号,然后使用我的模型来过滤消息,然后把疑似广告的数据都收集起来,我再人工确认下。

    (顺便说一下,tdlib 和 telegram-bot-api [^2]这两个库竟然都是同一个作者 Aliaksei Levin [^3]在维护,实在是太强了。)

    我现在需要做的就是添加各种大群,然后程序就会自动监听并收集数据,我再人工批量确认下。

    实现起来也不复杂,200 行代码就实现了这个监听消息,分析,并且收集的功能。

    得益于这个自动化的数据收集程序,我 1 周不到就收集了近上万条的高质量训练数据了,效率实在高太多太多了。

    懒惰真的是程序员的美德, 这个经历再次证明:自动化工具往往能成倍提升效率,这正是工程师价值的体现.

    5 推广

    所谓酒香也怕巷子深,没有用户使用,代码写得再好也没有意义。从产品角度,运营推广至关重要。

    作为个人开发者,我没有大量粉丝关注,也没有营销预算,因此采用了传统的推广方式:撰写博客并在相关社区分享。

    我撰写了两篇双语博客文章,中文版本分享至:

    英文版本发布至:

    虽然推广效果有限,但这些努力为项目带来了最初的用户关注。

    6 成果与数据

    上线半个月,截止到目前为止, 已经有超过 80 个群使用过这个机器人,用户数已经比我预期要多了:

    指标 数值
    GitHub Stars 106
    使用群组数 83
    训练数据量 10543

    最开心的是看到我自己的程序在这些群成功拦截垃圾广告,就很有成就感,证明我做的东西真的能用户解决问题。

    7 结语

    这半个月的运营让我深刻体会到:产品不是代码写完就结束,而是从用户反馈中不断迭代的开始。

    产品是需要持续运营的,而写代码只是产品生命周期的其中一个环节,甚至不是最耗费时间的环节。

    下一步,我计划进一步优化模型准确率,并探索多语言支持,也欢迎关注我的频道或提交 Issue 一起讨论。

    [^1]: https://github.com/tdlib/td
    [^2]: https://github.com/tdlib/telegram-bot-api
    [^3]: https://github.com/levlam
    [^4]: https://old.reddit.com/r/rails/comments/1n6p791/built_my_first_rails_project_a_telegram_spam/

    2 条回复    2025-09-15 08:03:37 +08:00
    BeCool
        1
    BeCool  
    PRO
       7 小时 31 分钟前
    感谢分享
    billzhuang
        2
    billzhuang  
       2 小时 35 分钟前 via iPhone
    感谢分享

    站在上帝视角,“宁可漏删,不可误删”,应该是此类产品的第一原则
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5984 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 02:39 · PVG 10:39 · LAX 19:39 · JFK 22:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.