文章主张先把WhatsApp消息作为事件分类,再把确需理解的内容交给大模型,而非让智能体直接处理所有Webhook。该架构能减少模型调用、提示词膨胀和错误回复,并改善人工转接。
我反复看到 WhatsApp bot 犯同一个错误:
有人把 Twilio 或 Meta webhook 直接接到 GPT-5、Claude 或 OpenClaw loop 上,写一段欢快的 system prompt,就把它称作架构。
用来做演示没问题。一到生产环境,事情就会变得古怪。
真正经得住考验的模式要朴素得多:
先分流,再对话
这意味着,你应该先把收到的 WhatsApp 消息当作一个事件处理,然后才把它当作一次对话。
当我开始用这种方式思考 WhatsApp bot 后,很多问题同时变得更容易解决:
减少对显而易见情况的愚蠢回复
围绕 WhatsApp 2025 年 template 定价,行为变得更加可预测
最近,r/openclaw 上一个关于在 Make 中构建 WhatsApp chatbot workflow 的小帖子,又让我想起了这一点。这个 workflow 本身没什么问题。更重要的启示是,大多数人一开始就选错了层级。
他们从 assistant 开始。
他们真正应该从 dispatcher 开始。
如果你使用 Meta WhatsApp Cloud API,那么在调用任何 LLM 之前,收到的 webhook 就已经告诉了你很多信息:
事件究竟是一条消息,还是一次状态更新
{
"object": "whatsapp_business_account",
"entry": [
{
"changes": [
{
"value": {
"messages": [
{
"from": "16505551234",
"type": "text",
"text": {
"body": "Does it come in another color?"
}
}
]
},
"field": "messages"
}
]
}
]
}
如果使用 Twilio WhatsApp,你会收到类似下面这样的表单字段:
光凭这些信息,就已经足够做出一些决定,没必要白白消耗一次模型调用。
没有 caption 的照片
送达/状态事件
明显的账单请求
非营业时间
这些情况都不应该直接进入一个庞大、开放式的 prompt。
这正是造成 token 浪费、延迟升高和行为脆弱的根源。
一个单体 Agent 最终会处理许多它根本不该看到的工作:
解读无意义的状态噪声
临场发挥处理账单流程
使用昂贵的推理回答重复、低风险的问题
在已经消耗大量上下文、试图避免转交之后,才决定是否交给人工处理
这不是智能,而是糟糕的路由。
如果你曾经看着用量分析,心想:“这东西为什么要在垃圾内容上浪费 token?”,那么答案通常出在上游。
监控当然有帮助。
openclaw status --usage
但用量 dashboard 只是尸检报告,路由才是治疗方案。
对于大多数 WhatsApp 客服和销售线索接入 workflow,我每次都会选择 n8n,而不是纯粹的 chat loop。
并不是因为 n8n 有什么魔力,而是因为它能让那些朴素但正确的决策变得容易。
标准化传入的 payload
根据确定性信号进行分支
只对真正需要理解的消息进行分类
把不明确的情况发送到显式 fallback
让 GPT-5 或 Claude 专注于范围明确的工作,而不是处理首次接触时的混乱局面
这是一种健康得多的设计。
下面是我会实际交付的模式。
Webhook 接收来自 Meta 或 Twilio 的事件
Code node 将 payload 标准化为统一结构
Switch node 对明显不需要 LLM 的情况进行路由
Text Classifier 只为真正的文本消息添加标签
CRM、队列或确定性回复处理已知类别
只有需要推理或起草内容的分支才会运行 LLM 步骤
标准化对象示例:
{
channel: "whatsapp",
from: "16505551234",
text: "Does it come in another color?",
hasMedia: false,
messageType: "text"
}
n8n 标准化代码示例:
const body = $json.body || $json;
const isTwilio = !!body.MessageSid;
if (isTwilio) {
return [{
channel: 'whatsapp',
provider: 'twilio',
from: body.From,
to: body.To,
text: body.Body || '',
hasMedia: Number(body.NumMedia || 0) > 0,
mediaCount: Number(body.NumMedia || 0),
messageType: Number(body.NumMedia || 0) > 0 ? 'media' : 'text'
}];
}
const msg = body.entry?.[0]?.changes?.[0]?.value?.messages?.[0];
const statuses = body.entry?.[0]?.changes?.[0]?.value?.statuses;
if (statuses?.length) {
return [{
channel: 'whatsapp',
provider: 'meta',
eventType: 'status',
raw: body
}];
}
return [{
channel: 'whatsapp',
provider: 'meta',
from: msg?.from,
text: msg?.text?.body || '',
hasMedia: msg?.type && msg.type !== 'text',
messageType: msg?.type || 'unknown'
}];
接下来,你的 Switch 逻辑就可以立刻剥离那些容易处理的情况:
eventType === "status"
messageType !== "text"
非营业时间
命中 invoice、refund、unsubscribe 等关键词
只有完成这些步骤后,才应该进行分类。
人们往往会在这里过度设计。
这里不需要一个才华横溢的 Agent,只需要一个可靠的 router。
好的类别往往都很朴素:
这些就足以过滤掉大量无意义的模型工作。
如果你使用 n8n Text Classifier 接收销售线索,我通常只会保留一个主要类别。
对许多 workflow 来说,意图重叠远不如明确的下一步有用。
pricing_request → 发送价格信息或创建 CRM 任务
urgent_customer_issue → 转入人工队列
billing_problem → 进入账单 workflow
other → fallback 审核
这与电子邮件分类自动化的经验本质上相同:
使用轻量级分类,避免昂贵的开放式推理。
这已经不只是工程偏好的问题了。
随着 WhatsApp Business Platform 在 2025 年调整定价,template 消息会按成功送达的消息数量收费,而在客户服务窗口内,非 template 消息免费。在某些情况下,还会提供免费的入口窗口。
这改变了我思考 bot 设计的方式。
chat-first bot 一开始就生成语言。triage-first workflow 则先判断究竟发生了什么。
这个差别很重要,因为现在 workflow 可以询问:
当前是否处于服务窗口内?
我真的需要使用 template 吗?
如果这条消息需要付费,它还值得发送吗?
我是否应该什么都不做,等待人工处理?
这就是架构直接影响成本行为的例子。
下面是开发者通常会关心的几个实用事项:
除非修改 N8N_PAYLOAD_SIZE_MAX,否则 n8n Webhook node 默认的最大 payload 大小为 16MB
Twilio 记录了每个 sender 的吞吐量限制,当你日后扩大 outbound messaging 规模时,这一点很重要
但如果你的第一步是“把所有东西都发送给模型”,这两点都救不了你
在编写任何“友好的 assistant” prompt 之前,我会先构建下面三个流程。
if status event -> ignore for LLM
if media and no caption -> media review queue
if known customer -> fetch CRM context
if text -> classify into support/billing/sales/spam/handoff
if support and enough context -> send to GPT-5 or Claude
if pricing request -> deterministic reply or CRM update
if urgent issue -> human queue
if obvious spam -> drop
else -> fallback branch
3)感知服务窗口的回复
if inside service window -> prefer non-template response
if outside service window -> decide whether template is justified
if low-value follow-up -> do nothing billable
如果你不使用 n8n,只想用代码实现核心逻辑,基本思路如下:
function routeMessage(msg) {
if (msg.eventType === 'status') {
return { action: 'ignore_status' };
}
if (msg.messageType !== 'text') {
return { action: 'media_review' };
}
const text = (msg.text || '').trim().toLowerCase();
if (!text) {
return { action: 'ignore_empty' };
}
if (['refund', 'invoice', 'unsubscribe'].some(k => text.includes(k))) {
return { action: 'deterministic_flow', queue: 'billing_or_policy' };
}
if (msg.isVip) {
return { action: 'human_handoff', priority: 'high' };
}
return { action: 'classify_text' };
}
在大多数真实系统中,单是这个函数所节省的钱,就会超过一个更花哨的 prompt。
一旦不再把每个 WhatsApp 事件都发送给一个庞大的 Agent,LLM 调用就会干净许多。
这才是真正适合使用 OpenAI-compatible endpoint 的地方:
在正确的分支上生成客服回复
当确定性路由无法继续处理时,进行 fallback 推理
如果你基于 n8n、Make、Zapier、OpenClaw 或自定义 Node/Python workflow 构建系统,那么 Standard Compute 可以直接替代 OpenAI API。
相同的 SDK 形式。固定月费。不按 token 计费。
这对 Agent workflow 非常重要,因为即使路由设计合理,随着时间推移,系统仍然会产生大量模型流量。
不同之处在于,现在模型调用都花在了有价值的工作上,而不是任由 bot 在每次 webhook 到来时随意发挥。
更重要的是,你可以构建自动化流程,而不用整天盯着 token 用量。
如果你的 bot 每天只收到五条消息,而且没人介意它偶尔胡扯几句,那么 chat-first 完全没问题。
任何人们需要信任的 workflow
那么 chat-first 就是一个陷阱。
我见过最好的 WhatsApp Agent,与其说像 chatbot,不如说更像 dispatcher。
知道服务窗口是否开放
以不同方式路由媒体与文本
将账单与销售分开处理
这样一来,当 GPT-5、Claude、Llama 或 Qwen 最终被调用时,它拿到的是一项干净、明确的任务。
这就是为什么系统会显得更聪明。
不是因为 prompt 变好了,而是因为 workflow 不再要求一个 Agent 扮演整家公司。
如果你正在构建 WhatsApp bot,我的建议很简单:
先建好前台接待,再聘请哲学家。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。