AstrBot 使用踩坑记录

AstrBot 使用踩坑记录

2026年8月12日·#技术分享AstrBot/Docker/NapCat/故障排除·1337 字 7 分钟
浏览量加载中...
AI 摘要

使用 AstrBot + NapCat 部署个人微信/QQ 机器人过程中遇到的各种问题及解决方案,持续更新。

踩坑不可怕,可怕的是同一个坑踩两遍。记录下来,下次秒查。


前言#

之前写了 AstrBot + NapCat 部署教程,部署完成后进入插件开发阶段。过程中遇到了一些问题,有些折腾了很久,因此把它们都记下来,方便以后快速定位。


问题一:发送视频失败——文件存在但容器找不到#

现象#

给机器人发视频链接,视频下载到服务器上了(目录里看得到文件),但机器人发不出来:

ENOENT: no such file or directory, open
'/AstrBot/data/plugin_data/astrbot_plugin_parser/cache/26bb248950ba2bda.mp4'

图片发送正常,只有视频出错。

原因#

AstrBot 和 NapCat 是两个独立的 Docker 容器,运行在同一个 astrbot-napcat 网络中。

  • AstrBot 容器有挂载 /root/astrbot_data → /AstrBot/data
  • NapCat 容器没有挂载这个路径

NapCat 发送视频时,需要在自己的容器里读取 file:///AstrBot/data/... 这个文件,但 NapCat 容器根本看不到这个路径——文件只存在于 AstrBot 容器里,NapCat 容器的文件系统是隔离的。

图片能发是因为图片走了另一条代码路径(不是 file:/// 绝对路径),不依赖容器内路径。

解决方案#

给 NapCat 容器加一条挂载,指向 AstrBot 的数据目录:

宿主机 /root/astrbot_data → NapCat 容器 /AstrBot/data

操作步骤#

1. 确认 AstrBot 数据在宿主机的实际路径:

Terminal window
docker inspect astrbot --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{end}}'
# 输出示例:/root/astrbot_data -> /AstrBot/data

2. 保存 NapCat 当前状态,然后重建加挂载:

Terminal window
# 先查 NapCat 的端口和挂载(重建时需要还原)
docker inspect napcat --format '{{json .HostConfig.PortBindings}}'
docker inspect napcat --format '{{json .Mounts}}'
# 保存当前状态(包括已安装的依赖)
docker commit napcat napcat_backup
# 停止并删除旧容器
docker stop napcat && docker rm napcat
# 重建容器,新增 AstrBot 数据挂载
docker run -d \
--name napcat \
--restart unless-stopped \
--network astrbot-napcat \
-p 3000:3000 -p 3001:3001 -p 6099:6099 \
-v <原配置目录1>:/app/napcat/config \
-v <原配置目录2>:/app/.config/QQ \
-v /root/astrbot_data:/AstrBot/data \
napcat_backup

⚠️ 不能直接用宝塔面板「编辑容器 → 添加挂载」——面板重建容器时不会继承原容器的 entrypoint/cmd,会报 no command specified 错误。必须用 docker commit + docker run 方式。

3. 验证:

Terminal window
# 确认 NapCat 能看到 AstrBot 的文件
docker exec napcat ls /AstrBot/data/plugin_data/astrbot_plugin_parser/cache/

看到文件列表就说明路径通了,再发一次视频测试。

根本原理#

Docker 容器的文件系统是隔离的。容器 A 里下载的文件,容器 B 默认看不到。只有把同一块宿主机目录挂载到两个容器,才能共享文件。视频发送走的是 file:/// 路径读取,NapCat 必须能在自己的容器里找到这个文件。


(后续问题持续更新中……)#


附:问题速查索引#

问题关键词解决思路
视频发送失败:文件不存在ENOENTfile:///AstrBot/data、容器挂载NapCat 容器加 AstrBot 数据挂载

新增踩坑:日程“2分钟后”提醒时间错乱 + 微信不推送(2026-08-22)#

现象/日程 3分钟后在会议室A开周会 高优 提前1分钟 在 02:14 发,机器人回 周会 时间2026-08-22 02:25:00 看似对,但日志显示 18:14 调度 02:25/提醒 列表 显示 提前10分,到点 02:39 日志 到点提醒 有但微信没收到,且 MessageChain 报错 Timeout context manager should be used inside a task / 'list' object has no attribute 'chain'

根因 1 - 时区datetime.now() 在你本机(Windows CST)是 02:xx,在 AstrBot 容器(OpenCloudOS 默认 UTC)是 18:xx,差 8 小时。SCHEDULE_PROMPT 没写时区,LLM 按 UTC 猜成 18:17allDay 误判不进提醒。

根因 2 - 标题残留:LLM 回 2分钟后周会_normalize 未去掉 2分钟后 前缀。

根因 3 - 调度BackgroundScheduler() 默认 UTC,remind_at 用 naive 的 02:24 被当 UTC 调度,到点不触发;且 origin 硬编码 weixin_oc 而实际是 weixin_personal_bglh:FriendMessage:...send_message 拿不到平台。

