# 一台 Mac Mini + 393 个自动化测试 = 企业级 AI 中间件

**— 一个人如何用开源工具搭建 98 分安全评分的 WhatsApp AI 助手**

![封面图1：安全评分 98/100 — 7 维度全量化](images/security_score.png)
![封面图2：393 个测试用例全部通过](images/full_regression.png)

---

> 这不是一篇教程，而是一份真实的工程日记。
>
> 一台 Mac Mini、两个开源大模型、393 个自动化测试、98/100 的安全评分 — 这是一个人用 3 个月做到的事情。本文完整记录了架构设计、安全体系、一次灾难性事故、以及从中提炼的可复制方法论。

---

## 一、先看数字

| 指标 | 数值 |
|------|------|
| 硬件成本 | 1 台 Mac Mini（Apple Silicon） |
| 大模型 | Qwen3-235B（文本）+ Qwen2.5-VL-72B（图片理解） |
| 自动化测试 | **393 个用例，13 个测试套件** |
| 安全评分 | **98/100（7 维度量化）** |
| 硬编码密钥 | **0 个** |
| 代码中真实手机号 | **0 个** |
| 发布前必须通过的检查项 | **19 项（100% 通过才允许推送）** |
| 生产环境体检项 | **14 项** |
| 从事故到全面恢复 | **< 30 分钟** |

如果这些数字让你觉得"这不可能是一个人做的" — 请继续看下去。关键不在于团队规模，而在于**你是否把安全交给了自动化机制，而不是人的记忆力**。

---

## 二、系统全貌：四层架构

```
用户 (WhatsApp)
    │
    ▼
┌─────────────────────────────────────────────────────┐
│  Gateway (:18789)     WhatsApp 接入 / 媒体存储      │
│  Tool Proxy (:5002)   策略过滤 / 图片注入 / 监控     │
│  Adapter (:5001)      认证 / 多模态路由 / Fallback   │
│  远程 GPU             Qwen3-235B + Qwen2.5-VL-72B   │
└─────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────┐
│  定时任务层    ArXiv / HN / 货代 / KB 摘要 / 趋势    │
│  监控层       三层健康探测 / 陈旧锁自愈 / 心跳金丝雀  │
│  DevOps 层    自动部署 / 漂移检测 / 全量回归测试      │
└─────────────────────────────────────────────────────┘
```

### 核心设计理念

**每一层只做一件事，每一层都可以独立测试。**

- **Gateway**（OpenClaw 开源框架）：负责 WhatsApp 协议接入和媒体文件存储
- **Tool Proxy**：策略过滤（24 个工具精简到 12 个）、图片 base64 注入、请求截断、token 监控
- **Adapter**：多 Provider 路由（文本 → Qwen3，图片 → VL 模型）、Fallback 降级（Qwen3 → Gemini）、智能路由（简单问题 → 快速模型）
- **远程 GPU**：纯算力层，我们不碰它的代码

### 智能路由：不是所有问题都需要 235B 参数

```python
def classify_complexity(messages):
    """纯函数：根据对话特征判断复杂度"""
    if len(messages) <= 2 and len(user_msg) < 100:
        return "simple"   # → 快速模型（低延迟、低成本）
    if has_tool_calls or has_multimodal:
        return "complex"  # → Qwen3-235B（强推理）
    return "complex"
```

一个简单的分类函数，节省了约 40% 的推理成本。**不需要 ML 模型来做路由 — 几个 if 语句就够了。**

---

## 三、一次事故改变了一切

2026 年 3 月 25 日，我执行了一行命令：

```bash
echo "0 9 * * 6 python3 ~/kb_trend.py" | crontab -
```

这行命令看起来人畜无害。但它**把 crontab 的全部 18 条定时任务替换成了只有 1 条**。

### "安静的死亡"

最可怕的不是系统 crash — crash 会有日志、有告警、有人注意到。最可怕的是**所有任务静默退出（exit 0），没有异常日志、没有告警、没有任何迹象**。

ArXiv 论文监控停了。HN 热帖抓取停了。KB 每日摘要停了。货代监控停了。备份停了。所有推送停了。

**而我直到第二天早上才发现。**

### 事后反思：5 类系统性缺陷

这次事故暴露的不只是一个操作失误，而是 5 类深层问题：

| # | 缺陷类别 | 具体表现 | 本质原因 |
|---|----------|---------|---------|
| 1 | **静默失败** | 锁获取失败时 `exit 0`（无日志） | 静默成功和静默失败外观相同 |
| 2 | **非原子写入** | `open("w") + json.dump`，crash 时半写损坏 | 多进程共享文件缺乏保护 |
| 3 | **监控循环依赖** | 告警通过 WhatsApp 推送，但 WhatsApp 依赖 Gateway | 监控系统依赖被监控对象 |
| 4 | **心跳盲区** | cron daemon 停止时无人知道 | 只检查 job 输出，不检查调度器本身 |
| 5 | **单点保护不足** | crontab 是所有任务的唯一调度源，无备份 | 关键组件缺乏冗余 |

