为什么值得为 6.6MB 写一篇部署长文
过去两年,我见过太多”部署文档”最后变成”依赖地狱日志”:先是 Node 版本不对,再是 Python 的 glibc 版本冲突,然后是某个 native 模块在 ARM 上编译失败,最后 Docker 镜像拉了一半超时。一个本该十分钟搞定的事情,硬生生拖成一下午。而当我第一次把 ZeroClaw 的发布包拖到一台 1 核 1G 的廉价云主机上、解压、执行 ./zeroclaw --version 秒出结果时,那种感觉像极了十年前第一次用 Go 编译出的单文件程序。
ZeroClaw 是 Rust 编写的极简个人 AI Agent,采用 Apache-2.0 协议,GitHub 上大约 31 到 33K star。它的卖点不是”功能最多”,而是”部署最不折腾”:一个约 6.6MB 的单二进制文件,一份 TOML 配置,就能把 20 多家模型提供商、30 多种消息渠道接起来,甚至还能直接驱动 GPIO、I2C、SPI、USB 外设去做硬件侧的小项目。
这篇文章不是官方 README 的翻译,而是一份面向”真要在自己机器、NAS、树莓派、边缘盒子上把它跑起来”的实战教程。我会逐段拆开 TOML 配置模板,把四种沙箱方案摆在一起对比,讲清楚 6.6MB 背后到底做了哪些架构取舍,也会把社区里最常见的报错一条条列出来。所有命令都是可以直接复制执行的。核心关键词「ZeroClaw 部署」会贯穿全文,但更重要的是让你在读完以后真的能跑通。ZeroClaw 部署的门槛低,不代表没有坑,坑往往出在配置语义和沙箱边界上。
Rust 单二进制:部署体验的天花板是怎么炼成的
三种运行时模型的三次”体检”
要理解 ZeroClaw 为什么让人觉得”轻”,得先明白它在运行时模型上属于哪一类。业界的 Agent 框架大致分三档:
第一档是”解释器 + 包管理器”,比如基于 Python 或 Node 的框架。优势是生态大、改代码快;代价是目标机器上必须有一套匹配的运行时,虚拟环境、依赖锁文件、编译型依赖一样都跑不掉。你部署的不是一个程序,而是一整套”环境假设”。
第二档是”容器镜像”,把一个完整运行环境打包进镜像。它解决了”环境一致性”,但把复杂度转移到了容器运行时:目标机器要有 Docker 或 Podman,镜像动辄几百 MB,冷启动多一层文件系统开销,权限与数据卷挂载又是一门学问。
第三档是”静态单二进制”,编译器把运行时、标准库、业务逻辑全部塞进一个 ELF 文件里,目标机器上不需要任何语言运行时。ZeroClaw 属于这一档。你部署的是一个”文件”,而不是一个”环境”。
这个差别在纸面上很小,在实操中巨大。举一个我自己的例子:同样一台只有 512MB 内存的 ARM 小盒子,跑一个 Python Agent,光是解释器加依赖就吃掉两百多兆常驻内存,再挂个向量库基本就 Danger Zone 了;换成 ZeroClaw 这种 Rust 单二进制,常驻内存通常只有几十兆量级,剩下的内存可以留给真正的任务。
6.6MB 背后的四个取舍
很多人会问:Rust 程序为什么能小到 6.6MB?一个 hello world 级别的 Rust 程序加上标准库,在开启优化后通常也就几百 KB 到一两兆。从一个”能跑 HTTP、能跑 WebSocket、能接几十家模型、能接几十家消息渠道”的完整 Agent 来看,6.6MB 是相当克制的数字。我认为这背后至少有四个明确的取舍:
取舍一:不做”全家桶”。ZeroClaw 的定位是极简个人 Agent,它没有内置重型向量数据库、没有内置可视化前端、没有内置几十个插件的运行时。需要的能力用配置组合,而不是用代码堆叠。这种”少即是多”的哲学直接反映在二进制体积上。
取舍二:同步优先、异步克制。Rust 的 async 生态很强,但 async 运行时(例如完整的 tokio 全家桶)会明显增加体积。极简 Agent 的并发模型不需要极端的异步编排,把异步限制在 IO 边界,能省下不少代码路径和依赖。
取舍三:链接与符号裁剪。发行版二进制通常开启了链接时优化(LTO)、去除调试符号(strip)、panic 使用 abort 策略。这几项叠加起来,往往能把体积砍掉三分之一甚至更多。
取舍四:可选特性编译。Rust 的 feature 机制让你只编译用到的模块。要 GPIO 就开硬件特性,不要硬件就不编译它。这让”最小可用体积”和”能力完整体积”之间有了弹性空间。官方统计的 6.6MB 是一个基准值,你自己编译时可以按需增删。
这四点说明一件事:体积不是目的,体积是设计纪律的结果。一个愿意在依赖上克制、在特性上模块化的项目,部署体验自然就好。ZeroClaw 部署之所以让人省心,本质上是”决策被前置到了编译期”。
冷启动与内存足迹的真实意义
单二进制的第二个好处是冷启动。解释型运行时在启动时要加载解释器、初始化字节码、导入一堆模块,冷启动常常是秒级;容器化方案还要叠加容器创建、网络命名空间初始化的时间。单二进制的冷启动通常在小几十毫秒到几百毫秒之间。
这在”常驻服务”场景下感受不明显,但在两个场景下是决定性的:一是被 Cron 或 systemd timer 定时拉起的一次性任务,二是边缘设备上”按需唤醒”的硬件场景。前者决定你每天几百次调用里有多少时间花在启动上,后者决定电池能撑多久。
内存足迹同理。Rust 没有 GC,内存分配是确定的,峰值可预测。对于要长期跑在 NAS 或树莓派上的个人 Agent 来说,”不会因为一次内存泄漏把整台机器拖垮”是一件很朴素但很珍贵的事。ZeroClaw 部署到资源紧张的环境时,这种确定性的价值远高于纸面性能数字。
ZeroClaw 部署前的环境准备
支持的系统与架构
ZeroClaw 的发布包通常覆盖主流的目标组合。选择之前,先确认你的系统:
# 查看系统架构与发行版
uname -m # x86_64 / aarch64 / armv7l
uname -s # Linux / Darwin
cat /etc/os-release 2>/dev/null | head -3
ldd --version 2>/dev/null | head -1
# 查看可用内存与磁盘
free -h
df -h /usr/local
常见的目标组合包括 Linux x86_64、Linux aarch64(树莓派 4/5、ARM 云主机、部分 NAS)、macOS(Intel 与 Apple Silicon)。如果你的架构不在官方 Release 列表里,就走源码编译路线。
必装工具清单
下载发布包只需要 curl、tar 或 unzip、sha256sum。走源码编译则需要 Rust 工具链。另外建议准备好 git、jq(调试 JSON 接口很方便)、tmux(跑长任务)。
# Debian / Ubuntu
sudo apt update
sudo apt install -y curl tar unzip git jq tmux ca-certificates
# macOS (Homebrew)
brew install curl jq tmux
# 校验工具
which curl tar unzip sha256sum jq
如果你要在没有 Internet 的内网机器上部署,提前在能上网的机器上下载好对应架构的发布包,用 U 盘或跳板机传过去即可——这正是单二进制的优势,不需要先在目标机上准备一堆依赖源。
下载与安装:发布包与源码编译两条路
路线一:从 Release 下载预编译二进制
这是绝大多数人的第一选择。以 GitHub Release 为例,流程是”确定版本 → 下载对应架构包 → 校验 → 解压 → 放到 PATH → 验证”。
# 1. 查询最新版本号(不依赖 API 也行,直接看 Release 页面)
LATEST=$(curl -s https://api.github.com/repos/zeroclaw/zeroclaw/releases/latest \
| jq -r .tag_name)
echo "latest = ${LATEST}"
# 2. 确认本机架构并拼接包名
ARCH=$(uname -m)
case "$ARCH" in
x86_64) PKG="zeroclaw-${LATEST}-linux-x86_64.tar.gz" ;;
aarch64) PKG="zeroclaw-${LATEST}-linux-aarch64.tar.gz" ;;
armv7l) PKG="zeroclaw-${LATEST}-linux-armv7.tar.gz" ;;
*) echo "需走源码编译"; exit 1 ;;
esac
# 3. 下载
curl -fL -o "/tmp/${PKG}" \
"https://github.com/zeroclaw/zeroclaw/releases/download/${LATEST}/${PKG}"
# 4. 校验(Release 页一般提供 .sha256 文件)
curl -fsSL -o "/tmp/${PKG}.sha256" \
"https://github.com/zeroclaw/zeroclaw/releases/download/${LATEST}/${PKG}.sha256"
cd /tmp && sha256sum -c "${PKG}.sha256"
校验通过后再解压安装:
# 5. 解压并安装到 /usr/local/bin
tar -xzf "/tmp/${PKG}" -C /tmp
sudo install -m 0755 /tmp/zeroclaw /usr/local/bin/zeroclaw
# 6. 验证
zeroclaw --version
zeroclaw --help
# 7. 确认体积(这是本文标题里的 6.6MB 大概位置)
ls -lh /usr/local/bin/zeroclaw
file /usr/local/bin/zeroclaw
如果你希望”每个用户一个版本、不影响系统”,可以装到 ~/.local/bin,并确保它在 PATH 里:
mkdir -p ~/.local/bin
install -m 0755 /tmp/zeroclaw ~/.local/bin/zeroclaw
grep -q '.local/bin' ~/.zshrc || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
exec zsh -l
zeroclaw --version
macOS 上下载的二进制可能被 Gatekeeper 拦截,如果出现”无法验证开发者”,执行:
xattr -d com.apple.quarantine /usr/local/bin/zeroclaw
路线二:从源码编译
源码编译适合三类人:官方没提供你架构的包、想裁剪特性、想跟进最新 commit。Rust 工具链推荐用 rustup 安装,稳定版即可。
# 安装 Rust 工具链(已安装可跳过)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
rustc --version
cargo --version
# 拉取源码
git clone --depth 1 https://github.com/zeroclaw/zeroclaw.git
cd zeroclaw
# 编译(release 模式,开启体积优化)
cargo build --release
# 产物位置与体积
ls -lh target/release/zeroclaw
如果编译卡在链接阶段,先确认你装了系统链接器与 pkg-config:
# Debian / Ubuntu 编译依赖
sudo apt install -y build-essential pkg-config libssl-dev
# 如果是 aarch64 交叉编译到树莓派,需要额外 target
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu
# 交叉编译还要指定链接器(示例,路径按你的工具链调整)
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
不想污染全局配置时,可以用 Cargo.toml 里的体积优化段。下面是通用写法,直接加到项目根目录:
[profile.release]
opt-level = "z" # 体积优先,可换 "s" 或 3
lto = true
codegen-units = 1
panic = "abort"
strip = true # 等价于编译后 strip
完整发布产物的最终装机流程与路线一一致,把 target/release/zeroclaw 装到 PATH 即可。ZeroClaw 部署的这一步,无论走哪条路,最终都收敛到”一个可执行文件”。
用 systemd 把它做成常驻服务
如果打算长期运行,建议用 systemd 管理。下面是一份最小可用的 unit 文件:
sudo tee /etc/systemd/system/zeroclaw.service >/dev/null <<'EOF'
[Unit]
Description=ZeroClaw personal agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=zeroclaw
ExecStart=/usr/local/bin/zeroclaw --config /etc/zeroclaw/config.toml
Restart=on-failure
RestartSec=3
Environment=RUST_LOG=info
# 内存与文件描述符上限
LimitNOFILE=65535
MemoryMax=512M
[Install]
WantedBy=multi-user.target
EOF
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/zeroclaw zeroclaw 2>/dev/null || true
sudo mkdir -p /etc/zeroclaw /var/lib/zeroclaw
sudo chown -R zeroclaw:zeroclaw /var/lib/zeroclaw
sudo systemctl daemon-reload
sudo systemctl enable --now zeroclaw
sudo systemctl status zeroclaw --no-pager
journalctl -u zeroclaw -n 50 --no-pager
TOML 五段配置逐段拆解
ZeroClaw 的配置哲学只有一句:一个文件、五个段落、声明式。所有运行时行为由 TOML 描述,不散落到环境变量和各种 dotfile 里。这种设计让”配置即文档”成为可能——把一份配置提交进 Git,就完整复现了这台 Agent 的全部行为。下面给出一份完整的配置模板,再逐段讲语义。
# /etc/zeroclaw/config.toml
# ---------- 1. 全局 ----------
[general]
name = "home-agent"
log_level = "info" # trace | debug | info | warn | error
data_dir = "/var/lib/zeroclaw"
timezone = "Asia/Shanghai"
max_history = 40 # 单会话保留轮数
locale = "zh-CN"
# ---------- 2. 模型提供商 ----------
[provider]
default = "openai"
[provider.openai]
kind = "openai"
base_url = "https://api.openai.com/v1"
model = "gpt-4o-mini"
timeout = 60
[provider.ollama]
kind = "ollama"
base_url = "http://127.0.0.1:11434"
model = "qwen2.5:7b"
[provider.deepseek]
kind = "openai-compatible"
base_url = "https://api.deepseek.com/v1"
model = "deepseek-chat"
# ---------- 3. 消息渠道 ----------
[channel]
enabled = ["cli", "telegram", "dingtalk"]
[channel.cli]
kind = "cli"
[channel.telegram]
kind = "telegram"
allow = ["123456789"] # 白名单,限制使用者
[channel.dingtalk]
kind = "dingtalk"
webhook = "https://oapi.dingtalk.com/robot/send?access_token=xxx"
secret = "${DINGTALK_SECRET}"
# ---------- 4. 工具与沙箱 ----------
[agent]
tool_timeout = 30
max_turns = 12
allow_shell = true
[sandbox]
backend = "bubblewrap" # landlock | bubblewrap | seatbelt | docker
workdir = "/var/lib/zeroclaw/work"
allow_net = true
[sandbox.bwrap]
unshare_net = true
tmpfs_size = "256M"
# ---------- 5. 硬件外设(可选) ----------
[hardware]
enabled = false
board = "raspberry-pi"
allowed = ["gpio", "i2c"]
i2c_bus = 1
gpio_pins = [17, 27, 22]
把这五段读完,你就掌握了 ZeroClaw 的全部”控制面”。下面逐段展开。
第一段 [general]:身份与落盘
[general] 管的是”这个 Agent 是谁、日志放在哪、记忆存多久”。几个容易踩的点:
data_dir 是会话历史、缓存、日志的根目录,务必给一个可写的、不在只读分区下的路径。systemd 部署时要把这个目录的属主设成运行用户,否则会在第一次写入时崩溃。max_history 直接影响上下文成本:设置过大时,多轮对话会把 token 消耗拉高;设置过小时,Agent 会”忘事”。我个人的经验是日常助手 30 到 50 轮足够,长任务型 Agent 可以适当下调,靠显式工具调用去检索外部记忆。
log_level 排查期用 debug,稳定运行期用 info。trace 会打印每一次模型请求的完整 payload,包含密钥风险,不建议长期开启。timezone 影响定时任务与日志时间戳,跨时区协作的机器容易在这里出问题。
第二段 [provider]:默认模型与多后端
[provider] 是”模型接入层”。核心思想是两级:default 指定默认后端,其余后端子表按名字索引。你可以配置多个后端,运行时按需切换(例如本地 Ollama 兜底、云端模型主力)。
关键字段只有几个:kind 是协议族,决定用哪种请求格式;base_url 是接口根路径;model 是模型标识;timeout 是超时秒数。绝大多数国内厂商都兼容 OpenAI 协议,所以 kind = "openai-compatible" 就能接上,这也是”20+ 模型提供商”能用一个二进制造出来的原因——不是为每家写适配器,而是复用同一套协议。
API Key 不要明文写进 TOML,用环境变量占位。ZeroClaw 的配置支持 ${VAR} 形式的插值,配合 systemd 的 EnvironmentFile 最干净:
# /etc/zeroclaw/env (chmod 600)
OPENAI_API_KEY=sk-xxxx
DEEPSEEK_API_KEY=sk-xxxx
DINGTALK_SECRET=SECxxxx
# systemd unit 中增加
EnvironmentFile=/etc/zeroclaw/env
配置里写 api_key = "${OPENAI_API_KEY}" 即可。这个习惯能救你:TOML 一旦提交到 Git,明文密钥就再也收不回来了。
第三段 [channel]:消息入口与白名单
[channel] 决定”用户从哪个口子跟 Agent 说话”。enabled 是启用列表,下面的子表逐个描述渠道参数。30+ 渠道的背后同样是”统一消息抽象”:每个渠道负责把平台事件转成内部标准消息,把内部回复渲染回平台格式。所以新增一个渠道,业务逻辑完全不用动。
安全上有一条铁律:任何面向公网或多人群聊的渠道都必须配白名单。Telegram 的 allow 填用户 ID,钉钉或企业微信要校验签名。缺少白名单是最常见的”安全事故”来源——陌生人给你的 Agent 发”帮我读一下这个文件”,后果不必展开。
渠道排布上我建议”一主一备”:CLI 作为调试主入口,Telegram 或钉钉作为日常移动入口,其余按实际需要再加。渠道开得越多,出问题的面越大,ZeroClaw 部署的稳固程度与渠道数量成反比,这与功能多少无关,与暴露面大小有关。
第四段 [agent] 与 [sandbox]:工具与隔离
[agent] 控制”Agent 能做什么、做多久”。allow_shell 是是否允许执行 shell 命令,这是风险最高的一项开关;max_turns 是一次任务最多迭代多少轮,防止模型陷入死循环无限烧 token;tool_timeout 是单个工具调用的超时。
[sandbox] 是整份配置里最值得花时间的一段。默认建议”开 shell、上沙箱”,而不是”关 shell 但裸跑”——前者给了能力又划了边界,后者能力弱但边界也没有。backend 选哪种,下一节专门讲。子表 [sandbox.bwrap] 是 Bubblewrap 专属参数,unshare_net = true 表示命令执行时不给网络,这能有效阻断”工具执行后被远程下指令”的横向风险。
第五段 [hardware]:可选的外设能力
[hardware] 是 ZeroClaw 与其他 Agent 框架最大的差异化:它能把模型的能力延伸到物理世界。enabled 关闭时,这部分代码路径不生效;board 用于选择目标板卡的引脚映射;allowed 是允许访问的总线类型;gpio_pins 是白名单引脚。
即便不开硬件,理解这段也有意义:它体现了”能力即配置”的设计——不需要写驱动代码,配置里声明引脚,Agent 就能理解”控制 17 号引脚”这个请求。ZeroClaw 部署在树莓派上时,这一段会让你的 Agent 从”会聊天”变成”会干活”。
四种沙箱方案对比与选择
沙箱是 ZeroClaw 部署的核心安全议题。Agent 要执行 shell、要读写文件,就意味着它拥有了你的 uid 的权限。沙箱的作用是把这份权限收窄到一个可控边界。ZeroClaw 提供四种后端,各自适用的平台和防护强度不同。
| 维度 | Landlock | Bubblewrap | Seatbelt | Docker |
|---|---|---|---|---|
| 适用平台 | Linux 5.13+ | Linux(普遍) | macOS | Linux / macOS |
| 依赖 | 无(内核原生) | 需安装 bwrap | 无(系统原生) | 需 Docker 守护进程 |
| 隔离粒度 | 文件系统与网络能力受限 | 命名空间 + 挂载隔离 | 沙盒配置文件限制 | 完整容器隔离 |
| 启动开销 | 极低(同进程内) | 低(数十毫秒) | 低 | 较高(百毫秒级) |
| 网络隔离 | 可按规则禁用 | unshare_net 可断网 | 支持 | network=none |
| 配置复杂度 | 低 | 中 | 低 | 高(镜像、卷) |
| 适用场景 | 现代内核服务器 | 桌面 Linux、NAS | macOS 本地开发 | 多租户、强隔离 |
Landlock:内核原生,零依赖的首选
Landlock 是 Linux 内核的土地化安全模块,5.13 起合入。它的特点是”以进程为粒度收窄权限”,不需要额外安装任何软件,也不需要 root。ZeroClaw 调用 Landlock 后,子进程只能访问被显式允许的路径,越界访问会被内核直接拒绝。
它适合”内核足够新、想保持零依赖”的服务器。缺点是它对新旧内核版本敏感,发行版内核太老会直接报”不支持”。检测方法:
# 查看内核版本
uname -r
# 查看内核是否编译进 Landlock(若为 y 或 m 即可用)
zgrep CONFIG_SECURITY_LANDLOCK /proc/config.gz 2>/dev/null || \
grep CONFIG_SECURITY_LANDLOCK /boot/config-$(uname -r)
# 查看 LSM 列表里是否启用了 landlock
cat /sys/kernel/security/lsm 2>/dev/null
内核版本低于 5.13、或者 LSM 列表里没有 landlock,就别用这个后端。
Bubblewrap:桌面与 NAS 的甜点位
Bubblewrap(bwrap)是 Flatpak 背后的沙箱工具,特点是利用用户命名空间做”轻量容器”,不需要 root、启动极快。它能同时隔离文件系统、PID、网络。对大多数 Linux 个人用户来说,这是防护力度与使用成本平衡得最好的一档。
# Debian / Ubuntu
sudo apt install -y bubblewrap
# Fedora
sudo dnf install -y bubblewrap
# 验证
bwrap --version
# 验证用户命名空间是否可用(很多系统默认限制)
sysctl kernel.unprivileged_userns_clone 2>/dev/null
cat /proc/sys/user/max_user_namespaces
如果 max_user_namespaces 为 0,bwrap 会报”创建命名空间失败”。这是 ZeroClaw 部署中最常见的沙箱报错之一,解决办法在后文排查章节展开。
Seatbelt:macOS 的原生答案
Seatbelt 是 macOS 的系统沙盒机制(sandbox-exec 背后的能力)。ZeroClaw 在 macOS 上会自动选择它。它的优点是”原生、无需安装”,缺点是 Apple 对它逐年收紧,部分能力的行为会随系统版本变化。如果你在 Mac 上开发、在 Linux 上部署,要记得两边沙箱语义不完全等价,别指望”本地能跑,线上一定能跑”。
Docker:强隔离,但别为它而部署它
Docker 后端把每次工具执行放进容器里。它的隔离最彻底,适合多租户、适合”Agent 可以执行陌生代码”的高风险场景。但代价也最明显:目标机要常驻 Docker 守护进程,镜像要维护,数据卷要挂载,启动开销更高。
我的建议很直接:个人单机、单用户场景,别用 Docker 后端。你会为了”更强的隔离”重新引入”容器运行时”这层复杂度,而 ZeroClaw 单二进制的存在意义恰恰是消灭这类依赖。只有在确实需要强隔离时,Docker 才划算。
怎么选:一张决策路径
把上面的信息压缩成三条判断:
一、macOS 用户,直接用 Seatbelt,无需任何额外安装。
二、Linux 用户,先看内核:5.13 及以上、且 /sys/kernel/security/lsm 里有 landlock,优先用 Landlock;否则装 bwrap 用 Bubblewrap。这两者对 95% 的个人部署场景足够。
三、需要跑陌生人提交的代码、或者多人共用一台机器,才考虑 Docker,并且接受它的复杂度。
这里有一个很多人忽略的点:沙箱的目标不是”绝对安全”,而是”让错误可控”。Agent 被提示词注入攻击时,如果它只能改沙箱里的目录、不能联网,损失就是可回滚的。反过来,即便你用了 Docker,如果挂载了宿主机的整个 home,隔离也形同虚设。沙箱配置的语义比沙箱类型更重要。
模型提供商接入:一次配置,二十家切换
协议族的思想:为什么不需要为每家写适配器
20 多家模型提供商听起来很多,但实际只有少数几种”协议族”:OpenAI 兼容、Anthropic 风格、以及一批本地推理服务(Ollama、vLLM 等)。ZeroClaw 的接入层按协议族抽象,kind 字段决定用哪套转换逻辑。因此接入一家新提供商,常常只是一个 base_url 加一个 model 的差别。
下面列几个常见的接入配置,覆盖云厂商与本地部署:
[provider.anthropic]
kind = "anthropic"
base_url = "https://api.anthropic.com"
model = "claude-sonnet-4"
api_key = "${ANTHROPIC_API_KEY}"
[provider.qwen]
kind = "openai-compatible"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
model = "qwen-max"
api_key = "${DASHSCOPE_API_KEY}"
[provider.glm]
kind = "openai-compatible"
base_url = "https://open.bigmodel.cn/api/paas/v4"
model = "glm-4-plus"
api_key = "${ZHIPU_API_KEY}"
[provider.vllm]
kind = "openai-compatible"
base_url = "http://127.0.0.1:8000/v1"
model = "Qwen2.5-14B-Instruct"
api_key = "none" # 本地服务常不校验
接入的四个校验步骤
接完配置后不要急着全渠道开跑,按四步验证最省时间:
第一步,验证连通性。单独发一次最小请求,确认 base_url 与密钥都对,排除网络和代理问题。
第二步,验证模型名。模型标识拼错是最高频错误,返回 404 或 400 基本都是这个原因。
第三步,验证工具调用能力。不同模型对 function calling 的支持差异很大,有些模型能聊天但不能可靠地调用工具,表现是”Agent 一直说话但不干活”。
第四步,验证超时与重试。长上下文任务容易被 60 秒超时截断,把 timeout 调大或者换更快的模型。
# 快速验证 OpenAI 兼容接口
curl -sS "$BASE_URL/chat/completions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"'"$MODEL"'","messages":[{"role":"user","content":"ping"}]}' \
| jq -r '.choices[0].message.content'
主力 + 兜底的双后端策略
我的实践建议是至少配两个后端:一个云端强模型做主力,一个本地 Ollama 或小模型做兜底。云端接口抖动、额度用尽、被限流时,兜底后端能让 Agent 不至于”整个失联”。在 [provider] 里用 default 指定主力,跑批任务时按需切换。
双后端还带来一个额外好处:隐私分级。涉及个人数据、本地文件、硬件的任务,路由到本地模型;纯公开知识的问答,走云端大模型。这是ZeroClaw 部署在个人场景里最实用的一种”能力配置”,而不只是省钱。
消息渠道接入:三十种入口的取舍
渠道抽象的收益
30 多个渠道意味着你可以从 Telegram、Slack、Discord、钉钉、飞书、企业微信、邮件、Webhook、甚至串口和命令行来跟同一个 Agent 交互。底层是同一套会话状态和同一批工具,渠道只负责”传输层渲染”。
这个抽象的现实收益是:你在 Telegram 里问的问题,Agent 在本地环境里执行,结果回到 Telegram。从用户的视角看,Telegram 变成了一个”遥控器”,控制的是你家那台机器。
三个必须加的护栏
渠道一多,护栏就必须前置。我总结三条:
第一,用户白名单。任何渠道都要限制”谁能用”。Telegram 的 allow、Slack 的工作区、钉钉的机器人签名,都必须配齐。
第二,读权限与写权限分离。敏感渠道只给”查询类工具”,写入、执行类工具只在受信任的私聊或本地 CLI 里开放。ZeroClaw 的 [agent] 段与沙箱边界配合,可以实现”同一个 Agent、不同入口不同权限”的效果(通过不同实例配置实现)。
第三,限流与审计。max_turns 控制单次任务,tool_timeout 控制单次工具。再养成看日志的习惯,每接入一个新渠道观察一周。
# 观察某渠道的请求量(假设使用 systemd + journald)
journalctl -u zeroclaw --since "24 hours ago" | grep -i "channel=telegram" | wc -l
# 观察工具调用中最频繁的类型
journalctl -u zeroclaw --since "24 hours ago" | grep "tool_call" | awk -F'tool=' '{print $2}' | sort | uniq -c | sort -rn | head
很多人接渠道的过程是”一口气全接上,然后开始收拾事故”。我的建议正好相反:先接 CLI,再每周加一个。ZeroClaw 部署的稳固性,靠的是逐步扩大暴露面,而不是一次性铺开。TOML 配置结构高度一致,加渠道的成本很低,所以慢慢来完全不影响效率。
硬件玩法入门:从 GPIO 到边缘 Agent
为什么这是 ZeroClaw 最被低估的能力
大多数 Agent 框架的”行动”边界止于文件系统和网络。ZeroClaw 支持 GPIO、I2C、SPI、USB,能把行动延伸到物理世界:开关一盏灯、读取温湿度传感器、驱动继电器、接收串口消息。这不是”炫技”,而是把 Agent 从”信息助理”变成”自动化控制器”的杠杆。
更值得说的是”单二进制”与”硬件”的组合效应。边缘设备最怕环境折腾:树莓派上装 Python 依赖、编译 native 模块、处理内核驱动,每一项都是新的失败点。而单二进制的 ZeroClaw 可以把一份 6.6MB 的文件丢到 SD 卡上就跑,系统盘接近只读都能工作。这种”轻承载能力”是硬件场景里最值钱的东西。
最小可行硬件配置
以树莓派为例,先准备系统与权限。用户需要加入 gpio 组(或使用 udev 规则),并启用 I2C 总线:
# 启用 I2C(树莓派)
sudo raspi-config nonint do_i2c 0
# 确认 I2C 设备节点存在
ls -l /dev/i2c-*
groups
# 如果不在 gpio/i2c 组:
sudo usermod -aG gpio,i2c,spi $USER
newgrp gpio
# 安装 i2c-tools 用于扫描设备地址
sudo apt install -y i2c-tools
i2cdetect -y 1
硬件配置按前文模板把 [hardware] 打开:
[hardware]
enabled = true
board = "raspberry-pi"
allowed = ["gpio", "i2c"]
i2c_bus = 1
i2c_addr = "0x76" # 常见 BME280 传感器地址
gpio_pins = [17, 27, 22]
然后在对话里用自然语言请求:”把 17 号引脚拉高 3 秒再拉低”、”读一下 0x76 的温度和湿度”。Agent 会调用对应的硬件工具完成,而不是给你一段让你自己跑的脚本。这才是”Agent”应有的形态:你说目标,它负责执行。
三个可落地的硬件小项目
第一,环境监控播报:BME280 接 I2C,定时读取温湿度,超过阈值时发到钉钉群。适合机柜、储藏室、温室。
第二,物理开关控制:GPIO 驱动继电器模块,接一盏补光灯或风扇。配合 Telegram 渠道,手机就能远程开关。
第三,串口消息中继:USB 接单片机或旧设备,ZeroClaw 读取串口内容,转成人类可读的消息推到 IM,反过来也能把指令写回串口。这一项让很多”哑设备”接入了 Agent。
硬件接入的安全边界
硬件场景的”风险”是物理性的:误触继电器可能造成财产损失,误配 GPIO 可能短路。因此硬件配置里务必使用 allowed 与 gpio_pins 白名单,把可控引脚收敛到最小集合。另外建议在继电器与主控之间加光耦隔离,把电源与信号分开。
更隐蔽的风险来自模型幻觉:模型可能编造一个不存在的引脚号或不存在的寄存器地址。所以硬件工具应该做严格校验——非法引脚直接报错,不要”尽力而为”。这也是为什么硬件能力一定要有配置层白名单,而不是让模型自由发挥。
常见报错排查手册
安装阶段报错
“No such file or directory” 而文件明明存在。多见于 ARM 交叉编译或 aarch64 包在 x86 上跑,本质是动态链接器或 ABI 不匹配。用 file 确认二进制架构,用 ldd ./zeroclaw 看是否缺 glibc 版本。
file $(which zeroclaw)
ldd $(which zeroclaw)
# 若提示 GLIBC_2.34 not found,说明系统过旧,需用更旧 glibc 构建的包或源码编译
下载包校验失败。通常是代理或 CDN 缓存导致的截断。重下并对比大小:
curl -fL -o /tmp/p.tar.gz --retry 3
ls -l /tmp/p.tar.gz
sha256sum /tmp/p.tar.gz
配置阶段报错
解析错误 “expected a table, found string”。TOML 的段落是 [a.b],不是重复写两次 [a] 再补字段。检查是否把 [provider.openai] 写成 [provider] 下再加了一行 openai = "..."。
环境变量没有生效。${VAR} 插值依赖进程环境。systemd 下必须配 EnvironmentFile,交互式 shell 下要确保 export 了,而不仅是写在 rc 文件里没有重新加载。
# 验证 systemd 服务能看到哪些环境变量
sudo systemctl show zeroclaw -p Environment
sudo systemctl show zeroclaw -p EnvironmentFiles
# 验证 shell 里变量有效性
printenv OPENAI_API_KEY | head -c 8
运行时阶段报错
401 / 403。密钥错误或没有权限。常见原因是密钥带了多余空格、用了只有列表权限的子 key,或者 base_url 带了多余路径(比如自己多写了一个 /v1)。
404 model not found。模型名拼错,或者提供商侧的模型标识与官方文档不一致。逐个字符对比。
请求超时。长上下文任务秒数不够;或本地推理的首次加载非常慢。调大 timeout,并且启用流式输出降低体感延迟。
沙箱报 “创建命名空间失败” 或 “Landlock not supported”。两种处理:一是查内核,二是查用户命名空间限制。
# Bubblewrap 场景
cat /proc/sys/user/max_user_namespaces
# 临时放开
sudo sysctl -w user.max_user_namespaces=28633
# 永久(在 /etc/sysctl.d/99-userns.conf 中写)
echo "user.max_user_namespaces=28633" | sudo tee /etc/sysctl.d/99-userns.conf
sudo sysctl --system
# Landlock 场景
uname -r
cat /sys/kernel/security/lsm
# 若没有 landlock,换 backend = "bubblewrap"
日志写入失败 “permission denied”。systemd 服务以 zeroclaw 用户运行,但 data_dir 属主是 root:
sudo chown -R zeroclaw:zeroclaw /var/lib/zeroclaw
sudo -u zeroclaw test -w /var/lib/zeroclaw && echo writable
Agent 不停调用工具、陷入循环。典型是 max_turns 太大或工具返回值含糊。首先把 max_turns 降到 6 到 8,然后检查工具是否返回了明确的成功/失败。模糊的返回值会让模型反复尝试。
硬件报 “permission denied /dev/gpiomem”。用户不在 gpio 组,或者容器/沙箱没有放行设备节点。硬件场景建议直接不用可感知的沙箱后端,而用”用户权限 + 白名单”的方式管理风险。
与其他 Agent 框架的横向对比
选框架没有绝对标准,只有匹配度。下表从部署视角对比几类常见方案:
| 维度 | ZeroClaw | Python 类 Agent 框架 | Node.js 类 Agent 框架 | 容器化部署方案 |
|---|---|---|---|---|
| 分发形态 | 单二进制(约 6.6MB) | 源码 + 虚拟环境 | 源码 + node_modules | 容器镜像 |
| 运行时依赖 | 无 | Python + 依赖 | Node + 依赖 | Docker/Podman |
| 冷启动 | 数十毫秒级 | 秒级 | 秒级 | 百毫秒到秒级 |
| 内存占用 | 低(无 GC) | 较高 | 中 | 中到高 |
| 部署目标 | 服务器、NAS、树莓派、边缘盒 | 服务器、开发机 | 服务器、前端集成 | 服务器、集群 |
| 硬件外设 | GPIO/I2C/SPI/USB 原生 | 需自行集成 | 需自行集成 | 需透传设备 |
| 生态丰富度 | 精简 | 极丰富 | 丰富 | 视框架而定 |
| 上手成本 | 低(配置即用) | 中 | 低到中 | 高 |
| 最适合 | 个人 Agent、边缘自动化 | 研究、快速试验 | Web 场景 | 团队多租户 |
该选它的信号
如果你的关键词里有”长期运行”、”资源紧张”、”硬件”、”不想装依赖”、”要装在一台没人管的小机器上”,ZeroClaw 就是合适的。特别是”一台常年在角落跑、半年不出问题”的需求,它的优势是压倒性的。
如果你更看重”有几百个现成的 Python 库”、”团队都写 Python”、”要做复杂的实验流水线”,Python 类框架仍然是最佳选择。Rust 单二进制的优势是以工程性换来的,代价是生态宽度。
一个不那么主流的观点
我认为 Agent 框架的下一轮竞争不在”能力多寡”,而在”承载门槛”。今天大多数人部署 Agent 的痛点是环境,而不是功能——模型能力正在被拉平,而部署体验的差异是结构性的。单二进制的意义,是让”智能”变成一个可拷贝的文件,而不是一套要维护的系统。ZeroClaw 部署之所以值得单独写一篇,正是因为它在”承载”这件事上有明确主张,而不是又堆了一遍能力清单。
另一个容易被忽略的点是”版本可回滚性”。单二进制回滚就是换一个文件;解释型框架回滚要回滚依赖锁、运行时版本、代码目录。在个人设备上,一次失败升级的恢复成本,往往比升级本身更让人头疼。这也是Rust 单二进制在运维上的隐性收益。
一份 30 天运维节奏建议
部署完成只是起点。为了让这份”轻”持续下去,我建议一个朴素的 30 天节奏:
第 1 到 3 天:只跑 CLI 与一个主力模型,观察日志与内存曲线,确认无异常。
第 4 到 7 天:接入一个消息渠道,配上白名单,观察一周的请求特征。
第 8 到 14 天:开启沙箱中的 shell 能力,从小范围的目录开始,逐步扩大允许路径。这一步不要跳,边界是调出来的,不是一次设好的。
第 15 到 21 天:加入第二个模型后端做兜底,模拟一次主力不可用,验证切换逻辑。
第 22 到 30 天:如果涉及硬件,从只读传感器开始(温度、开机状态),再逐步过渡到继电器这类有动作的输出。
整个过程的配置变更都应在一份 TOML 文件的版本控制里留下痕迹。ZeroClaw 部署的最好实践不是”一次配置完美”,而是”每一次改动都可追溯、可回滚”。单二进制的版本管理是文件级的,配合 git 管 config.toml,你就得到了一台”可复刻”的 Agent。
FAQ
ZeroClaw 真的只有 6.6MB 吗?会不会启动后体积变大?
6.6MB 指的是发行版二进制文件在磁盘上的体积,这个数字通常来自开启链接时优化、去除调试符号后的产物。启动后它不”解压”任何东西,所以不会有解释型运行时那种”启动后磁盘暴涨”的现象。运行时产生的额外体积主要来自日志、会话历史与缓存,它们都在 data_dir 下,可以设置轮转。
需要提醒的是,如果你从源码编译且关闭了优化、保留了调试符号,产物可能显著大于 6.6MB——这是正常的,说明你编译的是开发版本而不是发布版本。想要接近官方体积,请加上前面提到的 [profile.release] 优化段。另外,不同目标架构的二进制体积会有差异,ARM 版本往往略有不同。ZeroClaw 部署时建议先用 ls -lh 确认一下体积是否在合理区间,如果相差数倍,多半是编译配置问题。
TOML 配置里能不能同时写多个模型提供商?怎么切换?
可以,而且这是推荐做法。[provider] 下用 default 指定默认后端,其余以子表形式并存,例如 [provider.openai]、[provider.ollama]、[provider.deepseek]。每个子表的 kind、base_url、model 相互独立,互不干扰。
切换方式有两种:一是改 default 后重启服务;二是通过不同的渠道或不同的会话上下文指定后端(具体取决于所用版本的配置能力)。我实践中更常用”双实例”方案:一份配置面向公网渠道用云端强模型,另一份面向本地 CLI 用本地模型,两个 systemd 服务并存,互不影响。这种做法的好处是隔离彻底,坏处是多占一份常驻内存——不过在 ZeroClaw 的内存足迹下,这点开销可以忽略。TOML 的段落式结构让这种”一机多实例”的部署非常自然,只要两份配置的 data_dir 和端口不冲突即可。
四种沙箱到底该选哪个?新手最容易犯什么错?
给一个直接答案:macOS 用 Seatbelt;Linux 新内核用 Landlock;内核旧或不确定就用 Bubblewrap;只有需要跑不可信代码或多人共用时才上 Docker。
新手最容易犯的错有两个。第一是”沙箱配了,但挂载/白名单放得太宽”,比如把整个家目录都允许访问,等于没隔离。第二是”以为沙箱能兜底所有风险”,于是在 [agent] 里打开了 shell,又在沙箱里允许网络——这样提示词注入就能把数据外传。正确的组合是:最小路径 + 最小引脚 + 默认断网,按需放行。
还有一个细节:不同沙箱后端的”路径语义”不完全一样,workdir 之外是否可见系统库目录,在 Landlock 与 bwrap 下表现不同。建议每次更换后端,都用一条无害命令验证(比如 ls /etc 应该被拒绝),确认边界生效后再开放实际工具。
20 多家模型提供商,是不是每一家都要单独写适配器?
不需要。ZeroClaw 按协议族抽象接入层,绝大多数提供商兼容 OpenAI 协议,只需要 kind = "openai-compatible" 加上正确的 base_url 与 model 即可。这也是它能用一个精简二进制覆盖这么多提供商的原因:复用协议,而不是复制代码。
真正需要注意的不是”能不能接”,而是”接上之后能不能用好”。核心差异在工具调用(function calling)的支持程度上:有些模型协议兼容、但工具调用不稳定,表现为 Agent 反复说”我准备执行了”却不真正调用。这类问题不会在配置阶段暴露,只会在跑任务时出现。所以接入新提供商的验证清单应该包含”让它完成一次真实的工具调用”,而不只是”能回一句话”。另外,模型名、速率限制、上下文长度这三项也因提供商而异,建议在配置注释里记下每家的差异,避免以后排查时反复翻文档。ZeroClaw 部署的复杂度不在接线,而在选型。
GPIO 硬件功能安全吗?会不会把设备烧了?
风险是真实的,但可控。Three 层防护可以做到 99% 的安心:第一层是配置白名单,gpio_pins 和 allowed 只放开实际使用的引脚与总线;第二层是硬件隔离,继电器回路与控制信号之间加光耦,电源分开走;第三层是操作约束,涉及”输出动作”的引脚,不给公网渠道用,只在本地或受信任的私聊里开放。
另一个需要警惕的是模型幻觉导致的”非法写入”。模型可能编造一个引脚号或寄存器地址,所以硬件工具层面必须做严格校验:不在白名单里的引脚直接拒绝,不做”尽力而为”的容错。这一条在软件层就能挡住绝大部分误操作。
如果你的项目涉及强电(220V 以上的负载),请务必使用成品继电器模块与合格电源,不要在面包板上拼强电回路。GPIO 只负责弱电信号,这是底线。在这个前提下,把 ZeroClaw 部署到树莓派上做温湿度监控、灯光控制、串口消息中继,都是非常成熟且安全的玩法。
部署到内网、没有外网的时候怎么办?
这正是单二进制的擅长场景。你只需要在一台能上网的机器上把对应架构的发布包下载好,连同 .sha256 校验文件一起拷到 U 盘,拿到内网机器上解压安装即可,目标机不需要任何语言运行时、不需要包管理器联网、不需要私有源。整个”部署依赖”就是一个文件。
没有外网时,模型后端建议用本地的 Ollama 或 vLLM,它们在内网 base_url 指向 127.0.0.1 或内网 IP 即可。消息渠道也要换成内网可达的(自建 Webhook、企业微信私有化、或用 CLI 模式)。这时 TOML 五段配置里唯一的改动的就是 base_url 和渠道类型,其余全部不动。
需要注意的只有两点:一是内网机器的时间同步要正常,否则模型接口的签名类鉴权会失败;二是离线环境拿不到 bwrap 等依赖,如果选用 Bubblewrap 后端,要提前把安装包一并准备好。这也是为什么在内网场景我更推荐 Landlock——它是内核原生的,装完就没有任何外部依赖。ZeroClaw 部署到离线环境时,”零外部依赖”从一句口号变成了实打实的便利。








暂无评论内容