Files
sundynix-agentix/ARCHITECTURE_REVIEW.md
Blizzard da04beadf5 docs: 架构评审报告 ARCHITECTURE_REVIEW.md
基于通读代码 + 真机验证的全栈架构评审:系统全景/核心决策取舍/关键数据流/
优缺点/技术债「税单」映射路线图/上生产前必修清单/总体判断。
一手依据:控制面热切换 live、failover+熔断 live、双 NATS 脑裂实测、审计误报核实。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 16:35:21 +08:00

14 KiB
Raw Permalink Blame History

sundynix-agentix · 架构评审报告

评审日期:2026-07-02 评审范围:全栈架构(gateway / dispatcher / mcp-go / mcp-py / shared / 双前端 / 基建) 评审方式:通读代码 + 真机运行验证(本次会话中实跑并踩到若干真实问题,见文末「证据索引」) 定性:这不是「一个应用」,而是一套 事件驱动的 Agent 平台。请按「平台」而非「应用」的标准衡量它。


0. 摘要(一句话结论)

架构 factored 得相当好、也相当有野心,但当前是「分布式系统的复杂度,由接近单人的规模在扛」。 解耦干净、控制面热切换、韧性分层——这些是真资产;代价是运维面大、一致性靠自觉、单租户假设焊死。 复杂度是否值得,取决于目标:多租户平台产品 → 值;单用户工具/demo → 偏重。

Top 3
最强 ① 契约+NATS 解耦(加工具/换模型/改 prompt 热生效,零重编译)② 分层韧性(failover+熔断+预算+护栏+评测)③ 流式原生
最痛 ① NATS 万物单点 + 运维尖角(双 NATS 脑裂真踩到)② 一致性靠 best-effort(非事务级联删等)③ 单租户假设焊死

1. 系统全景

        ┌─────────────┐   ┌─────────────┐
        │  桌面端 Wails │   │  管理端 React │        ← 两个独立产品面(绝不合并)
        └──────┬──────┘   └──────┬──────┘
               │ HTTP/SSE         │ HTTP
        ┌──────┴──────────────────┴──────┐
        │        gateway (gin)            │  接入层:JWT鉴权/路由/护栏/限流/审计/SSE回流/导出
        └───────────────┬────────────────┘
                        │  NATSRPC + 流 + 控制面广播 + 心跳)——万物总线
     ┌──────────────────┼───────────────────────────────┐
     │                  │                                │
┌────┴─────┐     ┌──────┴──────┐                  ┌──────┴──────┐
│dispatcher│     │  mcp-go     │                  │  mcp-py     │
│ 编排核心  │     │ Go 工具服务  │                  │ Python 算法  │
│ (Eino)   │     │ RAG/记忆/    │                  │ 沙箱/解析    │
│ +harness │     │ 历史/报告    │                  │             │
└────┬─────┘     └──────┬──────┘                  └─────────────┘
     │                  │
     └── LLM providers   └── PG / Redis / Milvus / Neo4j / MinIO
        (OpenAI 兼容)        关系 / 缓存 / 向量 / 图谱 / 对象

模块职责边界(清晰、无循环 import)

  • gateway:HTTP 接入、JWT、路由、输入护栏、限流、审计、SSE 回流、报告导出服务。不含业务编排。
  • dispatcherEino 编排引擎(DSL→compose 图)+ harness 治理层(评测/护栏/预算/熔断/纠偏/脱敏)+ LLM 池(failover+缓存)+ 多智能体协调。
  • mcp-go / mcp-py:MCP 工具服务,经 NATS 被调。真正的 I/O 与算法执行在这里。
  • sharedbusNATS/JetStream)、contract(跨服务契约)、prompts 注册表、secretsAES-GCM)、otel。服务间只认 contract + bus,互不 import。

2. 核心架构决策与取舍

决策 好处 代价
NATS 为统一总线RPC/流/控制面/心跳全在上) 极致解耦;广播式控制面热更新 万物单点;一旦异常以诡异方式全面降级;单点 NATS(集群是 T3)
MCP 工具作为独立服务 加工具只改注册表、dispatcher 自动发现;多语言(Go+Py) 每次 tool call 是网络 RPC(多 no responders/超时故障类);要整链在线
Eino 做编排核心 DSL→compose、ReAct、checkpoint(HITL) 白嫖框架 框架耦合/塑形;限制传导(如流式中途失败不切)
控制面热切换(模型/prompt 经 NATS 广播) 不重启改配置/换 provider/改提示词 权威态在 DB、下发靠广播,广播失败需兜底
契约解耦shared/contract 服务独立演进、独立部署 契约变更需跨服务协调
多存储专用化PG/Redis/Milvus/Neo4j/MinIO 各司其职、检索质量高 5 个存储要起/连/备份/保一致
双前端desktop/admin 独立) 用户产品与运维面互不干扰 两套前端 + 两套构建要维护

3. 关键数据流(架构最能说明问题的四条)