从这次事故中提炼的三条铁律：

> **1. 任何 `exit 0` 的代码路径都应有日志** — 静默成功和静默失败外观相同
>
> **2. 共享状态文件必须原子写入** — 被多进程读写的文件一律 `tmp + replace`
>
> **3. 监控不能依赖被监控对象** — 告警通道必须有独立回退

---

## 四、安全体系：7 维度 98/100 分

事故之后，我花了一整天重建安全体系。不是零散地"加几个检查"，而是**系统性地设计了一套可量化、可验证、可持续改进的安全评分机制**。

```
🔐 安全评分：98/100

✅ 密钥管理      15/15  ██████████
✅ 测试门禁      15/15  ██████████
⚠️ 数据完整性    13/15  ████████░░
✅ 部署安全      15/15  ██████████
✅ 传输安全      15/15  ██████████
✅ 审计追踪      15/15  ██████████
✅ 可用性        10/10  ██████████
```

### 4.1 密钥管理（15/15）

```python
# ✅ 正确做法：环境变量
API_KEY = os.environ.get("REMOTE_API_KEY")

# ❌ 绝对禁止：硬编码
API_KEY = "sk-abc123..."  # 这行代码会被自动扫描拦截
```

每次推送前，自动扫描所有 `.py` 和 `.sh` 文件：

```bash
# 这些扫描必须全部为空才允许推送
grep -r "sk-[A-Za-z0-9]{20,}" . --include="*.py" --include="*.sh"
grep -r "+852[0-9]{8}" . --include="*.py" --include="*.sh"
```

### 4.2 测试门禁（15/15）

**393 个测试用例，100% 通过才允许推送。没有例外。**

```
📋 第一层：单元测试（13 个套件）
  🧪 proxy_filters    67 tests   策略过滤/截断/SSE
  🧪 cron_health      94 tests   锁/心跳/告警/完整性
  🧪 adapter          36 tests   路由/Fallback/认证
  🧪 status_update    33 tests   原子读写/嵌套字段/CRUD
  🧪 kb_business      44 tests   全业务逻辑/安全模式
  🧪 audit_log        19 tests   链式哈希/篡改检测
  ... 其他 7 个套件

📋 第二层：注册表 + 文档一致性
📋 第三层：安全扫描（密钥/手机号/危险模式/审计完整性）
📋 第四层：代码质量（覆盖率 + bandit 静态分析）
```

**一行命令，四层检查**：

```bash
bash full_regression.sh
# 输出：19 通过 / 0 失败 / 共 393 个测试用例
# ✅ 全量回归测试通过，可以安全推送
```

### 4.3 链式哈希审计日志（15/15）

这是我最得意的设计之一。

```json
{"ts":"2026-03-26T10:00:00","actor":"cron","action":"set",
 "target":"health.services","summary":"gw:200/px:200/ad:200",
 "prev":"0000000000000000","hash":"ff8b3e48226f158f"}

{"ts":"2026-03-26T10:01:00","actor":"claude_code","action":"add",
 "target":"recent_changes","summary":"V30.2 安全评分体系",
 "prev":"ff8b3e48226f158f","hash":"7c55d603b7ee14a1"}
```

**每条记录包含前一条的 SHA256 哈希**。如果有人篡改或删除了中间的某条记录，链就会断裂：

```python
def verify_chain():
    """校验审计日志完整性"""
    prev_hash = "0" * 16
    for entry in read_all_entries():
        if entry["prev"] != prev_hash:
            return False  # 链断裂 = 被篡改
        prev_hash = entry["hash"]
    return True
```

**每次运行 `full_regression.sh`，审计日志完整性是自动检查项之一。** 篡改 → 校验失败 → 禁止推送。

### 4.4 原子写入：消除"半写"风险

所有被多进程读写的文件（status.json、stats.json、meta.json）都使用同一个模式：

```python
# ❌ 危险：crash 时文件可能只写了一半
with open("status.json", "w") as f:
    json.dump(data, f)

# ✅ 安全：要么是完整的旧文件，要么是完整的新文件
tmp = "status.json.tmp"
with open(tmp, "w") as f:
    json.dump(data, f)
os.replace(tmp, "status.json")  # 原子操作
```

`os.replace()` 是操作系统级别的原子操作 — 不存在"半写"状态。

### 4.5 Cron 三层保护：同一个错误不会犯第二次

| 层 | 工具 | 作用 |
|----|------|------|
| 预防 | `crontab_safe.sh` | 自动备份 + 条目数验证 + 回滚保护 |
| 检测 | `auto_deploy.sh` | 每小时检查条目数，< 10 条立即告警 |
| 恢复 | `~/.crontab_backups/` | 每日自动备份，一键恢复 |

```bash
# ❌ 禁止：这就是导致事故的命令
echo "0 9 * * 6 ..." | crontab -

# ✅ 安全：自动备份 + 条目数验证
bash crontab_safe.sh add '0 9 * * 6 python3 ~/kb_trend.py'
# 输出：备份完成(18条) → 添加成功 → 验证通过(19条)
```

