diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..98ae64d --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,445 @@ +# iAs 代码调用图谱 + +> 微信 AI 智能助手 —— 完整架构与调用关系 + +--- + +## 1. 全局架构总览 + +```mermaid +flowchart TB + subgraph CLI["CLI 入口 (main.rs)"] + A1["clap::Parser Cli 解析"] + A2["cmd_login"] + A3["cmd_listen"] + A4["cmd_send"] + A5["cmd_whoami"] + A6["cmd_usage"] + A7["cmd_tool"] + A8["cmd_daemon"] + end + subgraph DAEMON["守护进程 (daemon.rs)"] + B0["run()"] + B1["spawn_consumers()"] + B2["llm_consumer_loop"] + B3["tool_consumer_loop"] + B4["send_consumer_loop"] + B5["run_llm_round / resume_llm_round"] + B6["handle_chat_result"] + B7["execute_tool"] + end + subgraph QUEUE["消息队列 (queue/)"] + C1["MessageQueue 公平轮转"] + C2["QueueRunner 路由调度"] + C3["EnqueueHandle"] + C4["ConsumerChannels"] + end + subgraph LLM["LLM 对话系统 (llm/)"] + D1["Conversation 对话管理器"] + D2["chat_with_tools() / run_tool_loop()"] + D3["DeepSeekProvider"] + D4["LlmProvider trait"] + D5["StreamReceiver"] + end + subgraph CONTEXT["上下文管理 (context/)"] + E1["ChatSession 消息历史+摘要"] + E2["builder Token估算+上下文构建"] + E3["MemoryStore 长期记忆"] + E4["read_summaries"] + end + subgraph TOOLS["工具系统 (tools/)"] + F1["BuiltinRegistry 工具注册表"] + F2["ApprovalManager 审批管理"] + F3["build_capability_guide"] + F4["unpack_call_params"] + subgraph BUILTINS["内置工具 (builtins/)"] + G1["datetime"] + G2["weather"] + G3["web_search"] + G4["fetch_page"] + G5["memos"] + G6["amap"] + end + end + subgraph WECHAT["微信通道 (wechat/)"] + H1["WeChatClient"] + H2["receive_messages()"] + H3["send_text()"] + H4["login()"] + H5["notify_start/stop"] + end + subgraph DB["数据库 (db/)"] + I1["Database::connect()"] + I2["models CRUD 操作"] + end + subgraph OTHER["其他模块"] + J1["state.rs 文件状态回退"] + J2["scheduler.rs 定时任务"] + J3["logger.rs 日志初始化"] + J4["channel/mod.rs ChannelId"] + J5["ipc.rs UDS 协议(已废弃)"] + J6["worker.rs 旧架构(已废弃)"] + end + + A1 --> A2 & A3 & A4 & A5 & A6 & A7 & A8 + A3 --> B0 + A8 --> B0 + B0 --> B1 + B1 --> B2 & B3 & B4 + B2 --> B5 & B6 + B3 --> B7 + B0 --> C1 & C2 & C3 + C2 --> C4 + C4 --> B2 & B3 & B4 + B2 --> D1 + D1 --> D2 + D2 --> D3 + D3 --> D4 + D4 --> D5 + D1 --> E1 + D2 --> E2 + B2 --> E3 & E4 + D2 --> F1 + B3 --> F1 & F2 + B7 --> F1 & F3 & F4 + F1 --> G1 & G2 & G3 & G4 & G5 & G6 + B4 --> H1 + H1 --> H2 & H3 + B0 --> I1 + B2 --> I2 + B4 --> I2 + A2 --> I2 & J1 + A3 --> J1 + B0 --> J1 & J2 + A1 --> J3 +``` + +--- + +## 2. 消息处理全链路 + +```mermaid +sequenceDiagram + participant WX as 微信用户 + participant WC as WeChatClient + participant MQ as MessageQueue + participant QR as QueueRunner + participant LC as LLM Consumer + participant TC as Tool Consumer + participant SC as Send Consumer + participant LLM as DeepSeek API + participant BT as BuiltinRegistry + + WX->>WC: 发送消息 + WC->>MQ: enqueue(UserMessage) + MQ->>QR: dequeue (公平轮转) + QR->>LC: llm_tx.send(UserMessage) + LC->>LC: 加载历史/记忆/摘要 + LC->>LLM: chat_stream(上下文) + LLM-->>LC: 流式回复 + tool_calls + + alt 有工具调用 + LC->>MQ: enqueue(ToolCall) + MQ->>QR: dequeue + QR->>TC: tool_tx.send(ToolCall) + + alt 高风险工具 + TC->>TC: ApprovalManager.create() + TC->>MQ: enqueue(LLMReply: 确认码) + MQ->>QR: dequeue + QR->>SC: send_tx.send(LLMReply) + SC->>WC: send_text(确认码) + WX-->>WC: 回复确认码 + WC->>MQ: enqueue(UserMessage: 确认码) + MQ->>QR: dequeue + QR->>LC: llm_tx.send(确认码) + LC->>TC: ApprovalManager.handle_reply() + TC-->>LC: Approved + LC->>MQ: enqueue(ToolCall + approved=true) + MQ->>QR: dequeue + QR->>TC: tool_tx.send(ToolCall) + end + + TC->>BT: execute(工具名, 参数) + BT-->>TC: SkillResult + TC->>MQ: enqueue(ToolResult) + MQ->>QR: dequeue + QR->>LC: llm_tx.send(ToolResult) + LC->>LLM: resume_tool_loop() + LLM-->>LC: 最终回复 + end + + LC->>MQ: enqueue(LLMReply) + MQ->>QR: dequeue + QR->>SC: send_tx.send(LLMReply) + SC->>WC: send_text(回复) + WC->>WX: 显示回复 +``` + +--- + +## 3. 模块依赖关系 + +```mermaid +flowchart LR + subgraph CORE["核心层"] + MAIN["main.rs"] + DAEMON["daemon.rs"] + CLI["cli.rs"] + end + subgraph PIPELINE["消息管线"] + QUEUE["queue/"] + CHANNEL["channel/"] + end + subgraph AI["AI 层"] + LLM["llm/"] + CTX["context/"] + end + subgraph TOOL["工具层"] + TOOLS["tools/"] + BUILTINS["tools/builtins/"] + APPROVAL["tools/approval.rs"] + end + subgraph IO["IO 层"] + WECHAT["wechat/"] + DB["db/"] + STATE["state.rs"] + SCHED["scheduler.rs"] + end + subgraph UTIL["工具层"] + LOG["logger.rs"] + IPC["ipc.rs"] + WORKER["worker.rs"] + end + + MAIN --> CLI & DAEMON & LOG & STATE & DB & CTX & LLM & TOOLS & WECHAT & SCHED + DAEMON --> QUEUE & CHANNEL & WECHAT & DB & STATE & LLM & CTX & TOOLS & SCHED + QUEUE --> CHANNEL + LLM --> CTX & TOOLS + TOOLS --> BUILTINS & APPROVAL + CTX --> DB + TOOLS --> DB + APPROVAL --> DB + DB --> STATE + WORKER --> IPC & LLM & TOOLS +``` + +--- + +## 4. 数据流(消息生命周期) + +```mermaid +flowchart TB + START(["📱 用户发消息"]) --> A["WeChatClient receive_messages()"] + A --> B["入库: chat_records (inbound)"] + B --> C["PipelineMessage kind: UserMessage"] + C --> D["MessageQueue 公平轮转"] + D --> E["加载历史消息 (最近20条)"] + E --> F["加载长期记忆 (MemoryStore)"] + F --> G["加载摘要 (read_summaries)"] + G --> H["构建上下文 (builder)"] + H --> I["Conversation chat_with_tools()"] + I --> J{"LLM 调用了工具?"} + J -->|"是"| K["Tool Consumer 执行工具"] + K --> L{"高风险?→ 审批流程"} + L --> M["结果回喂 LLM"] + M --> I + J -->|"否"| N["LLM 生成最终回复"] + N --> O["Send Consumer send_text()"] + O --> P["入库: chat_records (outbound)"] + P --> ENDD(["📱 用户收到回复"]) +``` + +--- + +## 5. 关键函数调用关系 + +### 5.1 工具执行链路 + +```mermaid +flowchart TB + subgraph LLM_SIDE["LLM 侧"] + A["LLM 调用 call_capability()"] + B["ToolExecutor (闭包)"] + C["返回 ASYNC_MARKER + 工具名"] + end + subgraph QUEUE_SIDE["队列侧"] + D["PipelineMessage::tool_call()"] + E["MessageQueue.enqueue()"] + F["QueueRunner → Tool Consumer"] + end + subgraph TOOL_SIDE["工具侧"] + G["tool_consumer_loop()"] + H{"高风险?"} + I["ApprovalManager 审批流程"] + J["execute_tool()"] + K{"工具类型?"} + L["BuiltinRegistry.execute()"] + M["上下文工具 直接处理"] + N["unpack_call_params()"] + end + subgraph RESULT["结果回喂"] + O["PipelineMessage::tool_result()"] + P["LLM Consumer resume_llm_round()"] + Q["Conversation resume_tool_loop()"] + end + + A --> B --> C --> D --> E --> F --> G + G --> H + H -->|"是"| I --> J + H -->|"否"| J + J --> K + K -->|"内置工具"| L + K -->|"上下文工具"| M + K -->|"call_capability"| N --> K + J --> O --> P --> Q +``` + +### 5.2 审批流程 + +```mermaid +flowchart TB + A["LLM 请求高风险工具"] --> B["ApprovalManager.create(user_id, tool)"] + B --> C["生成 6 位确认码 SHA-256 哈希存储"] + B --> D["创建 oneshot channel"] + C --> E["发送消息给用户 ⚠️ 操作确认"] + D --> F["等待用户回复 超时 5 分钟"] + F --> G{"用户回复"} + G -->|"匹配确认码"| H["ApprovalDecision::Approved"] + G -->|"输入 0/取消"| I["ApprovalDecision::Rejected"] + G -->|"不匹配(最多3次)"| J["减少尝试次数"] + G -->|"超时"| K["ApprovalDecision::Expired"] + J --> F + H --> L["重新入队 UserMessage + approved_tool"] + I --> M["回复用户: 已取消"] + K --> N["回复用户: 已超时"] +``` + +### 5.3 上下文构建流程 + +```mermaid +flowchart TB + A["ChatSession (消息历史)"] --> B["estimate_tokens()"] + B --> C{"Token 超 budget? (默认 28000)"} + C -->|"是"| D{"checkpoint 之前有未摘要消息?"} + D -->|"是"| E["trigger_overflow_summary() → 调用 LLM 生成摘要"] + D -->|"否"| F["裁剪最早的消息 直到符合 budget"] + C -->|"否"| G{"空闲超时? (12h 无消息)"} + G -->|"是"| H["trigger_idle_summary() → 清空消息, 保留摘要"] + G -->|"否"| I["build_context() → 组装最终上下文"] + E --> I + F --> I + H --> I + I --> J["发送给 LLM"] +``` + +--- + +## 6. 文件依赖矩阵 + +| 文件 | 依赖的关键模块 | +|------|---------------| +| `main.rs` | cli, daemon, db, llm, context, tools, wechat, state, scheduler, logger | +| `daemon.rs` | queue, channel, wechat, db, state, llm, context, tools, scheduler | +| `cli.rs` | clap (独立) | +| `llm/conversation.rs` | context/builder, context/types, llm/provider, llm/types | +| `llm/deepseek.rs` | llm/provider, llm/types | +| `llm/provider.rs` | llm/types | +| `llm/types.rs` | serde (独立) | +| `context/types.rs` | llm/types | +| `context/builder.rs` | context/types, llm/types | +| `context/tools.rs` | db/models | +| `queue/message_queue.rs` | channel/mod | +| `queue/runner.rs` | queue/message_queue | +| `tools/builtin.rs` | tools/types, tools/builtins/* | +| `tools/approval.rs` | db/models | +| `tools/mod.rs` | tools/types | +| `wechat/client.rs` | wechat/types | +| `wechat/types.rs` | serde (独立) | +| `db/mod.rs` | db/models | +| `db/models.rs` | sqlx (独立) | +| `state.rs` | serde (独立) | +| `scheduler.rs` | db/models | +| `worker.rs` | ipc, llm, tools (已废弃) | +| `ipc.rs` | serde (已废弃) | + +--- + +## 7. 启动流程 + +```mermaid +flowchart TB + START(["ias listen --llm"]) --> A["main()"] + A --> B["clap::Parser::parse()"] + B --> C{"命令类型"} + C -->|"Tool"| D["cmd_tool() 直接执行工具"] + C -->|"Login"| E["cmd_login() 扫码登录"] + C -->|"Listen/Service"| F["cmd_listen()"] + + F --> G["加载 .env"] + F --> H["Database::connect()"] + H --> I{"数据库可用?"} + I -->|"是"| J["创建 MemoryStore (DB 模式)"] + I -->|"否"| K["创建 MemoryStore (文件模式)"] + + F --> L["加载认证信息"] + L --> M{"已登录?"} + M -->|"否"| N["报错退出"] + M -->|"是"| O["WeChatClient.set_auth()"] + + O --> P["WeChatClient.notify_start()"] + P --> Q["创建 ApprovalManager"] + Q --> R["创建 Conversation + ToolExecutor"] + R --> S["启动 Scheduler (定时任务)"] + S --> T["启动 listen_loop()"] + + T --> U["WeChatClient.receive_messages()"] + U --> V{"收到消息?"} + V -->|"是"| W["enqueue PipelineMessage"] + W --> X["LLM/Tool/Send 消费者处理"] + V -->|"否/超时"| U +``` + +--- + +## 8. 消费者架构(三消费者) + +```mermaid +flowchart TB + subgraph QUEUE2["消息队列"] + Q["MessageQueue 公平轮转"] + R["QueueRunner 路由"] + end + subgraph LLM_C["LLM Consumer"] + L1["接收: UserMessage / ToolResult / ScheduledTask"] + L2["加载用户历史 + 记忆 + 摘要"] + L3["创建/恢复 Conversation"] + L4["chat_with_tools() / resume_tool_loop()"] + L5{"有异步工具等待?"} + L6["发送 LLMReply"] + L7["保留 session"] + L8["清理 session"] + end + subgraph TOOL_C["Tool Consumer"] + T1["接收: ToolCall / ApprovalRequest"] + T2{"高风险 + 未审批?"} + T3["ApprovalManager.create()"] + T4["发送确认码"] + T5["execute_tool()"] + T6["发送 ToolResult"] + end + subgraph SEND_C["Send Consumer"] + S1["接收: LLMReply"] + S2["WeChatClient.send_text()"] + S3["入库: chat_records (outbound)"] + end + + Q --> R + R -->|"UserMessage / ToolResult"| L1 + R -->|"ToolCall"| T1 + R -->|"LLMReply"| S1 + L1 --> L2 --> L3 --> L4 + L4 --> L5 + L5 -->|"是"| L7 + L5 -->|"否"| L6 +``` \ No newline at end of file