# 网关(Gateway)项目架构流程图 > 基于代码现状绘制的架构图(backend + frontend + agent 联动)。 > 端口:后端 `:8000`、前端 `:5173`、Agent `:8001`、Redis 远程实例 `45.207.192.237:56987/0`。 --- ## 一、系统总体架构图(分层) ```mermaid flowchart TB subgraph OUT["外部调用方"] CLI["CLI 客户端 / 模型对话
提交任务(带 auth)"] end subgraph FE["前端运维后台(Vue3 + Vite + Element Plus):5173"] TV["TaskView 任务管理
列表/筛选/详情/取消/重置"] AV["AgentView Agent 管理
卡片/标签/负载/下线"] LV["LogView 日志审计
按 request_id/agent_id 筛选"] CV["ControlView 总览
任务/Agent 统计"] API["api/index.ts
fetch 封装(/api/admin/*)"] end subgraph GW["网关后端(FastAPI + Uvicorn):8000"] direction TB subgraph API_L["API 层(app/api/)"] A1["/api/cli/*
任务提交"] A2["/api/agent/*
注册/心跳/结果回传"] A3["/api/admin/*
运维后台查询与管控"] end subgraph SVC["服务层(app/services/)"] S1["TaskService 任务池
受理/取消/重置/超时"] S2["AgentService Agent 池
注册/心跳/下线/剔除"] S3["Scheduler 规则调度
选人→绑定→推送→回退"] S4["RelayService 通信中转
正向推送/反向收结果"] S5["HeartbeatService
心跳扫描(60s)"] S6["TimeoutService
任务超时检查(5s)"] end subgraph REPO["存储层(app/repository/)"] R1["TaskRepo"] R2["AgentRepo"] R3["LogRepo"] end subgraph LOOP["后台循环(scheduler_loop.py)"] L1["heartbeat_loop
Lock:lock:heartbeat"] L2["dispatch_loop(2s)
Lock:lock:scheduler"] L3["timeout_loop
Lock:lock:timeout"] end end subgraph RD["Redis 存储(DB0)"] K1["task:info:{id} Hash
task:pending / task:running Set"] K2["agent:info:{id} Hash
agent:all / agent:tag:{tag} Set"] K3["agent:heartbeat ZSet"] K4["lock:* 分布式锁"] K5["log:audit List"] end subgraph AG["Agent 服务(ADK ApiServer):8001"] direction TB AG0["api_server.py
REST /run /run_sse
SQLite 会话 / InMemory 记忆"] AG1["task_receiver.py
POST /tasks/{id}
校验 auth → 202 → 后台线程"] AG2["gateway_client.py
注册 / 心跳 / 回传结果"] AG3["ADK InMemoryRunner
执行 dev_app(my_agent)"] end CLI -->|"POST /api/cli/tasks"| A1 FE --> API API -->|"/api/admin/*"| A3 A1 --> S1 A2 --> S2 A3 --> S1 & S2 S1 & S2 & S3 & S4 & S5 & S6 --> R1 & R2 & R3 L1 -->|"调用"| S5 L2 -->|"调用"| S3 L3 -->|"调用"| S6 S5 -->|"Lock"| K4 S3 -->|"Lock"| K4 R1 & R2 & R3 --> K1 & K2 & K3 & K5 S3 -->|"Scheduler 选中 Agent"| S4 S4 -->|"POST {endpoint}/tasks/{request_id}
期望 202"| AG1 AG1 -->|"校验通过后后台线程"| AG3 AG3 -->|"执行完成"| AG2 AG2 -->|"POST /api/agent/result"| A2 AG2 -->|"心跳 /api/agent/heartbeat(10s)"| A2 ``` --- ## 二、任务全生命周期时序图(完整闭环) ```mermaid sequenceDiagram autonumber participant CLI as CLI / 对话模型 participant GW as 网关后端(FastAPI :8000) participant RD as Redis participant LOOP as SchedulerLoop 后台循环 participant AG as Agent 服务(:8001) participant ADK as ADK InMemoryRunner Note over AG,ADK: Agent 启动:register → 每 10s heartbeat CLI->>GW: POST /api/cli/tasks {auth, task_type, tags, payload} GW->>GW: TaskService.submit(幂等:RequestID 复用) GW->>RD: hset task:info:{id} + sadd task:pending GW-->>CLI: 200 {request_id} loop dispatch_loop(每 2s,持 lock:scheduler) LOOP->>RD: 取 task:pending 成员 LOOP->>GW: Scheduler.dispatch_pending(batch) GW->>RD: AgentRepo.by_tags(tags) 标签匹配 GW->>GW: 负载过滤(load < max_concurrent) GW->>GW: 最低负载 + 在线最久者优先 GW->>RD: 任务置 running + 绑定 agent_id
task:pending→task:running,agent 负载 +1 GW->>AG: RelayService.dispatch_command
POST {endpoint}/tasks/{id} {auth, payload} alt 推送成功(202) AG->>AG: 校验 auth → 后台线程接收任务 AG-->>GW: 202 {ok, request_id, status:"accepted"} AG->>ADK: 运行 agent(InMemoryRunner.run_async) ADK-->>AG: 最终输出文本 AG->>GW: POST /api/agent/result {success, progress:100, result} GW->>RD: 更新任务 success + 释放 agent 负载
task:running 移除 GW-->>CLI: (前端可查) else 推送失败(网络错误 / 非 202) AG-->>GW: 4xx/5xx 或无响应 GW->>RD: 回退:任务置 pending + 解绑 + 释放负载
task:running→task:pending end end Note over LOOP,RD: heartbeat_loop:60s 扫 agent:heartbeat ZSet,
超 120s 未心跳 → 标记 offline
timeout_loop:5s 扫 running,超时 → failed ``` --- ## 三、规则调度决策流程(Scheduler) ```mermaid flowchart LR START(["dispatch_pending
取 task:pending 批量"]) --> T1{"任务存在且为 pending?"} T1 -- 否 --> END(["跳过"]) T1 -- 是 --> T2{"按 task_tags 标签匹配
AgentRepo.by_tags(tags)"} T2 -- 无候选 --> END2(["保持 pending
等待下次调度"]) T2 -- 有候选 --> T3["负载过滤
current_load < max_concurrent"] T3 -- 空 --> END2 T3 -- 非空 --> T4["排序:最低负载优先
负载相同时在线最久优先"] T4 --> T5["绑定 Agent
task:info 置 running + agent_id
task:pending→task:running"] T5 --> T6["agent 负载 +1
adjust_load(agent, +1)"] T6 --> T7["RelayService.dispatch_command
POST {endpoint}/tasks/{id}"] T7 --> T8{"HTTP 202?"} T8 -- 是 --> OK(["下发成功
记录 dispatch 日志"]) T8 -- 否 --> T9["回退:task 置 pending + 解绑
task:running→task:pending
agent 负载 -1"] T9 --> END2 ``` --- ## 四、Agent 端任务处理流程 ```mermaid flowchart TB RECV["POST {endpoint}/tasks/{request_id}"] --> AUTH{"auth == GATEWAY_AUTH?"} AUTH -- 否 --> 401["401 invalid auth"] AUTH -- 是 --> THREAD["启动 daemon 后台线程
(立即返回 202 accepted)"] THREAD --> PROMPT["payload → prompt
(prompt / cmd / 兜底序列化)"] PROMPT --> RUN["InMemoryRunner.run_async
user_id=gateway, session=task-{id}"] RUN --> OUT["收集最终文本输出"] OUT --> REP["gateway_client.report_result
POST /api/agent/result"] RUN --> ERR["异常捕获"] ERR --> REPF["report_result(status=failed, error_info)"] ``` --- ## 五、Redis 数据结构一览 | 前缀 / 键 | 类型 | 用途 | | --- | --- | --- | | `task:info:{request_id}` | Hash | 任务全量信息(状态/绑定 Agent/进度/结果),TTL 24h | | `task:pending` | Set | 待调度任务索引 | | `task:running` | Set | 执行中任务索引 | | `agent:info:{agent_id}` | Hash | Agent 信息(endpoint/标签/并发上限/负载/心跳时间) | | `agent:all` | Set | 全部 Agent 索引 | | `agent:tag:{tag}` | Set | 能力标签 → Agent 索引(调度匹配用) | | `agent:heartbeat` | ZSet | score=最后心跳时间戳(剔除离线用) | | `lock:heartbeat` / `lock:scheduler` / `lock:timeout` | String | 分布式锁,防多实例重复执行后台循环 | | `log:audit` | List | 全链路审计日志(dispatch/progress/result) | --- ## 六、技术栈与端口汇总 ```mermaid flowchart LR subgraph 后端 B["Python + FastAPI + Uvicorn
redis-py(asyncio) + httpx
端口 8000"] end subgraph 前端 F["Vue 3 + Vite + Element Plus
端口 5173(/api 代理到 8000)"] end subgraph Agent A["Python + Google ADK v2.5
FastAPI ApiServer + InMemoryRunner
端口 8001"] end subgraph 存储 R["Redis(远程 45.207.192.237:56987/0)
任务池 + Agent 池 + 索引 + 日志 + 锁"] end B <--> R B <-->|"HTTP 推送 / 结果回传"| A F -->|"/api/admin/*"| B ``` --- ## 七、任务状态机 ```mermaid stateDiagram-v2 [*] --> pending: submit 受理(幂等) pending --> running: 调度器选 Agent 并推送成功 pending --> pending: 无可用 Agent / 推送失败回退 running --> success: Agent 回传 result(success) running --> failed: Agent 回传 failed running --> failed: 超时 / 用户取消 pending --> failed: 用户取消 success --> pending: 手动重置(重新调度) failed --> pending: 手动重置(重新调度) success --> [*]: TTL 归档 failed --> [*]: TTL 归档 ```