### 4.6 监控不能依赖被监控对象

```
                    ┌──────────────┐
                    │  WhatsApp    │ ← 告警推送
                    │  Gateway     │
                    └──────┬───────┘
                           │
                    如果 Gateway 挂了？
                    告警也发不出去了。
                           │
                    ┌──────▼───────┐
                    │ 本地回退      │
                    │ ~/.openclaw  │ ← 无论推送成功与否
                    │ _alerts.log  │    都写本地日志
                    └──────────────┘
```

**告警系统必须有一条不依赖被告警服务的通道。** 这是 V30 事故后最深刻的教训。

---

## 五、持续安全机制：分数只升不降

安全不是一次性工作。系统会腐烂，依赖会过期，新代码会引入新风险。

我的解法是**六重闭环**，每一层独立工作，任何一层检测到退化都会阻断：

```
┌─────────────────────────────────────────────────┐
│  ① 发布门禁：393 用例 100% 通过才允许推送         │
│  ② 安全评分：7 维度量化，写入共享状态可追踪        │
│  ③ 审计日志：每次写操作自动记录，链式哈希防篡改     │
│  ④ bandit：Python 静态安全分析                   │
│  ⑤ preflight：14 项生产环境体检                  │
│  ⑥ 漂移检测：每小时 md5 全量比对仓库 vs 运行时     │
└─────────────────────────────────────────────────┘
```

**关键设计原则**：

1. **安全是自动化的** — 不依赖人记住要做什么
2. **安全是量化的** — 98/100，不是"感觉安全"
3. **安全是不可绕过的** — 门禁 = `exit 1`
4. **安全是可追溯的** — 审计日志 = 谁在何时做了什么
5. **安全是单调递增的** — 新功能必须维持或提升分数

---

## 六、可复制的方法论

如果你也在做类似的事情（个人 AI 项目、小团队中间件、开源工具集成），以下是我认为最值得复制的实践：

### 6.1 一行命令验证一切

```bash
bash full_regression.sh
```

不需要记住"要跑哪些测试"、"要检查哪些文件"、"要扫描哪些模式"。**一行命令，全部搞定。** 如果你的项目需要超过一行命令来验证安全性，那就是不够自动化。

### 6.2 安全评分而非安全清单

清单的问题是"打勾就忘"。评分的好处是**趋势可追踪**：

```
V29:   75/100
V30:   85/100（+10：cron三层保护、原子写入）
V30.1: 90/100（+5：审计日志、KB完整性）
V30.2: 98/100（+8：安全评分体系、bandit、覆盖率）
```

每次迭代，分数必须 ≥ 上一版本。**这才是真正的"持续安全"。**

### 6.3 从事故中提取铁律而非补丁

事故后最容易犯的错误是"针对这个具体问题加一个检查"。正确的做法是**提取系统性原则**：

- 不是"给 crontab 加个备份" → 而是"**所有单点组件都必须有三层保护（预防/检测/恢复）**"
- 不是"给这个文件改成原子写入" → 而是"**所有被多进程读写的文件一律原子操作**"
- 不是"加个本地日志" → 而是"**监控系统的告警通道不能依赖被监控对象**"

**铁律比补丁持久。**

### 6.4 三合一宪法

这套系统之所以能持续进化，是因为它不是一个人在维护 — 它是三方协作的闭环：

```
用户（WhatsApp）
  │ 提供：专业领域深度、使用反馈、优先级决策
  │
  ├─── 共享状态：~/.kb/status.json ───┐
  │                                    │
Claude Code                       OpenClaw
  提供：高效设计与部署              提供：数据复利
  每次开工读状态                    （自动抓取、积累、推送）
  每次收工写变更                    每天生成知识摘要
```

**一个人做不到的事情，一个人 + AI + 自动化系统可以做到。**

---

## 七、写在最后

我不是安全专家，不是大厂工程师，不是运维老兵。

我只是一个**认真对待每次事故**的人。

crontab 被清空那天，我可以选择"手动恢复一下就算了"。但我选择了花一整天时间去追问：**为什么会发生？还有哪些类似的风险？如何确保不再发生？**

393 个测试用例不是一天写出来的，98 分安全评分不是一次达到的。它们是每次犯错后多问一句"下次怎么避免"的累积。

**安全不是目标，是习惯。**

**自动化不是效率工具，是安全基础设施。**

**一台 Mac Mini 就够了 — 只要你愿意认真对待它。**

---

> **技术栈**：OpenClaw（WhatsApp AI 框架）+ Qwen3-235B + Qwen2.5-VL-72B + Python + Bash + Mac Mini
>
> **开源地址**：[github.com/bisdom-cell/openclaw-model-bridge](https://github.com/bisdom-cell/openclaw-model-bridge)
>
> 如果这篇文章对你有帮助，欢迎点赞收藏。有问题可以评论区交流，我会逐一回复。
