本文由 辛梓煜@词元2号站(www.ciyuanerhao.com)撰写,转载请注明出处。
快速摘要
如果你只想要一个结论:AstrBot 是目前把「一个 AI 助手,同时活在十几个聊天软件里」这件事做得最完整的开源方案。它的核心不是某个花哨功能,而是一套三层解耦的架构——消息平台适配层负责把 QQ、飞书、钉钉、Telegram、Slack 的协议差异抹平;模型接入层把 OpenAI、Anthropic、Gemini、DeepSeek、Ollama 本地模型统一成同一套调用接口;中间的核心调度层负责会话、上下文、人格、工具调用和插件分发。最快的上手方式是 uv tool install astrbot --python 3.12 三条命令起服务,浏览器打开 6185 端口配置;最稳的生产方式是 Docker Compose,把协议端和主程序放进同一个网络。真正拉开它和同类项目差距的,是 Agent Sandbox(隔离沙盒执行代码)、原生 MCP 协议接入、原生知识库 RAG,以及一千多个可一键安装的社区插件。
这篇文章不打算做功能罗列。我会从「为什么这类工具一直做不好」讲起,把架构原理、部署路径的取舍、协议对接的真实链路、沙盒的安全边界、知识库的向量维度陷阱、插件的最小可运行代码,一条条拆开讲清楚。中间穿插我自己折腾时踩过的坑和排错清单。
想看完整拆解,往下翻。
一、为什么「多平台 AI 助手」这件事一直做不好
1.1 每个平台都在说自己的方言
先说清楚问题本身。
你想给自己搞一个 AI 助手,希望它能在 QQ 群里回答问题,也能在飞书工作群里帮你查资料,还能在 Telegram 上陪你聊两句。听起来是一个需求,实际上是三套完全不同的工程。
QQ 这边,官方机器人有一套报备和权限体系,个人号则要走 OneBot 协议实现端;飞书是标准的开放平台事件订阅 + 回调验签;Telegram 是 Bot API 的长轮询或者 Webhook;Slack 又是一套 Events API 加 Socket Mode。它们的消息格式不一样,鉴权方式不一样,富媒体(图片、语音、文件)的传输方式更是各走各的路。
这意味着什么?意味着你写一遍逻辑,得改四遍适配。而且改完之后维护成本会指数上升——任何一个平台调整了接口,你都得回去补。
我自己最早的做法是:给每个平台各写一个小脚本,共用一个后端 API。写到第三个的时候就写不下去了。不是技术上做不到,是心态上崩了:同一个「查天气」的功能,我需要在四个地方分别处理消息解析、分别处理回复格式、分别处理错误重试。
1.2 把问题拆开看:三层解耦才是正解
后来我想明白了,这件事真正的解法是分层。
一个成熟的聊天机器人框架,至少要把三件事拆干净:
- 协议层:负责和各个聊天软件收发消息,把千奇百怪的原始报文翻译成一种统一的内部表示;
- 调度层:负责会话管理、上下文维护、人格注入、工具选择、权限校验、插件分发;
- 能力层:负责真正干活——调用大模型、执行代码、检索知识库、访问外部工具。
三层之间用统一的数据结构通信。协议层换一个平台,调度层不用动;能力层换一个模型,协议层也不用动。
这个思路听起来朴素,但要真正落地,工作量非常可观。AstrBot 值得聊的地方,恰恰是它把这三层都做完了,而且做得比较干净。
二、AstrBot 到底是个什么东西
2.1 一句话定位
按官方仓库的描述,它是一个开源的一站式 Agentic 个人和群聊助手,可以在数十款主流即时通讯软件上部署,此外还内置了一个类似 OpenWebUI 的轻量化 ChatUI。项目由 AstrBotDevs 团队维护,用 Python 编写,采用 AGPL-v3 许可证,代码完全公开。
我更愿意用另一种说法来解释它:它是一台「消息中继 + 智能调度」的路由器。左边插着各种聊天软件,右边插着各种大模型和工具,中间那个盒子负责把两边的语言翻译通、把上下文管起来、把该调的工具调起来。
这个定位很重要。它不是一个「AI 聊天软件」,而是一个把 AI 能力接进你已有沟通渠道的基础设施。你不需要让身边的人下载新 App,他们照常在原来的群里说话,助手就在那儿。
2.2 整体架构长什么样
我把它的运行链路画成了这张图,看完基本就理解了它的骨架:
flowchart TB
subgraph P["协议层 · Platform Adapters"]
A1[QQ / OneBot v11]
A2[飞书 / 钉钉 / 企微]
A3[Telegram / Slack / Discord]
A4[内置 ChatUI]
end
subgraph C["核心调度层 · Core"]
B1[消息事件 AstrMessageEvent]
B2[会话与上下文管理]
B3[人格 / 唤醒规则 / 权限]
B4[插件与事件钩子分发]
B5[函数工具管理器]
end
subgraph E["能力层 · Providers & Tools"]
D1[LLM 提供商]
D2[Embedding / Rerank]
D3[STT / TTS]
D4[MCP 服务器]
D5[Agent Sandbox]
D6[知识库 RAG]
end
P --> B1 --> B2 --> B3 --> B4 --> B5
B5 --> D1 & D2 & D3 & D4 & D5 & D6
B5 --> R[结果消息链]
R --> P
消息从任何一个协议适配器进来,被规整成统一的事件对象;核心层依次做上下文拼接、人格注入、唤醒判断、插件钩子分发;需要调用能力的时候,走函数工具管理器分发到具体的提供商;最后把结果重新打包成消息链,原路返回给对应的平台。
2.3 消息链和统一会话标识:两个关键抽象
框架好不好用,很大程度取决于抽象设计得干不干净。这里有两个概念,理解了它们,后面看插件开发会顺很多。
第一个是消息链(message chain)。
一条消息不是一个字符串,而是一串「消息段」的有序列表。一段纯文本、一张图片、一个 @ 提及、一段语音,各自是一个段。为什么要这么设计?因为不同平台对富媒体的表达完全不同,只有把消息拆成段的序列,才能在中间层做统一处理,最后由适配器负责翻译成目标平台的具体格式。
用白话讲:消息链就是一个「乐高积木清单」,中间层只管往清单里加积木、改积木,具体拼成什么样由每个平台自己决定。
第二个是统一会话标识(unified_msg_origin,文档里常缩写成 umo)。
QQ 群聊里的会话 ID 是群号,私聊里是对方 QQ 号,飞书那边又是另一套 chat_id。如果只用平台自己的 ID,跨平台就会撞车——某个 QQ 群号可能刚好和某个飞书群 ID 一样。
所以框架引入了一个组合标识,把「平台类型 + 会话类型 + 会话 ID」拼在一起,作为全局唯一的会话锚点。上下文存哪、人格用哪个、沙盒工作区放哪个目录,全都按这个标识来分。
这个设计的好处在实操中很明显:你在 QQ 群和飞书群里跟同一个助手说话,两边的对话历史是完全隔离的,不会串。
三、消息平台适配层:一次接入,处处可用
3.1 支持范围:官方维护与社区维护
这是我觉得这个项目最扎实的部分。按官方仓库当前的清单整理如下:
|
平台 |
维护方 |
备注 |
|
|
官方维护 |
官方机器人体系 |
|
OneBot v11 |
官方维护 |
对接第三方协议实现端 |
|
Telegram |
官方维护 |
Bot API |
|
企微应用 & 企微智能机器人 |
官方维护 |
企业场景常用 |
|
微信客服 & 微信公众号 |
官方维护 |
需公众号后台配置 |
|
飞书 |
官方维护 |
开放平台事件订阅 |
|
钉钉 |
官方维护 |
企业内部应用 |
|
Slack |
官方维护 |
国际团队常用 |
|
Discord |
官方维护 |
社区场景 |
|
LINE |
官方维护 |
— |
|
Satori |
官方维护 |
通用协议 |
|
KOOK |
官方维护 |
语音社区 |
|
Misskey |
官方维护 |
联邦宇宙 |
|
Mattermost |
官方维护 |
自建团队沟通 |
|
|
官方维护 |
标注为将支持 |
|
Matrix |
社区维护 |
通过社区插件适配器 |
|
Rocket.Chat |
社区维护 |
通过社区插件适配器 |
|
VoceChat |
社区维护 |
通过社区插件适配器 |
这里有个细节值得注意:社区维护的适配器是以插件形式存在的。这说明它的适配器体系本身就是可插拔的——你如果要接一个清单里没有的内部沟通系统,不需要改主程序,按适配器接口写一个插件就行。
3.2 「协议实现端」是什么,为什么 QQ 个人号要多一层
新手最容易卡住的地方在这儿。接飞书、钉钉、Telegram 都是填个 App ID 和密钥就完事,为什么接 QQ 个人号要多装一个东西?
原因是 QQ 个人号没有对外开放的机器人 API。所以社区的做法是:在服务器上跑一个无头的 QQ 客户端(也就是没有图形界面的 QQ),它以正常客户端的身份登录,然后把收到的消息按照一套公开规范(OneBot v11)转成标准的 WebSocket 或 HTTP 报文对外暴露。
这个中间件就叫协议实现端。NapCatQQ 是目前用得最多的一个,本质上就是在跑一个无界面 QQNT 实例。
用一个比喻说清楚这个分工:
- 协议实现端 = 耳朵和嘴巴,负责在 QQ 这一侧真正地听和说;
- AstrBot = 大脑,负责思考该说什么;
- 两者之间用 WebSocket 连起来,构成完整闭环。
它本身不含任何业务逻辑,纯粹是消息通道层。理解了这一层,你就明白为什么 QQ 那条链路需要两个容器、两套端口。
3.3 连接方向和端口:反向 WebSocket 到底谁连谁
这是新手排错时最常搞混的点,我单独画个时序图:
sequenceDiagram
participant N as 协议实现端<br/>(NapCat, 端口 6099 是它的面板)
participant A as AstrBot<br/>(监听 6199)
participant U as 用户 QQ
Note over A: 启用 OneBot v11 适配器<br/>在 6199 端口开一个 WS 服务端
N->>A: 主动发起连接 ws://host:6199/ws
A-->>N: 握手成功,日志出现「适配器已连接」
U->>N: 在群里发送一条消息
N->>A: 按 OneBot v11 格式推送事件
A->>A: 解析成消息链 → 调度 → 调用模型
A->>N: 下发回复动作
N->>U: 以 QQ 客户端身份发出消息
关键结论:反向 WebSocket 里,AstrBot 是服务端,协议实现端是客户端,由后者主动去连前者。
对应的端口分工是这样的:
|
端口 |
归属 |
用途 |
|
6185 |
AstrBot |
WebUI 管理面板 |
|
6199 |
AstrBot |
反向 WebSocket 服务端 |
|
6099 |
协议实现端 |
它自己的管理面板(扫码登录在这儿) |
我第一次配的时候就栽在 URL 末尾少写了 /ws,日志一直刷连接被拒绝,找了半小时。这个路径后缀不能省。
还有一个高频坑:如果两个服务都跑在 Docker 里,连接地址不能写 127.0.0.1。容器里的 127.0.0.1 指的是容器自己,不是宿主机。同一个 Compose 网络下,直接用服务名当主机名(比如 ws://astrbot:6199/ws)才是对的。
四、模型接入层:把所有模型抹平成一套接口
4.1 OpenAI 兼容协议是这个行业的最大公约数
我自己折腾下来最深的一个体会:现在做 AI 应用集成,只要支持「OpenAI API 兼容」,就等于支持了市面上八成的模型服务。
因为绝大多数国内外的模型提供商,都会额外提供一个兼容 OpenAI 请求格式的接入点。你只需要改 base_url 和 api_key,代码一行不动就能切换后端。
AstrBot 就是这么设计的。它的提供商配置里有一个「自定义」选项,能对接任何 OpenAI API 兼容的服务。在这之上,它又为常见的几家做了预设,省掉你手填地址的麻烦。
按官方文档整理,模型侧的支持矩阵大致是:
|
类型 |
提供商 |
|
对话大模型 |
OpenAI、Anthropic、Google Gemini、Moonshot AI、智谱 AI、DeepSeek、ModelScope、OneAPI |
|
本地部署 |
Ollama、LM Studio |
|
API 网关(支持多模型) |
AIHubMix、优云智算、硅基流动、PPIO 派欧云、302.AI、小马算力 |
|
智能体平台(LLMOps) |
Dify、阿里云百炼应用、Coze |
|
语音转文本(STT) |
OpenAI Whisper、SenseVoice、Xiaomi MiMo Omni |
|
文本转语音(TTS) |
OpenAI TTS、Gemini TTS、GPT-Sovits 系列、FishAudio、Edge TTS、阿里云百炼 TTS、Azure TTS、Minimax TTS、Xiaomi MiMo TTS、火山引擎 TTS |
|
嵌入与重排序 |
兼容 OpenAI API 与 Gemini API 的嵌入服务、重排序服务 |
4.2 本地部署路线:数据不出门的方案
如果你处理的是敏感内容,或者单纯不想让对话数据经过第三方,本地模型是可行的。
通过 Ollama 或 LM Studio,整套链路可以完全在本机跑完,不依赖任何外部接口。代价是硬件——中等规模的模型至少要十几 GB 显存才跑得舒服,纯 CPU 推理的响应速度在聊天场景里基本没法接受。
我的实际做法是混合路线:日常闲聊和通用问答走云端的高性价比模型,涉及内部文档的问答走本地小模型 + 本地知识库。 这个组合在成本和隐私之间的平衡点比较舒服。
一个提醒:并不是所有模型都能直接用。我遇到过某些视觉模型在这套框架下调用失败的情况,日志里报的错还比较隐晦。所以换模型之后,务必先在 WebUI 自带的聊天页面测一轮,别直接上生产群。
4.3 语音链路:让助手能听会说
多模态这块的设计比较有意思。它把语音拆成了两条独立的链路:
flowchart LR
V1[用户发语音] --> S1[STT 转文本]
S1 --> L[LLM 处理]
L --> S2{是否开启 TTS}
S2 -- 是 --> T1[文本转语音] --> V2[回复语音消息]
S2 -- 否 --> V3[回复文本消息]
这两条链路可以单独开关。有些场景你希望助手能听懂语音但用文字回(方便别人截图存档),有些场景反过来。分开配置就很灵活。
这里有个部署方式相关的坑要提前说:如果用普通的 docker run 方式部署协议实现端,可能收不到语音和文件数据,只能收到文字和图片。这会直接导致语音转文字和沙盒的文件输入功能失效。官方文档里推荐用 Docker Compose 的方式,把两者放在同一套编排里,这个问题就不会出现。
4.4 还有一层:图像描述提供商
这是个容易被忽略但很实用的配置。
框架允许你单独指定一个「图像描述模型提供商」。当用户发来一张图片时,如果你的主对话模型不支持多模态输入,框架会先用这个提供商生成一段图片的文字描述,再把描述作为上下文的一部分喂给主模型。
这个设计等于给不支持看图的模型打了个补丁。配置里还能自定义描述用的提示词模板,默认是让模型用中文描述图片内容。
五、部署实操:五条路径怎么选
我把官方支持的部署方式全试了一遍,这一节讲清楚每条路的适用场景。
5.1 路径一:uv 一键部署(体验最快)
uv 是一个 Python 包与环境管理工具,速度比传统方式快很多。这条路是官方推荐给「熟悉命令行、想快速体验」的用户的。
# 安装工具本体(Windows / Linux / macOS 通用,也可以用 pip install uv)
pip install uv
# 安装 AstrBot,指定 Python 3.12
uv tool install astrbot --python 3.12
# 初始化环境,仅首次执行
astrbot init
# 启动
astrbot run
启动完成后浏览器打开 http://localhost:6185,默认账号是 astrbot,初始密码在启动日志里能看到。第一件事就是改密码,别拖。
后续更新用这条:
uv tool upgrade astrbot --python 3.12
两个必须知道的限制:
- 这个项目需要 Python 3.12 或更高版本,
--python 3.12这个参数就是确保工具环境用对版本; - 通过 uv 部署的实例,不支持在 WebUI 里点按钮升级,必须回到命令行执行上面的升级命令。
macOS 用户还有个小现象:因为系统的安全检查机制,首次运行命令可能要等十几二十秒才有反应,这是正常的,别以为卡死了。
5.2 路径二:Docker Compose(生产首选)
服务器上长期跑,我强烈建议走这条。理由不是「Docker 更高级」,而是三个非常具体的好处:
- 环境完全隔离,不会污染宿主机的 Python 环境;
- 协议实现端和主程序在同一个 Compose 网络里,可以用服务名互相访问,省掉一堆网络配置的麻烦;
- 数据目录挂载出来,备份和迁移就是复制一个文件夹的事。
官方仓库里带了 compose 配置,克隆下来直接起:
git clone https://github.com/AstrBotDevs/AstrBot
cd AstrBot
docker compose up -d
国内服务器拉镜像慢的话,改一下 compose.yml 里的镜像地址,换成国内的镜像加速地址即可:
services:
astrbot:
image: m.daocloud.io/docker.io/soulter/astrbot:latest
ports:
- "6185:6185" # WebUI
- "6199:6199" # 反向 WebSocket
volumes:
- ./data:/AstrBot/data
restart: always
./data 这个目录非常关键,配置、会话记录、插件全在里面。做定时备份的时候,备份这一个目录就够了。
5.3 路径三:桌面客户端 / 启动器(不想碰命令行)
如果你只想在自己电脑上用,完全不想碰服务器和终端,有两个选择:
- 桌面客户端(AstrBot-desktop):面向桌面使用,以内置的 ChatUI 作为主要入口,官方明确说明不推荐用于服务器场景;
- 启动器(AstrBot Launcher):图形化管理工具,支持版本下载、多实例管理、数据备份、Python 运行环境自动配置。适合想要环境隔离多开的用户——比如你要同时跑一个测试实例和一个正式实例。
我个人更推荐启动器这条路给非技术用户。多开和备份这两个能力,在你开始认真用之后会非常有价值。
5.4 路径四:面板类部署(宝塔 / 1Panel / CasaOS)
已经在用运维面板的,官方文档里对这三个都有专门的部署说明,都是在应用商店里点几下的事。CasaOS 这条特别适合家用 NAS 场景——你在家里的 NAS 上跑一个助手,全家都能用。
辛梓煜@词元二号站 这边实测下来,面板类部署的优点是可视化程度高、日志和端口管理方便,缺点是遇到需要进容器执行命令的场景(比如后面要讲的 MCP 依赖安装)会稍微绕一点。
5.5 路径五:包管理器与云端一键
还有两个偏小众但很省事的:
- AUR:Arch Linux 用户可以用
yay -S astrbot-git直接装,走系统包管理器; - 云平台一键部署:不想自己管服务器的,有第三方云服务提供了一键部署入口;
- Kubernetes:仓库里带了 k8s 目录,有集群环境的可以直接用。
5.6 选型对照表
我把五条路径的取舍整理成表,直接对着选:
|
部署方式 |
上手难度 |
适合场景 |
主要限制 |
|
uv 一键 |
低 |
快速体验、本地调试 |
不支持 WebUI 内升级 |
|
Docker Compose |
中 |
服务器长期运行、生产 |
需要理解容器网络 |
|
桌面客户端 |
极低 |
个人本机使用 |
不适合服务器 |
|
启动器 |
极低 |
多实例、需要备份 |
仅桌面端 |
|
面板 / AUR / K8s |
中到高 |
已有运维体系 |
依赖既有环境 |
我的建议很简单:先用 uv 或桌面客户端跑通一遍,把配置流程摸熟;确认要长期用了,再迁到 Docker Compose 上去。 前期不要一上来就折腾容器编排,容易在网络问题上浪费大量时间,还没看到效果就放弃了。
六、把 QQ 链路完整走通:一次实操记录
这是最典型也最容易出问题的一条链路,我完整走一遍。
6.1 五个步骤
第一步,起两个容器。
主程序容器映射 6185 和 6199 两个端口,协议实现端容器映射它自己的面板端口 6099,两者放在同一个网络里。用 Compose 的话这些都在配置文件里写好了。
第二步,登录协议实现端。
浏览器打开 http://服务器IP:6099,进面板需要一个 Token,从容器日志里拿:
docker logs napcat
进去之后会看到一个二维码,用准备好的 QQ 号扫码登录。
这里有个非常重要的提醒:不要用你的主号。 无头客户端属于非官方登录方式,存在账号被风控的可能。用一个专门的小号,而且这个小号最好不是刚注册的(新号更容易触发风控)。
第三步,在主程序侧开启适配器。
进管理面板 → 机器人 → 创建机器人 → 消息平台类别选 OneBot v11 → 启用适配器。反向 WebSocket 端口保持 6199,可以设一个连接密钥(Token)增加安全性。保存。
第四步,在协议实现端配连接。
回到 6099 的面板 → 网络配置 → 新建 → 选择「WebSocket 客户端」:
- URL 填
ws://主机地址:6199/ws(Compose 部署就填ws://astrbot:6199/ws) - Token 填上一步设的密钥
- 心跳间隔和重连间隔建议都改成 1000 毫秒
- 勾选启用,保存
第五步,验证。
盯着主程序的控制台日志,看到「aiocqhttp(OneBot v11) 适配器已连接」就说明握手成功了。然后用另一个 QQ 号私聊机器人,发一条 /help,有回复就全通了。
别忘了最后一步:进配置页 → 其他配置 → 管理员 ID,填你自己的 QQ 号(不是机器人的)。不填的话很多管理指令你没权限用。
6.2 排错清单
我把踩过和见过的问题整理成表,出问题按顺序对照排查:
|
现象 |
大概率原因 |
处理方式 |
|
连接被拒绝(ECONNREFUSED) |
主程序没在监听 6199 |
确认适配器已启用并保存 |
|
容器间连不上 |
用了 |
改成 Compose 服务名 |
|
一直重连不成功 |
URL 末尾少了 |
补上路径后缀 |
|
握手后立刻断开 |
两侧 Token 不一致 |
重新复制粘贴一遍 |
|
收得到文字收不到语音 |
部署方式导致的数据通道限制 |
改用 Compose 部署 |
|
扫码登录一直失败 |
容器内存不足 |
给容器留出 1GB 以上 |
|
日志有 GPU 相关报错 |
无头环境的正常现象 |
可以忽略,不影响功能 |
|
面板打不开 |
端口映射或防火墙 |
检查映射与安全组规则 |
6.3 安全上的三条硬规矩
这块我必须多说两句,因为很多教程不讲:
- 协议实现端的管理面板(6099)绝对不要直接暴露在公网。 那个面板能操作已登录的 QQ 账号,泄露出去后果很严重。只走内网访问,或者通过 SSH 隧道转发。
- 首次登录管理面板后立刻改默认密码。 默认凭据是公开的,不改等于门开着。
- 定期备份数据目录。 配置、会话历史、插件数据全在里面,丢了就得从头再来。
七、Agent 能力:沙盒、MCP 与 Skills
这一节是我认为最值得单独拿出来讲的部分,也是这个项目和普通「聊天机器人 + API 转发」的分水岭。
7.1 从「代码执行器」到「Agent 沙盒」
早期版本里有一个代码执行器功能,从 v4.12.0 开始被沙盒环境取代了。这个演进的方向很清楚:从「能跑代码」变成「能安全地跑代码,并且跑完的环境还能接着用」。
目前它提供了两种执行环境,在配置页的「使用电脑能力」里选:
local 模式——把执行能力挂在主程序所在的宿主环境上。Agent 可以调用本机的 Shell、本机的 Python、本机的文件系统工具。
这个模式的能力边界,等同于主程序进程本身的权限。它能访问什么,取决于进程的系统权限、运行用户、工作目录和操作系统限制。说白了:主程序能干的事,Agent 都能干。 这个模式很方便,但风险显而易见,官方文档里也明确提示要谨慎使用。
在 local 模式下,框架会给每个会话准备一个独立的工作区目录,目录名由会话标识规范化而来(不适合做文件名的字符会被替换成下划线)。本地文件工具的相对路径会解析到这个工作区下。
sandbox 模式——把执行动作放到隔离环境里。
这才是推荐的用法。它的好处不只是安全,还有一个很实用的特性:会话级资源复用。
7.2 会话级复用是什么意思
这个概念第一次听可能有点抽象,我举个例子说清楚。
假设你在群里让助手帮你分析一份数据。它跑了一段 Python,把数据读进内存,画了张图发给你。然后你说「把横轴改成对数刻度再画一遍」。
如果每次执行都是全新的一次性环境,那第二次得从头再读一遍数据、重新装一遍依赖。如果环境能复用,第二次就可以直接在已有的状态上改。
框架的做法是:按会话标识缓存沙盒实例。在默认的主 Agent 流程下,这个标识通常就等于消息会话的统一标识。所以同一个会话的后续请求,会继续复用同一个沙盒;沙盒失效了会自动重建。
配置里还有几个参数值得注意:
warm_pool_size:预热池大小,提前准备好几个沙盒实例,减少首次调用的等待时间。资源紧张时可以调小甚至关掉;- TTL:沙盒的存活时长,超时会被回收;
- 工作区根目录:对于新版驱动器,固定是
/workspace。调用文件系统工具时要传相对路径(比如reports/result.txt),而不是绝对路径(/workspace/reports/result.txt)。这个细节写插件时很容易踩。
另外还有一个面向「电脑使用」(Computer Use)的沙盒运行时,能通过统一的 SDK 创建 Linux、macOS、Windows、Android 等不同类型的沙盒,暴露 Shell、截图、鼠标、键盘、文件系统等接口。浏览器能力不是所有配置档都有,需要选支持浏览器能力的配置档才会挂载相关工具。
7.3 MCP:让助手接上外部工具
MCP 是一套让大模型和外部工具对话的开放协议。用一句白话解释:它规定了「工具应该怎么自我介绍」和「模型应该怎么调用工具」,只要双方都守这个规矩,任何工具都能即插即用。
从 v3.5.0 开始,框架原生支持这个协议,可以添加多个服务器、使用它们提供的函数工具。
配置文件在数据目录下,首次启动如果找不到会自动创建:
data/mcp_server.json
大多数服务器用 uv 或者 npm 启动,所以你的环境里得有这两个工具。Docker 部署的话,如果镜像里没带 Node,需要进容器装一下:
docker exec -it astrbot /bin/bash
apt update && apt install curl -y
# 装 nvm 后安装 Node 22
nvm install 22
node -v && npx -v
Docker 部署还有一个约定:把服务器装在 data 目录下,这样容器重建之后不会丢。
实际配置起来其实很轻。一个典型的服务器配置大概长这样:
{
"mcpServers": {
"arxiv-search": {
"command": "uvx",
"args": ["arxiv-mcp-server"],
"env": {}
}
}
}
加完之后,模型在对话里就能自动判断什么时候该调用这个工具、传什么参数。你不需要写任何胶水代码。
这件事的价值在于解耦。 主程序不用为每一个新工具改代码,工具方也不用关心是哪个客户端在调用它。写一个自己的服务器也不复杂,本质就是一个按规范返回结构化数据的服务,Python 或者 TypeScript 都行。
7.4 Skills:给 Agent 的操作说明书
Skills 是另一套机制,可以理解成给 Agent 准备的「操作手册包」——里面通常包含说明文档和可执行的代码片段、脚本。
它的一个特点是高度可复用:同一份技能包可以在不同的项目和客户端之间通用。
在这个框架里,Skills 的优先级规则设计得比较细,我整理成表:
|
优先级 |
来源 |
说明 |
|
最高 |
当前会话工作区 |
同名时覆盖所有其他来源,仅对当前请求生效 |
|
次高 |
本地 Skills |
优先于插件内置和沙盒专属 |
|
中 |
插件内置 Skills |
优先于沙盒专属 |
|
最低 |
沙盒专属 Skills |
仅在没有同名的其他来源时注入 |
上传方式是在管理面板的插件页面找到 Skills 入口,按格式要求上传。
有一个前置条件必须注意:如果选了沙盒执行环境但没有真正启动沙盒模式,Skills 是不会传给 Agent 的。这个坑我见过好几个人踩,表现是「上传了技能包但助手完全不知道有这回事」。
7.5 关于安全边界,我的实际态度
讲完能力得讲讲风险,这块不能含糊。
让一个大模型能在你的服务器上执行任意代码和 Shell 命令,本质上是把一部分控制权交给了一个概率模型。它绝大多数时候会按你的意图行事,但不保证百分之百。
我自己的三条原则:
- 能用沙盒就绝不用 local 模式。 方便一点点,不值得拿宿主机换。
- 给沙盒的网络访问做限制。 需要访问外部资源就配代理并做白名单,不要让它裸奔。
- 群聊场景一定要做权限控制。 一个开放的群里,任何人都能给助手发指令。如果助手有执行能力,就意味着任何人都能间接在你的服务器上做事。权限体系一定要开,管理员指令和普通用户指令必须分开。
八、知识库与 RAG:让助手回答你自己的问题
8.1 先说清楚 RAG 是什么
RAG 的全称是检索增强生成,白话讲就是「开卷考试」。
模型本身不知道你公司的内部文档写了什么。RAG 的做法是:先把你的文档切成小块、转成向量存起来;用户提问时,先用问题去向量库里检索最相关的几段,把这几段和问题一起塞给模型,让它照着这些材料回答。
这样模型就不用「背下」你的资料,而是每次现查现答。好处是资料更新只要重新入库,不需要重新训练模型。
8.2 完整流程
从 4.5.0 版本开始,知识库被重新设计并成为原生功能。整个流程是这样的:
flowchart TD
A[上传文档 md/txt/docx/xlsx/pptx] --> B[Markitdown 转成 Markdown]
B --> C[切分成文本块 chunk]
C --> D[嵌入模型转成向量]
D --> E[(向量库)]
Q[用户提问] --> QE[问题转成向量]
QE --> S[相似度检索]
E --> S
S --> R[重排序模型精排]
R --> P[拼进提示词]
P --> L[LLM 生成回答]
具体操作分四步:
第一步,配嵌入模型。 打开服务提供商页面 → 新增服务提供商 → 选择 Embedding。目前支持兼容 OpenAI API 和 Gemini API 的嵌入服务。
第二步,配重排序模型(可选但推荐)。 同样在服务提供商页面新增,选择重排序。重排序的作用是对初检的结果做二次精排,能明显提升召回质量。
第三步,创建知识库并上传文档。 进知识库页面点创建。框架用 Markitdown 把非文本文件转成对模型友好的 Markdown 格式,支持 md、txt、docx、xlsx、pptx 等格式,其中 md 和 txt 兼容性最好。单次最多同时上传 10 个文件,单文件不超过 128 MB。
大文件处理会比较慢,可以另开一个标签页在控制台看进度。上传成功会有绿色提示。
第四步,测试和切换。 页面上有「搜索内容」功能可以直接测召回效果,这个测试不消耗模型调用。聊天时用 /kb use 知识库名称 切换,完整指令看 /kb help。
它支持多知识库管理,配置文件里可以为不同的配置档指定不同的默认知识库。配置项里有一个「默认知识库名称」,留空就表示不启用。
8.3 一个必须记住的坑:向量维度不能改
这是官方文档里专门用警告标出来的:一旦某个知识库选定了嵌入模型,就不要再修改该提供商的模型或向量维度信息。
原因是向量库里存的是固定维度的向量。你换了模型,新问题生成的向量维度和库里存的对不上,轻则召回率断崖式下跌,重则直接报错。
如果确