Appearance
基于AstrBot、n8n 与 MAA 的可通过消息控制的自动化明日方舟实践
明日方舟的日常操作比较固定:公开招募、基建换班、信用购物、领取奖励。MAA 已经能处理这些工作,但平时还需要打开电脑、启动游戏、选择任务,再看一遍结果。我想把这段操作变成一个手机入口:在 QQ 或微信里说“帮我完成明日方舟今天的每日任务”,由常开机的 Mac 接下任务,执行完把结果发回来。
这套方案把现成工具串起来:AstrBot 接收消息和调用模型,n8n 管理工作流与定时任务,maa-cli 执行游戏操作。需要补的代码集中在两处:把用户的话变成可校验的任务参数,以及让执行过程具备并发控制、日志和失败收尾。
本文记录截至 2026 年 10 月 11 日的实现。QQ 到 n8n、SSH、uv、MAA 启动与关闭游戏的链路已有实测;完整 daily、实际用药刷关和微信自然语言入站仍待逐项验收。流程图表示实现设计,不代表所有业务分支都已经完成真实游戏测试。
先把目标缩小到一台 Mac、一个账号
最初考虑的是能管理多设备、多服务的调度台。实际搭建时,先收缩到单账号、单机执行、手机发起、消息回传。多设备访问、TaskHub 面板、DSH 或 Codex 执行代码任务,留到这条链路稳定以后再接。
| 入口 | 示例 | 行为 |
|---|---|---|
| 每日任务 | 帮我完成明日方舟今天的每日任务 | 唤醒、公招、基建、信用购物、领奖、关闭游戏 |
| 指定组合 | 帮我在明日方舟公招并领取奖励 | 执行指定任务,最后关闭游戏 |
| 单独刷关 | 帮我在明日方舟吃两瓶理智药刷 1-7 | 指定关卡与最多两瓶药;不用源石 |
| 定时执行 | 每天北京时间 01:00、11:00 | 执行 daily,结果发送至指定 QQ 会话 |
这里的 daily 不包含刷理智。刷关是独立任务,避免一句“做每日任务”就顺带消耗理智药。daily、单独 fight 和任务组合结束时都会自动补上关闭游戏。
每个工具负责什么
| 组件 | 职责 | 部署位置 |
|---|---|---|
| QQ 官方机器人、微信机器人 | 手机消息入口、结果回传 | AstrBot 平台接入 |
| AstrBot | 会话管理、模型接入、插件调用 | Docker 容器 |
| 指令路由插件 | 自然语言识别、歧义追问、参数校验 | AstrBot 插件 |
| n8n 桥接插件 | 平台与发送者白名单、任务提交 | AstrBot 插件 |
| n8n | Webhook、定时触发、SSH、结果通知 | 独立 Docker 容器 |
| Python 执行器 | 固定任务计划、去重、执行锁、日志、收尾 | Mac 宿主机,使用 uv |
| maa-cli 与 PlayCover | 游戏连接、MAA 任务执行 | Mac 宿主机 |
NapCat 也在同一套 Compose 中运行,但服务于另一个机器人用途。这条自动化入口只开放 QQ 官方机器人和微信机器人,NapCat 不是 QQ 官方接入的必经组件。
AstrBot、n8n、NapCat 分容器部署,由 Compose 统一管理。PlayCover 和 MAA 留在宿主机,因为游戏依赖真实 macOS 图形会话。n8n 通过 SSH 调用 Mac 上的固定执行器。第一版只由 n8n 负责定时,不再引入第二套 APScheduler 调度,避免同一任务维护两份时间规则。
从手机消息到游戏执行
先跑通固定指令,再接自然语言,可以把故障分成“入口识别”和“游戏执行”两类。
text
手机 QQ / 微信消息
-> AstrBot 校验平台与发送者
-> 自然语言路由(固定指令跳过)
-> n8n 桥接插件提交结构化请求
-> n8n Webhook 返回受理结果
-> SSH 调用 Mac 上的 uv 执行器
-> maa-cli 连接 PlayCover,执行任务并关闭游戏
-> n8n 通过 AstrBot 将摘要发回原会话“任务已受理”只说明系统接到了请求,不能当作“任务已完成”。游戏资源更新、登录和执行可能持续数分钟,Webhook 不应该占着机器人消息处理过程一直等待。
下面是脱敏后的桥接协议示例,不是可直接导入的完整工作流:
json
{
"message": "maa run fight stage=1-7 medicine=2",
"action": "run",
"tasks": ["fight"],
"stage": "1-7",
"medicine": 2,
"platformId": "YOUR_PLATFORM_ID",
"senderId": "YOUR_SENDER_UID",
"umo": "YOUR_ORIGINAL_SESSION",
"requestId": "UNIQUE_REQUEST_ID"
}umo 让结果回到原会话;requestId 用于日志关联和同一请求去重,聊天中不显示编号。定时流程没有新用户消息,需要单独配置固定 QQ 通知会话。Webhook 使用 Basic Auth,n8n 继续检查身份与参数,不能只因为请求来自插件就跳过校验。
自然语言提取参数,固定代码决定能不能执行
我使用现成的 astrbot_plugin_command_router,只允许路由到 astrbot_plugin_n8n:maa,不让模型从所有插件里随意挑选动作。
模型分两步选择插件和指令,随后进行固定校验:候选指令在允许列表内、置信度至少 0.85、参数能够绑定到目标函数且类型正确。药量和关卡还要与原始消息核对,模型不能自行加药或猜关卡。
| 用户消息 | 处理结果 |
|---|---|
| 帮我完成明日方舟今天的每日任务 | daily,不含 fight |
| 帮我打开明日方舟刷取关卡 | 上次关卡,不用药 |
| 帮我吃两瓶理智药刷明日方舟 1-7 | fight,指定关卡、最多两瓶药 |
| 帮我在明日方舟吃几瓶药刷关卡 | 追问数量,不立即执行 |
| 如何让明日方舟自动刷关? | 属于询问,不提交任务 |
“几瓶”不是合法药量。待补全请求保留五分钟,可以回复“两瓶”或“取消”,并按会话与发送者隔离。这套规则是自己的任务适配,复杂否定、引用和多轮表达仍需要增加测试,不能把一次模型识别正确当成通用识别能力。
固定指令仍然保留,识别不确定时可以使用:
text
/n8n maa daily
/n8n maa run recruit base credit award
/n8n maa run fight
/n8n maa run fight stage=1-7 medicine=2n8n 如何连接宿主机
n8n 在 Docker 中运行,它的 localhost 指向容器自身,不是 Mac。Docker Desktop 环境中,SSH 节点通过 host.docker.internal 连接 Mac,端口填写宿主机 SSH 端口,凭据保存在 n8n Credentials 中。
AstrBot 调用同一 Compose 网络中的 n8n 则使用 http://n8n:5678/...。容器服务名、宿主机地址和浏览器里的 localhost 是三个不同的连接场景。
先确认 maa-cli 能独立连接 PlayCover。配置目录通过 maa dir config 获取:
toml
# profiles/playcover-n8n.toml
[connection]
preset = "PlayCover"
address = "localhost:1717"端口使用游戏窗口标题显示的 MaaTools 地址,1717 是本机示例。PlayCover 需要使用支持 MaaTools 的版本,并启用游戏对应设置。
最小测试只做 StartUp:
toml
# tasks/qq-test.toml
[[tasks]]
name = "开始唤醒测试"
type = "StartUp"
[tasks.params]
client_type = "Official"
start_game_enabled = falsesh
maa run qq-test --profile playcover-n8n --batch --dry-run
maa run qq-test --profile playcover-n8n --batch这个测试要求游戏已经启动。dry-run 只生成计划,不操作游戏,因此 Unstarted 不是连接失败证据。实际运行成功后,再把相同调用方式接入 n8n SSH 节点。
Python 执行器使用 uv 管理:
sh
uv sync --project integrations/maa --frozen
uv run --frozen --project integrations/maa python -m unittest discover \
-s integrations/maa -p 'test_*.py' -v这两条命令用于已有执行器工程的环境与测试,不会自动部署本文全部功能。SSH 调用固定执行器时使用 uv、maa 的绝对路径和明确项目目录,避免后台会话缺少交互式 PATH。聊天原文不拼接成 shell 命令,而是先转换成允许的任务参数。
daily 配置与 MAA GUI 独立
GUI 中勾选任务,不意味着 maa-cli 会读取同一组设置。当前参数集中在执行器的 task_catalog.json,每次生成独立任务文件并保存配置快照。
| 任务 | 当前配置 |
|---|---|
| 唤醒 | 先验证启动和登录,失败就不继续 |
| 公招 | 最多 4 次、刷新标签、不使用加急许可 |
| 基建 | 队列轮换 mode=20000,沿用已有队列,不修改原排班;无人机用于贸易站龙门币 |
| 信用购物 | 优先招聘许可、赤金;黑名单加急许可、家具零件;溢出也不忽略黑名单 |
| 奖励 | 领取日常与周常奖励 |
| 关闭游戏 | 所有组合最后自动补入;异常后也尝试收尾 |
reserve_max_credit 有一个细节:第二轮普通购物在信用低于 300 时停止,但第一轮优先商品购买不受此阈值限制。所以“信用不溢出后停止”并不是每笔购买都严格守住 300 的统一余额下限。
刷理智也有两种数量:当前 times 使用很大的上限,series=0 表示 AUTO 代理倍率。AUTO 选择的是单次代理连战倍率,不是每日总次数。默认不用药、不用源石;指定两瓶表示最多允许使用两瓶,不保证最终一定消耗两瓶。
定时与手动请求复用执行入口
定时流程生成 daily 请求,后面的任务执行与手动流程共用。调整基建或购物参数时,只维护一份业务逻辑。
容器和工作流时区都设为 Asia/Shanghai。Schedule Trigger 配置两个规则:
text
0 0 1 * * * # 每天 01:00
0 0 11 * * * # 每天 11:00这是 n8n 的六字段 cron 示例,第一项是秒。配置后还要发布工作流;关机期间错过的时间不补跑,执行锁忙时跳过。
执行器使用同一把进程锁,防止手机 fight 与定时 daily 同时控制游戏。MAA GUI 不共享此锁,自动化运行时不能再启动 GUI 任务。同一请求编号不重复操作,但两次新消息会生成不同编号,这不是对语义相同任务的全局去重。
踩坑与失败处理
| 问题 | 现象 | 处理方式 |
|---|---|---|
| 容器使用 localhost 连接 Mac | SSH 或 Webhook 失败 | 区分服务名与宿主机地址 |
| 设置 1080p 但窗口内容较小 | MAA 报分辨率不匹配 | 看实际内容与截图尺寸,不能只看设置框 |
| 游戏最小化或窗口被隐藏 | 截图异常、识别失败 | 保持登录、唤醒及游戏窗口可见 |
| 将受理当完成 | 用户误判任务状态 | 执行结束后另发逐项摘要 |
| 超时后马上重发 | 可能重复操作 | 先查执行记录,不自动重试原任务 |
| GUI、CLI 同时控制 | 输入和识别相互干扰 | 自动化期间不运行 GUI 任务 |
| 管理员 ID 子串匹配 | 会话或片段可能错误放行 | 完整 UID 精确匹配,同时限制平台 |
| 更新原作者插件 | 本地适配被覆盖 | 使用 fork,并核对持久化安装来源 |
Mac 常开机不等于游戏可以无条件后台运行。PlayCover 仍依赖真实图形会话,窗口显示和截图限制需要满足。第一版没有将控制端口直接开放到公网,也没有完成服务器 Web 登录访问。
大版本更新时先停止任务
资源热更新可以在启动阶段等待,整包更新需要新的游戏客户端。PlayCover 使用的脱壳 IPA 依赖来源提供新包,不能保证和官方同时发布。
目前执行器在任务前检查官方版本,发现官方版本高于本机就预防性停止。更新分支的设计包括查找匹配包、检查版本和 bundle ID、验证脱壳状态、备份后调用 PlayCover 导入,再用 StartUp 验证;失败时恢复备份并停止。
这一分支已有实现和测试,但没有用真实新版 IPA 完成覆盖安装验收,公开查包来源也未稳定打通。可以将取得的新版 IPA 放入专用 inbox,下一次任务触发时检查。现阶段不能称为“整包更新后已经能无人值守恢复”。
插件维护与验收边界
两份维护版保留原作者历史和 AGPL-3.0 许可证:
- n8n MAA 桥接维护版:固定任务入口、权限、超时、参数校验。
- 自然语言路由维护版:个人任务范围、追问补全、原消息校验。
n8n 的通用权限匹配、超时和错误处理单独提交了 上游 PR #2,不包含 MAA 专用适配。路由插件主要服务自己的项目,没有提交上游。
AstrBot 4.28.2 不仅读取 metadata.yaml 中的 repo,也保存安装来源。切换 fork 时应将安装方式设为 repository 并指向自己的仓库;仍指向市场的记录可能让更新使用原市场版本。
| 验证内容 | 截至本文日期的状态 |
|---|---|
| maa-cli 连接 PlayCover | StartUp 已实际成功 |
| n8n → SSH → uv → 启动与关闭 | 已真实执行,最近一次约 53.3 秒 |
| QQ 官方机器人结果通知 | 接口成功,通知确认通过 |
| 模型参数与路由校验 | 模型参数验证、隔离路由测试通过 |
| 完整 daily、真实用药刷关 | 待真实游戏验收 |
| 微信自然语言完整入站 | 待端到端验收 |
| 新版 IPA 覆盖与回滚 | 有代码与测试,待真实新版包验收 |
接下来可以将同一任务协议接入 TaskHub,让管理面板和原生客户端共用后台。新增任务先进入固定任务目录、完成参数验证,再开放自然语言入口,这样手机的表达方式可以灵活,真正执行的动作仍有明确边界。
相关项目
文中配图为架构与流程示意,不包含个人会话、凭据或模型密钥;协议和命令示例需要结合自己的平台配置与执行器使用。