🚀 启动流程

应用启动时,Tauri Shell 初始化 Rust 后端,依次建立数据库连接、加载配置、启动 Socket.IO 服务器,最后激活所有已启用的渠道监听器。

flowchart TD A([🖥️ 用户启动 OpenHuman]) --> B[Tauri App 初始化] B --> C[加载 config.toml] C --> D[初始化 SQLite 数据库\nmemory.db + migrations] D --> E[解密并加载 Credentials\nAES-GCM + Argon2] E --> F[启动 tokio 异步运行时] F --> G{首次启动?} G -->|是| H[引导 Onboarding UI\n连接第一个集成] G -->|否| I[启动 Socket.IO 服务器\nsocketioxide on localhost] H --> I I --> J[注册 RPC 控制器\n三层路由初始化] J --> K[启动 Channel 监听器\nSlack / Email / Telegram …] K --> L[启动 Scheduler Gate\n20min autofetch 定时器] L --> M[发送 ready 事件到前端] M --> N([✅ 应用就绪]) style A fill:#1a2e1a,stroke:#22c55e,color:#86efac style N fill:#1a2e1a,stroke:#22c55e,color:#86efac style G fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe style H fill:#1a2030,stroke:#3b82f6,color:#93c5fd

🔌 Socket.IO 实时通信流程

前端 React 与后端 Rust 通过 Socket.IO WebSocket 实时双向通信。连接建立后,后端将 7 个异步事件桥激活,将内部领域事件广播至对应房间。

sequenceDiagram participant FE as 前端 React participant SIO as Socket.IO Server (Rust) participant CORE as openhuman Core participant LLM as LLM Provider FE->>SIO: connect() SIO-->>FE: ready { client_id } Note over FE,SIO: 自动加入个人房间 + "system" 房间 FE->>SIO: chat:start { message, thread_id } SIO-->>FE: chat:accepted { request_id } SIO->>CORE: 分发到 Agent Engine loop Agent 工具调用循环 CORE->>LLM: 发送 prompt + 工具列表 LLM-->>CORE: streaming text_delta CORE-->>SIO: text_delta / tool_call 事件 SIO-->>FE: 实时推送 delta CORE->>CORE: 执行工具调用 CORE-->>SIO: tool_result 事件 SIO-->>FE: tool_result end CORE-->>SIO: chat_done { full_response } SIO-->>FE: chat_done FE->>SIO: rpc:request { method, params } SIO->>CORE: RPC 三层路由 CORE-->>SIO: rpc:response SIO-->>FE: rpc:response FE->>SIO: chat:cancel { request_id } SIO->>CORE: 取消正在进行的推理
ℹ️
7 个异步事件桥:chat · voice · notifications · auth · companion_state · screen_intelligence · wallet — 每个桥独立转发对应领域的内部 Rust 事件到 Socket.IO 房间。

🤖 Agent 工具调用循环(Tool-Calling Loop)

Agent 引擎实现标准的 ReAct 模式:LLM 输出工具调用指令 → 本地执行工具 → 结果回传 → 继续推理,直到 LLM 输出最终回答或触发子 Agent 调度。

flowchart TD START([收到用户消息 / 触发事件]) --> TRIAGE[Trigger Triage 分类\n判断优先级和路由] TRIAGE --> HARNESS[Session Harness 初始化\n加载 Memory Context\nTokenJuice 压缩] HARNESS --> PROMPT[构建 System Prompt\n角色 + 工具列表 + 记忆片段] PROMPT --> LLM_CALL[调用 LLM Provider\nHTTP / Local 路由] LLM_CALL --> DECISION{LLM 输出类型?} DECISION -->|text delta| STREAM[流式推送 text_delta\n到 Socket.IO] STREAM --> DECISION DECISION -->|tool_call| TOOL_EXEC[工具执行器\n校验 Agent Tool Policy] TOOL_EXEC --> TOOL_TYPE{工具类型?} TOOL_TYPE -->|文件系统/Git| FS[文件系统工具\ncoding toolkit] TOOL_TYPE -->|Web搜索| WEB[搜索 + 爬虫] TOOL_TYPE -->|MCP 工具| MCP[MCP Client/Server] TOOL_TYPE -->|集成 API| API[118+ 集成 API] FS & WEB & MCP & API --> TOOL_RESULT[工具结果回传\n推送 tool_result 事件] TOOL_RESULT --> LLM_CALL DECISION -->|sub_agent| SUB[子 Agent 调度\norchestrator/planner\nresearcher/code_executor] SUB --> SUB_LOOP[子 Agent 独立循环] SUB_LOOP --> MERGE[合并子 Agent 输出] MERGE --> LLM_CALL DECISION -->|final_answer| MEMORY_WRITE[写入 Memory Tree\n更新知识图谱] MEMORY_WRITE --> DONE([✅ chat_done 推送]) style START fill:#1a2e1a,stroke:#22c55e,color:#86efac style DONE fill:#1a2e1a,stroke:#22c55e,color:#86efac style DECISION fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe style TOOL_TYPE fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe

