把「大肥鱼」接进 QQ:一次从零到稳定的部署复盘

环境:阿里云 ECS · Ubuntu 26.04 LTS · 2 vCPU / 1.7 GiB / 40 GB
时间:2026-11-01 ~ 11-02
说明:文中所有 IP、QQ 号、AppID、API Key、密码均已替换为占位符,请按自己的实际情况填写。

0. TL;DR

一句话:「让一个模型在 QQ 群里像人一样说话」,拆开是三件事——接一张嘴(消息通道)、写一份人设(提示词)、让它有记忆和情绪(插件)。

两条路线都跑通了:

路线组成特点我的选择
路线一官方 QQ Bot + DeepSeek Harness(dsh)官方通道、扫码即用、零封号风险、主动发言受限先跑通,后停用
路线三NapCat + AstrBot + DeepSeek个人号协议、人格化程度高、插件生态丰富、有封号风险最终在用

如果只想「让鱼在群里正常说话」,路线一省心到离谱,二十分钟能搞定。
如果想要「会发表情包、会改签名、会记仇、会自己插话」,只有路线三。

本文涉及的全部开源仓库(人设包、表情包素材、协议端、插件)整理在第 15 节,其中包含两个「已失效仓库」的记录,省得你顺着旧链接白找。

1. 开始之前:先想清楚要什么

动手前先把需求拆成四层,否则很容易在「装插件」里迷路:

  1. 通道:消息从哪来、回到哪去
  2. 人格:它说话的味道
  3. 能力:记忆、表情包、改资料、主动发言
  4. 稳定性:掉线怎么办、封号怎么办、内存够不够

这四层的优先级是倒过来的:稳定性 > 人格 > 能力 > 通道。
因为通道挂了你会立刻知道,而「人格不像」「记忆错乱」往往要跑一天才发现,返工成本高得多。


2. 环境盘点与第一道坎

2.1 机器

Ubuntu 26.04.1 LTS
2 vCPU / 1735 MiB / 40 GB
Node.js v22.23.4(apt 自带版本太老,必须另行安装)

2.2 第一道坎:网络

这台机器在国内,遇到的问题按顺序是:

目标状态解法
deb.nodesource.com✅ 通直接装
registry.npmjs.org / github.com✅ 通直接 clone
registry-1.docker.io❌ 超时配置镜像加速
我这台本机的 web_fetch❌ 全部“解析到非公网 IP”改用 Node 的 https 模块直连

顺手记一个排查技巧:curl: (35) schannel: AcquireCredentialsHandle failed 不是网络问题,是 TLS 凭据拿不到;而 node -e 'require("https").get(...)' 往往能通——因为 Node 走自己的 OpenSSL,不依赖系统证书存储。

2.3 Docker 镜像加速

// /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run",
    "https://dockerproxy.net"
  ],
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}

实测 docker.m.daocloud.io 返回 401 是正常的(说明 Registry API 在响应),不代表不可用。


3. 路线一:官方 QQ Bot + dsh(20 分钟)

3.1 装

curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
npm i -g pnpm @deepseek-ai/dsh      # pnpm 必须单独装,dsh 的插件管理依赖它

dsh --version                        # 0.2.1-rc.5

3.2 三步接入

dsh plugin --profile qqbot add @tencent-connect/dsh-qqbot
dsh --profile qqbot

首次启动会打印二维码,同时打印一条可点击的绑定链接:

https://q.qq.com/qqbot/openclaw/connect.html?task_id=<uuid>&source=dsh-qqbot&_wv=2

服务器上没有图形界面也没关系——把这条链接发到手机浏览器打开即可扫码。绑定成功后凭据自动写入:

~/.dsh/profiles/qqbot/cordis.patch.yml

之后重启不再需要扫码(这一点我实测过三次)。

3.3 一个关键认知

dsh 在 systemd 下不能扫码(无 TTY)。正确的顺序永远是:

前台手动跑一次 → 扫码绑定 → 凭据落盘 → 再交给 systemd 托管

