55d50417a9
failover/熔断的运行时态原来只在 dispatcher 日志、admin 看不到 —— 本次接到概览可见:
- harness: CircuitBreaker.Snapshot() 只读观测访问器(state + fails,不动状态机)
- llm: Pool.ModelHealth() 上报主备链每模型 {provider,model,role,state,fails};
buildWithFallbacks 把模型名↔breaker 配对(同包直接读 failoverModel.breakers);
newFailoverModel 改返回具体类型以便读 breakers
- dispatcher 心跳 payload 加 models[]
- gateway /admin/overview 独立超时 Ping dispatcher,合并进 models.health
- admin 概览「模型路由」新增「运行时链路态(实时)」:逐模型状态点
(🟢在线/🔴熔断中+失败数/🟡半开探测/单点)
- 单测:Snapshot、Pool.ModelHealth(名字↔态配对/单点/空)
- live:配坏主→提交任务打熔断→概览显示 broken-demo「熔断中·失败3」,备用在线
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1509 lines
35 KiB
Markdown
1509 lines
35 KiB
Markdown
# sundynix-agentix · Web SaaS 架构重构实施文档
|
||
|
||
> 版本:v2.0-refactor
|
||
> 日期:2026-07-06
|
||
> 基于:`ARCHITECTURE_DESIGN.md` 当前完整版
|
||
> 目标:在保留现有事件驱动、Eino 编排、NATS 总线、MCP 工具化优势的基础上,将系统从「桌面端 + 云编排平台」升级为「可商业化的 Web SaaS Agent 平台」。
|
||
|
||
---
|
||
|
||
## 0. 重构结论
|
||
|
||
当前架构已经具备较强的 Agent 平台雏形:
|
||
|
||
- Gateway 作为唯一 HTTP 接入层。
|
||
- Dispatcher 使用 Eino 作为编排核心。
|
||
- NATS + JetStream 承载任务、工具 RPC、token 流、控制面广播。
|
||
- Redis Stream 支持 SSE 断点回放。
|
||
- mcp-go / mcp-py 承载工具服务。
|
||
- LLM Pool 支持 OpenAI-compatible Provider、failover、熔断、缓存。
|
||
- Harness 层已经覆盖 guardrail、脱敏、预算、评测纠偏等能力。
|
||
|
||
但如果要做 Web SaaS 商业化,需要优先补齐以下核心能力:
|
||
|
||
1. **Client 层重构**:从「桌面端主产品」调整为「Web App 主产品 + Desktop Connector 可选」。
|
||
2. **Task Runtime 独立化**:把任务状态机、重试、取消、恢复、审批 checkpoint、幂等从 dispatcher/gateway 中抽象出来。
|
||
3. **Model Gateway 独立化**:把 LLM Pool 升级为模型网关,承载模型路由、用量计量、成本核算、套餐权限、BYOK、fallback。
|
||
4. **多租户/RBAC 前置**:全链路补 `tenant_id / workspace_id / project_id`,避免后期大规模重构。
|
||
5. **Tool / MCP 分层**:拆分 Internal Tools、Remote MCP Gateway、Tool Policy Engine。
|
||
6. **NATS Subject 规范化**:把 Command、Event、Stream、Tool RPC、Control、Health 分区,避免“万物总线”失控。
|
||
7. **Billing Usage Meter 先落事件**:不必马上接 Stripe/支付,但必须先把用量事件和成本账本做出来。
|
||
8. **生产化迁移机制**:逐步替换 GORM AutoMigrate,补充 migration、幂等、审计、数据隔离策略。
|
||
|
||
---
|
||
|
||
## 1. 重构目标
|
||
|
||
### 1.1 产品目标
|
||
|
||
将系统从当前形态:
|
||
|
||
```text
|
||
Desktop App + Admin Console + Cloud Agent Backend
|
||
```
|
||
|
||
升级为:
|
||
|
||
```text
|
||
Web SaaS Agent Platform
|
||
+ Optional Desktop / Local Connector
|
||
+ Admin Console
|
||
```
|
||
|
||
目标产品能力:
|
||
|
||
- 用户可在 Web App 中创建工作区、项目、任务、Agent 图和知识库。
|
||
- Agent 编排默认在服务端执行。
|
||
- 远程 MCP、内部工具、模型调用、计费全部由服务端统一管控。
|
||
- 桌面端不再是唯一用户入口,而是可选的本地能力扩展。
|
||
- 后续可支持 Local Agent / Desktop Connector 处理本地文件、Shell、本地 MCP。
|
||
|
||
### 1.2 技术目标
|
||
|
||
- 保留现有 Go + Eino + NATS + MCP 方向。
|
||
- 降低 Gateway 和 Dispatcher 的职责耦合。
|
||
- 增加 SaaS 必备的租户、计费、权限、审计、模型成本能力。
|
||
- 让 Agent 任务支持暂停、恢复、取消、重试、审批、断点回放。
|
||
- 让模型和工具调用都可计量、可审计、可限流、可降级。
|
||
- 为后续微服务拆分、K8s、NATS 集群、DB HA 做边界准备。
|
||
|
||
---
|
||
|
||
## 2. 当前架构问题清单
|
||
|
||
### 2.1 Client 层定位偏桌面端
|
||
|
||
当前文档中用户工作产品是 Wails 桌面端,Web 管理端仅用于运维控制台。这个定位更适合桌面 Agent,而不是 Web SaaS。
|
||
|
||
**风险:**
|
||
|
||
- SaaS 用户入口不清晰。
|
||
- 本地文件能力和云端 Agent 能力边界混合。
|
||
- 后续做团队协作、组织计费、浏览器任务面板会被桌面端假设限制。
|
||
|
||
**重构方向:**
|
||
|
||
- Web App 成为主用户产品。
|
||
- Admin Console 保留为管理端。
|
||
- Desktop/Wails 改为 Optional Local Connector。
|
||
|
||
---
|
||
|
||
### 2.2 NATS 承载语义过多
|
||
|
||
当前 NATS 承载任务、工具 RPC、token 流、执行轨迹、控制面广播、心跳、持久队列。
|
||
|
||
**风险:**
|
||
|
||
- Subject 命名膨胀。
|
||
- Command/Event/Stream/Query 混用。
|
||
- 任务状态散落在消息链路中。
|
||
- 调试和权限治理变复杂。
|
||
|
||
**重构方向:**
|
||
|
||
- 保留 NATS 作为事件和工具总线。
|
||
- 明确 Command Bus、Event Bus、Stream Bus、Tool RPC、Control Plane、Health 的命名规范。
|
||
- 引入 Task Runtime 作为任务生命周期事实源。
|
||
|
||
---
|
||
|
||
### 2.3 Task Runtime 不够独立
|
||
|
||
当前任务生命周期分散在 Gateway、NATS、Dispatcher、Redis Stream、DB FSM、approval checkpoint 中。
|
||
|
||
**风险:**
|
||
|
||
- 取消、暂停、恢复、审批重试、Worker 崩溃恢复逻辑分散。
|
||
- 很难统一做任务幂等和任务审计。
|
||
- 后续引入 Temporal 或多 Worker 会迁移困难。
|
||
|
||
**重构方向:**
|
||
|
||
- 增加 Task Runtime Layer。
|
||
- MVP 阶段用 PostgreSQL FSM + NATS/JetStream。
|
||
- 生产阶段可演进到 Temporal。
|
||
|
||
---
|
||
|
||
### 2.4 LLM Pool 应升级为 Model Gateway
|
||
|
||
当前 LLM Pool 已经具备 failover、缓存、热配置、breaker,但仍偏模型池实现,而不是 SaaS 计费核心。
|
||
|
||
**风险:**
|
||
|
||
- 模型能力、价格、用户套餐、token 用量、成本账本分散。
|
||
- 不利于接入多 Provider、BYOK、企业模型网关。
|
||
- 不利于真实计费。
|
||
|
||
**重构方向:**
|
||
|
||
- 独立 Model Gateway / Model Runtime 概念。
|
||
- 统一 Provider Adapter、Usage Meter、Cost Calculator、Routing Policy、Capability Registry。
|
||
|
||
---
|
||
|
||
### 2.5 多租户和 RBAC 尚未进入核心数据模型
|
||
|
||
当前文档明确是 `owner_id` 单租户假设,多租户/RBAC 尚未启动。
|
||
|
||
**风险:**
|
||
|
||
- 表结构、Redis key、NATS envelope、MinIO object path、Milvus/Neo4j namespace 后期都要重构。
|
||
- 计费、审计、权限无法天然支持组织/团队。
|
||
|
||
**重构方向:**
|
||
|
||
- 立即在核心 Contract 和数据表中引入 `tenant_id`。
|
||
- 同步引入 `workspace_id / project_id / user_id / role / permission`。
|
||
|
||
---
|
||
|
||
### 2.6 Tool / MCP 层边界需要重拆
|
||
|
||
当前 mcp-go 同时承载 RAG、记忆、历史、报告、元工具;mcp-py 承载算法工具,但部分为桩。
|
||
|
||
**风险:**
|
||
|
||
- 内部工具和远程 MCP 混合。
|
||
- Tool 权限、审计、套餐限制没有独立中枢。
|
||
- Python 算法层如果长期为桩,会影响产品真实可用性。
|
||
|
||
**重构方向:**
|
||
|
||
- 拆成 Internal Tool Services、Remote MCP Gateway、Tool Policy Engine。
|
||
- Python 工具必须从“链路已通”走向“至少一条真实可用核心能力”。
|
||
|
||
---
|
||
|
||
## 3. 目标架构总览
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
|
||
subgraph CLIENT["1. Client Layer"]
|
||
WEB["User Web App\nNext.js/React + React Flow\nTask Console / DSL Designer / Artifact Viewer"]
|
||
ADMIN["Admin Console\nModel / Billing / Tenant / Audit / Ops"]
|
||
LOCAL["Optional Local Connector\nWails/Tauri\nLocal FS / Shell / Local MCP"]
|
||
end
|
||
|
||
subgraph GATEWAY["2. Gateway Layer"]
|
||
GW["Go Gateway\nAuth / RateLimit / Guardrail Tier1\nTask API / SSE / Admin API"]
|
||
end
|
||
|
||
subgraph TASK["3. Task Runtime Layer"]
|
||
FSM["Task FSM\nsubmitted/running/waiting/done/failed"]
|
||
APPROVAL["Approval Checkpoint"]
|
||
IDEMP["Idempotency / Retry / Cancel / Resume"]
|
||
EVENTLOG["Task Event Log"]
|
||
end
|
||
|
||
subgraph BUS["4. Event Bus Layer"]
|
||
NATS["NATS + JetStream"]
|
||
REDISSTREAM["Redis Stream\nSSE Replay"]
|
||
end
|
||
|
||
subgraph DISPATCHER["5. Agent Dispatcher Layer"]
|
||
EINO["Eino Compose Engine"]
|
||
PLANNER["Planner / Router / Context Manager"]
|
||
TOOLRUN["Tool Executor"]
|
||
HARNESS["Harness\nGuardrail Tier2 / Eval / Budget / Desensitize"]
|
||
end
|
||
|
||
subgraph MODEL["6. Model Gateway Layer"]
|
||
ROUTER["Routing Policy"]
|
||
ADAPTER["Provider Adapters\nOpenAI-compatible / vLLM / Ollama / Future Claude"]
|
||
USAGE["Usage Meter / Cost Calculator"]
|
||
BREAKER["Failover / Breaker / Cache"]
|
||
end
|
||
|
||
subgraph TOOL["7. Tool & MCP Layer"]
|
||
POLICY["Tool Policy Engine\nAllow/Deny/Approval/Quota/Audit"]
|
||
GOTOOLS["Internal Go Tools\nRAG / Memory / History / Report / External API"]
|
||
PYTOOLS["Internal Python Tools\nSandbox / Parser / OCR / Code Interpreter"]
|
||
REMOTEMCP["Remote MCP Gateway\nOAuth / Registry / Remote Servers"]
|
||
end
|
||
|
||
subgraph DATA["8. Data Layer"]
|
||
PG["PostgreSQL"]
|
||
REDIS["Redis"]
|
||
MINIO["MinIO"]
|
||
MILVUS["Milvus"]
|
||
NEO4J["Neo4j"]
|
||
JAEGER["Jaeger / OTel"]
|
||
end
|
||
|
||
WEB --> GW
|
||
ADMIN --> GW
|
||
LOCAL --> GW
|
||
GW --> FSM
|
||
FSM --> NATS
|
||
NATS --> EINO
|
||
EINO --> ROUTER
|
||
EINO --> POLICY
|
||
POLICY --> GOTOOLS
|
||
POLICY --> PYTOOLS
|
||
POLICY --> REMOTEMCP
|
||
ROUTER --> ADAPTER
|
||
ADAPTER --> USAGE
|
||
USAGE --> PG
|
||
EINO --> NATS
|
||
NATS --> REDISSTREAM
|
||
REDISSTREAM --> GW
|
||
GW --> WEB
|
||
GW --> ADMIN
|
||
FSM --> PG
|
||
EVENTLOG --> PG
|
||
GOTOOLS --> MILVUS
|
||
GOTOOLS --> NEO4J
|
||
GOTOOLS --> MINIO
|
||
PYTOOLS --> MINIO
|
||
GW --> REDIS
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 分层重构设计
|
||
|
||
## 4.1 Client Layer 重构
|
||
|
||
### 当前形态
|
||
|
||
```text
|
||
Desktop Wails = 用户工作产品
|
||
Admin React = 运维控制台
|
||
```
|
||
|
||
### 目标形态
|
||
|
||
```text
|
||
User Web App = 主产品
|
||
Admin Console = 运维/商业后台
|
||
Optional Local Connector = 本地能力扩展
|
||
```
|
||
|
||
### User Web App 职责
|
||
|
||
- 工作区 / 项目 / 任务管理。
|
||
- Agent DSL 画布编排。
|
||
- 任务运行控制台。
|
||
- Plan 审核、HITL 审批。
|
||
- Token stream / exec event 实时展示。
|
||
- Artifact / Report / Knowledge Base 预览。
|
||
- 团队成员和权限入口。
|
||
- 套餐、用量、账单入口。
|
||
|
||
### Admin Console 职责
|
||
|
||
- 模型配置。
|
||
- Provider 配置。
|
||
- 价格配置。
|
||
- 租户管理。
|
||
- 用户管理。
|
||
- 审计日志。
|
||
- Guardrail 事件。
|
||
- 模型健康和熔断状态。
|
||
- MCP 工具注册与状态。
|
||
- 系统运行 overview。
|
||
|
||
### Optional Local Connector 职责
|
||
|
||
- 本地文件系统访问。
|
||
- 本地 Shell 执行。
|
||
- 本地 Git 操作。
|
||
- 本地 MCP Server 连接。
|
||
- 本地另存为、系统通知、应用打开。
|
||
- 将本地能力以受控 Tool 形式暴露给服务端或本地 Agent。
|
||
|
||
### 重构建议
|
||
|
||
目录可调整为:
|
||
|
||
```text
|
||
/apps
|
||
/web # 用户 Web App
|
||
/admin # 管理后台
|
||
/desktop-connector # 可选本地连接器,原 Wails 逐步迁移
|
||
```
|
||
|
||
---
|
||
|
||
## 4.2 Gateway Layer 重构
|
||
|
||
### Gateway 应保留职责
|
||
|
||
- HTTP API 入口。
|
||
- Auth / JWT / Session。
|
||
- Rate Limit。
|
||
- CORS。
|
||
- RequestID / OTel / Audit middleware。
|
||
- Guardrail Tier1。
|
||
- DSL Schema Validation。
|
||
- Task API。
|
||
- SSE/WebSocket Fanout。
|
||
- Admin API。
|
||
- Report download/export endpoint。
|
||
|
||
### Gateway 不应承担职责
|
||
|
||
- 不做 Agent 编排。
|
||
- 不做复杂 DSL execution plan assembly。
|
||
- 不做工具路由。
|
||
- 不做模型路由。
|
||
- 不直接访问内部工具实现。
|
||
|
||
### Gateway 推荐模块结构
|
||
|
||
```text
|
||
/services/gateway
|
||
/cmd
|
||
/internal
|
||
/api
|
||
/task
|
||
/workspace
|
||
/project
|
||
/billing
|
||
/admin
|
||
/sse
|
||
/middleware
|
||
auth.go
|
||
ratelimit.go
|
||
guardrail.go
|
||
audit.go
|
||
observe.go
|
||
/validator
|
||
dsl_schema.go
|
||
/client
|
||
task_runtime_client.go
|
||
event_stream_client.go
|
||
```
|
||
|
||
---
|
||
|
||
## 4.3 Task Runtime Layer 新增
|
||
|
||
### 为什么要新增
|
||
|
||
Agent SaaS 的任务不是普通 HTTP 请求,而是长生命周期对象。任务可能经历:
|
||
|
||
```text
|
||
submitted → queued → running → waiting_approval → running → done
|
||
submitted → queued → running → failed → retrying → running → done
|
||
submitted → queued → running → cancelled
|
||
submitted → queued → running → timeout
|
||
```
|
||
|
||
这些状态不应该散落在 Gateway、Dispatcher 和 NATS 消息中。
|
||
|
||
### Task Runtime 职责
|
||
|
||
- Task FSM 状态机。
|
||
- TaskRun 实例管理。
|
||
- StepRun 状态管理。
|
||
- Approval checkpoint。
|
||
- Retry / Cancel / Resume / Timeout。
|
||
- 幂等键管理。
|
||
- Worker lease / heartbeat。
|
||
- Event Log 落库。
|
||
- Task 级并发控制。
|
||
- Tenant 级并发控制。
|
||
|
||
### MVP 实现
|
||
|
||
MVP 不必马上引入 Temporal,可以用:
|
||
|
||
```text
|
||
PostgreSQL tasks/task_runs/task_events
|
||
+ NATS JetStream durable consumer
|
||
+ Dispatcher worker heartbeat
|
||
+ Redis lock 可选
|
||
```
|
||
|
||
### 生产演进
|
||
|
||
后续可迁移到:
|
||
|
||
```text
|
||
Temporal Workflow
|
||
+ Go Activity Worker
|
||
+ Eino Agent Activity
|
||
+ NATS Event Fanout
|
||
```
|
||
|
||
### 推荐状态机
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> submitted
|
||
submitted --> queued
|
||
queued --> running
|
||
running --> waiting_approval
|
||
waiting_approval --> running: approved
|
||
waiting_approval --> rejected: rejected
|
||
running --> done
|
||
running --> failed
|
||
running --> timeout
|
||
running --> cancelling
|
||
cancelling --> cancelled
|
||
failed --> retrying
|
||
retrying --> queued
|
||
done --> [*]
|
||
rejected --> [*]
|
||
cancelled --> [*]
|
||
timeout --> [*]
|
||
```
|
||
|
||
### 核心表草案
|
||
|
||
```sql
|
||
CREATE TABLE sundynix_tasks (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
workspace_id UUID NOT NULL,
|
||
project_id UUID,
|
||
owner_user_id UUID NOT NULL,
|
||
title TEXT NOT NULL,
|
||
status TEXT NOT NULL,
|
||
dsl JSONB NOT NULL,
|
||
current_run_id UUID,
|
||
idempotency_key TEXT,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
deleted_at TIMESTAMPTZ
|
||
);
|
||
|
||
CREATE TABLE sundynix_task_runs (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
task_id UUID NOT NULL,
|
||
status TEXT NOT NULL,
|
||
attempt INT NOT NULL DEFAULT 1,
|
||
started_at TIMESTAMPTZ,
|
||
finished_at TIMESTAMPTZ,
|
||
error_code TEXT,
|
||
error_message TEXT,
|
||
worker_id TEXT,
|
||
heartbeat_at TIMESTAMPTZ,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE TABLE sundynix_task_events (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
task_id UUID NOT NULL,
|
||
run_id UUID,
|
||
event_type TEXT NOT NULL,
|
||
event_payload JSONB NOT NULL,
|
||
trace_id TEXT,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE TABLE sundynix_approval_checkpoints (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
task_id UUID NOT NULL,
|
||
run_id UUID NOT NULL,
|
||
node_id TEXT NOT NULL,
|
||
status TEXT NOT NULL,
|
||
request_payload JSONB NOT NULL,
|
||
response_payload JSONB,
|
||
requested_by UUID,
|
||
approved_by UUID,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
resolved_at TIMESTAMPTZ
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 4.4 Agent Dispatcher Layer 重构
|
||
|
||
### 保留能力
|
||
|
||
当前 dispatcher 的这些能力建议保留:
|
||
|
||
- Eino compose 单编排引擎。
|
||
- DSL → compose 图编译。
|
||
- 分支、并行、map、coordinator、approval。
|
||
- ReAct 工具调用。
|
||
- Token stream 和 exec event。
|
||
- Harness 治理层。
|
||
|
||
### 需要调整的边界
|
||
|
||
Dispatcher 不应该直接承担完整任务生命周期,而应该从 Task Runtime 领取任务执行:
|
||
|
||
```text
|
||
Task Runtime 发布 RunCommand
|
||
→ Dispatcher 执行 Agent Graph
|
||
→ Dispatcher 发布 TaskEvent / StreamEvent
|
||
→ Task Runtime 更新状态
|
||
```
|
||
|
||
### Dispatcher 推荐职责
|
||
|
||
- 编译 DSL 为 Eino compose graph。
|
||
- 执行 graph。
|
||
- 管理上下文。
|
||
- 调用 Model Gateway。
|
||
- 调用 Tool Policy Engine。
|
||
- 产出 token stream / exec events。
|
||
- 产出节点级执行结果。
|
||
- 产出评测结果。
|
||
|
||
### Dispatcher 不应职责
|
||
|
||
- 不直接做计费结算。
|
||
- 不直接管理租户权限。
|
||
- 不直接存储模型密钥。
|
||
- 不直接暴露 HTTP API。
|
||
|
||
### 推荐接口
|
||
|
||
```go
|
||
type AgentExecutor interface {
|
||
Execute(ctx context.Context, req ExecuteRequest) (<-chan AgentEvent, error)
|
||
Cancel(ctx context.Context, runID string) error
|
||
Resume(ctx context.Context, req ResumeRequest) error
|
||
}
|
||
|
||
type ExecuteRequest struct {
|
||
TenantID string
|
||
WorkspaceID string
|
||
ProjectID string
|
||
TaskID string
|
||
RunID string
|
||
UserID string
|
||
DSL DSLGraph
|
||
Input map[string]any
|
||
Policy ExecutionPolicy
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4.5 Model Gateway Layer 新增
|
||
|
||
### 为什么独立
|
||
|
||
模型调用是 SaaS 成本、体验和商业化的核心,不应该只是 dispatcher 内部的 `llm/pool.go`。
|
||
|
||
Model Gateway 要统一处理:
|
||
|
||
- Provider Adapter。
|
||
- 模型能力注册。
|
||
- 模型路由。
|
||
- 套餐可用模型。
|
||
- BYOK。
|
||
- Usage metering。
|
||
- Cost calculation。
|
||
- Failover。
|
||
- Circuit breaker。
|
||
- Cache。
|
||
- Structured output 适配。
|
||
- Tool calling 适配。
|
||
- Prompt caching 预留。
|
||
|
||
### 目标结构
|
||
|
||
```text
|
||
Model Gateway
|
||
├── Provider Registry
|
||
├── Capability Registry
|
||
├── Routing Policy
|
||
├── Provider Adapter
|
||
├── Usage Meter
|
||
├── Cost Calculator
|
||
├── Failover Manager
|
||
├── Breaker Manager
|
||
├── Cache Layer
|
||
└── Admin Runtime State
|
||
```
|
||
|
||
### Provider Adapter 接口建议
|
||
|
||
```go
|
||
type ModelProvider interface {
|
||
Name() string
|
||
Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error)
|
||
Stream(ctx context.Context, req ChatRequest) (<-chan ChatStreamEvent, error)
|
||
CountTokens(ctx context.Context, req TokenRequest) (*TokenUsage, error)
|
||
Capabilities(ctx context.Context, model string) ModelCapabilities
|
||
}
|
||
|
||
type ModelCapabilities struct {
|
||
SupportsTools bool
|
||
SupportsVision bool
|
||
SupportsJSONMode bool
|
||
SupportsReasoning bool
|
||
SupportsEmbeddings bool
|
||
MaxContextTokens int
|
||
MaxOutputTokens int
|
||
}
|
||
```
|
||
|
||
### Usage Event 表
|
||
|
||
```sql
|
||
CREATE TABLE sundynix_model_usage_events (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
user_id UUID NOT NULL,
|
||
task_id UUID,
|
||
run_id UUID,
|
||
provider TEXT NOT NULL,
|
||
model TEXT NOT NULL,
|
||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||
cached_tokens BIGINT NOT NULL DEFAULT 0,
|
||
cost_usd NUMERIC(18,8) NOT NULL DEFAULT 0,
|
||
latency_ms BIGINT,
|
||
status TEXT NOT NULL,
|
||
error_code TEXT,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
```
|
||
|
||
### 路由策略示例
|
||
|
||
```text
|
||
route_policy:
|
||
tenant_plan: pro
|
||
task_type: report_generation
|
||
preferred_models:
|
||
- deepseek-chat
|
||
- qwen-plus
|
||
fallback_models:
|
||
- local-vllm-qwen
|
||
max_cost_usd: 0.20
|
||
max_latency_ms: 30000
|
||
require_tool_calling: true
|
||
```
|
||
|
||
---
|
||
|
||
## 4.6 Tool / MCP Layer 重构
|
||
|
||
### 目标分层
|
||
|
||
```text
|
||
Tool & MCP Layer
|
||
├── Tool Policy Engine
|
||
├── Internal Go Tools
|
||
├── Internal Python Tools
|
||
└── Remote MCP Gateway
|
||
```
|
||
|
||
### Tool Policy Engine 职责
|
||
|
||
每一次工具调用前,都必须经过 Tool Policy Engine:
|
||
|
||
```text
|
||
Dispatcher → Tool Policy Engine → Tool Service / Remote MCP
|
||
```
|
||
|
||
策略结果:
|
||
|
||
```text
|
||
allow
|
||
deny
|
||
require_approval
|
||
quota_exceeded
|
||
plan_required
|
||
rate_limited
|
||
```
|
||
|
||
### Tool Policy 请求结构
|
||
|
||
```go
|
||
type ToolPolicyRequest struct {
|
||
TenantID string
|
||
WorkspaceID string
|
||
ProjectID string
|
||
UserID string
|
||
TaskID string
|
||
RunID string
|
||
ToolName string
|
||
ToolType string // internal_go, internal_py, remote_mcp, local_connector
|
||
Arguments map[string]any
|
||
RiskLevel string // low, medium, high, critical
|
||
}
|
||
```
|
||
|
||
### Tool Audit 表
|
||
|
||
```sql
|
||
CREATE TABLE sundynix_tool_call_events (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
user_id UUID NOT NULL,
|
||
task_id UUID,
|
||
run_id UUID,
|
||
tool_name TEXT NOT NULL,
|
||
tool_type TEXT NOT NULL,
|
||
risk_level TEXT,
|
||
policy_decision TEXT NOT NULL,
|
||
input_hash TEXT,
|
||
output_hash TEXT,
|
||
latency_ms BIGINT,
|
||
status TEXT NOT NULL,
|
||
error_code TEXT,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
```
|
||
|
||
### Internal Go Tools
|
||
|
||
适合继续由 Go 承载:
|
||
|
||
- RAG search。
|
||
- Wiki search。
|
||
- Memory。
|
||
- History。
|
||
- Report render/export。
|
||
- External API connectors。
|
||
- Metadata tools。
|
||
- Health/list_tools。
|
||
|
||
### Internal Python Tools
|
||
|
||
必须从桩逐步真实化:
|
||
|
||
- P0:Secure Code Sandbox 真实可用。
|
||
- P0:Code Interpreter 至少支持 Python 片段执行 + 超时 + 输出限制。
|
||
- P1:MinerU / OCR 文档解析真实可用。
|
||
- P1:多模态解析任务异步化。
|
||
|
||
### Remote MCP Gateway
|
||
|
||
Remote MCP Gateway 单独负责:
|
||
|
||
- MCP Server Registry。
|
||
- OAuth token vault。
|
||
- Tool discovery。
|
||
- Tool allowlist / denylist。
|
||
- Per-tenant tool policy。
|
||
- Per-plan tool availability。
|
||
- Remote tool audit。
|
||
- Remote tool quota。
|
||
|
||
---
|
||
|
||
## 4.7 NATS Subject 规范化
|
||
|
||
### 当前问题
|
||
|
||
当前 NATS 是统一总线,但 subject 分类需要更严格,否则后期难以运维。
|
||
|
||
### 推荐 Subject 命名
|
||
|
||
```text
|
||
# Command
|
||
sundynix.cmd.task.submit
|
||
sundynix.cmd.task.cancel
|
||
sundynix.cmd.task.resume
|
||
sundynix.cmd.task.approve
|
||
sundynix.cmd.task.reject
|
||
|
||
# Event
|
||
sundynix.events.task.created
|
||
sundynix.events.task.queued
|
||
sundynix.events.task.started
|
||
sundynix.events.task.waiting_approval
|
||
sundynix.events.task.completed
|
||
sundynix.events.task.failed
|
||
sundynix.events.task.cancelled
|
||
|
||
# Stream
|
||
sundynix.streams.task.<task_id>.token
|
||
sundynix.streams.task.<task_id>.exec
|
||
sundynix.streams.kb.<ingest_id>.progress
|
||
|
||
# Tool RPC
|
||
sundynix.tools.go.<tool_name>
|
||
sundynix.tools.py.<tool_name>
|
||
sundynix.tools.remote_mcp.<server_id>.<tool_name>
|
||
|
||
# Control Plane
|
||
sundynix.control.model.updated
|
||
sundynix.control.prompt.activated
|
||
sundynix.control.tool.registry_updated
|
||
sundynix.control.policy.updated
|
||
|
||
# Health
|
||
sundynix.health.gateway
|
||
sundynix.health.dispatcher
|
||
sundynix.health.mcp_go
|
||
sundynix.health.mcp_py
|
||
sundynix.health.model_gateway
|
||
```
|
||
|
||
### Envelope 标准
|
||
|
||
```go
|
||
type Envelope[T any] struct {
|
||
ID string `json:"id"`
|
||
Type string `json:"type"`
|
||
Version string `json:"version"`
|
||
TenantID string `json:"tenant_id"`
|
||
WorkspaceID string `json:"workspace_id,omitempty"`
|
||
ProjectID string `json:"project_id,omitempty"`
|
||
UserID string `json:"user_id,omitempty"`
|
||
TaskID string `json:"task_id,omitempty"`
|
||
RunID string `json:"run_id,omitempty"`
|
||
TraceID string `json:"trace_id,omitempty"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
Payload T `json:"payload"`
|
||
}
|
||
```
|
||
|
||
### 使用原则
|
||
|
||
- Command:表示“请求系统执行某动作”。
|
||
- Event:表示“某事实已经发生”。
|
||
- Stream:表示“高频、可回放、面向前端展示的事件流”。
|
||
- Tool RPC:表示“内部工具请求-响应”。
|
||
- Control:表示“运行时配置变更广播”。
|
||
- Health:表示“探活和状态查询”。
|
||
|
||
---
|
||
|
||
## 5. 多租户与 RBAC 重构
|
||
|
||
## 5.1 为什么必须前置
|
||
|
||
Web SaaS 的最小商业单位不是 user,而是 tenant / organization。
|
||
|
||
如果后期再补多租户,会影响:
|
||
|
||
- PostgreSQL 表结构。
|
||
- Redis key。
|
||
- NATS envelope。
|
||
- MinIO object path。
|
||
- Milvus collection/partition。
|
||
- Neo4j node/edge namespace。
|
||
- MCP token。
|
||
- 模型 Key。
|
||
- 审计日志。
|
||
- 计费账本。
|
||
|
||
### 5.2 基础租户模型
|
||
|
||
```text
|
||
Tenant
|
||
└── Workspace
|
||
└── Project
|
||
└── Task
|
||
└── TaskRun
|
||
```
|
||
|
||
### 5.3 推荐核心表
|
||
|
||
```sql
|
||
CREATE TABLE sundynix_tenants (
|
||
id UUID PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
slug TEXT UNIQUE NOT NULL,
|
||
plan TEXT NOT NULL DEFAULT 'free',
|
||
status TEXT NOT NULL DEFAULT 'active',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE TABLE sundynix_tenant_members (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
user_id UUID NOT NULL,
|
||
role TEXT NOT NULL,
|
||
status TEXT NOT NULL DEFAULT 'active',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
UNIQUE(tenant_id, user_id)
|
||
);
|
||
|
||
CREATE TABLE sundynix_workspaces (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
name TEXT NOT NULL,
|
||
created_by UUID NOT NULL,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE TABLE sundynix_projects (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
workspace_id UUID NOT NULL,
|
||
name TEXT NOT NULL,
|
||
description TEXT,
|
||
created_by UUID NOT NULL,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
```
|
||
|
||
### 5.4 RBAC 初版角色
|
||
|
||
```text
|
||
owner
|
||
admin
|
||
member
|
||
viewer
|
||
billing_admin
|
||
```
|
||
|
||
### 5.5 权限动作示例
|
||
|
||
```text
|
||
tenant.manage
|
||
billing.manage
|
||
workspace.create
|
||
project.create
|
||
task.create
|
||
task.run
|
||
task.cancel
|
||
task.approve
|
||
model.use
|
||
model.manage
|
||
tool.use
|
||
tool.manage
|
||
kb.read
|
||
kb.write
|
||
audit.read
|
||
```
|
||
|
||
### 5.6 数据隔离规则
|
||
|
||
- 所有核心表必须有 `tenant_id`。
|
||
- 所有查询必须默认带 `tenant_id`。
|
||
- 所有 Redis key 带 tenant 前缀。
|
||
- 所有 NATS envelope 带 `tenant_id`。
|
||
- 所有 MinIO path 带 `tenant_id/workspace_id/project_id`。
|
||
- Milvus 推荐使用 tenant partition 或 metadata filter。
|
||
- Neo4j 节点和关系必须带 `tenant_id`。
|
||
|
||
Redis Key 示例:
|
||
|
||
```text
|
||
sundynix:{tenant_id}:task:{task_id}:stream
|
||
sundynix:{tenant_id}:rate:{user_id}
|
||
sundynix:{tenant_id}:session:{session_id}
|
||
```
|
||
|
||
MinIO Path 示例:
|
||
|
||
```text
|
||
tenants/{tenant_id}/workspaces/{workspace_id}/projects/{project_id}/artifacts/{artifact_id}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Billing 与 Usage Meter 重构
|
||
|
||
## 6.1 原则
|
||
|
||
第一阶段不一定要接支付,但必须先做 Usage Meter。
|
||
|
||
真实计费依赖以下用量:
|
||
|
||
- 模型 input/output/cached token。
|
||
- 模型成本。
|
||
- 工具调用次数。
|
||
- 远程 MCP 调用次数。
|
||
- Code Sandbox 执行时长。
|
||
- 文档解析页数。
|
||
- 向量入库 token/条数。
|
||
- 存储空间。
|
||
- 任务运行时长。
|
||
|
||
### 6.2 Billing Event 表
|
||
|
||
```sql
|
||
CREATE TABLE sundynix_usage_events (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
user_id UUID,
|
||
task_id UUID,
|
||
run_id UUID,
|
||
event_type TEXT NOT NULL,
|
||
resource_type TEXT NOT NULL,
|
||
resource_name TEXT,
|
||
quantity NUMERIC(18,6) NOT NULL,
|
||
unit TEXT NOT NULL,
|
||
unit_price NUMERIC(18,8),
|
||
cost NUMERIC(18,8),
|
||
currency TEXT DEFAULT 'USD',
|
||
metadata JSONB,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
```
|
||
|
||
### 6.3 账单聚合表
|
||
|
||
```sql
|
||
CREATE TABLE sundynix_usage_daily_rollups (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id UUID NOT NULL,
|
||
date DATE NOT NULL,
|
||
resource_type TEXT NOT NULL,
|
||
quantity NUMERIC(18,6) NOT NULL,
|
||
cost NUMERIC(18,8) NOT NULL,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
UNIQUE(tenant_id, date, resource_type)
|
||
);
|
||
```
|
||
|
||
### 6.4 计费阶段
|
||
|
||
```text
|
||
阶段 1:仅记录 usage_events。
|
||
阶段 2:按天 rollup,后台展示成本。
|
||
阶段 3:套餐 quota + 超额限制。
|
||
阶段 4:接支付系统。
|
||
阶段 5:企业账单、发票、成本中心。
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 数据流重构
|
||
|
||
## 7.1 Task Run Flow
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as Web App
|
||
participant G as Gateway
|
||
participant T as Task Runtime
|
||
participant N as NATS
|
||
participant D as Dispatcher
|
||
participant M as Model Gateway
|
||
participant P as Tool Policy
|
||
participant Tool as Tool/MCP
|
||
participant R as Redis Stream
|
||
|
||
U->>G: POST /tasks with DSL
|
||
G->>G: Auth + RateLimit + Guardrail Tier1 + DSL Schema Validation
|
||
G->>T: Create Task
|
||
T->>T: Create TaskRun + FSM=submitted/queued
|
||
T->>N: Publish cmd.task.run
|
||
D->>N: Subscribe cmd.task.run
|
||
D->>D: Compile DSL to Eino Graph
|
||
D->>M: Stream Chat / Tool Calling
|
||
D->>P: Check Tool Policy
|
||
P->>Tool: Allow and Call Tool
|
||
D->>N: Publish task events/token stream
|
||
N->>R: Persist stream events
|
||
G->>R: Read Redis Stream
|
||
G->>U: SSE token/exec events
|
||
D->>T: Report final status
|
||
T->>T: FSM=done/failed/timeout
|
||
```
|
||
|
||
---
|
||
|
||
## 7.2 Approval Flow
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant D as Dispatcher
|
||
participant T as Task Runtime
|
||
participant R as Redis Stream
|
||
participant G as Gateway
|
||
participant U as Web App
|
||
|
||
D->>T: Create Approval Checkpoint
|
||
T->>T: FSM=waiting_approval
|
||
T->>R: Event approval.required
|
||
G->>R: SSE read
|
||
G->>U: Show approval card
|
||
U->>G: POST /tasks/:id/approvals/:approval_id/approve
|
||
G->>T: Approve checkpoint
|
||
T->>T: FSM=queued/running
|
||
T->>D: Resume run command
|
||
```
|
||
|
||
---
|
||
|
||
## 7.3 Model Usage Flow
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant D as Dispatcher
|
||
participant M as Model Gateway
|
||
participant P as Provider
|
||
participant B as Usage Meter
|
||
participant DB as PostgreSQL
|
||
|
||
D->>M: Chat/Stream request
|
||
M->>M: Route model + check plan + budget
|
||
M->>P: Provider API
|
||
P-->>M: Stream/Response + usage
|
||
M->>B: Emit model_usage_event
|
||
B->>DB: Store usage/cost
|
||
M-->>D: Return response
|
||
```
|
||
|
||
---
|
||
|
||
## 7.4 Tool Call Flow
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant D as Dispatcher
|
||
participant P as Tool Policy Engine
|
||
participant A as Approval Runtime
|
||
participant Tool as Internal/Remote Tool
|
||
participant Audit as Tool Audit
|
||
|
||
D->>P: tool_call_request
|
||
P->>P: Check tenant/plan/risk/quota
|
||
alt allow
|
||
P->>Tool: Call tool
|
||
Tool-->>P: Tool result
|
||
P->>Audit: Write allow event
|
||
P-->>D: result
|
||
else require approval
|
||
P->>A: Create approval checkpoint
|
||
P-->>D: wait approval
|
||
else deny
|
||
P->>Audit: Write deny event
|
||
P-->>D: policy denied
|
||
end
|
||
```
|
||
|
||
---
|
||
|
||
## 8. DSL 重构建议
|
||
|
||
### 8.1 DSL 增加版本和执行策略
|
||
|
||
```json
|
||
{
|
||
"version": "2.0",
|
||
"kind": "agent_graph",
|
||
"metadata": {
|
||
"name": "Research Report Agent",
|
||
"description": "Generate report from KB and web tools"
|
||
},
|
||
"execution_policy": {
|
||
"timeout_seconds": 1800,
|
||
"max_retries": 2,
|
||
"max_cost_usd": 0.5,
|
||
"require_approval_for_high_risk_tools": true
|
||
},
|
||
"nodes": [],
|
||
"edges": []
|
||
}
|
||
```
|
||
|
||
### 8.2 Node 增加风险和权限声明
|
||
|
||
```json
|
||
{
|
||
"id": "tool_1",
|
||
"kind": "tool",
|
||
"label": "Search Wiki",
|
||
"config": {
|
||
"tool_name": "kb_search",
|
||
"risk_level": "low",
|
||
"requires_approval": false,
|
||
"timeout_seconds": 30
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.3 DSL 校验分层
|
||
|
||
Gateway 只做:
|
||
|
||
- JSON schema 校验。
|
||
- 节点 ID 重复。
|
||
- 悬挂边。
|
||
- 节点数量限制。
|
||
- 边数量限制。
|
||
- 不允许的节点 kind。
|
||
|
||
Dispatcher 做:
|
||
|
||
- 编译为 Eino graph。
|
||
- execution plan assembly。
|
||
- branch default 检查。
|
||
- map 并发策略。
|
||
- tool availability 检查。
|
||
- model capability 检查。
|
||
|
||
---
|
||
|
||
## 9. 目录结构重构建议
|
||
|
||
```text
|
||
sundynix-agentix/
|
||
apps/
|
||
web/
|
||
admin/
|
||
desktop-connector/
|
||
|
||
services/
|
||
gateway/
|
||
task-runtime/
|
||
dispatcher/
|
||
model-gateway/
|
||
tool-policy/
|
||
mcp-go/
|
||
mcp-py/
|
||
|
||
shared/
|
||
contract/
|
||
envelope.go
|
||
task.go
|
||
dsl.go
|
||
model.go
|
||
tool.go
|
||
billing.go
|
||
tenant.go
|
||
bus/
|
||
nats.go
|
||
subjects.go
|
||
jetstream.go
|
||
auth/
|
||
otel/
|
||
secrets/
|
||
prompts/
|
||
errors/
|
||
|
||
deployments/
|
||
docker-compose/
|
||
k8s/
|
||
|
||
migrations/
|
||
postgres/
|
||
|
||
docs/
|
||
architecture/
|
||
api/
|
||
dsl/
|
||
operations/
|
||
```
|
||
|
||
MVP 阶段不一定物理拆成所有服务,但代码目录应按目标边界组织。
|
||
|
||
---
|
||
|
||
## 10. 分阶段实施计划
|
||
|
||
## Phase 0:架构边界整理,1–2 周
|
||
|
||
目标:不大改功能,先把概念和 contract 对齐。
|
||
|
||
任务:
|
||
|
||
- [ ] 在架构文档中新增 Task Runtime Layer。
|
||
- [ ] 在架构文档中新增 Model Gateway Layer。
|
||
- [ ] 在架构文档中拆分 Internal Tools / Remote MCP Gateway / Tool Policy Engine。
|
||
- [ ] 统一 NATS Subject 命名规范。
|
||
- [ ] 定义 Envelope v1。
|
||
- [ ] 核心 contract 增加 `tenant_id/workspace_id/project_id` 字段。
|
||
- [ ] 明确 Web App、Admin Console、Desktop Connector 三类客户端边界。
|
||
|
||
交付物:
|
||
|
||
- `docs/architecture/ARCHITECTURE_DESIGN_V2.md`
|
||
- `shared/contract/envelope.go`
|
||
- `shared/bus/subjects.go`
|
||
|
||
---
|
||
|
||
## Phase 1:多租户骨架与 Task Runtime,2–4 周
|
||
|
||
目标:让任务运行具备 SaaS 数据隔离和统一状态机。
|
||
|
||
任务:
|
||
|
||
- [ ] 新增 tenant/workspace/project 表。
|
||
- [ ] 核心任务表补 `tenant_id/workspace_id/project_id`。
|
||
- [ ] Redis key 加 tenant namespace。
|
||
- [ ] NATS envelope 强制带 tenant_id。
|
||
- [ ] 新增 task_runs/task_events/approval_checkpoints。
|
||
- [ ] Gateway 创建任务改为写 Task Runtime。
|
||
- [ ] Dispatcher 从 Task Runtime command 中领取任务。
|
||
- [ ] Task 状态变更统一落 task_events。
|
||
- [ ] SSE 从 Redis Stream + task_events 恢复历史。
|
||
|
||
交付物:
|
||
|
||
- `services/task-runtime`
|
||
- `migrations/postgres/001_tenant_task_runtime.sql`
|
||
- 任务运行状态机测试。
|
||
|
||
---
|
||
|
||
## Phase 2:Model Gateway 与 Usage Meter,2–4 周
|
||
|
||
目标:模型调用从“能用”升级为“可商业化”。
|
||
|
||
任务:
|
||
|
||
- [ ] 从 dispatcher 中抽出 model runtime。
|
||
- [ ] 定义 ModelProvider 接口。
|
||
- [ ] 实现 OpenAI-compatible Provider。
|
||
- [ ] 实现 vLLM/Ollama Provider。
|
||
- [ ] 增加 model_capabilities 表。
|
||
- [ ] 增加 model_usage_events 表。
|
||
- [ ] 增加价格配置表。
|
||
- [ ] 增加 route policy。
|
||
- [ ] Admin 展示模型健康、熔断状态、成本。
|
||
- [ ] 每次模型调用写 usage event。
|
||
|
||
交付物:
|
||
|
||
- `services/model-gateway`
|
||
- `sundynix_model_usage_events`
|
||
- Admin Model Runtime 页面。
|
||
|
||
---
|
||
|
||
## Phase 3:Tool Policy 与 Remote MCP Gateway,2–5 周
|
||
|
||
目标:工具调用可管控、可审批、可审计、可计费。
|
||
|
||
任务:
|
||
|
||
- [ ] 新增 Tool Policy Engine。
|
||
- [ ] 每次工具调用前经过 policy check。
|
||
- [ ] 高风险工具支持 require_approval。
|
||
- [ ] 工具调用写 `tool_call_events`。
|
||
- [ ] mcp-go 工具注册增加 risk_level、required_plan、permissions。
|
||
- [ ] mcp-py 至少真实化一个核心工具。
|
||
- [ ] Remote MCP Gateway 独立出 registry、OAuth、audit。
|
||
- [ ] Admin 增加 Tool Registry / Tool Audit 页面。
|
||
|
||
交付物:
|
||
|
||
- `services/tool-policy`
|
||
- `sundynix_tool_call_events`
|
||
- Tool risk policy 文档。
|
||
|
||
---
|
||
|
||
## Phase 4:Web App 主产品化,3–6 周
|
||
|
||
目标:让 Web App 成为主产品入口。
|
||
|
||
任务:
|
||
|
||
- [ ] 新建或迁移 User Web App。
|
||
- [ ] React Flow DSL Designer Web 化。
|
||
- [ ] Task Run Console。
|
||
- [ ] Artifact Viewer。
|
||
- [ ] Approval UI。
|
||
- [ ] Usage / Billing 页面。
|
||
- [ ] Workspace / Project / Team 页面。
|
||
- [ ] Desktop Connector 改为可选本地能力。
|
||
|
||
交付物:
|
||
|
||
- `/apps/web`
|
||
- 用户任务闭环:创建 → 执行 → 审批 → 查看结果 → 查看用量。
|
||
|
||
---
|
||
|
||
## Phase 5:生产硬化,持续
|
||
|
||
目标:上线准备。
|
||
|
||
任务:
|
||
|
||
- [ ] AutoMigrate 替换为 migration 工具。
|
||
- [ ] NATS 集群。
|
||
- [ ] PostgreSQL 备份/恢复。
|
||
- [ ] Redis HA。
|
||
- [ ] MinIO bucket policy。
|
||
- [ ] TLS。
|
||
- [ ] Secret rotation。
|
||
- [ ] OTel 指标完善。
|
||
- [ ] Prometheus/Grafana。
|
||
- [ ] Admin 熔断态和失败原因可视化。
|
||
- [ ] 数据删除和租户注销流程。
|
||
|
||
---
|
||
|
||
## 11. MVP 收敛范围
|
||
|
||
为了避免重构过度,MVP 建议保留以下能力:
|
||
|
||
```text
|
||
必须做:
|
||
- Web App 任务入口
|
||
- Gateway
|
||
- Task Runtime DB FSM
|
||
- Dispatcher + Eino
|
||
- Model Gateway 基础版
|
||
- OpenAI-compatible Provider
|
||
- NATS + Redis Stream
|
||
- mcp-go 基础工具
|
||
- tenant_id 全链路
|
||
- usage_events 记录
|
||
- SSE 任务流
|
||
|
||
暂缓:
|
||
- Temporal
|
||
- NATS 集群
|
||
- 完整 K8s
|
||
- 完整计费支付
|
||
- 完整 mcp-py 算法集群
|
||
- 完整多模型市场
|
||
- 完整 prompt 灰度实验
|
||
- 完整企业审计
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 风险与规避
|
||
|
||
| 风险 | 影响 | 规避 |
|
||
|---|---|---|
|
||
| 继续以桌面端为主产品 | Web SaaS 定位不清 | Web App 主产品化,Desktop Connector 可选 |
|
||
| NATS 语义过载 | 后期难维护 | subject 分区 + envelope 标准 |
|
||
| 任务状态散落 | 取消/恢复/审批困难 | Task Runtime 独立 |
|
||
| 模型调用不可计量 | 无法商业化 | Model Gateway + usage_events |
|
||
| 没有 tenant_id | SaaS 后期重构巨大 | 立即补全 tenant/workspace/project |
|
||
| 工具调用无策略 | 安全和套餐不可控 | Tool Policy Engine |
|
||
| mcp-py 长期为桩 | 产品能力虚 | P0 真实化 sandbox 或 parser |
|
||
| AutoMigrate 上生产 | 数据迁移不可控 | goose/atlas/migrate |
|
||
| Guardrail 只在入口 | 工具风险失控 | Tool-call 前置 policy + output guard |
|
||
|
||
---
|
||
|
||
## 13. 最终建议
|
||
|
||
这次重构不是推翻当前架构,而是做一次 SaaS 化升级:
|
||
|
||
```text
|
||
保留:
|
||
- Go 主后端
|
||
- Gateway 接入层
|
||
- Eino Dispatcher
|
||
- NATS + JetStream
|
||
- Redis Stream 回放
|
||
- mcp-go/mcp-py 工具化
|
||
- Harness 治理层
|
||
- 控制面热切换
|
||
|
||
新增/强化:
|
||
- User Web App 主产品
|
||
- Task Runtime
|
||
- Model Gateway
|
||
- Tenant/RBAC
|
||
- Usage Meter
|
||
- Tool Policy Engine
|
||
- Remote MCP Gateway
|
||
- NATS Subject 规范
|
||
- Migration 生产化
|
||
```
|
||
|
||
优先级最高的不是继续堆 Agent 能力,而是先把 SaaS 底座补齐:
|
||
|
||
```text
|
||
P0:tenant_id 全链路 + Task Runtime + Model Gateway + Usage Meter
|
||
P1:Tool Policy + Remote MCP + Web App 主产品化
|
||
P2:生产硬化 + Temporal/K8s/NATS Cluster
|
||
```
|
||
|
||
完成这次重构后,sundynix-agentix 将从一个能力很强的内部/桌面混合 Agent 平台,升级为一个具备商业化基础的 Web SaaS Agent 平台。
|