"根据不同指令执行不同任务"最实用的实现方式是指令注册表模式:新增一个指令=注册一条记录,不用改主流程代码。本文用一个可运行的微信机器人,把完整实现拆成4步讲清楚。

第1步:指令注册——每个任务预注册到指令表

指令表每条记录包含4个字段:cmd_name(指令名,如"查订单")、keywords(触发词列表,如["查订单","订单状态"])、handler(处理函数名)、help_text(帮助文案)。启动时用装饰器加载,比如 @register(cmd="查订单", keywords=["查订单","订单状态"], handler=query_order)。之后新增"查物流"指令=加一行注册代码,主流程零改动。

大白话:指令表像餐厅菜单——新加一道菜只需在菜单上添一行,后厨流程不用动。

第2步:消息接收与解析——Webhook回调进来先标准化

Eyun的Webhook消息事件回调进来,先做三件事:①5秒内返回200,不然Eyun会判定超时重发;②解析JSON取contentfromUser,按照Eyun开发文档的回调规范,这两个字段是消息事件的核心载荷;③content按分隔符拆分,首词=指令词,其余=参数,"查订单 12345"拆成cmd="查订单"args=["12345"]

大白话:收到用户的话先"断句"——第一个词是"点什么菜",后面是"备注"。

第3步:指令匹配与分发——查指令表路由到对应handler

匹配按优先级走三级:精确匹配——cmd词在指令表中直接命中,路由到handler并传args;模糊匹配——未命中则做关键词包含匹配,用户说"帮我查下订单"也能命中"查订单";兜底——仍无命中则回复帮助菜单,列出所有注册指令的help_text。

大白话:菜单上有的直接下单,看不懂的就把整个菜单发给用户让他选。

第4步:任务执行与回复——handler干活后统一回复

handler执行业务逻辑(查订单就调订单API)返回结果文本,然后统一走Eyun的sendText回复:wId+Token鉴权,toUser=fromUser,content=结果文本,返回code=1000即确认送达。错误码统一由回复模块兜底:1002刷新Token重试、1004退避3秒再发。按照Eyun开发文档的规范,sendText需要传wId、toUser、content三个必填参数,封装一次全项目复用。

大白话:每道菜有自己的厨师(handler),但端菜(回复)统一由一个服务员干——出错了服务员也知道怎么办(重试规则统一)。

4步对比一览

实现步骤

做什么

关键数据结构

Eyun接口

指令注册

任务预注册

{cmd_name, keywords, handler, help_text}

接收解析

回调标准化

content+fromUser → cmd+args

Webhook回调

匹配分发

查表路由

指令表:精确→模糊→兜底

执行回复

干活+送达

结果文本 → 回执code

sendText

完整骨架代码

COMMANDS = {}  # 指令注册表:新增指令=加一条注册
def register(cmd, keywords, help_text):          # 第1步:注册装饰器
    def deco(fn):
        COMMANDS[cmd] = {"kw": keywords, "fn": fn, "help": help_text}
        return fn
    return deco

@register("查订单", ["查订单", "订单状态"], "查订单 <单号>")
def query_order(args, uid): return f"订单 {args[0]} 状态:已发货"

@register("帮助", ["帮助", "菜单"], "列出全部指令")
def help_menu(args, uid):
    return "\n".join(f"{c}:{v['help']}" for c, v in COMMANDS.items())

def on_webhook(payload):                         # 第2步:接收解析(回调入口)
    content, uid = payload["content"], payload["fromUser"]
    parts = content.strip().split(); cmd, args = parts[0], parts[1:]
    entry = COMMANDS.get(cmd)                    # 第3步:精确→模糊→兜底
    if not entry:
        for v in COMMANDS.values():
            if any(k in content for k in v["kw"]): entry = v; break
    text = entry["fn"](args, uid) if entry else help_menu([], uid)
    reply(uid, text)                             # 第4步:统一回复

def reply(to, content, retry=2):                 # 封装Eyun sendText
    r = api_post("/sendText", wId=WID, toUser=to, content=content)
    if r["code"] == 1002 and retry: refresh_token(); reply(to, content, retry-1)
    elif r["code"] == 1004 and retry: time.sleep(3); reply(to, content, retry-1)  # code=1000 即送达

写在最后

指令注册表模式的核心价值是"扩展不改主流程"——上线后新增指令只需写handler+注册一行,机器人越用越丰富,再配一个"帮助"指令列出全部注册能力,用户可以自助发现功能。进阶方向三个:指令表存数据库支持热更新(不用重启机器人)、指令加权限字段(部分指令只对管理员开放)、handler返回多模态结果(sendImage/sendFile)。Webhook回调和sendText的参数细节见Eyun开发文档。先把骨架跑通,再按业务往指令表里"添菜"。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