# Agent 架构概览 AstroResearch 内置了一个基于 **ReAct** (Thought → Action → Observation) 范式的科研智能体引擎 (`src/agent/`),参考 Claude Code 的分层设计。以下对各子系统的架构、数据流和内部逻辑进行完整说明。 ### 整体架构 ```mermaid graph TD subgraph API["API 层"] SSE["SSE /api/chat/agent"] Sessions["Session CRUD"] Metrics["GET /api/chat/metrics"] Audit["GET /api/chat/sessions/:id/audit"] AskUser["问答 /api/chat/questions + /api/chat/answer"] end subgraph Runtime["AgentRuntime — ReAct 引擎"] RunTurn["run_turn() 主入口"] SP["SystemPrompt 组装器"] CtxBuild["Context Builder 上下文构建"] ReAct["ReAct 主循环"] Streaming["streaming.rs 流式处理"] Executor["executor.rs 并行执行"] Finalize["finalize.rs 会话收尾"] TokenBudget["token_budget.rs"] CircuitBreaker["circuit_breaker.rs"] end subgraph Tools["工具系统 (tools/)"] AgentTool["AgentTool trait"] Registry["ToolRegistry"] FS["filesystem/ (6 工具)"] Astro["astro/ (7 工具)"] AskUserT["ask_user"] SubAgentT["subagent/delegate_research"] TeamT["team/ (4 工具)"] BG["background (2 工具)"] end subgraph CrossCutting["横切关注点"] Hooks["HookRegistry (9 事件)"] Skills["SkillRegistry (两层加载)"] Memory["MemoryManager (项目记忆)"] Permission["PermissionChecker"] FileCache["FileStateCache (Read 去重)"] end subgraph DB["持久化"] AgentSessions["agent_sessions"] AgentMessages["agent_messages"] AgentTasks["agent_tasks"] AgentAudit["agent_audit_log"] end SSE --> RunTurn RunTurn --> SP RunTurn --> CtxBuild --> DB RunTurn --> ReAct ReAct --> Streaming --> Tools ReAct --> Executor --> Tools ReAct --> TokenBudget ReAct --> CircuitBreaker ReAct --> Finalize Hooks -.-> ReAct Hooks -.-> Tools Skills -.-> Tools Memory -.-> SP Permission -.-> Tools FileCache -.-> Tools ``` --- ### ReAct 运行循环 (`runtime/`) 主循环由 `AgentRuntime::run_turn()` 驱动,分为 4 个阶段: #### 完整生命周期 ```mermaid sequenceDiagram participant FE as 前端 SSE participant RT as AgentRuntime participant DB as SQLite participant LLM as LLM API participant Tools as ToolRegistry FE->>RT: POST /api/chat/agent { question, session_id? } Note over RT: Phase 1 — 会话管理 RT->>DB: create_or_resume_session() alt 新会话 DB-->>RT: session_id = uuid, turn_index = 0 else 恢复会话 DB-->>RT: 验证存在 + 计算 turn_index end RT->>RT: 触发 OnSessionStart hook RT-->>FE: SSE session { session_id, title } Note over RT: Phase 2 — 上下文构建 RT->>RT: build_initial_context() RT->>RT: ① 组装 SystemPrompt (静态 section + 记忆注入) RT->>DB: ② 加载历史消息 load_history_for_llm() RT->>DB: ③ 恢复未完成任务 (agent_tasks) RT->>RT: ④ 检查压缩/清理上下文 RT->>DB: ⑤ 保存用户消息 RT->>RT: ⑥ 运行 PreToolUse hooks 过滤 Note over RT: Phase 3 — ReAct 循环 loop 每步迭代 (step ≤ max_steps) RT->>LLM: chat_stream(messages + tool_defs) LLM-->>RT: ReasoningDelta / TextDelta / ToolCallsComplete RT-->>FE: SSE thought / text_delta / tool_call alt 无工具调用 → 最终答案 RT->>DB: 保存 assistant 消息 RT-->>FE: SSE text_delta → usage → done Note over RT: break 循环 else 有工具调用 RT->>RT: 检查 token 预算 + 熔断器 RT->>RT: validate_and_prepare() — 去重 + 过滤 RT->>Tools: execute_parallel() — 并行执行 Tools-->>RT: (tool_call_id, name, output) RT-->>FE: SSE tool_result { tool_call_id, name, output } RT->>DB: 保存 tool 消息 + 审计日志 RT->>RT: 运行 PostToolUse hooks RT->>RT: 检测压缩需求 (auto_compact) end RT->>RT: 检测循环终止条件 end Note over RT: Phase 4 — 会话收尾 RT->>DB: 更新 turn_count + updated_at RT->>DB: calculate_and_persist_metrics() RT->>RT: 运行 OnSessionStop hook RT-->>FE: SSE done ``` #### 并行工具执行模型 ```mermaid sequenceDiagram participant ReAct as ReAct 循环 participant Val as validate_and_prepare participant Exec as execute_parallel participant T1 as Tool A participant T2 as Tool B participant FE as 前端 SSE ReAct->>Val: LLM 返回 [tool_call_a, tool_call_b] Val->>Val: 去重检测 + 权限验证 Val-->>ReAct: prepared_calls[] + has_duplicate 标志 ReAct->>FE: 发送 tool_call SSE (逐一) ReAct->>Exec: 启动 execute_parallel() par 并行执行 Exec->>T1: tool_a.execute(args_a) Exec->>T2: tool_b.execute(args_b) end T1-->>Exec: ToolOutput { content, is_error } Exec-->>FE: SSE tool_result (立即推送) T2-->>Exec: ToolOutput { content, is_error } Exec-->>FE: SSE tool_result (立即推送) Exec-->>ReAct: Vec<(tool_call_id, name, args, output, cancelled)> ReAct->>ReAct: PostToolUse hooks + 审计日志 + 持久化 ``` - **并发上限**:由 `max_concurrent_tools` 环境变量控制,默认不限制 - **Sibling Abort**:仅 `causes_sibling_abort() = true` 的工具(如 `download_paper`)能在出错时中断兄弟任务 - **InterruptBehavior**:`Block` 工具(如 `ask_user`)不可被用户取消;`Cancel` 工具可在取消信号时中断 - **超时控制**:每个工具有独立超时,默认 120s(`AGENT_TOOL_TIMEOUT_SECS`) ---