06 · 技术资料:服务器 Agent 层(P6)
#🚨 开工前先读这一条
2026-07-30 深夜的实地勘察发现:东京 VPS(tky,66.42.32.208)此刻正处于一次进行中的高负载 / IO 阻塞事件,不是历史问题,是活的故障。
实测证据(勘察时 + 写文档时二次确认):
load average: 107.76 / 101.55 / 71.36 ← 8 核机器,正常应 < 8
%steal 94.46, %idle 0.34 ← CPU 几乎被虚拟化层抢走
vmstat 的 b 态进程数:104 / 62 ← 正常应接近 0
swap 从 0 涨到 5.6% 并持续上涨
systemd-journald 因 watchdog 超时被 ABRT 杀死,restart counter = 3
<HOME>/monitor/sysmon.log 从 22:15 起断更 ← 监控脚本自己被卡死了
勘察时两条只读的 ps aux 卡死 10 分钟无输出这套特征和历史上那次 inode_switch_wbs kworker 风暴(触发条件:密集短连接 SSH)高度吻合。
#因此 P6 的第一件事不是施工,是体检
# 健康门:必须全部满足才允许进入 P6 的任何新增操作
ssh <VPS> 'cat /proc/loadavg; tail -3 <HOME>/monitor/sysmon.log; systemctl is-active systemd-journald'| 条件 | 门槛 |
|---|---|
| 1 分钟 load average | < 8 |
<HOME>/monitor/sysmon.log |
最近 10 分钟内有新行(监控活着) |
systemd-journald |
active,且没有持续重启 |
任一条不满足 → P6 整体降级:
- ⛔ 不做任何新增部署(连建 profile 都不做)
- 只做一次只读采证(下面 §1 的命令清单),把输出存进
docs/night/vps-health.md - 在
blockers.md顶部写一条🚨 需要人类立即处理:东京 VPS 负载风暴 - 转去做别的阶段或收尾
⚠️ 无论健康与否,全程都要控制 SSH 连接次数。 密集短连接正是历史触发条件。
✅ 正确做法:一次 SSH 跑一串命令(用 && 或 heredoc 拼起来)。
⛔ 错误做法:每条命令开一个新 ssh <VPS> '...'。
#1. 只读采证命令(一次连接跑完)
ssh <VPS> 'bash -s' <<'EOF'
echo "===== 负载 ====="; cat /proc/loadavg; uptime
echo "===== 内存 ====="; free -h
echo "===== 磁盘 ====="; df -h /
echo "===== 监控最近 10 行 ====="; tail -10 <HOME>/monitor/sysmon.log
echo "===== journald ====="; systemctl is-active systemd-journald
echo "===== 端口 ====="; ss -tlnp 2>/dev/null | head -40
echo "===== docker ====="; docker ps --format '{{.Names}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}' 2>/dev/null
echo "===== 运行中的自定义服务 ====="; systemctl list-units --type=service --state=running --no-pager --no-legend | head -40
echo "===== hermes 目录结构 ====="; find <HOME>/.hermes -maxdepth 2 -type d 2>/dev/null
echo "===== hermes 帮助 ====="; timeout 30 /usr/local/lib/hermes-agent/venv/bin/python -m hermes_cli.main --help 2>&1 | head -60
echo "===== nginx server_name ====="; nginx -T 2>/dev/null | grep -E 'server_name|listen ' | head -30
echo "===== env 文件位置(只列路径) ====="; find /root -maxdepth 3 -name "*.env" -o -maxdepth 3 -name ".env" 2>/dev/null
EOF把输出原样存进 docs/night/vps-health.md。⛔ 输出里若含任何密钥值,必须打码后再落盘。
#2. 现场已知事实(已勘察确认,不用重查)
#2.1 机器
agent-tky-01,Ubuntu 24.04.4 LTS,内核 6.8.0-136- 8 核 / 62G 内存 / 450G 盘(已用 97G,余 335G)
- 有 Docker 在跑(
/var/lib/docker/rootfs/overlayfs/*多个 overlay 挂载)→ Telegram bot / LINE bot 很可能是 Docker 容器,不在 systemd unit 里
#2.2 systemd 自定义服务清单(⛔ 全部碰不得)
| unit | 说明 | 级别 |
|---|---|---|
hermes-gateway.service |
Hermes 网关本体 | 🔴 生产核心 |
feishu-bot.service |
拉斐尔飞书 bot | 🔴 生产核心 |
grok-shim.service |
grok-4.5 反代,Hermes 大脑依赖 | 🔴 生产核心 |
ollama.service |
本地 LLM,拉斐尔依赖 | 🔴 依赖链上 |
ashare-auto-git.service |
读 <HOME>/.hermes/.env |
🟡 别碰 |
ashare-recommend.service |
🟡 别碰 | |
actions.runner.LeoLee0812-brain-daily... |
自建 CI runner | 🟡 别碰 |
scribe-api.service / scribe-worker@.service |
白板视频渲染 | 🟡 别碰 |
n8n.service / redis.service |
🟡 别碰 | |
novnc.service / vncserver.service |
图形桌面 | 🟢 辅助 |
tky-boot-alert.service |
开机告警 | 🟢 辅助 |
#2.3 Hermes
# /etc/systemd/system/hermes-gateway.service(已读)
ExecStart=/usr/local/lib/hermes-agent/venv/bin/python -m hermes_cli.main gateway run
WorkingDirectory=<HOME>/.hermes
Environment="HERMES_HOME=<HOME>/.hermes"
ExecStopPost=-/usr/local/lib/hermes-agent/venv/bin/python -m gateway.cgroup_cleanup
Restart=always- 装在
/usr/local/lib/hermes-agent/(Python venv),HERMES_HOME =<HOME>/.hermes ExecStopPost调gateway.cgroup_cleanup→ Hermes 内部用 cgroup 管子进程,多 profile 可能自带资源边界(推测,未证实)- ⚠️ 最大信息缺口:
-p <profile>的确切语义没验证到。上一版方案里写的hermes profile create emp_wang --clone命令未经实证,⛔ 不要当成事实照抄。 - P6 第一步必须先跑
hermes_cli.main --help拿到真实的子命令,再决定怎么建 profile。
#2.4 拉斐尔飞书 bot(新 bot 照抄的范式)
# /etc/systemd/system/feishu-bot.service(已读)
Environment=BOT_BACKEND=hermes
Environment=OLLAMA_MODEL=qwen2.5:3b
ExecStart=/bin/bash -c 'lark-cli event consume im.message.receive_v1 --as bot < <(tail -f /dev/null) | /usr/bin/python3 <HOME>/night-run/bot_bridge.py'
Restart=always- 接入方式:长连接,但不是自己写 WebSocket,而是用
lark-cli event consume输出 NDJSON,管道给<HOME>/night-run/bot_bridge.py处理 - 新 bot 照抄这个结构:另起一份 unit 文件,换成新 App 的凭据和新的 bridge 脚本。⛔ 不要改
feishu-bot.service
#2.5 🔴 顺手发现的安全隐患
feishu-bot.service 里把 DEEPSEEK_API_KEY 明文写在 Environment= 行(不是 EnvironmentFile=)。任何能跑 systemctl cat feishu-bot 的人都能看到明文。
今晚 ⛔ 不要修它(改 unit + restart 会重启生产 bot,且机器正在风暴中)。写进 blockers.md 作为「明天建议人类处理」的一条。
#2.6 密钥文件
<HOME>/.hermes/.env(600)—— 被多个服务共读:ashare-auto-git.service明确EnvironmentFile=-引用它,Hermes 本体大概率也读它<HOME>/monitor/monitor.env(600)—— 监控阈值 + 飞书 webhook- ⛔ 绝对不要覆盖、不要重写这两个文件。 只允许追加,且追加前必须备份。
#3. 如果健康门通过 —— 增量施工步骤
总原则:只新增,不修改,不删除。每一步做完停下来看一眼负载。
#步骤 0 · 备份(不做这步不许往下走)
ssh <VPS> 'D=<HOME>/backup-baton-$(date +%Y%m%d-%H%M) && mkdir -p $D && \
cp -a <HOME>/.hermes/.env $D/hermes.env.bak && \
cp -a /etc/systemd/system/feishu-bot.service $D/ && \
cp -a /etc/systemd/system/hermes-gateway.service $D/ && \
chmod -R 600 $D && ls -la $D'#步骤 1 · 摸清 Hermes 的真实 profile 机制
ssh <VPS> 'timeout 60 /usr/local/lib/hermes-agent/venv/bin/python -m hermes_cli.main --help 2>&1 | head -80; \
echo "---"; find <HOME>/.hermes -maxdepth 2 -type d'按 --help 的真实输出决定后面怎么做。 ⛔ 不要凭上一版文档里的命令硬试。
拿不到帮助 / 命令挂起 → 记 blocker,P6 到此为止。
#步骤 2 · 先建 1 个 profile,观察
只建 emp_wang 一个。建完:
1. 跑一次简单提问,确认能出结果
2. 等 5 分钟,再看 load average 和 sysmon.log
3. load 没涨、监控正常 → 才建第二个、第三个⛔ 禁止一次性把 3 个 profile 全建出来。 这台机器已经证明过自己会失控。
#步骤 3 · 每个 profile 写入 SOUL 铁律(AC-8.2.3)
这是整个 Agent 层最关键的一段。历史教训(raphael-lore 那次):即使强制预加载 skill,模型依然会跳过检索、凭训练记忆自信编造,连人名都编得很像。
必须写成和"铁律"同级的强制条款:
## 铁律(不可违背)
涉及任何客户、报价、合同、供应商、交接的问题,**必须先执行 baton-kb 检索**。
回答必须带出处(文件名 + 页码)。
**绝对禁止凭记忆编造。** 检索不到就明确说"我的资料里没有"。
涉及交接来的内容,必须标注「来源:<前任> 交接,<日期>」。
你只知道自己资料库里的东西。别人的资料你看不到,也不许猜。⚠️ Hermes 的 MEMORY.md 有注入上限约 2200 字符,只放人设和指针,别塞知识。知识走 skill 反向 HTTP 调 Vercel 的 /api/search。
#步骤 4 · 瘦服务(agentd)
- 只绑
127.0.0.1,⛔ 不要暴露到公网 - 端口必须先看
ss -tlnp再选,⛔ 不要硬编码(8000-8100 段常被占) - 每员工一个队列:不同人并行,同一人串行(Hermes 是有状态会话,同一 profile 并发会互相踩上下文 —— 这是踩过的坑)
- systemd unit 必须加资源限制(现有 unit 都没加,这是这台机器失控的原因之一):
MemoryMax=2G CPUQuota=100%
#步骤 5 · 飞书新应用(若凭据可用)
- ⚠️ 必须是新建的独立 App ID。复用拉斐尔的应用会两边抢答。
- ✅ 已确认:不同 App ID 的长连接各收各的事件,不会抢消息(飞书事件订阅按应用维度隔离)
- 新起一份 unit,照抄
feishu-bot.service的结构,⛔ 不要改原文件 - 凭据要人工在飞书后台创建 → 拿不到就跳过,记 blocker(AC-8.3.3)
#4. P6 的红线(再列一遍,因为最容易在深夜手滑)
⛔ rm / rm -rf —— 任何情况下都不许
⛔ systemctl stop | disable | mask —— 任何现有服务
⛔ pip uninstall / apt remove
⛔ 覆盖 <HOME>/.hermes/.env 或任何现有 .env(只许追加,且先备份)
⛔ 修改任何现有的 systemd unit 文件
⛔ kill 任何不是你自己刚起的进程
⛔ 删掉 <HOME>/.hermes 或 mv 走它
⛔ 密集短连接 SSH(一次连接跑一串命令)
⛔ 一次性拉起多个新进程如果你怀疑自己已经影响了现有服务:立刻停手 → 用备份恢复 → 在 blockers.md 最顶部写 🚨 需要人类立即处理 + 完整现场记录 → 只做验收包和邮件,别的什么都别做。
#5. P6 的降级路径(很可能会用上)
| 情况 | 降级到 |
|---|---|
| 机器仍在风暴中 | 只采证 + 写报告,AC-8.* 全部标 SKIPPED |
hermes --help 拿不到 / profile 机制不明 |
只写一份「明天照着做的操作单」,AC-8.2.* 标 BLOCKED |
| 飞书凭据拿不到 | 跳过飞书,只做命令行验证(AC-8.3.2 标 SKIPPED,这是 AC 里明确允许的) |
| 时间不够(已过 T+8:30) | 直接放弃 P6,去做 P7 验收包。这是总纲 §3.2 里第一个该砍的阶段 |
P6 全部跳过不算失败。 服务器安全 > 功能进度。明早人类看到一份诚实的「机器在风暴中,我没敢动」的报告,比看到一台被搞坏的服务器好一万倍。
来源:沉淀/03-项目方案与交接/接棒-通宵施工包-20260731/06-技术资料-服务器Agent层.md(整理于 2026-08-18)