反过来做(先写 unit 再启动)会一直卡在二维码界面。

3.4 为什么最后停用了它

官方通道的限制很硬:被动回复。用户不说话,它不能说话。
对「群里的活人感」这个目标来说,这条限制是致命的——它永远只能当客服,不能当群友。

systemctl disable --now dsh-qqbot 之后配置全部保留,随时可以切回来。


4. 路线三:NapCat + AstrBot

4.1 架构

QQ 用户 ──▶ QQ 服务端 ──▶ NapCat(协议端)
                              │  反向 WebSocket
                              ▼
                          AstrBot(大脑)
                              │
                    ┌─────────┴─────────┐
                 DeepSeek          硅基流动
                (聊天/总结)        (记忆向量)

方向别搞反:AstrBot 的 aiocqhttp 适配器是反向 WS 服务端(监听 6199),NapCat 作为客户端连上去。
所以配置写在 NapCat 侧:

"websocketClients": [{
  "name": "astrbot",
  "url": "ws://astrbot:6199/ws",
  "token": "<你的token>",
  "reconnectInterval": 3000
}]

4.2 docker-compose

services:
  napcat:
    image: mlikiowa/napcat-docker:latest
    container_name: napcat
    restart: unless-stopped
    environment:
      - NAPCAT_UID=1000
      - NAPCAT_GID=1000
      - ACCOUNT=<小号QQ>
      - NAPCAT_QUICK_PASSWORD=<小号密码>
      - TZ=Asia/Shanghai
    mem_limit: 800m
    volumes:
      - ./napcat/config:/app/napcat/config
      - ./napcat/qq:/app/.config/QQ
      - ./napcat/cache:/app/napcat/cache
    networks: [botnet]

  astrbot:
    image: soulter/astrbot:latest
    container_name: astrbot
    restart: unless-stopped
    depends_on: [napcat]
    environment:
      - TZ=Asia/Shanghai
    mem_limit: 700m
    ports:
      - "127.0.0.1:6185:6185"        # 面板只绑本机,走 SSH 隧道
    volumes:
      - ./astrbot/data:/AstrBot/data
    networks: [botnet]

networks:
  botnet:
    driver: bridge

三个细节值得单独说:

  1. ACCOUNT:不设它,NapCat 只会走扫码;设了才会尝试快速登录
  2. NAPCAT_QUICK_PASSWORD:token 失效时的兜底,能省掉无数次半夜扫码
  3. mem_limit:1.7 GiB 的机器不给容器设上限,一个内存泄漏就能把整机拖死

4.3 AstrBot 后台密码

首次启动会生成随机强密码,默认的 astrbot 已经失效。密码只在启动日志里打印一次:

docker logs astrbot 2>&1 | grep "Initial password"

忘了也没关系,重启一次就会重新打印。

4.4 模型配置

AstrBot v4 的 provider 结构是「连接」与「模型」分离的:

{
  "provider_sources": [{
    "id": "deepseek-flash_source",
    "type": "openai_chat_completion",
    "key": ["sk-****"],
    "api_base": "https://api.deepseek.com/v1"
  }],
  "provider": [{
    "id": "deepseek-flash",
    "model": "deepseek-flash",
    "provider_source_id": "deepseek-flash_source",
    "custom_extra_body": { "thinking": { "type": "disabled" } }
  }]
}

thinking: disabled 很重要——DeepSeek 的思考过程会拖慢首字延迟,而且对「短句聊天」毫无意义。


5. 人格:从 Markdown 到数据库

5.1 人设来源

用了社区配置包 zexuanw958-svg/dafeiyu-config-pack 的 persona/大肥鱼.md,里面有一个占位符 {OWNER_QQ},必须替换成真实 QQ 号——它不只是装饰,人设里靠它识别「谁才是主人」,防止有人在群里冒充。