根因 4 - 推送MessageChain().message() 在 APScheduler 线程里会触发 asyncio.timeout 必须在 task 内用的校验;且 hasattr(MessageChain, 'chain')list 别名误判,导致 Plain/str 直接丢给 send_messageno attribute chain

修复(v1.0.20 → v1.0.28)

  1. 统一上海时区blog_writer_core.py:12 + main.py:27 新增 SHANGHAI_TZ = timezone(timedelta(hours=8)) + now_shanghai(),全量 datetime.now()now_shanghai()(13+10 处),SCHEDULE_PROMPT时区为 Asia/Shanghai + 时间基准:{now} 动态填入,2分钟后=基准+2分钟 明确规则。

  2. 标题与相对时间兜底_parse_schedule_time 新增 (\d+分钟后|半小时后) 相对分支(基准用传入的 now),parse_schedule 清洗标题去掉 2分钟后/半小时后main.py:564 _normalize_schedule_data 对 LLM 仍错的 00:00:0017:57 用本地正则重算覆盖(>120秒偏差即覆盖)。

  3. 调度持久化BackgroundScheduler(timezone=SHANGHAI_TZ)REMINDER_FILE = data/schedules_reminder.jsonremind_before + origin_restore_reminders 按上海解释,_schedule_remindoriginevent.unified_msg_origin)并 DateTrigger(run_date=remind_at_tz)_handle_remind 按条显示实际 1分 而非默认 10分

  4. 推送兼容_send_reminddef _make_chain 优先 MessageChain(chain=[Plain]) / MessageChain([Plain]),不调 .message()(避 timeout),_send_remind_syncself._loop = get_running_loop()run_coroutine_threadsafe(..., self._loop)send_message 先试 origin 纯文本/Plain/[Plain],再按 origin 解析平台名 weixin_personal_bglh 兜底。

验证02:223分钟后…提前1分钟 → 回 02:25:00/提醒 列表 显示 02:24:00 (提前1分)02:24:00.002 日志 到点提醒主动推送 via origin 成功,微信收到 🔔 日程提醒:周会 时间到了103 单测 OK,打包 v1.0.28 main.py:291 日志可定位)。

教训:系统时区、LLM 时区、调度器时区三处必须同一 Asia/Shanghai;相对时间必须本地正则兜底;MessageChain 构造与 send_message(origin, chain) 必须按官方文档 from astrbot.core.message.message_event_result import MessageChain + MessageChain().message() / chain=[Plain] 双试,且调度线程不能直接 asyncio.timeout

最后更新于 2026-08-12,距今已过 32 天

部分内容可能已过时

评论区

[ 标签 ]
# AI5# AI 编程2# AI工具1# Ajax2# Apifox1# AstrBot2# Astro2# CC Switch1# CDN2# Claude Code1# claudecode2# ClaudeCode1# Cloudflare2# CloudFlare2# CloudFlare-ImgBed1# coc3# CSS6# DeepSeek3# deepseek2# DELETE1# Docker1# EdgeOne3# Gist1# git1# GitHub1# hexo-circle-of-friends1# HTML6# HTTP2# Java23# java13# JavaScript5# JDBC3# JSON1# JUnit1# Logback1# Maven6# Muse Spark1# Mybatis1# MyBatis4# MySQL11# MySql1# NapCat1# obsidian1# Obsidian4# OpenCode4# ORM1# PathVariable1# PicGo1# py4# RequestBody1# RequestMapping1# RESTful风格1# skills1# Slf4j1# SpringBoot11# SQL2# Svelte2# TailwindCSS1# Telegram2# Tlias2# Vercel1# Vue7# Waline3# WebDAV1# Web基础6# WinSCP1# YAML1# 三层架构1# 中二宣言1# 书籍1# 使用文档10# 写作1# 刷步数1# 前端32# 动态1# 动漫1# 单词2# 博客6# 博客工作流1# 博客开发2# 参数接收1# 友链1# 反思2# 图床4# 地图1# 备份1# 奇思妙想1# 存储1# 学习方法3# 学校1# 宝塔面板3# 宝宝9# 导航栏1# 工具2# 开发1# 开发工具1# 开发规范1# 开心1# 影视2# 微信1# 性能优化2# 总结1# 想法15# 感受1# 感悟11# 指南1# 插件4# 故障排除1# 效率工具2# 教程7# 数据库10# 斩神1# 日常87# 日志框架1# 朋友圈1# 朱元璋1# 模板1# 测试1# 游戏2# 生活迁移1# 电影2# 碎碎念1# 视觉识别1# 网络教室1# 羊毛2# 脚本1# 脚本工具1# 自动化2# 蓝奏云1# 订阅推荐2# 记录2# 评论系统1# 词根1# 词缀1# 说说1# 足迹1# 跑步2# 路径参数1# 转载1# 运动1# 部落冲突1# 配置1# 随机图1# 音乐3# 音标1# 饮食1# 驼峰命名1# 高德地图1
[ 公告 ]

如果你喜欢,那么欢迎来到我的世界!

了解更多
[ 音乐 ]
封面

音乐

暂未播放

0:000:00
暂无歌词
找不到相关结果。
[ contents ]
[ 全部文章 ]