02 · 架构与组件

全景

┌─────────────── Android 平板(与企微同机)───────────────┐
│  企业微信 App  ←无障碍事件/点击→  SevFishComVBot App          │
│                                    ├ Service  循环:读会话/读消息/执行指令 │
│                                    ├ Observer 监听:无障碍窗口变化        │
│                                    └ WeworkRoomUtil / WeworkOperationImpl: 定位与操作 │
└───────────────────────────┬──────────────────────────────────┘
                            │ WebSocket (JSON)  ws://host:8765/webserver/wework/{client_id}
┌───────────────────────────┴──────────────────────────────────┐
│  FastAPI 服务端 (uvicorn, 8765)                                │
│                                                                │
│  routes/    websocket 接入 · admin 后台 · api · ext 客户控制台 │
│             workflows / tasks / memory / knowledge / tables …  │
│  services/  aivbot_service  连接注册表 + 事件分发 + 自动回复 v2  │
│             agent_service   LLM 调用 + 工具构建/执行/授权/审计  │
│             task_service    定时 + 条件触发                     │
│             memory_service  长期记忆                            │
│             workflow_engine 节点执行                            │
│             knowledge/table/group/robot/skill/ext_user/provision│
│  models/    agent workflow task robot group message table      │
└───────┬───────────────────────────────┬────────────────────────┘
        │                               │
   MySQL 8(唯一持久层)            LLM / Embedding(OpenAI 兼容 HTTP)

图里以平板为例:企微的平板端和手机端能同时在线,机器人跑平板不会挤掉本人手机;用手机当执行端也能跑,代价是那台手机的企微长期占用登录(见 01-项目介绍)。

服务端:14 个 service,各管一段

service职责什么时候碰它
aivbot_service★ 与客户端通信的唯一核心:维护 active_connections 注册表、send_command 下发指令、事件订阅、自动回复 v2 引擎(合并窗口、设备级并发限额)协议、收发、回复触发
agent_service★ LLM 调用、system prompt 拼装、工具定义与执行、逐项授权校验、tool_call_audit 落库智能体行为、工具、权限
workflow_engine / workflow_service节点执行器 / 工作流 CRUD 与运行日志工作流
task_servicecron/interval/once/offset 调度 + 条件触发(事件流 → 轻量信号 → 共享轮询三层)任务
memory_service长期记忆:客户、别名自愈、事实去重、注入拼装、护栏记忆
memory_cleanup_service定时让模型压缩合并智能体写入的记忆(只动 source='agent')记忆清理
knowledge_service知识库:切块、向量化(本地哈希或 embedding 接口)、相似度检索知识库
table_service数据表格:建表、CRUD、筛选、CSV 导出、按表授权表格
group_service组织与成员、成员类型(设备/表格/智能体/知识库/记忆集)组织
robot_service设备注册、绑定智能体、记忆集绑定设备
skill_service技能:按群类型/关键词/正则命中后作为软约束注入技能
ext_user_service外网客户账号、会话、可见范围/ext
provision_service「AI 配置组织」的 10 个 provision_* 工具与默认提示词自动建组织
main.py 钩子启动时连库、ensure_table()、在线状态清零、自增值抬到 1000启动

服务端:路由与页面

  • websocket.py — 三条连接路径:/webserver/wework/{client_id}(正式)、/ws/{client_id}、/ws
  • admin.py — 管理后台(HTML 直出,无前端构建):首页/成员/设备/回复策略/智能体/知识库/长期记忆/表格/工作流/任务/技能/安全日志
  • api.py / aivbot_api.py — 内部 HTTP API(状态、设备、指令下发)
  • ext.py — 客户控制台 /ext(只读为主,唯一可写的是长期记忆)
  • provision.py — 配置智能体的对话台
  • 其余 agents/workflows/tasks/memory/knowledge/tables/skills/groups/test — 对应资源

数据模型(MySQL,启动时自动建表)

表说明
orgs / org_group_members组织 / 成员(成员类型决定资源归属)
robots设备:设备号、名称、绑定的智能体、在线状态(在线判定不读这列,见下)
agents / agent_conversations智能体(LLM 配置、system prompt、工具授权、指令授权)/ 会话记录
reply_strategies回复策略:config = {room_type: {mode, merge_window, track_duration}}
workflows / workflow_runs / workflow_node_logs工作流定义 / 每次运行 / 每个节点
tasks任务:触发器 × 动作
memory_sets / memory_customers / memory_items / robot_memory_sets / memory_cleanup_log长期记忆五表
knowledge_bases / knowledge_chunks知识库 / 切块与向量
data_tables / agent_table_grants数据表格 / 按表授权
skills技能
tool_call_audit每次工具调用(含失败)
messages会话消息(用于上下文与审计)

两条容易踩的实现约定

  1. 在线状态唯一事实来源是内存里的 active_connections,不是 robots.status 列。列只是"最后一次连接事件",多条路径不会回写它。改状态相关逻辑时按注册表判。
  2. 表自增值在启动时被抬到 1000,新 id 从 1000 起。测试别断言 id=1。

客户端:三个 Gradle 模块

模块内容
app全部业务:activity(设置/引导/日志)、service(无障碍服务、循环、操作实现)、observer、utils、model
baselibrary基础库
floatwindow悬浮窗(EasyFloat)

关键文件:

  • service/WeworkLoopImpl.kt — 主循环:切会话列表、判断未读、进房间、读消息、上报
  • service/WeworkOperationImpl.kt — 具体操作:发消息、@、拉群、加好友、转发……(对应服务端 203~234 号指令)
  • utils/WeworkRoomUtil.kt — 房间标题/类型的判定(搜索页、无群名外部群都在这处理)
  • Constant.kt — 服务器地址与本地自动化开关(SP 持久化)

一条消息的旅程

客户在群里发一句
  → 客户端无障碍读到「外部群·某群·张三: 在吗」
  → WS: {"type":101, ...}                     aivbot_service 入队
  → 命中 auto-reply 判定(room_type × mode)   回复策略
  → 合并窗口(默认 30s) 内同一房间同一人的消息攒批
  → agent_service.generate_reply              拼 system + 记忆 + 知识库 + 技能
  → LLM 决定「调用 device_command_203 发送」
  → tool 授权校验 → send_command 下发 203       WS
  → 客户端进房间、发送、回执
  → WS: {"type":203 回执 success_list/fail_list} → 审计 + 会话记录

部署拓扑(最小可用)

一台 Linux(2C4G 起步)
  ├─ MySQL 8(本机)+ venv + systemd 托管的 fastapi(端口 8765)
  ├─ 可选:Docker 一条命令起(compose 里自带 MySQL,未生产验证)
  └─ (可选)Caddy/Nginx 反代 + HTTPS,仅当你需要给客户开 /ext
一台 Android 平板(推荐,也可以用手机;常开、充电、锁屏常亮免打扰按需)
  └─ 与企业微信同机,客户端填服务端内网地址
(可选)frp:让外网客户控制台访问内网服务端,见 06

需要有人帮忙落地?可以联系定制开发、私有化部署、联合交付或技术咨询。