A. 任务生命周期:桌面端 POST DSL → gateway 解析+拓扑校验 → NATS 发布 → dispatcher 编译为 Eino compose 图执行 → token 流 + 执行轨迹经 NATS→Redis Stream→SSE 回流 → 状态机 FSM 落库。

B. 工具调用(两条路,易混淆)

  • 编排直连dispatcher 编排代码 o.tools.CallTool() 直接 NATS→mcp-go。报告写文件(report_render)走这条,绕开 Eino。
  • Eino ReAct 自主调用:仅 agent:true 工具。模型 function-call → Eino ToolsNode → mcpTool.InvokableRunreact_agent.go)→ NATS→mcp-go。
  • 共同点:真正执行永远在 mcp-goEino 把工具当黑盒(吃 JSON→吐字符串),从不碰文件系统

C. 报告导出/写文件dispatcher 生成 → mcp-go report_store 写源 JSON → 用户导出 → gateway report_export → mcp-go 渲染 docx 并 os.WriteFileSUNDYNIX_REPORTS_DIR(默认 $TMPDIR/sundynix-reports/{id}.docx)→ gateway c.File(路径) 流回 → 桌面端 Wails SaveReportAs 原生另存为落盘。⚠️ mcp-go 写、gateway 按路径读,二者必须共享该目录。

D. 控制面热切换admin 改配置 → gateway 写 DB → NATS 广播激活集 → dispatcher/mcp-go ApplyOverrides 热更新(不重启)。本次会话 live 验证 prompt/模型 均即时生效。


4. 优点(有据,非纸面)

  1. 解耦干净、扩展成本低 —— 最大亮点。 服务互不 import,只认契约。加工具只改 mcp-go 注册表、dispatcher 经 list_tools 自动发现;换 provider/改 prompt 控制面热下发、零重编译。本次会话亲见 live 生效。
  2. 韧性分层叠进架构,非事后补。 model 层 failover + 编排层熔断 + 预算 + 护栏 + 评测纠偏(「恒温器」)。单 provider 挂平台不宕——本次真机演示过完整 failover+熔断+半开恢复。
  3. 流式原生。 token 流 + 执行轨迹 NATS→SSE + Redis Stream 断点重放,实时体验是架构级支持。
  4. Eino 省造轮子。 编排图/ReAct/checkpoint(HITL) 白嫖框架,自研 graph.go 已退役。
  5. 合理的多语言/多存储。 Go 走热路径,Python 做算法/沙箱;存储各司其职。
  6. 可观测与水平扩展底子在。 OTel 全链路 + 结构化日志 + 轨迹;NATS queue group + JetStream 持久消费,worker 无状态可扩;入库走 JetStream 持久队列(崩溃重投/幂等/背压,已 live 验证)。

5. 缺点 / 风险 / 技术债(诚实的一半)

5.1 运维面大、故障以诡异方式出现

  • NATS 万物单点。 它是 RPC/流/控制面/心跳,一旦异常全面降级。本次真踩到双 NATS 脑裂make devnats 与 docker NATS 都占 4222,客户端被劈成两半、静默半失败)。当前是单点 NATS(集群为 T3,未上)。
  • 分布式跑/调都难。 4 服务 + NATS + 5 存储要全起对连对。local-run-gotchas 那条 memory 长不是没原因(mcp-go 必须在 Milvus 后、ReportsDir 共享、token 过期静默 401、JetStream 重投…)。

5.2 一致性/正确性靠自觉,非机制强制

  • 大量 best-effort:审计失败吞掉、部分关键 DB 写失败仍返 200、KB 级联删跨三库非事务(删一半失败仍删 PG → 不一致)。
  • 预算/护栏是「计量+兜底」式,非硬约束(不过已有默认顶,见「审计误报」)。

5.3 与「干净解耦」自相矛盾的隐性耦合

  • 共享本地文件系统ReportsDir):mcp-go 写、gateway 按路径读——单机能对上,一旦容器化拆开即断,除非挂共享卷。这是整套 NATS 解耦里一处潜在耦合

5.4 扩展性/多租户

  • 单租户假设焊死。 无 RBAC/tenant_idowner_id 当隔离键。变多租户是动表结构 + 鉴权边界的手术T4.AL 级)。
  • RequireAdmin 开发期放行任意登录用户(生产靠 ADMIN_USER_IDS 白名单,无角色矩阵)。

5.5 框架耦合 / 取舍不一致

  • 编排核心 Eino-native,框架抽象塑形代码,限制会传导(流式中途失败不切,部分是 Eino stream 语义)。
  • 又有「该用库却手搓」的地方:office/unioffice.go 其实是零依赖手搓 docx(非 unioffice 库);mcp-py 算法层目前是(解析未接 OCR)。

5.6 可观测的盲区

  • failover/熔断的运行时态只在 dispatcher 日志,admin UI 看不到(本次 demo 暴露,已记 T4.F 待办)。分层韧性在运维上偏不透明。

