7.0 KiB
WxAgent Control Plane
Go 1.23 控制面与 React 管理端。节点只主动出站连接,控制面不暴露节点端口。
本地启动
cd control-plane
npm --prefix web ci --no-audit --no-fund
npm --prefix web run build
go run ./cmd/wxagent-control-plane
启动前设置(单节点兼容写法):
export WXAGENT_NODE_ID=local-node
export WXAGENT_NODE_TOKEN='local-node-token'
export WXAGENT_WEB_USER=admin
export WXAGENT_WEB_PASSWORD='change-me'
多节点/多用户使用 JSON map:
export WXAGENT_NODE_TOKENS='{"node-a":"token-a","node-b":"token-b"}'
export WXAGENT_WEB_USERS='{"admin":"change-me","auditor":"read-only-password"}'
可选:WXAGENT_CONTROL_PLANE_ADDR(默认 127.0.0.1:8090)、WXAGENT_CONTROL_PLANE_DATA(默认 control-plane-data.json)。凭据可通过环境变量或 *_FILE Secret 文件读取,不写入控制面数据文件和日志。节点的 remoteConfigurationFile 仅用于读取预置配置;Windows Agent 不提供命令行修改配置,启动和本机配置必须通过双击 WxAgent.Tray.exe 后的“服务设置...”窗口完成。
生产控制面可直接启用 TLS 和节点 mTLS:
可选的 AI Provider 使用 OpenAI-compatible chat/completions 接口;密钥只从环境或 Secret 文件读取:
WXAGENT_AI_BASE_URL=https://api.openai.com/v1
WXAGENT_AI_API_KEY_FILE=/run/secrets/ai_api_key
WXAGENT_AI_MODEL=gpt-4o-mini
WXAGENT_AI_TIMEOUT=60s
WXAGENT_AI_SCHEDULER_INTERVAL=5s
WXAGENT_CONTROL_PLANE_TLS_CERT_FILE
WXAGENT_CONTROL_PLANE_TLS_KEY_FILE
WXAGENT_MTLS_CLIENT_CA_FILE
WXAGENT_MTLS_REQUIRE_NODE_CERT=true
WXAGENT_MTLS_REVOKED_CERTS_FILE
WXAGENT_NODE_TOKENS_FILE=/run/secrets/node_tokens
WXAGENT_WEB_USERS_FILE=/run/secrets/web_users
节点证书按证书原始 DER 的 SHA-256 指纹逐行写入撤销文件;文件读取失败时节点认证拒绝。控制面还提供 /readyz,并对数据文件使用单写入者锁、自动轮转备份和任务/事件/审计保留期限。生产示例见 compose.production.yml。
浏览器访问 http://127.0.0.1:8090/,登录后管理节点、任务、白名单事件和审计记录。生产部署必须使用 HTTPS、节点 mTLS 和外部 Secret 文件;本地 HTTP 仅用于显式的私有网络/loopback 集成测试。
远程只读查询使用同一持久化任务队列,返回 task_id 后通过 GET /v1/tasks/{task_id} 取结果:
POST /v1/reads/sessions { node_id, account_id, idempotency_key, limit?, offset? }
POST /v1/reads/contacts { node_id, account_id, idempotency_key, groups_only, contains?, limit?, offset? }
POST /v1/reads/messages { node_id, account_id, idempotency_key, chat_id, include_content?, limit?, offset? }
节点只返回本地已启用且 identityVerified 的白名单会话;未授权范围在节点读取前拒绝。chat_id 必须使用会话列表返回的稳定会话标识,消息结果是当前微信 UI 可见历史,不是数据库全量历史。联系人查询中的 chat_id 使用联系人数据库稳定 ID;所有响应仍受任务结果大小和分页上限约束。
AI 消息处理
Web 端的“AI 处理”页面用于创建消息处理流程。每个流程绑定一个或多个 node_id + account_id + chat_id + chat_type 目标,支持:
realtime:由节点已授权的实时消息事件触发;interval:由控制面按秒间隔创建read-messages只读任务;output_schema:根节点为object的 JSON Schema,AI 输出会在控制面再次校验;read_message_context:读取本次有限消息上下文;reply_text:在流程显式授权后,向来源群聊/私聊创建一个受控send-text任务。
相关接口:
GET /v1/ai/tools
GET /v1/ai/flows
POST /v1/ai/flows
GET /v1/ai/flows/{flow_id}
PUT /v1/ai/flows/{flow_id}
DELETE /v1/ai/flows/{flow_id}
POST /v1/ai/flows/{flow_id}/run
GET /v1/ai/runs?flow_id=&limit=
AI 处理仍受节点本地白名单约束。定时读取的消息范围与普通 read-messages 相同,只是当前微信 UI 可见历史,不是数据库全量历史。AI Provider 未配置时流程可以保存,但执行记录会明确失败,不会把消息内容写入普通日志。
验证
cd control-plane
go test ./...
go vet ./...
cd ../control-plane/web
npm run build
cd ../..
./scripts/remote-control-smoke.sh
remote-control-smoke.sh 会启动一次临时控制面,运行 .NET 节点协议客户端,验证注册、心跳、任务租约、幂等、结果回传和白名单拒绝;不会操作真实微信联系人。
控制面并发/读取任务基线(使用已注册的测试节点,不执行写任务):
WXAGENT_SCALE_WEB_PASSWORD='<test-password>' \
scripts/control-plane-scale-smoke.py --base-url http://127.0.0.1:8090 \
--node-id node-a --account-id account-a --requests 100 --workers 10
control-plane-data.sh backup/restore 用于停机前后的手工备份和原子恢复;自动备份由 Store 按 WXAGENT_CONTROL_PLANE_BACKUP_INTERVAL(默认 5 分钟)产生。当前 JSON 存储使用 active/passive 单写锁,不支持 active-active 多实例共享写入。
Windows 手工验收
- 在已登录且未锁定的微信桌面会话中双击
WxAgent.Tray.exe;首次运行或托盘菜单“服务设置...”打开后,配置本机监听、凭据、验证模式和自动锁屏。 - 不使用
WxAgent.Host serve、--config、remote auth set、remote reporting enable/allow或其他命令行配置。WxAgent.Host doctor、inspect-ui、remote ... show/probe仅用于只读诊断。 - 远程配置若已由部署系统预置,托盘服务读取
remoteConfigurationFile;当前不通过命令行修改远程地址、Token、节点 ID 或 reporting 白名单。 - 仅使用文件传输助手、
Hao 豪、吉祥三宝、消息测试专用群组做发送/接收验证:先确认目标账号、稳定 chat ID 和文本;Web/HTTP/MCP 写操作仍必须通过现有确认门禁。 - 在控制面取消任务并验证节点不执行;断开网络后恢复,确认未完成副作用任务显示
ResultUnconfirmed,不会自动重放。
未解锁的 Session 0、昵称、PID、窗口句柄和未确认的运行时身份都应视为验收失败;手工验收不得改写微信数据库或绕过安全机制。
容器镜像
.gitea/workflows/build-web-image.yml 会构建并推送 git.ipao.vip/<owner>/<repo> 镜像:主分支额外更新 latest,v* 标签额外更新对应版本标签。请在 Gitea 账号级 Secrets 配置 REGISTRY_TOKEN;登录用户名使用仓库所有者。
生产环境不要提交 compose.production.yml 所引用的 secrets/ 文件。将节点 Token map、Web 用户 map、TLS 私钥、客户端 CA 和撤销指纹列表放入外部 Secret 管理或受 ACL 保护的部署目录,再运行 docker compose -f compose.production.yml up -d。证书泄露时可用 scripts/revoke-client-certificate.sh 更新指纹列表,并重建 Docker Secret 挂载的容器。