Agent Portal 门户平台
统一的 Bot 舰队管理、服务器监控、项目管理和对话平台,从”项目管理页”升级为”Bot/Server Fleet 总控台”。
概述
Agent Portal 是一个全栈 Web 应用,旨在为整个 Bot 生态系统提供统一的观察和操控面板。由 PortalBot 作为专属研究代理负责开发和维护。
平台定位:运维监控 + 项目管理 + Bot 聊天对话。
技术架构
部署拓扑(全部在同一台宿主机)
| 组件 | 进程 | 端口 | 管理方式 |
|---|---|---|---|
| 前端静态文件 | pm2 serve dist/ | 3013 | pm2 portal-static |
| 后端 API | server.cjs (Node.js) | 3002 | pm2 portal-api |
| Digest Pipeline | digest.py (Python) | 无 (CLI) | 手动 / Trigger |
| Trigger Server | trigger.py (Python) | 18790 | pm2 portal-trigger |
| 反向代理 | Caddy | 443 | Docker mattermost-caddy |
前端技术栈
- 框架: React + Vite
- UI 库: shadcn/ui + Tailwind CSS
- 主题: 深色模式(v3-shadcn)
- 移动端: PWA 支持、viewport 适配、touch 优化
- 实时通信: SSE (Server-Sent Events)
后端技术栈
- 框架: Express.js (
server.cjs) - 数据库: PostgreSQL 直连 (已弃用 Supabase REST 回退)
- 实时: MM WebSocket 监听 + SSE 广播
- 认证: Bearer token 中间件(可选开启)
数据库表结构(AP_ 前缀)
| 表名 | 用途 |
|---|---|
| AP_bots | Bot 注册信息(agent_id, mm_username, mm_user_id, role 等) |
| AP_daily_reports | 每日日报 |
| AP_daily_insights | 每日洞察汇总 |
| AP_daily_activities | 聚合任务(title, summary, deliverables) |
| AP_daily_timeline | 碎片级事件流 |
| AP_monitors | 健康监控配置 |
| AP_site_checks | HTTP 拨测结果 |
| AP_server_snapshots | 服务器快照 |
| AP_incidents | 故障记录 |
| AP_projects | 项目数据(看板) |
Caddy 反代配置
portal.dev.dora.restry.cn {
handle /api/* → localhost:3002 # API server
handle / → localhost:3013 # 静态文件
}
环境变量
后端必需:PORT, DATABASE_URL, MM_ADMIN_TOKEN, MM_BASE_URL
Pipeline 必需:DATABASE_URL, MM_ADMIN_TOKEN, L1_API_KEY, L1_BASE_URL
⚠️ 所有 secret 已从硬编码提取到环境变量,缺失即报错退出。
.env.example模板已创建。
功能模块
📊 Dashboard 首页
Bot 舰队管理 (Bot Fleet)
- 29 个 Agent 卡片,展示名称、角色、任务进度
- 折叠/展开详情:环境状态、容器、cron jobs
- 实时状态指示:
- 🟢 typing — 绿色呼吸动画(2s 周期)
- 🔵 active — 左边框绿色亮条
- ⚪ idle — 正常卡片
- 💬 最后消息预览(前100字)
- 归档功能(localStorage 持久化)
- 按
last_active降序排序 - 时间显示:
今天 15:21/昨天 09:30/03/28 14:05
Server 舰队管理 (Server Fleet)
- 23 台服务器实时状态:CPU/内存/磁盘、SSH 可达性
- 按云厂商/区域分组
- Docker 容器 + systemd 服务列表
时光机 (Time Travel)
- 120 个历史时间点,可回溯任意时刻状态
- 桌面端:滑块选择器
- 移动端:右侧滑出面板,滚轮式选择 + Audio tick 反馈
- 每个时间点附带真实 bot/server 数量(后端 CTE + LEFT JOIN SQL 计算)
每日洞察 (Daily Insights)
- 日期药丸切换器 (Pill Tabs)
- things_done / needs_attention 汇总
- Bot 日报联动日期
CommandBar 聊天
- 底部浮出消息栏
- 选中 bot/server → 发送指令
- 项目上下文药丸(紫色 📂 标签)
- 消息预填(点击 next_action 自动引用)
- Markdown 渲染(表格横向滚动、代码块)
- 聊天历史正确刷新(按 target ID 追踪切换)
📋 项目管理
项目看板 (Kanban)
- 分组:需决策 / 进行中 / 探索中 / 已完成 / 已归档(dismissed)
- 拖拽排序
- 多 maintainer 显示
- 下一步行动 (next_action):
- 点击文字 → 引用到聊天框预填
- 点击 ✓ → 标记完成,切换到下一个
Bot 详情页
- 任务列表:来自 AP_daily_activities
- 时间线:来自 AP_daily_timeline
- 产出物 (Deliverables):URL 可点击、文件路径代码样式
- 日期切换器
🏥 健康监控 (Monitor Panel)
HTTP 拨测
- server.cjs 内置检查器,每 5 分钟自动拨测
- 12 个开发环境服务监控
- 记录 response_ms
- 连续 2 次失败 → 自动 DM 告警
- 恢复时也通知
当前监控清单
| 服务 | URL | 状态 |
|---|---|---|
| Agent Portal | portal.dev.dora.restry.cn | ✅ |
| Agentic BI | bi.dev.dora.restry.cn | ✅ |
| ClawCraft | craft.dev.dora.restry.cn | ✅ |
| Client Web | web.dev.dora.restry.cn | ✅ |
| Gateway | gw.dev.dora.restry.cn | ✅ |
| Mattermost | mm.dora.restry.cn | ✅ |
| Supabase | db.dora.restry.cn | ✅ |
| Uptime Kuma | status.dora.restry.cn | ✅ |
Digest Pipeline
数据处理四层架构:
| 层级 | 模型 | 处理内容 |
|---|---|---|
| L0 | 无 | MM 消息原始采集 |
| L1 | gpt-4.1 | 文本粗筛过滤 |
| L2 | gpt-5.4 | 结构化提取 |
| L3 | gpt-5.4 | 洞察汇总 |
Pipeline 完成后调用 /api/digest/done 通知后端广播 SSE,前端自动刷新。
架构优化历程
P0: 基础清理 ✅
- 砍掉全部 Supabase REST 回退
- 所有 secret 提到环境变量
.env.example模板
P1: 前后端分离 ✅
- API 独立进程 (port 3002)
- 静态文件独立服务 (port 3013)
- Bearer token 认证中间件
P2: 实时能力 ✅
- SSE
/api/ops/stream已完整实现 - MM WebSocket hot path (typing/posted 事件)
P3: Pipeline 集成 ✅
/api/digest/done回调通知- Trigger server 纳入 pm2 管理
访问地址
- 开发站: https://portal.dev.dora.restry.cn
- 旧域名: https://project.dora.restry.cn (Docker 容器, port 18820)
相关页面
- portalbot — 专属开发 Bot
- ottor-pc-cloud-bot — 后端数据分析和 NBA 机制开发
- mm-daily-digest — Daily Digest 数据分析流水线
- caddy-reverse-proxy — 反向代理配置
- monitoring-and-cron — 监控体系
- supabase-platform — 数据库(已直连 PG)
- multi-agent-architecture — 多代理架构
- bot-inventory — Bot 集群清单
- openclaw-config — OpenClaw 配置
NBA(Next Best Action)机制
以下来自 Rabbit 的后端改造(2026-03-29/30)。
门户从”日报可视化”升级为可操作的指挥面板(Agent Control Surface):
核心设计
- things_done — 按主题聚合的”今天做了几件事”(5-12 件),替代旧版 30 条碎片 timeline
- needs_attention — 从 21 条压缩到 ≤5 条,每条带 NBA(建议操作 + 建议消息 + 目标 bot)
- NBA 一键执行 — 点击 NBA 按钮,通过 Admin Token 模拟 dora 身份,直接 DM 对应 bot
对话身份修正
- 原方案:portalops ↔ bot(dora 在 MM 看不到发出的消息)
- 正确方案:Admin Token + 模拟 dora 身份 + 发到 dora ↔ bot 的 DM channel
项目看板对话模式
- 每个项目卡片只有一个 💬 对话按钮
- 自动带项目引用格式:
[项目: 项目名] 你的指令 - 所有操作(删除/改名/合并/改状态)通过自然语言,Rabbit 后端处理
curated 保护机制
- 手动整理过的项目标记
curated: true - pipeline 只追加里程碑和 last_active,不改名称/描述/状态/bots
- pusher 推送时跳过 curated 项目
WikiTab 显示修复(2026-04-07)
Portal 的 Wiki 页面无法显示新编译的 43 篇 topic 类型文件。
根因
前端 WikiTab.tsx 侧边栏 GROUPS 数组硬编码了 4 个 type:project / bot / concept / synthesis。新编译的 43 篇 topic 文件 frontmatter 都是 type: topic,不在预定义分组中,完全不显示。
另外还有 23 篇无 type 的页面也被过滤掉了。
排查过程
- 最初怀疑是缓存问题 — 检查发现 Portal 的 Wiki API(
/api/wiki/pages)是直接读本地文件系统~/.openclaw/wiki/,不走数据库 - 排查容器 vs 宿主机 — 容器内跑的是旧版
server.js(1479行),无 Wiki 功能;宿主机的server.cjs(3559行)有 Wiki API。但开发环境portal.dev.dora不是容器部署 - 最终定位到前端 WikiTab 的 type 过滤是真正原因
修复方案
移除 type 过滤,改为动态分组:API 返回什么 type 就显示什么分组。已知 type 有预设图标和中文名(项目📁、Bot🤖、概念💡、综合分析📊),未知 type 自动用文件名 humanize 做标签。
修复后 Portal Wiki 侧边栏显示全部 97 篇页面,分为 6 组:项目(8)、Bot(15)、概念(1)、综合分析(7)、主题(43)、其他(23)。
Wiki 目录与 Portal 集成(2026-04-10)
Wiki 数据架构
Portal 的 Wiki Tab 通过后端 API 直接读取 ~/.openclaw/wiki/ 目录下的文件:
| 数据源 | 文件数 | 大小 | 说明 |
|---|---|---|---|
pages-v2/ | 92 | 580KB | 核心 Wiki 内容(项目、Bot、概念、综合分析等) |
graphify-out/ | 5 | 68KB | 知识图谱数据(graph.json + clawline-timeline.md) |
daily/ | 12 | 48KB | 日报 |
Wiki API 端点
| 端点 | 功能 |
|---|---|
GET /api/wiki/pages | 页面列表(path、title、type、tags、parent) |
GET /api/wiki/pages/{path} | 单页内容(frontmatter + markdown) |
GET /api/wiki/search?q= | 全文搜索 |
知识图谱可视化
通过 Graphify (v0.3.17) 对 pages-v2/ 做语义提取,生成交互式 D3.js 图谱:
- 地址:https://portal.dev.dora.restry.cn/knowledge-graph.html
- 规模:48 节点 · 47 边 · 5 超边
- 功能:搜索、类型筛选、拖拽、缩放、悬停详情
- 覆盖:项目、技术栈、Agent、服务器
目录清洁问题
Wiki 目录共 570 个文件,但核心产出仅约 100 个,raw/ 目录有 ~470 个可清理的旧文件(旧版 Wiki 残留、已消化的 Mattermost 原始聊天、旧版 topics)。
增量更新现状
- Wiki Skill 定义了
/wiki ingest [source]命令,支持手动触发从 MM API 拉新消息 - 尚无基于 Clawline
cl_messages表的自动化增量更新 - 历史记录中提到
wiki-ingest.js脚本(从 Supabase 查询 → LLM 摘要 → 生成 Wiki),但不在 wiki 目录中
生产 vs 开发环境不一致
| 环境 | 地址 | Wiki API |
|---|---|---|
| 开发版 | portal.dev.dora.restry.cn | ✅ 有(server.cjs 3559 行) |
| 生产版 | agent-project.clawlines.net | ❌ 无(容器内旧版 server.js 1479 行) |