顺便说一句这个包的设计:它的 settings/pack.json 是一份「清单式」配置,把 6 个配套插件、两套表情包、语音/记忆/主动聊天的推荐参数都写在一处,再用 tools/import_dafeiyu.py 读清单改 AstrBot。这个思路值得借鉴——配置即文档,改哪项就改哪行,然后重跑一次导入。

我没有整包导入,而是按需取用(详见第 11 节):语音链路需要额外的豆包/Breeze key,对 1.7 G 的机器也不友好;插件则挑了对「像人」帮助最大的几个。

5.2 写进数据库

AstrBot 的人格存在 SQLite 里,personas 表。第一次 INSERT 会连撞三个坑:

sqlite3.IntegrityError: NOT NULL constraint failed: personas.created_at
sqlite3.IntegrityError: NOT NULL constraint failed: personas.sort_order

正确写法:

db.execute("""INSERT INTO personas
  (created_at, updated_at, persona_id, system_prompt,
   begin_dialogs, tools, skills, custom_error_message, folder_id, sort_order)
  VALUES (CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '大肥鱼', ?, '[]', '[]', '[]', NULL, NULL, 0)""", (prompt,))

然后把 agent_runner.config.persona.persona_id 指向它。

5.3 配套的基础设置

{
  "platform_settings.segmented_reply.enable": true,
  "platform_settings.segmented_reply.regex": ".*?(?:\\r?\\n+|[。?!~…]+)|.+$",
  "platform_settings.empty_mention_waiting": false,
  "agent_runner.config.compression.max_turns": 30,
  "provider_settings.datetime_system_prompt": true
}

分段回复是「一条条发」的关键——不切分的话,模型会一次吐出 200 字,立刻暴露是机器人。


6. 表情包:把 100 张 GIF 变成插件资源包

6.1 素材

diwer/ai-biaoqingbao 提供 100 张 512×512 的中文 GIF,带 catalog.json(编号、含义、分类)。分类正好是 7 组:首批常用、日常回应、抽象反应、打工摸鱼、情绪状态、亲密陪伴、祝福庆祝。

6.2 插件资源包的目录协议

meme_manager 认这个结构:

