# sundynix-agentix · 架构设计文档 > 版本:2026-07-26 > 定位:**事件驱动的多租户 AI Agent 平台**。以 NATS 为统一总线,服务经契约解耦,Eino 为编排核心,控制面热切换;桌面端 JARVIS 既是语音入口,也是能操作用户电脑的中枢。 > > **本文以代码为单一事实源。** `PROGRESS.md`(停更于 2026-06-19)与 `DEPTH_ROADMAP.md` 的汇总表已与代码脱节(详见 §9.14),仅作历史参考。 > > 配套文档:`ARCHITECTURE_REVIEW.md`(架构评审)、`DEPTH_ROADMAP.md`(路线图)、`EINO_ADOPTION.md`(Eino 采纳)、`SAAS_DESIGN.md` / `SAAS_P2_DESIGN.md`(多租户与计量)、`SPACE_DESIGN.md`(共享工作区)、`PAYMENT_DESIGN.md`(支付)、`VOICE_DESIGN.md`(语音)、`JARVIS_BRAIN_DESIGN.md`(JARVIS 中枢)、`LOCAL_AGENT_DESIGN.md`(本地执行)、`DEPLOY.md`(部署)。 --- ## 1. 系统概述 用户在桌面端搭一张编排图(或直接说话),任务经网关落库并发到 NATS;调度集群把 DSL 编译成 Eino compose 图执行,过程中自主调用工具(检索/联网/计算/操作用户电脑),Token 与执行轨迹实时流回界面;全程带计量计费、护栏、评测与链路追踪。 ### 1.1 Monorepo 结构 ``` sundynix-agentix/ ├── sundynix-shared/ 共享库:NATS 总线 / 契约 / 对象存储 / 密钥 / OTel / prompts ├── sundynix-gateway/ 第 2 层 业务网关(HTTP + WS + 平台工具 + 后台常驻) ├── sundynix-dispatcher/ 第 4 层 Agent 编排调度集群(无对外端口) ├── sundynix-mcp-go/ 第 5 层 Go I/O 型工具服务(RAG / 记忆 / 报告 / 图表) ├── sundynix-mcp-py/ 第 5 层 Python 算法型工具服务(沙箱执行 / 文档解析) ├── sundynix-desktop/ 桌面端(Wails v3 + React 19)——主产品面 ├── sundynix-admin/ 官网 + 运维控制台(同一 SPA,go:embed 进 gateway) ├── sundynix-web/ 薄 Web 面(租户自助:注册/组织/团队/账单) ├── deploy/ 三机部署配置 + NATS 集群配置 └── scripts/ 备份/恢复/RAG 评测 ``` `go.work` 只纳入 4 个后端模块(shared / gateway / dispatcher / mcp-go)。 **`sundynix-desktop` 刻意不入 workspace**(它是客户端,独立依赖),因此在该目录下跑 Go 命令必须 `GOWORK=off`。 ### 1.2 代码规模(实测) | 部分 | 源码 | 测试 | |---|---|---| | Go · gateway | 14,395 | 2,775 | | Go · dispatcher | 5,265 | 2,974 | | Go · mcp-go | 3,844 | 1,319 | | Go · shared | 2,173 | 681 | | Go · desktop | 697 | 271 | | TypeScript · desktop 前端 | 8,980 | 11 个前端测试文件 | | TypeScript · admin | 9,360 | (同上) | | TypeScript · web | 2,030 | (同上) | | Python · mcp-py | 520 | | --- ## 2. 分层架构总览 ```mermaid flowchart TB subgraph CLIENT["客户端层"] DESK["sundynix-desktop
Wails v3 + React 19
编排画布 · JARVIS · 本地 runner"] ADMIN["sundynix-admin
官网 / + 控制台 /admin"] WEB["sundynix-web
租户自助柜台"] end subgraph GW["第 2 层 · gateway(唯一对外入口)"] HTTP["HTTP API + SSE(gin)"] WS["WebSocket
语音 /voice/stream
本地执行器 /local/runner"] PLAT["平台工具提供方
platform_* / local_*"] BG["后台常驻
配置控制面 · 持久消费者
入库 worker 池 · 3 个 ticker"] end BUS{{"NATS + JetStream
统一总线(8MB payload)"}} subgraph WORK["执行层"] DISP["第 4 层 · dispatcher
Eino compose 编排
LLM 双池 + failover + 熔断
harness 治理"] MGO["第 5 层 · mcp-go
RAG 三路 / 记忆 / 报告 / 图表"] MPY["第 5 层 · mcp-py
Docker 沙箱 / 文档解析"] end subgraph STORE["存储层"] PG[("PostgreSQL 16
29 张表")] RDS[("Redis 7")] MLV[("Milvus 2.4.13")] BLV[("Bleve 全文")] NEO[("Neo4j 5")] OSS[("MinIO")] end LLM["LLM Provider
OpenAI 兼容 · DeepSeek"] VOLC["火山引擎
ASR / TTS"] DESK --> HTTP ADMIN --> HTTP WEB --> HTTP DESK <--> WS HTTP --> BUS WS --> VOLC BG <--> BUS PLAT <--> BUS BUS <--> DISP BUS <--> MGO BUS <--> MPY DISP --> LLM HTTP --> PG HTTP --> RDS HTTP --> OSS MGO --> MLV MGO --> BLV MGO --> NEO MGO --> OSS DISP --> BUS ``` ### 2.1 分层职责 | 层 | 组件 | 职责 | 对外端口 | |---|---|---|---| | 1 客户端 | desktop / admin / web | 交互与呈现 | — | | 2 接入 | **gateway** | 鉴权、租户/空间上下文、限流、护栏、审计、任务落库与发射、SSE/WS 回流、平台工具、后台常驻 | **8080**(生产 3000) | | 3 总线 | **NATS + JetStream** | 任务队列、回流、工具 RPC、控制面广播、KV checkpoint | 4222 | | 4 编排 | **dispatcher** | DSL→compose 图执行、ReAct 自主工具、多智能体、HITL 中断、评测纠偏 | 无(仅探针 8091) | | 5 工具 | **mcp-go / mcp-py** | I/O 型与算法型能力,队列组水平扩 | 无(仅探针 8092) | **关键设计**:dispatcher 与 mcp-\* 都**没有对外端口**,只通过 NATS 通信 —— 攻击面收敛到 gateway 一个进程。 --- ## 3. 服务详解 ### 3.1 gateway —— 业务网关 / 统一接入层 `github.com/sundynix/sundynix-gateway` · Go 1.25.8 · 入口 `cmd/server/main.go` | internal 包 | 职责 | |---|---| | `router` | Gin 装配:路由 + 中间件链 + CORS + admin SPA 回退 | | `handler` | 30+ 文件:task/agent/kb/report/space/tenant/billing/payment/voice/jarvis/prompt/admin/wechat/local_runner/platform_tools | | `middleware` | RequestID · Observe · Auth 系列 · TenantContext · SpaceContext · RateLimit · Guardrail · Audit · Require\*Role | | `store` | Postgres(GORM) + Redis 全部访问;迁移、租户作用域插件、leader 选主 | | `auth` | 无状态 JWT 签发/校验 + bcrypt | | `dsl` | 前端 JSON DSL → `contract.Task` 解析组装 + 拓扑校验 | | `guardrail` | 输入护栏 Tier1(归一化 + 注入正则 + env 黑名单) | | `payment` | 渠道抽象 + manager + 微信支付 | | `wechat` | 公众号带参二维码扫码登录 + 事件回调 | | `voice` | 火山 V3 流式 ASR/TTS 客户端 + 二进制帧协议 + 攒句器 | | `webui` | `go:embed` admin 产物打进二进制 | | `nats` | shared/bus 薄封装 | **技术栈** | 用途 | 库 | 版本 | |---|---|---| | Web 框架 | `gin-gonic/gin` | v1.12.0 | | SSE | `gin-contrib/sse` | v1.1.1 | | ORM | `gorm.io/gorm` + `driver/postgres` | v1.31.1 / v1.6.0 | | 缓存 | `redis/go-redis/v9` | v9.20.0 | | 鉴权 | `golang-jwt/jwt/v5` + `x/crypto`(bcrypt) | v5.3.1 / v0.53.0 | | ID | `bwmarrin/snowflake` | v0.3.0 | | WebSocket | `gorilla/websocket` | v1.5.3 | | 指标 | `prometheus/client_golang` | v1.23.2 | | 追踪 | `otelgin` + otel | v0.69.0 / v1.44.0 | | 支付 | `wechatpay-apiv3/wechatpay-go` | v0.2.21 | | 测试 DB | `glebarez/sqlite`(纯 Go 无 CGO,仅测试) | v1.11.0 | **后台常驻组件** | 组件 | 作用 | |---|---| | `ServeConfig` ×3 | 模型配置控制面应答(kind = chat / embedding / voice) | | `ServePrompts` | 激活 prompt 集下发 | | `ConsumeTaskStatus` | 任务状态落库 + **报告完成时主动语音播报** | | `ConsumeEval` / `ConsumeUsage` | 评测结果 upsert / 用量落库计费 | | `StartIngestWorkers` | JetStream 入库作业 worker 池(有界并发背压) | | `ServePlatformTools` | gateway 自己作为 MCP 工具提供方(见 §5.4) | | `StartReconcile` / `StartSubscriptionTicker` / `StartScheduleTicker` | 微信掉单补偿 / 订阅周期发放 / JARVIS 定时任务 | 三个 ticker 均带 **PG advisory lock 选主**(`store/leader.go`),多副本下只有一个实例真正扫。 **辅助 CLI**:`cmd/localsim`(模拟桌面本地执行器)、`cmd/voicesim`(免麦端到端语音链路模拟)、`cmd/voiceconfig`、`cmd/voicecheck`。 ### 3.2 dispatcher —— Agent 编排调度集群 `github.com/sundynix/sundynix-dispatcher` · Go 1.25.8 · **无 HTTP 业务端口** | internal 包 | 职责 | |---|---| | `eino` | 编排引擎全部:orchestrator · compose_compiler/graph/callbacks · react_agent · coordinator · checkpoint · memory_extract · report | | `harness` | 治理五件套:budget · circuitbreaker · eval · jailbreak · output | | `llm` | pool(热更新) · failover(主备链) · cache(输出缓存) | | `dsl` | DSL 图 → 对话计划编译 | | `nats` | shared/bus 薄封装 | **技术栈**:`cloudwego/eino v0.9.12` + `eino-ext/components/model/openai v0.1.13`(OpenAI 兼容协议)、otel v1.44.0。 另有 `cmd/loadtest`(阶梯并发压测器)。 ### 3.3 mcp-go —— Go I/O 型工具服务 core NATS request-reply,订阅 `sundynix.tools.go.>`,队列组 `mcp-go-workers`,探针 `:8092`。 **技术栈**:`blevesearch/bleve/v2 v2.4.2`(CJK 分词)、`milvus-sdk-go/v2 v2.4.1`、`neo4j-go-driver/v5 v5.24.0`、`go-redis/v9`、`gorm.io/gorm`。 > ⚠️ `internal/office/unioffice.go` **名字有误导性**:并不引任何第三方 Office 库,而是用标准库 `archive/zip` + 内联 OOXML/WordprocessingML XML 手工拼 `.docx`。 **工具注册表**(`internal/mcp/gateway.go` 的 `buildRegistry()` 是唯一事实源,dispatcher 经 `list_tools` 动态发现,加工具零改调度代码) 暴露给自主 agent(10 个):`wiki_search`(知识检索) · `memory_get`→`recall_user_memory` · `memory_upsert`→`remember_user_fact` · `history_get` · `web_search` · `web_fetch` · `calculator` · `current_datetime` · `sql_query`(仅 SELECT/WITH) · `chart`(bar/line/pie) 内部/流水线(13 个):`kb_ingest` · `kb_delete` · `kb_search` · `kb_graph` · `report_render` · `report_store` · `report_export` · `external_api`(带 SSRF 校验) · `memory_delete` · `memory_list` · `history_append` · `health` · `echo` ### 3.4 mcp-py —— Python 算法型工具服务 Python 3.11 · hatchling · **无 Web 框架**(纯 asyncio + `nats-py`),订阅 `sundynix.tools.py.>`,队列组 `mcp-py-workers`。 依赖:`nats-py>=2.7.0` · `python-docx` · `openpyxl` · `pypdf` · `docker>=7.1.0` | 工具 | agent 暴露 | 说明 | |---|---|---| | `run_code` | ✅ | Docker 沙箱 256m/10s | | `secure_sandbox` | ❌ | 更严档 128m/5s | | `parse_document` | ❌ | txt/md/csv 直读;docx/xlsx/pdf 按扩展名路由 | | `echo` | ❌ | | 两层防护:`sandbox.py` AST 静态守卫(拒 os/sys/subprocess/socket/ctypes/pickle 与 eval/exec/open)+ `interpreter.py` Docker 真隔离(禁网 / 非 root / 丢能力 / 限资源 / 一次性)。 `mineru.py`(多模态解析)目前为桩。 ### 3.5 shared —— 共享库 | 包 | 作用 | |---|---| | `bus` | NATS/JetStream 封装:流声明、任务收发、Token/Exec 回流、工具 RPC、5 条持久流、控制面、KV checkpoint;`trace.go` 把 W3C traceparent 塞进 NATS 头实现**跨总线链路串联**;消费侧解密 api_key | | `contract` | 三方共享契约:subject 常量、Task/ToolCall/ToolResult/各类 Event、入库 claim-check、报告对象键 | | `blob` | MinIO 封装;`cli==nil` 即降级回退本地盘,不阻断启动 | | `secrets` | **AES-256-GCM**,密钥由 `SUNDYNIX_SECRET_KEY` 经 SHA-256 派生;密文 `enc:1:`+base64url(nonce‖ct);无前缀原样返回(兼容旧明文) | | `otelx` | OTel 启动器(W3C 传播器 + OTLP/HTTP → Jaeger)+ 带 trace_id 的结构化 slog | | `prompts` | 受管提示词注册表(内置默认 + `PROMPTS_FILE` 覆盖 + 控制面热下发) | | `health` | 给无 HTTP 端口的服务起极小探针服务 | | `cmd/devnats` | 内嵌 nats-server,本地开发免装 | --- ## 4. NATS 总线契约 ### 4.1 任务主链(JetStream 持久) | 流 / Subject | 值 | 用途 | |---|---|---| | `SUNDYNIX_TASKS` | `sundynix.tasks.` | 任务队列,消费者 `dispatchers`(队列组负载均衡) | ### 4.2 回流(core NATS,即时不持久) | Subject | 用途 | |---|---| | `sundynix.streams.` | Token 流,结束用消息头 `X-Stream-End: 1` | | `sundynix.exec.` | 结构化执行节点事件(seq/node/kind/phase/label/ms) | | `sundynix.voice.event.` | JARVIS 语音事件(navigate / announce) | ### 4.3 工具调用(request-reply + 队列组) | Subject | 队列组 | 提供方 | |---|---|---| | `sundynix.tools.go.` | `mcp-go-workers` | mcp-go | | `sundynix.tools.py.` | `mcp-py-workers` | mcp-py | | `sundynix.tools.platform.` | `platform-tools-workers` | **gateway 自己** | | `sundynix.local.exec.` | — | 桌面端 runner(无订阅 = 离线,明确报不可用) | ### 4.4 回写(JetStream 持久 + 落库幂等 → at-least-once 重投安全) | 流 | 消费者 | Subject | 用途 | |---|---|---|---| | `SUNDYNIX_STATUS` | `gateway-status` | `sundynix.status.task` | 任务生命周期状态 | | `SUNDYNIX_USAGE` | `gateway-usage` | `sundynix.usage.task` | token 用量(计费凭据) | | `SUNDYNIX_EVAL` | `gateway-eval` | `sundynix.eval.task` | 自动评测结果 | | `SUNDYNIX_APPROVALS` | `approval-resumers` | `sundynix.approval.` | HITL 审批决定(抗离线) | | `SUNDYNIX_INGEST` | `ingest-workers` | `sundynix.ingest.` | 入库作业队列(claim-check:大文件先落 MinIO,消息只带 StageKey) | > ⚠️ 状态流 subject **必须在 `sundynix.tasks.>` 之外**,否则会被任务流捕获成「幽灵任务」自我放大。 **KV**:`SUNDYNIX_CHECKPOINTS`(TTL 24h)—— 键 `task_id` 存 compose checkpoint,键 `pending:task_id` 存 resume 记录。 ### 4.5 控制面 `sundynix.config..get` / `.updated`(kind = chat / embedding / voice)· `sundynix.prompts.get` / `.updated` · `sundynix.health.dispatcher`(心跳)。网关侧共用队列组 `gateway-workers`。 ### 4.6 Task.Meta 约定 `user_id` · `tenant_id` · `session_id` · `safety_check` · `token_budget` · `model_profile`(=`voice`) · `intent`(=`report`) · `topic` · `kb` 状态机:`submitted → running → done|failed|timeout`,HITL 分支 `waiting → running|rejected`。 评测分级:`ok`(≥0.75) / `warn`(0.5~0.75) / `poor`(<0.5)。 --- ## 5. 编排引擎 ### 5.1 执行路径 `Orchestrator.Handle` → `executeGraph` → `runComposeGraph` → **`execComposeGraph`**(`internal/eino/compose_compiler.go`,唯一引擎): 1. `dsl.Parse` + `dsl.Compile` → 建 `board`(黑板,进 compose 本地状态) 2. 无图/空图 → 退化为 compose 单轮对话 3. 建 `compose.Graph`:**边只传占位信号 `flowSignal`,真实数据全走黑板**(注册 no-op merge 支持 fan-in);DAG 触发让无依赖节点自动并行 4. `branch` 节点走 `AddBranch`;`approval` 节点在有 checkpoint 后端时编译为 `approvalInterruptLambda`(`compose.Interrupt` 落盘并释放 goroutine) 5. 编译失败 → 降级回自研 `graph.go`(已退役,保留作安全网) ### 5.2 节点类型(12 种) | kind | 作用 | |---|---| | `input` | 输入/查询 | | `memory` | 记忆召回 | | `retriever` | RAG 检索 | | `tool` | 显式工具调用 | | `agent` | LLM 推理;`autonomous: true` → 走 **ReAct 自主工具循环** | | `coordinator` | 多智能体:agent-as-tool 派给专家 + 并行 fan-out + 综合 | | `aggregate` | 汇聚 | | `approval` | **HITL 人工审批**(中断落盘) | | `render` | 渲染(报告等) | | `map` | 并行 fan-out | | `output` | 输出 | | `branch` | 条件分支(建图阶段单独处理,支持 else/default 兜底) | ### 5.3 ReAct 自主工具 `react_agent.go` 用 Eino `react.NewAgent`,工具集经 `list_tools` 从**三个提供方**动态发现(mcp-go / mcp-py / gateway platform)。 - `MaxStep` 默认 12(`REACT_MAX_STEP` 可调) - `StreamToolCallChecker` 扫描**整段流**判定工具调用(默认只看首片段,deepseek 等常先吐文本再给 tool call 会漏判) - `inject` 参数(user_id / session_id / task_id / kb / tenant_id)服务端运行时绑定,**不暴露给模型** - 工具可自报 `timeout_sec` 突破默认 3s(本地执行类要等用户点确认框) ### 5.4 平台工具族(gateway 提供,11 个) 平台操作的权威(提交关卡、归属校验、计费)都在 gateway,工具就长在权威所在地。 | 工具 | 作用 | |---|---| | `platform_recent_tasks` / `platform_task_status` | 查任务列表 / 单任务状态与输出 | | `platform_gen_report` | 派发报告任务(**走 preflightCore 同一关卡**:预算/暂停/积分硬拦截) | | `platform_open_view` | 切换客户端界面(navigate 白名单) | | `platform_schedule_create` / `_list` / `_cancel` | 定时任务增删查 | | `local_list_dir` / `local_read_file` | 看/读用户电脑(只读) | | `local_write_file` / `local_exec` | 写文件 / 执行命令(三道闸,见 §8.3) | **安全铁律**:一律 `inject user_id` + 服务端归属校验(越权查他人任务一律回「不存在」,不泄露存在性);会烧钱的提交必须过 `preflightCore`。 ### 5.5 harness 治理层 | 组件 | 作用 | |---|---| | `budget.go` | token 预算估算(CJK≈1 tok/字),触顶中止整图 | | `circuitbreaker.go` | 三态熔断(阈值 3 次连续失败 / 冷却 20s / 半开 1 次探测) | | `eval.go` | 规则 + LLM-as-judge 评测,异步 off 热路径;低分触发自动纠偏 | | `jailbreak.go` | Tier2 越狱分类(severity ≥0.7 才拦) | | `output.go` | 发射层逐片脱敏(sk-\* / AKIA\* / JWT / Bearer),跨分片不漏检 | --- ## 6. LLM 治理 ``` cachingModel(输出缓存) └─ failoverModel(主备链,每模型独立熔断器) ├─ 主模型(active) └─ 备用模型(其它 enabled chat 模型) ``` - **双池**:工作主力 `pool`(chat) + JARVIS 语音 `voicePool`(voice),语音池空则**透明回落**工作池 - **热更新**:经 NATS 配置控制面(`SubscribeModelConfigUpdated` + 启动时 `FetchModelConfigWithRetry`) - **接入方式**:`eino-ext/openai`,OpenAI 兼容协议(当前用 DeepSeek 在线 API,不拉本地 Ollama) - 单次请求超时 120s;`LLM_FORCE_STUB=1` 走降级桩(压测用) - 暴露 `ModelHealth`(provider/model/role/state/fails)供 admin 展示 - **已知局限**:Stream 仅在建流同步报错时切备,已开始回流 token 的中途失败不切 - **输出缓存**:`respCache` TTL 60s(`LLM_CACHE_TTL_S`,0=关)、容量 512(`LLM_CACHE_MAX`),key = sha256 **Prompt 版本化**:`shared/prompts` 内置默认 → `PROMPTS_FILE` 覆盖 → `sundynix_prompt` 表 + admin 热切换(含 diff 与撤销),不重编译即可改。 Known key:`graph.extract` · `eval.quality` · `eval.refine` · `guard.jailbreak` · `coordinator.lead` · `memory.extract` --- ## 7. 数据存储 ### 7.1 中间件职责 | 中间件 | 版本 | 用途 | |---|---|---| | NATS + JetStream | 2-alpine(max_payload 8MB) | 统一总线(见 §4) | | PostgreSQL | 16-alpine | 主业务库,29 张表 | | Redis | 7-alpine | 会话 / 限流 / 任务输出缓存(TTL 48h) / 扫码 ticket;有内存降级兜底 | | Milvus | v2.4.13 standalone | RAG 向量路 | | etcd | v3.5.14 | 仅 Milvus 元数据依赖 | | MinIO | RELEASE.2023-03-20 | 文档正文 blob、报告源/产物(bucket `sundynix-docs`)+ Milvus 段存储 | | Neo4j | 5-community | RAG 图谱路(三元组) | | Jaeger | all-in-one 1.60 | OTLP 收集 + trace UI | | **Bleve** | 进程内库(非容器) | RAG 全文路,scorch 落盘 `BLEVE_PATH` —— **唯一需要给 mcp-go 挂持久卷的原因** | ### 7.2 数据表全清单(29 张) 命名:`TablePrefix: sundynix_` + `SingularTable: true`。公共基类 `BaseModel` = 雪花字符串 id + created/updated + 软删。 | # | 模型 | 表 | 职责 | |---|---|---|---| | 1 | `User` | `sundynix_user` | 平台用户 | | 2 | `Task` | `sundynix_task` | 一次提交的编排任务(DSL);业务 id `task_xxx` 单列供 NATS subject | | 3 | `Eval` | `sundynix_eval` | 自动评测结果,按 task_id upsert | | 4 | `LLMModel` | `sundynix_model` | 模型后端配置,每 kind 同时刻仅一条 Active | | 5 | `KB` | `sundynix_kb` | 知识库,`(space_id,name)` 唯一,分区键 `space_id/name` | | 6 | `Doc` | `sundynix_doc` | 入库文档主表(Obsidian 式文库) | | 7 | `Agent` | `sundynix_agent` | 编排定义,`(space_id,name)` 唯一 | | 8 | `DocLink` | `sundynix_doc_link` | `[[双链]]` 索引,供反链/关系图 | | 9 | `Pricing` | `sundynix_pricing` | 模型计价(每 1K token 输入/输出单价) | | 10 | `Prompt` | `sundynix_prompt` | 受管提示词版本,`(key,version)` 唯一 | | 11 | `AuditLog` | `sundynix_audit_log` | 敏感操作留痕,只增不改 | | 12 | `GuardrailEvent` | `sundynix_guardrail_event` | 输入护栏命中事件 | | 13 | `Tenant` | `sundynix_tenant` | 租户(计费/隔离单位),含物化余额列 | | 14 | `TenantMember` | `sundynix_tenant_member` | 用户↔租户成员关系 + 角色 | | 15 | `TenantInvite` | `sundynix_tenant_invite` | 可复用邀请码(扫码入组) | | 16 | `Space` | `sundynix_space` | 共享工作区(资源容器) | | 17 | `SpaceMember` | `sundynix_space_member` | 空间成员 + 空间内角色 | | 18 | `UsageEvent` | `sundynix_usage_event` | 用量明细,task_id 唯一 → 幂等 | | 19 | `CreditLedger` | `sundynix_credit_ledger` | 积分账本(append-only),余额 = SUM | | 20 | `UsageRollup` | `sundynix_usage_rollup` | 用量按租户/天聚合快照 | | 21 | `Setting` | `sundynix_setting` | 平台级键值配置 | | 22 | `CreditPack` | `sundynix_credit_pack` | 积分包商品 | | 23 | `PaymentOrder` | `sundynix_payment_order` | 充值订单(兑换码也写一行) | | 24 | `RedeemCode` | `sundynix_redeem_code` | 兑换码 | | 25 | `SubscriptionPlan` | `sundynix_sub_plan` | 订阅套餐 | | 26 | `Subscription` | `sundynix_subscription` | 已购订阅(到期即 expired,不自动续) | | 27 | `UserJarvis` | `sundynix_user_jarvis` | 每用户 JARVIS(名字/人设/自带火山 key,密文入库) | | 28 | `Schedule` | `sundynix_schedule` | 定时任务 | | 29 | `SchemaMigration` | `sundynix_schema_migration` | 已应用的版本化迁移记录 | ### 7.3 迁移机制 整段迁移在 **PG advisory lock**(key `20260721`,60s 超时兜底)内串行: `legacy(默认关) → AutoMigrate(29 模型) → 版本化 schemaSteps` 只有 AutoMigrate 失败才返回 error;版本化步骤失败只记日志下次重试。 **4 个版本化步骤**:账本 grant/adjust 的**部分唯一索引**(支付入账与退款的幂等闸)· 回填租户物化余额 · 微信 openid 唯一索引。 部分唯一索引不写在 struct tag 里 —— AutoMigrate 早于回填会撞车,必须回填后显式建。 破坏性 legacy 迁移需 `ALLOW_LEGACY_SCHEMA_MIGRATION=1` 显式开启(雪花 id 改造、双链改按 Doc.ID 关联)。 --- ## 8. 关键链路 ### 8.1 任务提交 → 编排 → 回流 ```mermaid sequenceDiagram participant C as 桌面端 participant G as gateway participant N as NATS participant D as dispatcher participant M as mcp-go participant L as LLM C->>G: POST /tasks (DSL) G->>G: 鉴权 → 租户/空间上下文 → 限流 → 护栏 G->>G: preflight:预算/暂停/计费租户/积分硬拦截 G->>G: launch:落库 + 起录像器 G->>N: publish sundynix.tasks (JetStream) G-->>C: 202 task_id C->>G: GET /tasks/:id/stream (SSE, token 走 query) N->>D: 消费任务 D->>D: DSL 编译为 compose.Graph loop ReAct 循环 D->>L: 推理(failover + 熔断 + 缓存) L-->>D: tool_call D->>N: request sundynix.tools.go N->>M: 队列组分发 M-->>D: ToolResult end D-->>N: Token 流 sundynix.streams N-->>G: 订阅回流 G-->>C: SSE 逐字推送 D->>N: status / usage / eval(JetStream 持久) N->>G: 幂等落库 ``` ### 8.2 语音 JARVIS 全双工 ```mermaid sequenceDiagram participant U as 用户 participant C as 桌面端 participant G as gateway participant V as 火山 ASR/TTS participant D as dispatcher U->>C: 按住空格说话(PTT) C->>G: WS 二进制帧:PCM 16k 上行 G->>V: 流式 ASR(X-Api-Key 鉴权) V-->>G: 转写(部分/最终) G-->>C: transcript U->>C: 松开 → end G->>G: trySubmit:转写 → 组 DSL → 同一提交关卡 G-->>C: task_id G->>D: 提交任务(model_profile=voice → 走快模型) D-->>G: Token 流 G-->>C: reply(打字机,早于音频) G->>V: 攒句 → 双向流 TTS V-->>G: PCM 24k G-->>C: speaking + 音频帧 → tts_end C->>U: 无缝播放 ``` **要点** - ASR 与 TTS 是**不同帧族**(ASR 简帧无事件号;TTS V3 事件族带 event/session/gzip) - 下行**先订阅 token 流再建 TTS 会话** —— core NATS 无持久,订阅晚于产出会丢开头 - 客户端播放按 `nextStart` 预约到未来时刻,收到 `tts_end` 时**不能立即停**(合成远快于语速,停了只剩前几个字) ### 8.3 本地执行(JARVIS 操作用户电脑) ```mermaid sequenceDiagram participant D as dispatcher participant G as gateway participant R as 桌面 Go host participant U as 用户 Note over R,G: 登录后注册:WS /local/runner R->>G: 上线(携带授权目录白名单) G->>G: 队列组订阅 sundynix.local.exec D->>G: 调 local_exec(timeout_sec=160) G->>R: WS 转发 tool + args R->>R: 闸一:独立开关校验 R->>R: 闸二:硬黑名单(14 条正则,命中不弹框直接拒) R->>U: 闸三:原生确认框(默认按钮=拒绝,60s 无应答即拒) U-->>R: 允许 / 本次会话都允许 R->>R: 沙箱内执行(cwd 锁授权目录,60s 超时,输出 16KB 截断) R-->>G: 结果 G-->>D: ToolResult ``` **超时链必须外松内紧**:dispatcher 160s > gateway 150s > runner 转发 140s > 桌面端(审批 60s + 执行 60s)。 任一层比内层短,用户还在看确认框就会被判超时。 --- ## 9. 功能实现状态 图例:**✅ 已完成(live 验证)** · **🟡 部分** · **❌ 未做** ### 9.1 多租户 / 空间 / RBAC | 功能 | 状态 | |---|---| | Tenant/TenantMember + 注册自动建默认租户 + 存量回填 | ✅ | | **gorm 租户隔离插件**(查询/更新/删除自动加 tenant_id,创建自动填) | ✅ | | 租户角色 RBAC(owner/admin/member/viewer)+ 路由级校验 | ✅ | | 租户邀请码(二维码扫码入组) | ✅ | | Space 共享工作区(KB/Agent 按空间共享 + 空间角色 + 全员空间) | ✅ | | 用户 role 字段 + 角色表(把 `RequireAdmin` 从白名单升级为角色校验) | ❌ | | 用户管理接口(列举/禁用/改角色) | ❌ | ### 9.2 计量 / 计费 / 支付 | 功能 | 状态 | |---|---| | 计价配置 + usage_event 计量 + credit_ledger 账本 + daily rollup | ✅ | | 余额硬拦截(`CREDIT_ENFORCE`) | ✅ | | 支付渠道抽象 + 微信 Native(**真环境实测通过**) | ✅ | | 兑换码 / 人工核销 | ✅ | | 对账 + 退款(adjust 负分录 + 回退余额 + 审计) | ✅ | | 订阅套餐(周期发放 + 到期失效) | ✅ | | 发票 / Stripe | ❌ | ### 9.3 知识库 / RAG | 功能 | 状态 | |---|---| | **三路混合检索**(Bleve 全文 + Milvus 向量 + Neo4j 图谱,RRF k=60 融合 + rerank) | ✅ | | 中文分词修复(CJK bigram) | ✅ | | 离线检索评测(recall@k / MRR,hybrid vs 单路) | ✅ | | 大文件生产化(MinIO 正文 + 并发 embed + 窗口化图谱 + JetStream 持久队列,kill -9 续跑验证) | ✅ | | KB 级联删事务化(三库 + MinIO 先删、PG 最后)+ MinIO 孤儿 GC | ✅ | | Obsidian 式文库(Markdown + 双链 + 反链 + 关系图) | ✅ | | 检索持久化治理 / 列表分页 | 🟡 | | 多模态解析(MinerU/PaddleOCR) | 🟡 骨架,`mineru.py` 为桩 | ### 9.4 报告 | 功能 | 状态 | |---|---| | 报告编排(规划 → 分章并行 → 汇聚 → 存源) | ✅ | | Word(.docx) 渲染(自建零依赖 OOXML) | ✅ | | Markdown 导出 | ✅ | | PDF 导出 | 🟡 走 webview 打印;后端原生 PDF 未做 | | 分章 map 错误传播与汇总 | ✅ | ### 9.5 记忆 | 功能 | 状态 | |---|---| | memory CRUD + Profile 表 | ✅ | | P1 异步攒批 Consolidate(每 3 轮 LLM 对账 ADD/UPDATE/DELETE/NOOP + 软删) | ✅ | | P2 Score(Recency + Importance) 排序 + 衰减 + top30 截断 | ✅ | | P3 Relevance(语义相关性) | ✅ | | 会话历史 history_get/append | ✅ | ### 9.6 编排引擎 | 功能 | 状态 | |---|---| | Eino Phase A/B/C/D 全部(组件 → ReAct → compose 全图 → FSM) | ✅ | | compose 为唯一引擎(`graph.go` 已退役作降级网) | ✅ | | HITL 人工审批中断(checkpoint 落盘 + NATS 决定回传 + 抗离线) | ✅ | | 多智能体 coordinator(agent-as-tool + 定制 brief + 并行 fan-out + 专家超时) | ✅ | | Branch else/default 兜底 · DSL 拓扑校验 · 工具动态发现 | ✅ | | handoff / adk 可中断多智能体 | ❌ | | 编译图缓存 | ❌ 判定为 premature(实测编译 ~13µs) | | 审批 checkpoint 落盘失败重试(现只 log → 任务永卡 waiting) | ❌ | ### 9.7 模型治理 | 功能 | 状态 | |---|---| | 模型路由 + Fallback + 每模型三态熔断 | ✅ | | 模型健康/熔断态 surface 到 admin | ✅ | | 输出缓存 | ✅ | | Prompt 版本化 v1(注册表)+ v2(DB 热切换 + diff + 撤销) | ✅ | | 工作模型与 JARVIS 语音模型分离 + 用量按实际模型计量 | ✅ | | Prompt 灰度 % A/B | ❌ | ### 9.8 评测 / 护栏 | 功能 | 状态 | |---|---| | 自动化评测(规则 + LLM 裁判,异步 off 热路径) | ✅ | | 裁判校准 + 低分自动纠偏闭环(live 真触发) | ✅ | | 输入护栏(注入检测 + 归一化 + 超大体拦截)+ 事件落库 | ✅ | | 输出护栏(跨分片密钥脱敏) | ✅ | | HITL 审批决定明细(理由)落库 | ❌ 现仅 who/when/status | | 前端评测质量面板 | ❌ 后端 `/tasks/:id/eval` 已有 | ### 9.9 语音 / JARVIS 中枢 | 功能 | 状态 | |---|---| | 火山 ASR + 双向流 TTS 全双工(新版 API Key 鉴权) | ✅ | | 语音触发任务(复用同一提交关卡) | ✅ | | PTT 按住说话 + 打断 + 连续对话 + 打字机文本流 | ✅ | | 每用户 JARVIS(名字/人设/自带豆包配置回落,语音不串主记忆) | ✅ | | 全屏钢铁侠 HUD(接真实音频电平) | ✅ | | **P1 平台工具族**(查任务/派报告,含越权拒绝与积分硬拦截验证) | ✅ | | **P2 动作通道**(语音让界面切页,三层白名单) | ✅ | | **P3 主动播报**(任务终态主动开口,正朗读则排队不抢麦) | ✅ | | 声纹 / 唤醒词 / 音色克隆 / 多语种 / ASR-TTS failover | ❌ 本期不做 | | P5 常驻 companion session | ❌ 暂缓(现靠 session history 串联已够用) | ### 9.10 本地执行 | 功能 | 状态 | |---|---| | **只读**:`local_list_dir` / `local_read_file` + runner 注册 + 沙箱(逃逸单测全拦) | ✅ | | **能动的手**:`local_write_file` / `local_exec` + 三道闸(独立开关 + 14 条黑名单 + 原生审批框) | ✅ | | 多目录白名单沙箱 + 空 path 自发现授权目录 | ✅ | | 离线优雅降级(runner 不在线明确报不可用,不挂起) | ✅ | | ToolPolicy 服务端策略下推 | 🟡 已有审批框 + 黑名单,下推未做 | | **档 B**:agent 循环下沉客户端(内环不过网) | ❌ 有决策门,未做 | | gateway LLM 代理端点(档 B 的地基) | ❌ | ### 9.11 定时任务 | 功能 | 状态 | |---|---| | `sundynix_schedule` + leader 锁 ticker(30s) + create/list/cancel 工具 | ✅ | | 存自然语言指令,到点走同一关卡执行 + 主动播报 | ✅ | | 先推进后提交防重复烧钱;停机错过的**不补跑** | ✅ | ### 9.12 可观测 / 运维 | 功能 | 状态 | |---|---| | Prometheus `/metrics`(路由模板低基数)+ 结构化日志 + X-Request-ID | ✅ | | `/healthz` `/readyz` 探针 + 依赖聚合健康 | ✅ | | **OTel 全链路**(otelgin + 跨 NATS traceparent 传播 → Jaeger) | ✅ | | admin 观测面(overview/status/tasks/spaces/usage/evals/datasources/orders/审计/护栏) | ✅ | | 检索试验台(跨租户 + 单路 mode 对比) | ✅ | | panic 进 trace span · TTFT/token-s 指标 | ❌ | | K8s / DB HA / TLS / DR 演练 | ❌(**例外:NATS 集群已落地**) | ### 9.13 客户端 | 端 | 状态 | |---|---| | desktop(编排画布 · ⌘K · SSE 轨迹 · 文库 · 知识图谱 · 记忆面板 · JARVIS HUD · 本地 runner · 服务器地址运行时可配) | ✅ | | admin(官网 + 控制台,go:embed 进 gateway) | ✅ | | web(租户自助:注册/组织/团队/账单) | ✅ | | 前端测试 | 🟡 11 个测试文件,集中在 lib 纯函数;视图层基本不测 | ### 9.14 ⚠️ 已知的文档记账偏差 以下 4 处**文档与代码不符,一律以代码为准**: 1. `PROGRESS.md` 停在 2026-06-19,其中「计费未做」「多租户未做」「Relevance 待 P3」均已被后续代码推翻。 2. `DEPTH_ROADMAP.md` 进度表写「T4 后端做实 0/6 组」,但正文里 T4.A/B/E 大量条目已勾 ✅。 3. `DEPTH_ROADMAP.md` Tier 3 写「NATS 集群未做」,实际三节点集群已在 128 落地。 4. `PAYMENT_DESIGN.md` 标题写「不做订阅」,但订阅套餐全套(表 + ticker + admin 页)已实现。 --- ## 10. 安全与治理 ### 10.1 中间件链(顺序有意义) ``` Recovery → otelgin → RequestID → Observe → cors → Auth → TenantContext → SpaceContext → RateLimit → Guardrail ``` **Auth 必须前置于 RateLimit** —— 否则无法按用户限流(企业网多人共享出口 IP 会互相拖累)。 ### 10.2 鉴权 - **JWT 无状态**(`internal/auth`),owner = 雪花 user.id;生产默认密钥 fail-fast - `Auth()` 非阻断解析 → `RequireAuth()` / `RequireAdmin()`(当前为 `ADMIN_USER_IDS` 白名单) - **`AuthFromHeaderOrQuery()`**:WS 与 SSE 带不了 Bearer 头,走 `?token=` —— 用于 `/tasks/:id/stream`、`/tasks/:id/exec`、`/kb/ingest/:id/stream`、`/reports/:id/export`、`/voice/stream`、`/local/runner` - 注册/登录各带 10/min 限流;微信公众号扫码登录独立通道 - **支付回调例外**:`/billing/callback/:channel` 无 Bearer,渠道验签是唯一的门 ### 10.3 密钥加密 `shared/secrets`:**AES-256-GCM**,密钥由 `SUNDYNIX_SECRET_KEY` 经 SHA-256 派生 32 字节;密文格式 `enc:1:` + base64url(nonce‖ciphertext),带版本前缀便于轮换。 **全链路**:gateway 保存时 Encrypt 落 PG → 密文原样过 NATS → dispatcher/mcp-go 在 bus 层 Decrypt。**api_key 在磁盘与线缆上都非明文**,仅构建 LLM 客户端时内存短暂还原。三服务的 `SUNDYNIX_SECRET_KEY` 必须一致。 微信支付商户私钥不落库不进镜像 —— 宿主目录只读挂载。 ### 10.4 租户隔离 `store/tenant_scope.go`:`tenantScopedMarker` 空接口(小写方法,只有本包模型能标记)+ 4 个 gorm callback(query/update/delete 前自动加 `tenant_id = ?`,create 前自动填)。 **两个必须记住的旁路**:系统级读(admin 聚合)与跨租户写(对账)都要 `WithoutTenant(ctx)` —— 漏了会出回归或对账崩。 ### 10.5 限流与审计 - **限流**:Redis 为主后端 + **进程内固定窗口 fail-safe 兜底**(Redis 挂时不再 fail-open,改宽松本地限流);已认证按 uid、未认证按 IP - **审计**:`Audit(db)` 只审计变更类(POST/PUT/DELETE/PATCH),best-effort 不拖垮主流程;挂在整个 `/admin` 组、prompt 激活/撤销、HITL 审批、租户成员变更、充值兑换 - **护栏事件**:命中落 `GuardrailEvent`(actor/kind/reason/signals/path/ip)→ admin 审计页 --- ## 11. 客户端形态 **三个独立产品面,绝不合并**: | 端 | 定位 | 技术栈 | dev 端口 | 路由 | |---|---|---|---|---| | desktop | **用户工作产品** | Wails v3.0.0-alpha2.117 + React 19 + TS 5.6 + Tailwind 3.4 + React Flow 12 | 9245 (wails3) / 5173 (纯 vite) | 无路由,`useState` | | admin | 官网(`/`) + 平台超管控制塔(`/admin`) | React 19 + react-router-dom 7 | 5174 | **BrowserRouter** | | web | 租户客户自助柜台 | React 19 + react-router-dom 7 | 5175 | **HashRouter**(纯静态托管即可深链) | **desktop 页面**(`ViewKey`):`home` 工作台 · `studio` 编排 · `kb` 知识库 · `runs` 运行 · `report` 报告 · `memory` 记忆 · `usage` 用量 **admin 页面**(17 条路由):仪表盘 / 服务状态 / 任务观测 / 自动评测 / 审计安全 / 模型配置 / 登录设置 / 语音设置 / 数据源RAG / 提示词 / 支付(配置·订阅·订单对账) / 租户用户 / 微信用户 / 空间 / 安全护栏 三端共用**自建 UI 组件**(`src/ui/`:Badge/Button/Card/Dialog/Input/Table/Tabs/Toast + cn),**未引任何组件库**。 测试统一 Vitest 4 + jsdom + Testing Library。 --- ## 12. 部署拓扑 ### 12.1 三机内网生产 ```mermaid flowchart LR USER["用户桌面端"] FRP["frp 映射"] subgraph M132["192.168.100.132 · 应用机"] GW["gateway 3000→8080
内嵌 admin UI"] DP["dispatcher"] MG["mcp-go"] MP["mcp-py"] end subgraph M128["192.168.100.128 · 基建机 + CI runner"] N1["NATS 三节点集群
4222/4223/4224
REPLICAS=3"] PG2[("PostgreSQL")] RD[("Redis")] ML[("Milvus + etcd")] NJ[("Neo4j")] JG["Jaeger"] end M126[("192.168.100.126
业务 MinIO
bucket sundynix-docs")] TX["162.14.122.200
微信 token 中控
静态 IP"] USER --> FRP FRP --> GW GW --> N1 DP --> N1 MG --> N1 MP --> N1 GW --> PG2 GW --> RD GW --> M126 MG --> ML MG --> NJ MG --> M126 GW --> JG DP --> JG GW --> TX ``` **要点** - **对外只暴露 132:3000**(gateway:API + admin UI + 语音 WS + 本地 runner WS),其余全部内网 - NATS 三节点 `cluster.name: sundynix-cluster`,routes 互指 6222;`NATS_STREAM_REPLICAS=3` 走 Raft quorum;三节点 `max_payload: 8MB` 必须一致 - 128 上的 Redis/Milvus/NATS **无认证**,靠防火墙只放行 132/126 网段 - 132 只读挂载两个宿主目录:微信支付商户私钥、微信域名校验文件(不进镜像、不进 git) - 备份 `scripts/backup.sh`(PG/Neo4j/Milvus/MinIO 卷),建议 cron 每日异机存档 ### 12.2 单机一体化 `docker-compose.prod.yml` 一条命令拉起应用 4 服务 + 全套基建(要求 Docker 24+/Compose v2、~8GB 内存)。 基建端口**一律不对宿主暴露**,只留 gateway 与可选 Jaeger UI。密钥用 YAML 锚点 `${SUNDYNIX_SECRET_KEY:?}` 强制 .env 必填。 ### 12.3 密钥模型 | 类别 | 内容 | 存放 | |---|---|---| | 引导密钥 / 基建凭据 | `SUNDYNIX_SECRET_KEY` · `JWT_SECRET` · PG/Neo4j/MinIO 密码 | `.env`,部署时填一次 | | 业务模型 key | LLM api_key · 语音 key · 支付配置 | **不进 .env**,登录 admin 配,AES 加密存 PG | 丢失主密钥 = 已存业务 key 全部失效。 首次管理员:注册第一个账号 → 取 user id → 填 `ADMIN_USER_IDS` → 重启 gateway。 --- ## 13. CI / CD ### 13.1 GitHub Actions(质量门,push main + PR) | Job | 内容 | 红门 | |---|---|---| | `go` | 4 模块 `build + vet + test -race` | ✅ 一票否决 | | `lint` | golangci-lint × 4 模块,`only-new-issues`(存量约 42 处不拦) | ✅ 仅新问题 | | `security` | `govulncheck`(advisory 不阻断)+ **`gitleaks` 扫提交历史(命中即失败)** | 部分 | | `web` | 三前端 `npm ci` + `tsc --noEmit` + `vitest` | ✅ | | `desktop` | macOS runner,`GOWORK=off`,先出前端产物供 go:embed | ✅ | | `py` | Python 3.11 pytest(含沙箱守卫测试) | ✅ | Go 1.25 / Node 20。所有 job 带 `if: !contains(github.server_url, 'sundynix.cn')` 避免内网 Gitea 误跑。 ### 13.2 Gitea Actions(内网真实 CD) push main → 128 runner:**不用 `actions/checkout`**(内网连不上 github.com,改 `git init + fetch --depth 1`)→ 构建 4 镜像 → `docker save | gzip` scp 到 132 → `docker load` + `up -d --no-build` → **健康检查门**(循环 20 次 curl `/healthz`,失败打日志并 exit 1)。 132 上的 `.env` 手工预放、**部署绝不覆盖**。 > ⚠️ **CD 无任何测试门** —— 测试只在 GitHub 侧跑,内网推送直接部署。 ### 13.3 Release tag `v*` → wails3 构建 macOS universal(lipo 合并)+ Windows amd64 → GitHub Release。旧版 App 启动查 `/releases/latest` 提示更新。 --- ## 14. 技术栈总表 | 领域 | 选型 | |---|---| | 后端语言 | Go 1.25(4 模块 workspace)+ Python 3.11(算法工具) | | Web 框架 | Gin v1.12.0 | | 编排引擎 | **CloudWeGo Eino v0.9.12** + eino-ext/openai | | 消息总线 | NATS 2 + JetStream(持久流 + KV) | | 主库 | PostgreSQL 16 + GORM v1.31.1(雪花 id + 软删 + 租户插件) | | 缓存 | Redis 7(+ 进程内降级) | | 向量 | Milvus v2.4.13 | | 全文 | Bleve v2.4.2(进程内,CJK bigram) | | 图谱 | Neo4j 5-community | | 对象存储 | MinIO(minio-go v7.2.0) | | LLM | OpenAI 兼容协议(DeepSeek 在线 API) | | 语音 | 火山引擎豆包 · 流式 ASR + 双向流 TTS v3 | | 可观测 | Prometheus + OpenTelemetry v1.44 + Jaeger 1.60 | | 桌面端 | Wails v3.0.0-alpha2.117(Go host + WKWebView) | | 前端 | React 19 + TypeScript 5.6 + Vite 5 + Tailwind 3.4 + React Flow 12 | | 前端测试 | Vitest 4 + jsdom + Testing Library | | 支付 | 微信支付 APIv3(Native 扫码) | | 密钥 | AES-256-GCM(`enc:1:` 版本化密文) | --- ## 15. 已知缺口 按优先级归类,均为**明确未做**而非遗漏: **架构演进** - 本地 agent 档 B(循环下沉客户端,内环不过网)+ 其地基 gateway LLM 代理端点 - ToolPolicy 服务端策略下推 - JARVIS 常驻 companion session(现靠 session history 串联) **治理补全** - 用户 role 字段与角色表(`RequireAdmin` 仍是 env 白名单) - HITL 审批决定理由落库 - 审批 checkpoint 落盘失败重试(现只 log,任务会永卡 waiting) - 预算硬顶兜底(budget ≤0 即无限) **生产硬化(Tier 3,等真实流量)** - DB HA · K8s 编排 · TLS 终止 · DR 演练 · 备份自动化 - panic 进 trace span · TTFT/token-s 细粒度指标 **产品功能** - 报告后端原生 PDF(现走 webview 打印) - 多模态文档解析去桩(MinerU/PaddleOCR) - Prompt 灰度 A/B - 前端评测质量面板(后端接口已有) - 语音:唤醒词 / 声纹 / 音色克隆 / ASR-TTS failover **文档债** - `architecture.md`(小写)是历史重复文件,内容早于本文,建议删除或改为指向本文的跳转 - `PROGRESS.md` / `DEPTH_ROADMAP.md` 汇总表需按 §9.14 校正