Autofetch 20 分钟同步周期

Scheduler Gate 每 20 分钟(可配置)触发一次全渠道数据拉取,将新邮件、日历事件、代码提交、文档编辑转换为 Markdown chunks,写入 Memory Tree。

flowchart LR TIMER([⏰ 20min 定时器触发]) --> GATE{Scheduler Gate\n检查条件} GATE -->|系统空闲\n非睡眠| FETCH[并行拉取所有已授权集成] GATE -->|系统繁忙| SKIP[跳过本轮\n记录 skip_count] FETCH --> GMAIL[Gmail 新邮件] FETCH --> GCAL[Google Calendar 事件] FETCH --> SLACK[Slack 新消息/频道] FETCH --> GITHUB[GitHub Commits/PRs] FETCH --> NOTION[Notion 页面更新] FETCH --> MORE[... 118+ 渠道] GMAIL & GCAL & SLACK & GITHUB & NOTION & MORE --> CONVERT[转换为 Markdown\n~3000 token 分块] CONVERT --> EMBED[生成向量嵌入\n实体/关系提取] EMBED --> INGEST[IngestionQueue 写入] INGEST --> SQLITE[(SQLite\nmemory.db)] INGEST --> VAULT[📁 Obsidian Vault\n~/.openhuman/vault] INGEST --> TREE_UPDATE[更新 Memory Tree\nsource → topic → global] TREE_UPDATE --> NOTIFY[推送 sync_complete\n到 Socket.IO] NOTIFY --> TIMER style TIMER fill:#0d2020,stroke:#14b8a6,color:#5eead4 style GATE fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe style SKIP fill:#1e1010,stroke:#6b7280,color:#9ca3af

🧠 Memory Tree 摄入管道

Memory 系统采用三层摘要树架构:原始数据层 → 主题摘要层 → 全局摘要层。新文档经过分块、嵌入、实体提取后进入 SQLite,背景作业维护三层树的一致性。

flowchart TD INPUT[📥 输入:文档/邮件/聊天/代码] --> PARSE[文档解析\nMarkdown / PDF / IMAP / JSON] PARSE --> CHUNK[分块器\n~3000 tokens / chunk\n重叠滑窗] CHUNK --> PARALLEL subgraph PARALLEL[并行处理] direction LR EMB[向量嵌入生成\nembedding model] ENTITY[实体/关系提取\nNER via LLM] FTS[FTS5 全文索引\nSQLite 写入] end PARALLEL --> STORE[(SQLite memory.db\n向量表 + 关系图 + FTS5)] STORE --> TREE_L1[🌿 第一层:Source Tree\n原始来源摘要\n每个 doc 独立摘要] TREE_L1 --> TREE_L2[🌲 第二层:Topic Tree\n跨来源主题聚合\n定期后台合并] TREE_L2 --> TREE_L3[🌳 第三层:Global Tree\n全局知识摘要\n周期性重建] TREE_L3 --> RECALL{查询召回} RECALL -->|关键词匹配| FTS_QUERY[FTS5 全文检索] RECALL -->|语义相似| VEC_QUERY[向量近邻搜索 ANN] RECALL -->|实体溯源| GRAPH_QUERY[知识图谱遍历] FTS_QUERY & VEC_QUERY & GRAPH_QUERY --> RANK[打分 + 排序\nRecallOpts 过滤] RANK --> CONTEXT[注入 Agent Context\nTokenJuice 压缩至预算] STORE --> VAULT_SYNC[定期同步到 Vault\nObsidian Markdown 文件] style INPUT fill:#1a2030,stroke:#3b82f6,color:#93c5fd style RECALL fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe style CONTEXT fill:#1a2e1a,stroke:#22c55e,color:#86efac

📡 RPC 三层路由(Tiered Dispatch)

所有来自前端的 RPC 请求经过三层路由:Legacy 别名重写 → Core 核心方法 → Controller 注册表 → Legacy 兜底 → 未知方法错误。

