第八章:消息分发与 Dispatcher 设计(系统进入可扩展阶段)
这一章是整个系统从“能解析消息”到“能处理业务逻辑”的分水岭。
上一章结束时,我们已经做到:
企业微信 → 解密 → 明文XML → Python对象
但目前的问题是:
所有消息都堆在 callback 里处理
这在工程上是不可接受的。
8.1 为什么必须要 Dispatcher
如果不做分发,会变成这样:
if text:
do_text()
elif event:
do_event()
elif image:
do_image()
问题:
- ❌ 代码越来越臃肿
- ❌ 无法扩展新消息类型
- ❌ AI逻辑混入入口层
- ❌ 不可测试
- ❌ 不可拆分部署
✔ 正确做法:Dispatcher模式
核心思想:
“入口只负责接收,处理交给不同模块”
8.2 系统分层设计
本章完成后的结构:
callback.py
↓
dispatcher.py
↓
handler/
├── text.py
├── event.py
├── image.py
└── file.py
8.3 Dispatcher设计
📌 dispatcher.py(核心)
from app.handlers.text import handle_text
from app.handlers.event import handle_event
from app.handlers.image import handle_image
class Dispatcher:
def dispatch(self, message: dict):
msg_type = message.get("MsgType")
if msg_type == "text":
return handle_text(message)
elif msg_type == "event":
return handle_event(message)
elif msg_type == "image":
return handle_image(message)
else:
return self.handle_unknown(message)
def handle_unknown(self, message):
print("未知消息类型:", message)
return None
8.4 Handler设计原则
每个 handler 必须满足:
✔ 单一职责
✔ 无外部依赖
✔ 可独立测试
✔ 可独立扩展
8.5 文本消息处理(核心入口)
📌 handlers/text.py
from app.core.llm import ask_llm
def handle_text(message: dict):
"""
文本消息处理
"""
user_id = message.get("FromUserName")
content = message.get("Content")
print(f"[TEXT] user={user_id}, content={content}")
# 这里先不接AI,只做结构验证
return {
"type": "text",
"reply": f"收到:{content}"
}
8.6 事件消息处理
📌 handlers/event.py
def handle_event(message: dict):
"""
事件消息处理
"""
event_type = message.get("Event")
print("[EVENT]", event_type)
if event_type == "subscribe":
return {
"type": "text",
"reply": "欢迎关注企业AI助手"
}
return {
"type": "text",
"reply": "事件已收到"
}
8.7 图片消息处理
📌 handlers/image.py
def handle_image(message: dict):
"""
图片消息处理
"""
pic_url = message.get("PicUrl")
print("[IMAGE]", pic_url)
return {
"type": "text",
"reply": "已收到图片"
}
8.8 callback接入Dispatcher
📌 callback.py(最终整合)
from fastapi import APIRouter, Request
from app.wecom.crypto import WeComCrypto
from app.wecom.parser import parse_encrypt_xml, parse_plain_xml
from app.handlers.dispatcher import Dispatcher
router = APIRouter()
crypto = WeComCrypto()
dispatcher = Dispatcher()
@router.post("/callback")
async def callback(request: Request):
params = dict(request.query_params)
msg_signature = params.get("msg_signature")
timestamp = params.get("timestamp")
nonce = params.get("nonce")
body = await request.body()
xml_str = body.decode("utf-8")
# 1️⃣ 外层解析
outer = parse_encrypt_xml(xml_str)
encrypt = outer.get("Encrypt")
# 2️⃣ 校验 + 解密
crypto.verify_signature(msg_signature, timestamp, nonce, encrypt)
plain_xml = crypto.decrypt_message(
msg_signature,
timestamp,
nonce,
xml_str
)
# 3️⃣ 明文解析
message = parse_plain_xml(plain_xml)
# 4️⃣ 分发
result = dispatcher.dispatch(message)
return "success"
8.9 当前系统能力状态
✅ 已完成能力
✔ 企业微信接入
✔ 消息解密
✔ XML解析
✔ 消息结构化
✔ Dispatcher路由
✔ Handler拆分
🚧 当前系统状态
企业微信消息流:
✔ 已进入系统
✔ 已可识别类型
✔ 已可分模块处理
但:
❌ 还没有AI
❌ 还没有Redis队列
❌ 还没有异步处理
8.10 Dispatcher的工程价值
这一章建立了一个非常关键的能力:
系统从“写死逻辑”变成“可扩展架构”
📌 未来扩展能力
以后你可以直接加:
voice.py
video.py
file.py
location.py
无需修改 callback。
8.11 本章总结
这一章完成后,系统已经具备:
👉 “可扩展消息处理架构”
入口层彻底解耦,业务开始模块化
🚀 下一章预告(第九章)
第九章:接入Redis消息队列(异步架构设计)
下一章我们会解决一个关键问题:
现在系统是同步处理
❌ callback等待AI
❌ 响应慢
❌ 无法扩展
下一步我们将引入:
Redis Queue
Producer / Consumer
Worker异步模型
👉 系统将从:
同步机器人 → 事件驱动架构系统