评论系统的幕后:登录、限流、AI 审核与 Workflows 编排
摘要
拆解博客评论系统的完整防线:登录、Turnstile、限流、异步 AI 审核、人工兜底,以及 Cloudflare Workflows 如何把这些环节编排起来。
这个博客的评论区不是匿名开放的。用户要先登录,提交时要过 Turnstile 和限流;但这还不够。只要评论最终会被公开展示,垃圾广告、恶意辱骂、甚至“忽略上面所有指令”这种 Prompt Injection,迟早都会混进来。
我的做法是把“入口防线”和“内容审核”拆开:
入口防线同步执行:登录、Turnstile、Rate Limit
内容审核异步执行:评论先入库,再交给 Cloudflare Workflows 跑 AI 审核
这样用户提交时不会被模型延迟卡住,而审核逻辑也能有独立的重试、降级和通知链路。
这不是只有 AI 的防线
系统前面有三层同步防护:
必须登录:只有登录用户才能提交
Turnstile 校验:拦截脚本和低质量流量
限流:限制接口提交速率
AI 审核解决的是第四层问题:通过了请求层校验的内容,是否适合公开展示。
另外还有一个小分支:管理员评论不走 AI,直接发布;普通用户评论才会进入 verifying 状态并触发异步审核。
整体流程
一条评论发布的完整链路:
除了普通回复,系统还有两个通知链:
新根评论提醒:用户新发评论时,立即通知管理员
待人工审核提醒:AI 把评论打到
pending时,发送审核通知
从 Queue 到 Workflows
评论审核不是“一进一出”的单点任务,而是有多阶段边界的流程。Cloudflare Workflows 的特性非常契合:
步骤独立执行(拉评论、文章、调 AI、发通知)
单个步骤可单独重试
依靠步骤名实现幂等
Workflows 的模型正好贴这个需求。骨架大概长这样:
step.do() 的名字不是装饰品。Workflows 会拿这个名字做步骤级别的幂等判断:前面的步骤已经成功了,后面崩了,恢复执行时不会把已经做完的步骤再跑一遍。
AI 审核的核心:给足上下文
仅把评论本身丢给模型做 safe: true/false 判断误杀率很高。做好审核主要靠这三点:
1. 审核标准必须写死,不能让模型自己猜
我在 system prompt 里把拒绝条件写得很明确,比如:
这样模型不是“自己形成口味”,而是在执行规则。
2. 口语化表达要单独放行
中文评论里有一类表达特别容易被误伤,比如:
“你这说得不对”
“太离谱了”
“笑死”
如果 prompt 不把这类场景点出来,模型很容易把“语气冲”和“恶意攻击”混为一谈。所以我额外加了一条规则:没有明显辱骂、仇恨、骚扰或恶意攻击时,这类短句应当允许通过。
3. 回复型评论必须挂载上下文
只看评论本身经常会误判。比如“你说的是什么垃圾”,单看像骂人,在上下文里可能只是讨论垃圾回收机制。
调 AI 之前需要一起带上这些信息:
文章标题
文章摘要
文章正文预览
根评论
被回复评论
实际传给模型的 user message 会更像这样:
误判的根源大多是没有喂够上下文。
结构化输出
严格约束为对象输出:
这样拿到的就是稳定的结构:
对接状态更新、后台展示会更稳。
审核理由跟随语言
如果评论是英文,审核理由就应该切成英文。这条规则可抽成通用函数,和标签推荐等功能复用:
异常与边界情况处理
工程落地更考验对异常的处理:
开发环境直接通过
本地调试如果每次都真调 Workers AI,既慢又浪费额度。所以开发环境里,我直接返回“自动通过”。
空评论直接转人工
workflow 会先把评论内容转成纯文本。如果转出来是空字符串,不会继续调 AI,而是直接标成 pending,让管理员处理。
AI 异常降级转人工
AI 调用超时或失败时,状态降为 pending,由人工兜底来决定,绝不直接删除或隐藏评论。
三条独立的通知链路
系统通知体系由并行互不干扰的三条链路组成:
1. 新根评论提醒
普通用户新发根评论时,系统会立即通知管理员。这个动作发生在评论创建阶段,不依赖 AI 审核结果。
2. 待人工审核提醒
如果 AI 判定不安全,或者 AI 服务不可用,评论会进入 pending。这时 workflow 会再发一条管理员待审核通知,里面带评论摘要和后台审核地址。
3. 回复通知
评论审核通过,而且这条评论是回复别人时,系统才会给被回复者发邮件。这里还做了几层防骚扰处理:
不通知自己回复自己
带退订链接
退订 Token 用 HMAC 签名,避免伪造
复用现有 Service 层
Workflow 是一个独立的 WorkflowEntrypoint,不走 TanStack Start 中间件,也拿不到注入对象的上下文字段。
解决方式是直接拼接依赖,传入已有的 Service 重复利用:
只要 context 的形状一致,Service 层的代码就能直接用,不绑死框架的请求生命周期。
这套模式不只用在评论审核
评论审核只是这个博客里 AI 能力的一部分。用同一套思路,我还做了两件事:
发布文章时自动生成摘要
根据正文推荐标签,并优先复用已有标签
它们共享同一个 Workers AI 模型,也共享同一套“语言跟随”“结构化输出”“上下文约束”的设计习惯。
把 AI 放进异步工作环节,整体链路会比同步阻塞稳得多。