flowchart TD REQ([📨 RPC Request\nmethod + params]) --> ALIAS[Tier 0: Legacy 别名重写\n将旧方法名映射到规范名] ALIAS --> T1{Tier 1: Core Methods\nmethod 以 core. 开头?} T1 -->|core.ping| PING[返回 {ok: true}] T1 -->|core.version| VERSION[返回运行中的 binary 版本] T1 -->|否| T2{Tier 2: Controller Registry\n已注册的 domain handlers?} T2 -->|匹配| SCHEMA[JSON Schema 参数校验] SCHEMA -->|校验失败| ERR_SCHEMA[错误: 参数格式错误] SCHEMA -->|校验通过| CTRL[调用注册 Controller Handler] CTRL --> RESP([✅ 返回响应]) T2 -->|不匹配| T3{Tier 3: Legacy Dispatcher\nOpenHuman 旧路由?} T3 -->|匹配| LEGACY[调用 Legacy Handler] LEGACY --> RESP T3 -->|不匹配| ERR_UNKNOWN[错误: unknown method\n⚠️ warning 日志] style REQ fill:#1a2030,stroke:#3b82f6,color:#93c5fd style RESP fill:#1a2e1a,stroke:#22c55e,color:#86efac style ERR_SCHEMA fill:#2e1010,stroke:#ef4444,color:#fca5a5 style ERR_UNKNOWN fill:#2e1010,stroke:#ef4444,color:#fca5a5 style T1 fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe style T2 fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe style T3 fill:#2a1f3a,stroke:#a855f7,color:#d8b4fe

🎭 Mascot 桌面伴侣状态机

桌面 Mascot 是一个有状态的动画角色,根据系统状态(空闲/思考/说话/监听/错误)切换动画和表情。状态由 companion_state 事件桥驱动。

stateDiagram-v2 [*] --> Idle : 应用启动 Idle --> Listening : 检测到唤醒词\n/ 用户点击 Idle --> Thinking : 收到 autofetch 通知\n/ 后台任务触发 Idle --> Speaking : TTS 播放开始 Listening --> Thinking : STT 识别完成\n发送消息 Listening --> Idle : 超时无输入\n/ 取消 Thinking --> Speaking : LLM 生成完成\n开始 TTS Thinking --> Idle : 静默回答(文字) Thinking --> Error : 推理错误\n/ 超时 Speaking --> Idle : TTS 播放完毕 Speaking --> Listening : 打断检测\n用户重新发言 Error --> Idle : 错误消除\n/ 重试 note right of Thinking tokenjuice 压缩中 工具调用执行中 子 Agent 运行中 end note note right of Speaking 唇形同步激活 ElevenLabs TTS 动画播放 end note
并发状态:Mascot 状态机与 Agent 循环、Autofetch 循环 并发运行,通过 companion_state 事件桥(Socket.IO 七桥之一)解耦,前端只消费状态事件,不直接调用后端逻辑。

⚙️ 运行时并发结构总览

OpenHuman 运行时由多个 tokio 异步任务并发运行,彼此通过 Event Bus 和 Socket.IO 解耦通信。

flowchart LR subgraph TOKIO[tokio 异步运行时] direction TB SIO_SERVER[Socket.IO 服务器\n持续监听前端连接] AGENT[Agent 引擎\n按需启动 per session] SCHEDULER[Scheduler Gate\n20min autofetch 循环] CHANNEL_SUP[Channel 监听器\nSlack/Email/Telegram…] INGEST_Q[IngestionQueue\n后台内存写入] HEALTH[心跳 + 健康检查\nPrometheus 指标] end subgraph BUS[Event Bus] direction LR EVT_CHAT[chat events] EVT_VOICE[voice events] EVT_NOTIF[notification events] EVT_SYNC[sync events] EVT_COMPANION[companion_state] end AGENT <-->|publish/subscribe| BUS SCHEDULER <-->|publish/subscribe| BUS CHANNEL_SUP <-->|publish/subscribe| BUS INGEST_Q <-->|subscribe| BUS SIO_SERVER <-->|7 async bridges| BUS subgraph FRONTEND[React 前端] CHAT_UI[Chat UI] MASCOT_UI[Mascot] STATUS_UI[状态栏] end SIO_SERVER <-->|WebSocket| FRONTEND style TOKIO fill:#0d1a0d,stroke:#22c55e,color:#86efac style BUS fill:#1a1030,stroke:#a855f7,color:#d8b4fe style FRONTEND fill:#0d1a30,stroke:#3b82f6,color:#93c5fd