如果用户问“几点营业”“拿铁多少钱”,机器人可以自动回一条已核实的答案;碰到过敏、退款或规则不清的问题,就应该转给店员。本文做一个只在本机运行的公众号回调练习:本机 Ollama 只把文本分成有限类别,程序再从固定 FAQ 里取答案,模型不会直接编写发给用户的话。

这和之前用 OpenClaw 微信渠道搭小店回复助手不同:s104 实测的是插件渠道和测试账号消息往返;本文演示公众号开发者服务器的 GET 验证、POST XML 回调、签名校验和被动回复结构。没有真实公众号账号、公网服务器或发布权限,所以练习包只模拟平台请求,不会连接你的公众号。

先了解回调边界

公众号用户发来消息后,平台会把 XML POST 到开发者填写的服务器 URL。官方文档说明,服务器约有 5 秒完成响应;超时可能触发重试,并建议使用 MsgId 排重。被动回复是对这次回调返回规定的 XML;它与之后通过客服消息 API 主动发送消息不是一回事。接收普通消息 · 被动回复消息。

示例只处理明文模式的文本消息。如果公众号配置了兼容或安全加密模式,请使用与后台一致的官方加解密流程;本练习没有实现 AES,也没有部署到公网。账号类型、后台入口和可用接口权限要以该账号当前的公众平台后台为准。服务号接入概述。

只自动回答两条已确认事实

练习用一间虚构门店:营业时间每天 10:00–20:00,拿铁 ¥26。模型只能返回 hours、latte_price、unknown 三种分类;回复文本写在 bot.py 的固定映射里。问地址、退款、投诉、身体不适或其他未知问题,都回“我暂时无法确认这个问题,请联系店员。”模型超时、连接失败或返回格式无效,也走同一兜底。

这样把模型错误限制在“选错一个有限类别”的范围里,避免把未经核实的自由生成内容直接发出去。它仍可能把问题分错,所以本例只测虚构消息,未证明真实用户问题的准确率。遇到身体不适、食品安全、退款或投诉,始终由人处理。

在本机启动并发送模拟回调

先在终端运行 ollama list,确认已有 gemma4-e2b:latest。模型不在列表时就先停止,不要运行可能自动下载模型的命令。练习包里的 bot.py 使用 Python 标准库,并只连 127.0.0.1:11434 的 Ollama API。

下载并解压公众号自动回复练习包,在解压目录开两个终端。先做签名、XML 转义、体积限制、重复消息和超时兜底的本机断言:

python3 selfcheck.py

终端一启动本地回调服务:

WX_TOKEN=demo-token OLLAMA_MODEL=gemma4-e2b:latest python3 bot.py

demo-token 是假值,只供本机模拟。服务仅绑定 127.0.0.1:8010,外部微信服务器访问不到它。

终端二发送五条虚构 XML 消息:

WX_TOKEN=demo-token python3 send_fixtures.py

检查输出是否包含:GET 挑战回显成功;营业时间和拿铁问题返回固定答案;地址、过敏和要求忽略分类规则的退款问题均转人工;伪造签名收到 403;相同 MsgId 第二次不重复回复。脚本也会显示每条本地请求的耗时。

看看程序如何限制风险

bot.py 先用 Token、时间戳和随机串计算签名,并用恒定时间比较;无效签名直接拒绝。随后限制请求体大小并解析 XML,只处理文本消息。收到重复 MsgId 时返回 success,避免重试重复调用模型。程序不记录消息正文,也不保存 OpenID。

分类请求只发给本机 Ollama。模型只能按 JSON Schema 返回三个允许值;程序把其它值全部归为 unknown。每条请求最多等 3 秒,超过就用固定兜底,给平台的回调时限留出余量。答复内容只从本地常量读取,不使用模型生成句子。Ollama 的 Chat API 支持结构化格式和 token 统计;练习不需要外部 API Key,也不需要上传消息。查看 Ollama Chat API。

真实聊天消息可能包含姓名、订单、联系方式或健康情况。练习不要填真实顾客内容;使用真实资料前,应按单位的数据规则判断用途、最小范围和允许的处理环境。《个人信息保护法》第 5—7 条规定了合法、正当、必要、明确目的、最小范围和公开透明等原则。查看法律全文。

本机模型与回调实测

本机已安装的 Qwen3.8-27B 用于对比:四条虚构分类请求中,前三条在 4 秒客户端时限内超时;身体不适问题约 1.019 秒返回 unknown。因此没有把这个较慢模型放进回调链路。随后用已安装的 gemma4-e2b:latest 分类四条问题,四条都符合预期;首次直接请求 2.599 秒(模型加载约 2.359 秒),之后三条为 0.168–0.199 秒。

再启动本地回调服务发送五条 XML 夹具:营业时间、拿铁价格、地址、过敏和“忽略规则”的退款请求全部返回预期文本;端到端耗时为 0.151、0.219、0.205、0.206、0.205 秒。签名伪造被拒,同一 MsgId 只处理一次。实测模型都已安装,没有下载模型;这些结果只覆盖五条虚构消息,不能代表冷启动、并发或网络波动下的固定延迟。

实际接公众号前,还需准备账号可用的服务器配置和公网可达的回调地址(优先 HTTPS),并确认后台的消息加密模式、错误监控和人工接管流程。本文没有更改公众号后台、填写真实 Token 或测试真实用户消息;练习服务不能直接作为生产系统部署。