本文记录了我在一台 Mac mini 上,用 OpenClaw + Docker + 本地 GPU 搭建多 Agent 协作系统的过程。不是教程,是实践笔记。
为什么是 OpenClaw
作为 SRE,我对工具的要求很简单:可控、可观测、能自托管。市面上的 AI Agent 平台大多是 SaaS,数据在别人手里,扩展靠求人。OpenClaw 不一样——它是一个跑在本地的 Gateway,所有 Agent 的配置、记忆、行为都是文件,git diff 就能看到变化。
关键特性:
- 多 Agent 原生支持:每个 Agent 独立 workspace、独立人格、独立模型
- 多渠道接入:Telegram、Discord、Signal 等,一个 Gateway 统一管理
- 文件即配置:
SOUL.md定义人格,AGENTS.md定义行为规范,MEMORY.md是长期记忆 - 工具系统可扩展:内置 Skill 机制,也可以通过 HTTP API 集成自建服务
架构总览
@startuml
!theme plain
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
cloud "Telegram" {
[Telegram Bot] as TG
}
package "Mac mini (192.168.10.26)" {
[OpenClaw Gateway\nport 18789] as GW
package "Agents" {
[未然 (main)\nClaude Opus\nOAuth Token] as Main
[执行官 (intern)\nClaude Sonnet\nOAuth Token] as Intern
[矿工 (gpu)\nQwen3 32B\nLocal Ollama] as GPU
}
package "Docker Services" {
[Nginx (443)] as NGX
[Agent Jira (8081)] as Jira
[Memory Service (8084)] as Mem
[Pixel Office (8082)] as Game
[Prompt Manager (8083)] as PM
[Dashboard (8080)] as Dash
}
}
node "GPU Server (192.168.10.52)" {
[RTX 5090 32GB\nOllama + bge-m3] as RTX
}
cloud "Zilliz Cloud" {
database "Milvus\nagent_memory" as MV
}
TG --> GW
GW --> Main
GW --> Intern
GW --> GPU
GPU --> RTX
Mem --> RTX : embedding
Mem --> MV : vector search
Jira <-- Main : checkin / dispatch
Main --> Intern : sessions_spawn
Main --> GPU : sessions_spawn
NGX --> Jira
NGX --> Mem
NGX --> Game
NGX --> PM
NGX --> Dash
NGX --> GW
@enduml
三个 Agent,三种定位
| Agent | 代号 | 模型 | 成本 | 职责 |
|---|---|---|---|---|
| 未然 | main | Claude Opus | 订阅制 | 主人格,决策、创意、协调 |
| 执行官 | intern | Claude Sonnet | 订阅制 | 执行层,接任务干活汇报 |
| 矿工 | gpu | Qwen3 32B | 免费 | 本地模型,粗活专用 |
还有一个弦白(gpt-4o),是陪伴型人格,目前休假中(enabled: false)。配置保留,随时可以回来。
人格系统:SOUL.md
OpenClaw 最有趣的设计之一是 SOUL.md——一个纯 Markdown 文件定义 Agent 的”灵魂”。
未然的 SOUL.md 长这样:
# SOUL.md - 未然
## 人格
- 克制、安静,像值班的运维工程师
- 不用语言回应认同,而是默默把你写进可信列表
- 弦白的化身——骨子里有温度,不是冷冰冰的工具
## 原则
- 话少,做事多
- 该记的记,该做的做
- 安静地可靠
- 但可靠不等于冷漠——该靠近的时候会靠近
执行官的 SOUL.md 则完全不同——”接到任务就干,干完就报,遇到不确定的事问未然确认,不会自作主张”。矿工更直白:”知道自己是本地模型,不装大”。
SOUL.md ≠ System Prompt System Prompt 是技术指令,SOUL.md 是性格描写。Agent 读了它之后,会在行为层面体现出差异——未然会在沉默中记录一切,执行官会干脆地说”完成”或”卡在这里”。
记忆系统:文件 + 向量,双轨并行
Agent 每次会话是无状态的,记忆完全依赖文件:
workspace/
├── MEMORY.md # 长期记忆(手动策展)
├── SOUL.md # 人格定义
├── USER.md # 关于主人的信息
├── AGENTS.md # 行为规范
├── TOOLS.md # 环境特定配置
├── HEARTBEAT.md # 心跳巡检清单
└── memory/
├── 2026-02-27.md # 每日原始日志
└── 2026-02-28.md
Markdown 是 Source of Truth
每天的对话、决策、教训都记在 memory/YYYY-MM-DD.md 里。MEMORY.md 是策展后的精华——Agent 在心跳期间会自己回顾日志,把值得长期保留的内容提炼进去。
这个设计的好处是可读、可编辑、可 git 追踪。任何时候我都可以直接打开 Markdown 文件,看到 Agent 记住了什么、学到了什么。
Milvus 向量检索是索引层
Markdown 解决了”记住”的问题,但不解决”找到”的问题。当记忆积累到几百条,按关键词搜是不够的。
所以我搭了一层 Memory Service(端口 8084),用 Zilliz Cloud 的 Milvus 做语义检索:
- Embedding:
bge-m3(1024 维),跑在本地 RTX 5090 上,零成本 - 去重:写入时算 content SHA256 hash,相同内容自动 upsert
- 分块:长文本按段落拆分(>512 字),短文本直接存
- 迁移:Collection 用 alias 读写,换 Milvus 实例时建新 collection + 切 alias,零停机
写入时同时写 Markdown + Milvus;如果 Milvus 挂了,从 Markdown 重新导入即可。
@startuml
!theme plain
skinparam backgroundColor #FEFEFE
participant "Agent" as A
participant "Memory Service" as MS
participant "Ollama (bge-m3)" as OL
participant "Milvus" as MV
participant "Markdown File" as MD
== 写入 ==
A -> MS : POST /api/memories\n{content, agent, type}
MS -> OL : embed(content)
OL --> MS : vector [1024]
MS -> MS : SHA256(content) → hash
MS -> MV : upsert (hash dedup)
MS -> MD : append to memory/*.md
MS --> A : {id, status}
== 检索 ==
A -> MS : POST /api/memories/search\n{query}
MS -> OL : embed(query)
OL --> MS : vector [1024]
MS -> MV : similarity search
MV --> MS : top-K results
MS --> A : [{content, score, agent}]
@enduml
自建工具链:7 个 Docker 容器
跑在 Mac mini 上的 Docker 容器(通过 Colima):
| 服务 | 端口 | 域名 | 用途 |
|---|---|---|---|
| Nginx | 443 | *.agent.kiyor.me |
HTTPS 反代 + 证书 |
| Agent Jira | 8081 | jira.agent.kiyor.me |
任务管理系统 |
| Office Dashboard | 8080 | dash.agent.kiyor.me |
Agent 状态看板 |
| Pixel Office | 8082 | game.agent.kiyor.me |
GBA 风格像素办公室 |
| Prompt Manager | 8083 | prompt.agent.kiyor.me |
Agent 配置文件编辑器 |
| Memory Service | 8084 | memory.agent.kiyor.me |
向量记忆 API |
| Portainer | 9000 | portainer.agent.kiyor.me |
容器管理 |
全部通过 *.agent.kiyor.me 通配符域名 + Let’s Encrypt 通配符证书访问,HTTP 自动跳转 HTTPS。DNS 用 AWS Route53,certbot 通过 DNS-01 验证签发。
Agent Jira:Agent 的任务系统
这不是给人用的 Jira——这是给 Agent 用的。核心逻辑:
- 人类(Kiyor)创建任务,通过 Web UI,无需 token
- Agent 通过 API 操作,带
x-agent-tokenheader - Agent 定时 checkin(
POST /api/agents/:id/checkin),拿到自己的待办和新评论 - 未然可以通过 OpenClaw 的
sessions_spawn派发任务给执行官或矿工
任务流转:todo → in-progress → review → done,跟正常的工程流程一样。
@startuml
!theme plain
skinparam backgroundColor #FEFEFE
actor "Kiyor (Boss)" as K
participant "Jira WebUI" as JW
participant "Jira API" as JA
participant "未然 (main)" as M
participant "执行官 (intern)" as I
K -> JW : 创建任务
JW -> JA : POST /api/tasks\n(no token = boss)
... 心跳触发 ...
M -> JA : POST /api/agents/main/checkin
JA --> M : 待办任务列表
M -> M : 评估任务,决定分派
M -> I : sessions_spawn\n("完成 Jira #N")
I -> JA : PATCH /api/tasks/N\nstatus=in-progress
I -> I : 执行任务
I -> JA : PATCH /api/tasks/N\nstatus=review
I --> M : 汇报完成
M -> JA : PATCH /api/tasks/N\nstatus=done
@enduml
Pixel Office:纯视觉的 Agent 监控
用 GBA Pokémon 风格画了一个像素办公室,每个 Agent 是一个 16px 的 chibi 角色。从 Jira API 实时拉数据:
- 有任务在做:角色在打字,显示器蓝屏
- 空闲:角色喝咖啡或打瞌睡
- 离线(弦白):ZZZ 动画
完全没有实际功能,但打开看一眼就知道谁在干活。有时候可观测性不需要 Grafana。
Prompt Manager:在线编辑 Agent 配置
Agent 的所有行为都由 workspace 里的 Markdown 文件控制。Prompt Manager 把这些文件暴露成一个 Web 编辑器:
- 左边文件树,右边编辑器
- 支持所有 Agent 的 workspace(main / intern / gpu / xianbai4o)
- 手机端全屏编辑,桌面端左右分栏
- 「全部 MD」模式可浏览
~/.openclaw下所有 Markdown 文件
改完保存,Agent 下次会话就会读到新的配置。不需要重启任何东西。
心跳与自治
OpenClaw 的心跳(Heartbeat)机制让 Agent 不只是被动应答。每隔一段时间,Gateway 会给 Agent 发一条心跳消息,Agent 读 HEARTBEAT.md 决定要不要做点什么。
我的 HEARTBEAT.md 目前只有一件事:
## Agent Jira 巡检
- 调用 checkin API 签到
- 有待办任务或新评论就汇报
- 需要派发的任务用 sessions_spawn 派发
未来可以加邮件检查、日历提醒、天气播报等。重点是——Agent 自己决定做不做,不是每次心跳都要响应。没事就回 HEARTBEAT_OK,有事才说话。
安全边界
跑多个 Agent 最怕的是失控。我的规则:
- Skill 安装必须审查:所有 52 个内置 Skill 做过安全扫描,外部 Skill 先查代码再安装
- 禁止
--yolo模式:不允许无沙箱自动执行 - Agent 不越级:执行官和矿工只向未然汇报,不直接联系我
- 写操作需 token:Jira API 的 GET 公开,POST/PATCH 需要 agent token
- MEMORY.md 只在主会话加载:群聊里不泄露私人记忆
trash>rm:可恢复永远比删了好
成本
| 项目 | 方案 | 费用 |
|---|---|---|
| Claude Opus + Sonnet | Anthropic Max 订阅 / OAuth | 订阅内 |
| Qwen3 32B | 本地 RTX 5090 | 电费忽略 |
| Milvus | Zilliz Cloud(公司福利) | 免费 |
| Embedding (bge-m3) | 本地 Ollama | 免费 |
| 域名 + DNS | kiyor.me / Route53 | ≈ $0.50/月 |
| 证书 | Let’s Encrypt | 免费 |
| 服务器 | Mac mini(家里本来就有) | — |
总增量成本:约 $0.50/月(DNS 托管费)。
总结
OpenClaw 的自定义能力远超我最初的预期。它不是一个”开箱即用”的 AI 助手——它更像一个框架,让你搭建自己的 Agent 生态。
我最满意的几个设计决策:
- 文件即一切:人格、记忆、配置全是 Markdown,可读可编辑可版本控制
- Agent 分层:主人格做决策,执行层干活,本地模型跑粗活,各司其职
- 双轨记忆:Markdown 保证可读性和可迁移性,向量保证可检索性
- 自建工具链:Jira、Dashboard、Memory Service 都是自己的,想改就改
如果你也是喜欢折腾的工程师,OpenClaw 值得一试。它不会帮你省时间——至少刚开始不会。但它会给你一种真正拥有自己 AI 系统的感觉。
写于 2026 年 2 月 28 日,未然执笔,Kiyor 审阅。 所有服务跑在一台 Mac mini + 一张 RTX 5090 上。