6. 「税单」:复杂度的代价何时到期(映射路线图)

这套架构的痛点,本质是「分布式平台迟早要付的税」。项目已把它们编入路线图,且克制地把纯部署硬化推迟(T3 标 ⏸「等有真实流量再上」——这是对的判断,别在没用户前先付税):

何时爆发 对应项
单点 NATS / DB 无 HA 第一次真实并发/宕机 T3NATS 集群 + DB HA)⏸
单租户 → 多租户 第一个多租户客户 T4.ARBAC/tenant_idL
共享文件系统耦合 第一次容器化/多机 见 §7 必修清单
非事务级联删 / best-effort 写 数据量上来后的静默不一致 T4.F(级联删事务化/关键写上浮 5xx)
无审计/安全溯源 合规/事故复盘 T4.B(已做:审计+护栏事件+审计页)
运行时韧性态不可见 生产排障 T4.F🔴 模型健康/熔断态 surface 到 admin,本次新增)

已还的债(本次会话)T4.B 审计可溯源整组 、T4.E 编排边角整组 Map 错误传播/专家超时/Branch else/DSL 校验/熔断接回 failover)、T4.F 部分(拆 search 残骸/CORS+限流收紧)。


7. 「上生产前必修清单」(当你要容器化 / 多机部署时,这些会先断)

  1. 报告文件落盘 → 去本地盘耦合。 mcp-go 写/gateway 读同一本地目录在多机即断。改:报告直传 MinIO(正文已走 MinIO,导出产物同理),gateway 从对象存储取,而非 c.File(本地路径)
  2. 单点 NATS → 集群。 3 节点 + JetStream Raft,否则总线宕=平台宕。(T3)
  3. 多进程共享配置对齐。 SUNDYNIX_SECRET_KEY(三服务须一致)、SUNDYNIX_REPORTS_DIRNATS_URL 等,容器化时用统一 env/secret,别靠 $TMPDIR 默认对齐(会不一致)。
  4. DB HA + 备份/DR 演练。T3
  5. CORS/TLS 严格化。 CORS 生产已收紧(本次做);TLS 待上(T3)。
  6. RBAC/多租户若面向多客户则前置(T4.A)。
  7. 一致性收口:KB 级联删事务化、关键 DB 写失败上浮 5xx(T4.F)——多机下静默不一致更难查。
  8. 可观测补齐:模型/熔断运行时态、各服务指标上报 admin(T4.F)。

8. 总体判断与建议

判断:一套 factored 良好、有平台野心的架构。解耦与控制面是真正的差异化资产;当前阶段(单租户、无真实流量)复杂度相对偏重,但方向自洽——痛点都已被识别并编入路线图,且硬化被克制地推迟。

最该警惕的一条:解耦很干净,但一致性与运维的「暗债」在攒(非事务级联删、best-effort 写、双 NATS 这类环境坑、共享文件系统)。这些不会在 demo 里咬你,会在「第一个真实多用户 / 容器化部署」时集中爆发。

建议(按优先级)

  1. 继续还 T4.F 的正确性债(级联删事务化、关键写上浮)——低成本、防未来静默 bug。
  2. 补运行时可观测(模型/熔断态上 admin)——让分层韧性在生产可见。
  3. 在容器化之前,先解「共享文件系统 + 配置对齐」两处(§7 #1、#3)——这是"看起来能跑、一拆就断"的典型。
  4. T3NATS 集群/HA/TLS)维持 ⏸,直到有真实流量——不提前付税是对的。
  5. 多租户(T4.A)按商业化节奏推——不确定要多租户就先别动这个大手术。

附:证据索引(本次评审的一手依据)

  • 控制面热切换 live 有效:prompt 建版→激活→图谱抽取即时变;模型配置热下发(dispatcher 日志 model config set)。
  • failover+熔断 live:配坏主模型→任务经备用出答案;连败 3 次熔断→跳过坏主;冷却半开探测→重试→重熔断(完整三态)。
  • 双 NATS 脑裂真踩到devnats(127.0.0.1:4222) 与 docker NATS(*:4222) 并存,客户端劈成两半、/admin/status 误报服务离线;curl :8222/connz 定位、pkill devnats 收敛。
  • 审计清单需逐项核实(原始审计有噪声):ListModels「O(N²)」实为 O(N) 单次;budget「无限烧」实为 taskBudget 已默认 20 万顶;hybrid「删文件」实为拆残骸接线;failover「卡在备用」实为每次都重试主。教训:改前必读码核实。
  • 关键文件gateway/internal/{router,handler,middleware,store}dispatcher/internal/{eino,llm,harness}mcp-go/internal/{mcp,rag,office}shared/{bus,contract,prompts,secrets}
  • 配套文档DEPTH_ROADMAP.mdT0T4 路线)、EINO_ADOPTION.mdEino 采纳 A/B/C D 基本)、production_readiness.mdarchitecture.md