packs/<pack_id>/
├── manifest.json
├── memes_data.json
└── memes/<分类名>/*.gif

manifest.json:

{
  "schema_version": 1,
  "id": "dafeiyu-biaoqingbao",
  "name": "大肥鱼表情包·100个中文GIF",
  "version": "1.0.0",
  "categories": { "抽象反应": { "description": "大肥鱼表情:抽象反应" } }
}

再把它登记进 registry.json 和 selection_rules.json(设成默认包)。

6.3 打包时踩的坑

用 PowerShell 的 Compress-Archive 打包,到 Linux 解压后所有目录变成了文件名的一部分:

memes\抽象反应\001-不服气.gif     ← 一个带反斜杠的完整文件名

因为 Windows 用 \ 作分隔符,而 zip 规范要求 /。解决方法是用 Python 的 zipfile 显式写 POSIX 路径:

rel = os.path.relpath(full, root).replace("\\", "/")
z.write(full, rel)

6.4 为什么值得用插件而不是自己写

我一开始自己写了个 80 行的插件,直接往回复链追加图片,能用。
但换成 meme_manager 之后才明白差别在哪:

它把分类目录注入到模型提示词里,模型才知道「我有哪些图可以挑」,然后用 &&抽象反应&& 这种标记下单。

自己写的插件只是「随机附一张图」,跟情绪无关;插件版是「有合适的才发」。这是「像人」和「像随机图片机器人」的区别。


7. 记忆:embedding 选型的成本账

7.1 三种方案

方案成本可行性
硅基流动 BAAI/bge-m3免费✅ 选它
百炼 text-embedding-v3约 0.0005 元/千 token ≈ 1–2 元/月✅ 也可
本机 ollama免费❌ 模型常驻 1.2 GB,1.7 G 机器跑不动

结论:embedding 从来不是钱的问题,是内存问题。

7.2 必踩的坑:维度

装完 livingmemory 启动直接失败:

ValueError: 无效的嵌入向量维度: 0。
请检查该知识库使用的 Embedding Provider 是否正确配置了 embedding_dimensions。

openai_embedding 适配器不会自动探测维度,必须在 provider 配置里显式写:

{ "embedding_model": "BAAI/bge-m3", "embedding_dimensions": 1024 }

7.3 记忆的机制

"reflection_engine": { "summary_trigger_rounds": 10 },
"recall_engine": { "top_k": 5, "recent_memory_count": 2 }

每 10 轮总结一次 → 存成带权重的记忆 → 回复时按语义召回 5 条 + 最近 2 条。
后台还有每日 00:05 的衰减/清理/备份调度。


8. 成本控制:两层概率

8.1 第一层:限流策略

AstrBot 默认 rate_limit.strategy = "stall",实现是:

await asyncio.sleep(stall_duration)   # 睡到下一个窗口

密集群聊时,超限的消息不是被丢弃,而是排队休眠——这是「延迟越堆越长」的元凶。

改成 "discard":超限直接丢,绝不排队。

8.2 第二层:回复概率

最初我自己写了个 reply_gate 插件(event.stop_event() 可真正阻止模型调用,实测有效),按 DeepSeek 计费时段分档:

  • 工作日 09:00–12:00、14:00–18:00 → 40%
  • 其余(含周末、节假日)→ 60%
  • @ / 引用 / 命令 → 100%

后来装了 group_chat_plus,把概率交给它,reply_gate 停用。

8.3 一个语义陷阱

group_chat_plus 的 initial_probability 不是「回复概率」,而是「进入 AI 读空气判断的概率」。
所以配 0.6 ≠ 回 60%,实际回复率明显更低——这是它比自建方案更「像人」的代价。

8.4 动态时段与平滑过渡

{
  "enable_dynamic_reply_probability": true,
  "reply_time_periods": "[{\"name\":\"高峰(上午)\",\"start\":\"09:00\",\"end\":\"12:00\",\"factor\":0.67}]",
  "reply_time_transition_minutes": 30,
  "reply_time_use_smooth_curve": true
}

实测日志(14:00 峰值边界):

13:53:27  原始=0.60  系数=0.69  结果=0.4121
13:54:37  原始=0.80  系数=0.68  结果=0.5444
13:58:35  原始=0.60  系数=0.67  结果=0.4022
14:00:00  原始=0.60  系数=0.67  结果=0.4020

系数从 0.69 平滑滑到 0.67——说明 30 分钟过渡是在峰值前的 30 分钟就开始爬坡的,不是整点突变。
好处是观感自然,代价是「中午的尾巴」被提前压掉了。想要硬边界就把过渡改成 10 分钟。


9. 稳定性:掉线、假在线与看门狗

这是整个项目最花时间的部分,也是最值得写的部分。

9.1 三次掉线,三种原因

时间现象原因
19:54KickedOffLine 登录已失效 + 弹二维码token 失效
22:38同上token 再次失效
11:09日志一片安静,什么错都没有会话静默失效(假在线)

第三种最坑:容器 Up、WS 连接 ESTABLISHED、AstrBot 显示「适配器已连接」,但 QQ 侧早就不推消息了。从外部完全看不出来,只有「群里人不理它」这个现象。

9.2 看门狗

# /usr/local/bin/napcat-watchdog.sh(核心逻辑)
RECENT=$(docker logs napcat --since 5m 2>&1)

if ! echo "$RECENT" | grep -qE "KickedOffLine|账号状态变更为离线|二维码已保存"; then
  exit 0
fi

# 10 分钟冷却,避免循环重启
[ $((now - last)) -lt 600 ] && exit 0

docker restart napcat

配 systemd timer 每 2 分钟跑一次。重启后入口脚本会带着 ACCOUNT + NAPCAT_QUICK_PASSWORD 自动登录,35 秒恢复。

9.3 看门狗的盲区

它只能检测有日志的掉线。第三种「静默失效」一个关键字都不触发,所以看门狗全程没动作。

要覆盖它,需要主动健康检查:给 NapCat 开一个本地 HTTP API,让看门狗主动问 get_status。
我试过从容器外连它的 WS(3001),三次都是 1006 异常断开——这条路没走通,留作后续。

9.4 一个非技术的根因

前两次掉线间隔 2 小时 44 分,规律得太可疑。最后发现是手机端同时登录着这个小号——个人号协议下,手机端上线/刷新会把协议端踢掉。

让用户在手机上退出这个小号之后:12 小时内 KickedOffLine 次数 0。

教训:掉线先问「这个号还在别处登陆吗」,比看一百行日志都快。

9.5 内存

1.7 GiB 总内存 / 加 2 GiB swap
napcat    ~240–290 MiB
astrbot   ~260–340 MiB(随插件增加)

swap 是必须的:不加的话,一次长上下文 + 多发消息就可能 OOM。


10. 踩坑总表

按「症状 → 原因 → 解法」整理,方便按图索骥。

#症状原因解法
1所有 URL 抓取失败,报“非公网 IP”本地网络策略把域名解析到内网用 Node https 直连绕过
2curl: (35) schannel: SEC_E_NO_CREDENTIALS取不到系统 TLS 凭据换 Node/OpenSSL 栈
3docker pull 一直超时Docker Hub 不可达配 registry-mirrors
4重启 NapCat 后要重新扫码只有扫码 token,没有密码兜底ACCOUNT + NAPCAT_QUICK_PASSWORD
5被踢后容器一直卡在二维码worker 内部重启不走入口脚本,-q 丢失看门狗 docker restart 容器
6日志无异常但群里不回会话静默失效(假在线)需要主动健康检查(未彻底解决)
7每 2 小时掉一次线手机端同时登录互踢手机端退出该账号
8zip 解压后目录变成文件名Windows \ vs zip 规范 /Python zipfile 写 POSIX 路径
9Unexpected UTF-8 BOMJSON 带 BOM(AstrBot 写的配置就是)读写都用 utf-8-sig
10NOT NULL constraint failed: personas.created_at表有非空列没给值INSERT 补齐 created_at/updated_at/sort_order
11无效的嵌入向量维度: 0适配器不自动探测维度显式配 embedding_dimensions: 1024
12启动时刷 faiss.swigfaiss_avx512 报错faiss 探测可选加速模块无害,忽略
13登录后台一直失败默认密码被替换成随机强密码`docker logsgrep "Initial password"`
14市场接口解析出 0 个插件返回的是 dict 不是 list按 dict 遍历
15git clone 报 could not read Username其实是 404(仓库没了)换源或用 codeload 直下 zip
16插件仓库 404市场条目过期(作者删库/改名)用替代品(如下)
17裸 @ 不回,且无任何日志empty_mention_waiting: false置 true,或在插件里自己处理
18偶发 IndexError: list index out of range空 wake_prefix 让 messages[0] 越界已知副作用,事件本身无内容,可忽略
19两套概率插件互相打架概率相乘(0.4 × 0.6 = 0.24)只保留一个概率决策方
201.7 G 内存跑浏览器自动化Chromium 常驻 300–600 MB换 4 G 以上机器再考虑

关于 #16 的替代品(2026-11 实测):

原仓库状态替代
Zhalslar/astrbot_plugin_qqprofile404Akusative/astrbot_plugin_qqprofile_ex
Zhalslar/astrbot_plugin_qzone404sujingyi1/astrbot_plugin_qzone

11. 最终形态

11.1 插件清单

插件作用自主行为
meme_manager表情包(100 张 / 7 分类)回复 35% 概率配图
group_chat_plus群聊读空气、打字模拟、错字非 @ 消息按概率接话
livingmemory长期记忆(bge-m3 向量)每 10 轮总结
dafeiyu_clean过滤模型漏出的内部标签无
dafeiyu_signature情绪触发改签名2 次/天
qqprofile_ex改签名/状态/昵称签名 240min、状态 60min 冷却;昵称已关
qzone发/看说说全手动(cron 全空)
reply_gate自建概率门(已停用)—

11.2 行为分层

纯定时(没人说话也会跑):记忆衰减/备份、索引重建 —— 都在后台,用户无感。

对话中自主(有人说话时自己加戏):接话、配图、改签名、改状态、总结记忆。

完全被动(必须指令):私聊/群聊回复、发说说、看说说、改昵称。


12. 运维手册

# 服务
cd /opt/napcat-bot && docker compose ps
docker compose restart astrbot      # 改配置后
docker compose restart napcat       # 会走密码自动登录

# 日志
docker logs astrbot --since 10m 2>&1 | grep -Ei "error|ERRO"
docker logs napcat --since 10m 2>&1 | grep -E "接收|发送"

# 概率判定
docker logs astrbot --since 1h 2>&1 | grep "动态时间调整"

# 掉线排查
docker logs napcat --since 6h 2>&1 | grep -c KickedOffLine
journalctl -u napcat-watchdog --since -6h | tail

# 面板(都只绑本机)
ssh -L 6185:127.0.0.1:6185 root@<服务器IP>   # AstrBot WebUI

13. 没做的事,以及原因

项目状态原因
语音输出(TTS)不做明确不需要;四条语音链路都要额外 key 或显卡
唱歌插件不做语音衍生功能
定时发说说不做主动行为最容易被风控,手动触发足够
主动找人聊天不做同上;且会打扰人
抖音群聊不做无官方群机器人 API,只能浏览器自动化;1.7 G 跑 Chromium 会拖垮现有服务
微信个人号暂不做只能靠逆向/托管协议,封号风险比 QQ 高一档
后两个表情包(官方市场)未装用 ai-biaoqingbao 的 100 张替代

14. 方法论:这次学到的东西

  1. 先打通最小链路,再叠功能。
    通道 → 模型 → 人格 → 插件,每一步都验证过再往上加。跳过任何一环,后面出问题都定位不到。
  2. 把「以为」变成「日志」。
    「它好像不回我」和「reply_gate 判定 p=0.40 roll=0.65 → skip」是两件事。前者需要猜,后者只需要看。
  3. 区分「主动」和「被动」是设计的基础。
    同一个机器人,哪些行为会自己冒出来、哪些必须被叫,必须能一句话说清。说不清就说明设计还没定型。
  4. 国内服务器部署,网络问题占一半工作量。
    Docker Hub、GitHub、npm,三条链路的状态各不相同,先测再动手。
  5. 复杂度要能被一句话解释。
    最后稳定下来的形态其实很简单:一个协议端、一个大脑、两个模型、几个插件。中间所有的折腾,都是在排除「不必要」。
  6. 风控是产品约束,不是技术 bug。
    个人号协议天然有封号风险。接受它,然后通过「用小号、降频率、别主动」把风险压到可接受——而不是幻想把它降到零。

15. 项目与素材来源

这次用到的全部仓库,按用途归类。注意:社区插件变动极快,链接随时可能 404,请以实际可达为准。

15.1 人设与配置包

项目链接说明
大肥鱼配置包zexuanw958-svg/dafeiyu-config-pack人设 Markdown + 6 个配套插件清单 + 语音/记忆参数 + 一键导入脚本

这个包是整个项目里信息密度最高的一个,值得单独读一遍——它不只是给了一份人设,而是把「一个能跑的大肥鱼需要哪些部件」列成了清单。

15.2 表情包素材

项目链接说明
大肥鱼表情包diwer/ai-biaoqingbao100 张中文 GIF(240/512 两档),带 catalog.json 分类目录

仓库里还有 NOTICE.txt 写明了二创来源与使用边界(不提供商用授权),如果要商用请先看那份说明。

15.3 平台与协议端

项目链接说明
NapCatNapNeko/NapCatQQQQ NT 协议端,输出 OneBot v11
NapCat Dockermlikiowa/napcat-docker本文使用的部署形态
AstrBotAstrBotDevs/AstrBot机器人框架(大脑)
DeepSeek Harnessdeepseek-ai/deepseek-harness路线一的官方 Agent 运行时

15.4 插件

插件链接用途
meme_manageranka-afk/astrbot_plugin_meme_manager表情包管理 + 语境发送
group_chat_plusHim666233/astrbot_plugin_group_chat_plus群聊读空气、打字拟态
livingmemorylxfight/astrbot_plugin_livingmemory长期记忆(向量检索)
qqprofile_exAkusative/astrbot_plugin_qqprofile_ex改签名/状态/昵称
qzonesujingyi1/astrbot_plugin_qzoneQQ 空间说说
dsh-qqbottencent-connect/dsh-qqbot路线一的官方 QQ Bot 通道

15.5 已失效的仓库(记录在此,省得后来人再踩)

仓库状态替代
Zhalslar/astrbot_plugin_qqprofile404Akusative/astrbot_plugin_qqprofile_ex
Zhalslar/astrbot_plugin_qzone404sujingyi1/astrbot_plugin_qzone

qqprofile_ex 是基于原版改的,多了「AI 自主改签名/状态/昵称 + 定时状态切换」,工具名换成 change_my_* 后反倒更不容易撞名。装完记得检查:它默认三个 auto_* 全开,其中改昵称建议关掉——群里突然换了名字,成员会一脸问号。

15.6 一点使用提醒

  1. 插件的协议要看清。group_chat_plus 是 AGPL-3.0,二次分发有传染性要求。
  2. 第三方插件等于把宿主机权限交给别人的代码。它们能读配置文件、能发网络请求。装之前至少扫一眼 main.py 有没有可疑的 subprocess。
  3. 表情包素材的版权边界比插件更麻烦。二创角色、AI 改绘、原图来源,这三层权利关系在素材仓库的 NOTICE.txt 里写得很清楚,商用前务必确认。

附录:几个可以直接复用的片段

A. 看门狗 systemd 单元

# /etc/systemd/system/napcat-watchdog.service
[Unit]
Description=NapCat offline watchdog
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/napcat-watchdog.sh
# /etc/systemd/system/napcat-watchdog.timer
[Unit]
Description=Run NapCat watchdog every 2 minutes

[Timer]
OnBootSec=3min
OnUnitActiveSec=2min
Unit=napcat-watchdog.service

[Install]
WantedBy=timers.target

B. 概率门插件的核心(AstrBot)

@filter.event_message_type(filter.EventMessageType.GROUP_MESSAGE)
async def gate(self, event: AstrMessageEvent) -> None:
    text = (event.message_str or "").strip()
    if text.startswith("/"):
        return
    # @ / 引用 必回
    for seg in event.get_messages():
        if isinstance(seg, Comp.At) and str(seg.qq) == str(event.get_self_id()):
            return
    prob = 0.4 if is_peak(datetime.now()) else 0.6
    if random.random() >= prob:
        event.stop_event()      # 关键:真正阻止模型调用

event.stop_event() 有效的原因:管道调度器在阶段之间检查 is_stopped(),命中就 break,
所以模型根本不会被调用——省的是真金白银。

C. 两份必须收好权限的文件

chmod 600 /opt/napcat-bot/docker-compose.yml            # 含小号密码
chmod 600 /path/to/astrbot/data/cmd_config.json        # 含所有 API Key
chmod 600 /path/to/astrbot/data/plugin_data/*/config.json

(全文完。如果这篇对你有用,欢迎在评论区交流;有踩到别的坑也欢迎补充。)

推荐文章

CC Switch 安装教程:从下载到一键切换 API 全流程图解

简介: CC Switch 是一款免费开源的跨平台 A...

益诗误删文件复盘

九月十九日下午,我在服务器上整理文件,敲了一条删除命令...

评论区(暂无评论)

我要评论

昵称
邮箱
网址
0/200
没有评论
可按 ESC 键退出搜索

0 篇文章已搜寻到~