AstrBot 使用踩坑记录

AstrBot 使用踩坑记录

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

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

封面图
AstrBot 使用踩坑记录 - 封面图

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


前言#

之前写了 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 必须能在自己的容器里找到这个文件。


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


附:问题速查索引#

问题关键词解决思路
视频发送失败:文件不存在ENOENT、file:///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:17,allDay 误判不进提醒。

根因 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_message 报 no 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:00 或 17:57 用本地正则重算覆盖(>120秒偏差即覆盖)。

  3. 调度持久化:BackgroundScheduler(timezone=SHANGHAI_TZ),REMINDER_FILE = data/schedules_reminder.json 存 remind_before + origin,_restore_reminders 按上海解释,_schedule_remind 存 origin(event.unified_msg_origin)并 DateTrigger(run_date=remind_at_tz),_handle_remind 按条显示实际 1分 而非默认 10分。

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

验证:02:22 发 3分钟后…提前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。

评论区

[ 标签 ]
# AI37# AI 编程2# AI工具1# AI绘图1# AI辅助开发2# Ajax7# Apifox1# AstrBot3# Astro2# CC Switch1# CDN2# Claude Code1# claudecode2# ClaudeCode1# Cloudflare2# CloudFlare2# CloudFlare-ImgBed3# coc4# CSS10# DeepSeek6# deepseek2# DELETE1# Docker5# EdgeOne3# Gist1# git1# GitHub1# hexo-circle-of-friends1# HTML9# HTTP10# ImageManager1# Java23# java13# JavaScript11# JavaWeb113# JDBC7# JSON2# JUnit1# LangChain25# Linux4# Logback1# Maven17# Muse Spark1# Mybatis1# MyBatis18# MySQL45# MySql1# NapCat1# Node.js1# obsidian2# Obsidian5# OpenCode4# ORM1# PathVariable1# PicGo1# PyCharm1# Python70# RequestBody1# RequestMapping1# RESTful风格1# skills1# Slf4j1# SpringBoot37# SpringMVC5# SQL2# Streamlit5# Svelte2# TailwindCSS1# Telegram3# Tlias2# Vercel1# vscode2# Vue20# Waline3# Web3# WebDAV1# Web基础6# Web开发6# WinSCP1# YAML1# 三层架构1# 中二宣言1# 书籍1# 使用文档10# 写作1# 函数2# 刷步数1# 前端52# 动态1# 动漫1# 包1# 单词2# 博客8# 博客工作流1# 博客开发2# 参数接收1# 友链1# 反思2# 后端48# 图床6# 地图1# 备份2# 大模型1# 奇思妙想1# 存储1# 学习方法6# 学校1# 宝塔面板3# 宝宝10# 实战4# 对象1# 导航栏1# 工具2# 布局2# 开发1# 开发工具1# 开发规范1# 开心1# 异常处理1# 影视2# 微信1# 性能优化2# 总结1# 想法15# 感受1# 感悟11# 指南1# 提示词工程2# 插件5# 故障排除1# 效率工具2# 教程10# 数据分析9# 数据库27# 数据结构1# 文件操作2# 斩神1# 日常95# 日志框架1# 朋友圈1# 朱元璋1# 模块1# 模板1# 正则表达式2# 测试3# 游戏2# 爬虫7# 生活迁移1# 电影2# 电脑1# 碎碎念1# 视觉识别1# 类1# 类型注解1# 网络基础2# 网络教室1# 羊毛2# 脚本2# 脚本工具1# 自动化2# 蓝奏云1# 表单1# 订阅推荐2# 记录2# 评论系统1# 词根1# 词缀1# 说说1# 足迹1# 跑步2# 路径参数1# 转载2# 运动1# 部署11# 部落冲突1# 配置1# 随机图1# 面向对象5# 音乐3# 音标1# 项目实战11# 饮食1# 驼峰命名1# 高德地图1
[ 公告 ]

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

了解更多
[ 音乐 ]
封面

音乐

暂未播放

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