# 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回流/导出
        └───────────────┬────────────────┘
                        │  NATS（RPC + 流 + 控制面广播 + 心跳）——万物总线
     ┌──────────────────┼───────────────────────────────┐
     │                  │                                │
┌────┴─────┐     ┌──────┴──────┐                  ┌──────┴──────┐
│dispatcher│     │  mcp-go     │                  │  mcp-py     │
│ 编排核心  │     │ Go 工具服务  │                  │ Python 算法  │
│ (Eino)   │     │ RAG/记忆/    │                  │ 沙箱/解析    │
│ +harness │     │ 历史/报告    │                  │             │
└────┬─────┘     └──────┬──────┘                  └─────────────┘
     │                  │
     └── LLM providers   └── PG / Redis / Milvus / Neo4j / MinIO
        (OpenAI 兼容)        关系 / 缓存 / 向量 / 图谱 / 对象
```

**模块职责边界（清晰、无循环 import）**
- **gateway**：HTTP 接入、JWT、路由、输入护栏、限流、审计、SSE 回流、报告导出服务。不含业务编排。
- **dispatcher**：Eino 编排引擎（DSL→compose 图）+ harness 治理层（评测/护栏/预算/熔断/纠偏/脱敏）+ LLM 池（failover+缓存）+ 多智能体协调。
- **mcp-go / mcp-py**：MCP 工具服务，经 NATS 被调。真正的 I/O 与算法执行在这里。
- **shared**：bus（NATS/JetStream）、contract（跨服务契约）、prompts 注册表、secrets（AES-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.InvokableRun`（react_agent.go）→ NATS→mcp-go。
- **共同点**：真正执行永远在 mcp-go；**Eino 把工具当黑盒（吃 JSON→吐字符串），从不碰文件系统**。

**C. 报告导出/写文件**：dispatcher 生成 → mcp-go `report_store` 写源 JSON → 用户导出 → gateway `report_export` → mcp-go 渲染 docx 并 `os.WriteFile` 到 `SUNDYNIX_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_id，`owner_id` 当隔离键。变多租户是**动表结构 + 鉴权边界的手术**（T4.A，L 级）。
- **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 | 第一次真实并发/宕机 | T3（NATS 集群 + DB HA）⏸ |
| 单租户 → 多租户 | 第一个多租户客户 | T4.A（RBAC/tenant_id，L）|
| 共享文件系统耦合 | 第一次容器化/多机 | 见 §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_DIR`、`NATS_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. **T3（NATS 集群/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.md`（T0–T4 路线）、`EINO_ADOPTION.md`（Eino 采纳 A/B/C✅ D 基本）、`production_readiness.md`、`architecture.md`。
