在 nanobot 对话框中实现 Model-Switcher 斜杠命令
在 nanobot 对话框中实现 Model-Switcher 斜杠命令
技术原理 + 操作手册:即使 AI 模型不可用,也能在对话框中切换模型
1. 背景与问题
1.1 nanobot 的多模型架构
nanobot 支持配置多个 AI 模型提供商(如 OpenAI、DashScope、百度千帆等),并通过 fallback 机制实现自动故障转移。当主模型不可用时,系统会自动切换到备用模型。
1.2 为什么需要在对话框中切换模型
在实际使用中,我们经常遇到以下场景:
- 模型故障:当前使用的模型 API 返回错误或限流
- 功能需求:某些任务需要特定模型(如代码生成用 Codex,中文优化用文心一言)
- 成本优化:根据任务复杂度选择不同价格的模型
1.3 关键挑战
如果通过 AI 模型来处理切换命令(如让 AI 执行 /model switch),会存在一个致命问题:当 AI 模型本身不可用时,切换命令也会失效。
这就好比门锁坏了,你却需要打开这扇门去拿备用钥匙。
2. 技术方案对比
2.1 方案 A:AI 层处理(loop.py)
实现方式:在 nanobot/agent/loop.py 的 _process_message() 方法中添加 /model 命令处理。
优点:
- 实现简单,代码集中
- 与现有
/new、/stop命令处理方式一致
缺点:
- ❌ 致命缺陷:如果当前 AI 模型不可用,命令无法执行
- 响应延迟较高(需要经过 AI 处理流程)
2.2 方案 B:通道层处理(feishu.py / telegram.py)
实现方式:在消息通道层(飞书/Telegram)直接拦截 /model 命令,调用 model_switcher.py 脚本执行,不经过 AI 模型。
优点:
- ✅ 高可用:即使 AI 模型挂了,命令依然可用
- ✅ 响应快:无需等待 AI 处理
- ✅ 解耦:命令执行与 AI 状态无关
缺点:
- 需要修改多个通道文件
- 代码分散在各通道实现中
2.3 方案选择
选择方案 B。
对于 model-switcher 这种基础设施级别的功能,可靠性优先于代码简洁性。当系统出现故障时,必须保证有可靠的逃生通道。
3. 核心实现原理
3.1 nanobot 消息处理流程
1 | 用户发送消息 |
3.2 拦截点选择
飞书通道:在 _on_message() 方法开头拦截
1 | async def _on_message(self, message_data: dict) -> None: |
Telegram 通道:使用 CommandHandler 注册 /model 命令
1 | self._app.add_handler(CommandHandler("model", self._on_model)) |
3.3 命令执行流程
1 | 用户发送 /model switch dashscope |
3.4 关键设计决策
直接调用脚本:通过
subprocess.run()调用model_switcher.py,而不是导入 Python 模块- 优点:隔离性好,脚本异常不影响主程序
- 缺点:有进程创建开销(可接受)
统一输出格式:所有子命令返回 Markdown 格式,便于阅读
超时保护:设置 30 秒超时,防止脚本卡死
4. 操作手册:重新部署
4.1 修改文件清单
| 文件路径 | 修改类型 | 说明 |
|---|---|---|
nanobot/channels/feishu.py |
修改 | 添加 _handle_model_command() 方法 |
nanobot/channels/telegram.py |
修改 | 添加 _on_model() 方法和 CommandHandler |
4.2 关键代码位置
4.2.1 feishu.py
位置:_on_message() 方法开头
关键逻辑:
1 | # 检查是否为 /model 命令 |
新增方法:_handle_model_command()
- 解析命令:
/model <subcmd> [args] - 有效子命令:
list,switch,status,test,fallbacks,watcher,health - 执行脚本:
python3 skills/model-switcher/model_switcher.py <subcmd> [args] - 格式化输出:Markdown 代码块
4.2.2 telegram.py
位置:BOT_COMMANDS 列表和 setup() 方法
关键逻辑:
1 | # 注册命令 |
新增方法:_on_model()
- 与 feishu.py 的
_handle_model_command()逻辑相同 - 使用
update.message.reply_text()返回结果
4.3 验证步骤
语法检查
1
2
3cd /home/admin/nanobot
python3 -m py_compile nanobot/channels/feishu.py
python3 -m py_compile nanobot/channels/telegram.py重启 nanobot
1
nanobot restart
测试命令
- 发送
/model— 应显示帮助信息 - 发送
/model list— 应显示可用模型列表 - 发送
/model status— 应显示当前模型状态 - 发送
/model switch <provider>— 应切换模型
- 发送
故障场景测试
- 配置一个无效的 API key
- 确认 AI 模型无法响应
- 发送
/model switch <其他provider> - 确认命令仍然可以执行
4.4 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
/model 无响应 |
命令未正确拦截 | 检查 _on_message() 中的 startswith 判断 |
| 提示 “Model switcher not found” | 脚本路径错误 | 确认 skills/model-switcher/model_switcher.py 存在 |
| 命令超时 | model_switcher.py 执行慢 | 检查网络连接或增加超时时间 |
| Telegram 不显示命令 | 未注册 BotCommand | 检查 BOT_COMMANDS 列表和 set_my_commands() |
5. 总结与扩展
5.1 设计模式总结
这次实现采用了 “通道层拦截” 模式:
- 适用场景:需要高可靠性的基础设施命令
- 核心思想:在消息进入 AI 处理流程之前拦截并处理
- 权衡:代码分散 vs 可靠性提升
5.2 可扩展的命令
基于同样的模式,可以添加其他基础设施命令:
| 命令 | 用途 | 实现难度 |
|---|---|---|
/restart |
重启 nanobot 服务 | 低 |
/status |
查看系统状态 | 低 |
/backup |
触发手动备份 | 中 |
/logs |
查看最近日志 | 中 |
5.3 注意事项
- 系统升级后需重新应用:这些修改在 nanobot 核心代码中,升级会被覆盖
- 备份修改:建议将修改保存为 patch 文件,便于快速恢复
- 测试环境先行:在生产环境应用前,先在测试环境验证
附录:快速恢复脚本
如果系统升级后需要快速恢复此功能,可以使用以下 patch:
1 | # 1. 备份当前文件 |
文章版本:v1.0
最后更新:2026-03-16
适用 nanobot 版本:v0.x