# sundynix-agentix · 语音交互设计文档

> 版本：2026-07-17
> 定位：让用户通过**语音**与 Agent 双向对话——语音命令让 Agent 干活（做任务/写报告/检索知识库），Agent 语音回答结果。
> 配套文档：`ARCHITECTURE_DESIGN.md`（架构总览）、`DEPTH_ROADMAP.md`（路线图）

---

## 1. 目标与范围

### 1.1 要做什么

用户对着麦克风说「帮我写一份关于 AI 医疗的报告」→ 系统实时识别语音 → 自动触发现有 Agent 编排 → Agent 边想边"说"结果给用户听。

**全链路**：

```
🎤 用户说话 → ASR(语音→文字) → 现有编排引擎(Eino) → Token 流 → TTS(文字→语音) → 🔊 用户听到
```

### 1.2 核心原则

1. **只加耳朵和嘴巴，不动大脑**——现有 Dispatcher/Eino/工具/RAG/报告 一行不改
2. **复用现有通信管道**——NATS token 流 + SSE 回流原样利用
3. **控制面统一管理**——语音配置（ASR/TTS）走现有的 admin 控制面 + NATS 热更新
4. **可降级**——语音服务不可用时平台文字功能不受影响

### 1.3 不做什么（本期）

- ❌ 语音唤醒 / 声纹识别
- ❌ 多人同时语音会议
- ❌ 视频通话
- ❌ 端到端语音大模型（绕开编排引擎的方案不考虑）

---

## 2. 火山引擎 API 选型

### 2.1 需要开通的服务

| 服务 | 用途 | API 协议 | 文档 |
|---|---|---|---|
| **流式语音识别** | 🎤 用户说话 → 文字 | WebSocket 双向流 | [流式语音识别 WebSocket](https://www.volcengine.com/docs/6561/1354869) |
| **双向流式语音合成 (V3)** | 🔊 文字 → Agent 说话 | WebSocket 双向流 | [双向流式 TTS WebSocket V3](https://www.volcengine.com/docs/6561/1329505) |

### 2.2 为什么选这两个

| 决策 | 原因 |
|---|---|
| **流式 ASR**（非一句话识别） | 用户说长句/多句时能实时出部分结果，体验像实时字幕 |
| **双向流式 TTS**（非 HTTP 非流式） | 可以边喂文字边拿音频，不用等全文生成完；与 token 流天然配合 |
| **不用端到端语音大模型 API** | 那个会绕开 Eino 编排引擎，图编排/工具调用/RAG/报告全废 |

### 2.3 火山引擎配置参数

```
# .env 新增（与现有 LLM 配置同级）
VOLC_ASR_APPID=          # 火山引擎 appid
VOLC_ASR_TOKEN=          # 火山引擎 access token
VOLC_ASR_CLUSTER=        # ASR 集群（如 volcengine_streaming_common）

VOLC_TTS_APPID=          # 可与 ASR 同一个 appid
VOLC_TTS_TOKEN=          # 可与 ASR 同一个 token
VOLC_TTS_CLUSTER=        # TTS 集群（如 volcano_tts）
VOLC_TTS_VOICE_TYPE=     # 音色（如 BV700_streaming）
```

---

## 3. 架构设计

### 3.1 整体架构（在现有 5 层上的增量）

```
┌── 客户端层 ─────────────────────────────────────────────────────────┐
│  桌面端 Wails / 浏览器                                               │
│                                                                      │
│  ┌────────────┐  ┌──────────────┐  ┌─────────────────┐              │
│  │ 🎤 录音按钮  │  │ 📝 实时转写显示│  │ 🔊 音频播放队列   │              │
│  │ MediaRecorder│ │  (边说边显字) │  │ (边收边播放)      │              │
│  └──────┬─────┘  └──────────────┘  └────────▲────────┘              │
│         │ 音频帧上行                    音频帧下行 │                     │
│         └──────────── WebSocket ────────────┘                        │
└────────────────────────┬────────────────────────────────────────────┘
                         │
┌── Gateway（接入层）─────┴────────────────────────────────────────────┐
│                                                                      │
│  新端点: GET /api/v1/voice/stream  (WebSocket 升级)                   │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐     │
│  │                   VoiceSession                               │     │
│  │                                                              │     │
│  │  上行链路：                                                    │     │
│  │  客户端音频帧 → volcASRClient(WS) → 转写文字 → 推回客户端显示   │     │
│  │                                       ↓                      │     │
│  │                              用户说完(静音检测/手动结束)         │     │
│  │                                       ↓                      │     │
│  │                              自动组装 DSL → POST /tasks       │     │
│  │                              （复用现有任务提交，零改动）         │     │
│  │                                                              │     │
│  │  下行链路：                                                    │     │
│  │  订阅 sundynix.streams.<task_id>（现有 token 流）              │     │
│  │      ↓                                                       │     │
│  │  SentenceBuffer（攒到句号/逗号/问号/感叹号/换行）               │     │
│  │      ↓                                                       │     │
│  │  volcTTSClient(WS) → 音频帧 → 推回客户端播放                   │     │
│  │                                                              │     │
│  └─────────────────────────────────────────────────────────────┘     │
│                                                                      │
│  现有路由/中间件/NATS 发布/SSE 回流 → 全部不动                         │
└──────────────────────────────────────────────────────────────────────┘
                         │
           ┌─────────────┴─────────────┐
           ▼                           ▼
    现有后端全套（不改）            火山引擎云端
    NATS → Dispatcher              ASR WebSocket 端点
    Eino 编排                      TTS WebSocket 端点
    MCP 工具
    RAG/报告/记忆
```

### 3.2 关键设计决策

| # | 决策 | 理由 |
|---|---|---|
| D1 | **语音逻辑全在 Gateway 内**，不加新微服务 | 音频只是 I/O 转码，不是业务逻辑；遵循 Monolith First |
| D2 | **Gateway ↔ 火山引擎直连 WebSocket** | 音频帧需毫秒级中继，过 NATS 多一跳反而增延迟 |
| D3 | **客户端 ↔ Gateway 用单条 WebSocket** | 同一连接承载上行音频 + 下行转写 + 下行 TTS 音频，用消息类型区分 |
| D4 | **转写完成后复用 POST /tasks 逻辑** | 语音只是输入方式替换，任务提交/编排/回流全走现有管道 |
| D5 | **TTS 攒句再合成** | 逐 token 喂 TTS 太碎（单字合成不自然）；攒到标点再喂，自然度好 |
| D6 | **语音配置走 admin 控制面** | 与模型配置同管理，支持热更新（改音色/切 provider 不重启） |

---

## 4. 数据流详解

### 4.1 上行：用户说话 → 触发任务

```
时间线 →
用户:     [====说话中====]  [停顿/点击结束]
          ↓↓↓↓↓↓↓↓↓↓↓↓↓
客户端:   音频帧(PCM 16kHz/16bit) 每100ms一帧(3.2KB)
          ↓ WebSocket binary
Gateway:  转发 → 火山 ASR WebSocket
          ← 部分转写结果(partial) ← 火山 ASR
          ← 最终转写结果(final)   ← 火山 ASR
          ↓
          推回客户端显示(实时字幕)
          ↓
          用户停止说话 → 取 final 结果
          ↓
          组装简单 DSL:
          {
            "version": "1",
            "nodes": [{"id":"input","kind":"input","config":{"text":"<转写文字>"}},
                      {"id":"agent","kind":"agent","config":{"autonomous":true}}],
            "edges": [{"source":"input","target":"agent"}]
          }
          ↓
          调用现有 h.SubmitTask() 内部逻辑（经 NATS 发布任务）
          ↓
          返回 task_id 给 VoiceSession（用于下行订阅）
```

### 4.2 下行：Agent 回答 → 用户听到

```
时间线 →
Dispatcher:  token: "人" → "工" → "智" → "能" → "在" → "医" → "疗" → "领" → "域" → "，" → ...
             ↓ sundynix.streams.<task_id>（现有，不改）
Gateway
VoiceSession: 订阅 token 流，逐 token 累积到 SentenceBuffer
              ↓
              遇到断句符（，。！？\n）→ 截取一句完整文字
              ↓
              喂给火山 TTS WebSocket → 收音频帧(PCM/opus)
              ↓
              WebSocket binary 推给客户端
              ↓
客户端:       AudioContext 播放队列，顺序播放每段音频
              同时文字也在屏幕上显示（双通道：看+听）
```

### 4.3 WebSocket 消息协议

客户端 ↔ Gateway 的 WebSocket 用 JSON 控制帧 + Binary 音频帧：

```
// 客户端 → Gateway

// 1. 开始录音
{"type": "asr_start", "session_id": "xxx", "graph": {...}}  // 可选携带编排图

// 2. 音频帧（binary，PCM 16kHz 16bit mono）
[binary data]

// 3. 停止录音
{"type": "asr_stop"}

// 4. 打断 TTS 播放（用户开始说下一句时）
{"type": "tts_interrupt"}

// ---

// Gateway → 客户端

// 1. ASR 部分结果（实时字幕）
{"type": "asr_partial", "text": "人工智能在医"}

// 2. ASR 最终结果
{"type": "asr_final", "text": "人工智能在医疗领域的应用"}

// 3. 任务已提交
{"type": "task_submitted", "task_id": "task_xxx"}

// 4. 文字流（同步显示）
{"type": "text_chunk", "text": "人工智能在医疗领域，"}

// 5. TTS 音频帧（binary，带前缀字节区分）
[0x01][binary audio data]   // 0x01 前缀标识这是 TTS 音频

// 6. 回答完毕
{"type": "done"}

// 7. 错误
{"type": "error", "message": "ASR 连接失败"}
```

---

## 5. 模块设计

### 5.1 新增文件清单

```
sundynix-gateway/
  internal/
    voice/                          ← 新增包
      session.go                    ← VoiceSession：管理一次语音对话的生命周期
      asr.go                       ← 火山 ASR WebSocket 客户端封装
      tts.go                       ← 火山 TTS WebSocket 客户端封装
      sentence_buffer.go           ← Token 流攒句器
      config.go                    ← 语音配置（appid/token/cluster/voice）
    handler/
      voice.go                     ← WebSocket 升级 + VoiceSession 入口（新增）
    router/
      router.go                    ← 加一条路由（改 1 行）

sundynix-desktop/frontend/
  src/
    components/
      VoiceButton.tsx              ← 🎤 按住说话按钮 + 录音逻辑（新增）
      VoicePlayer.tsx              ← 🔊 TTS 音频播放队列（新增）
    lib/
      voice.ts                     ← WebSocket 连接管理 + 音频采集/播放（新增）

sundynix-admin/
  src/pages/
    DatasourcesPage.tsx            ← 加语音配置表单（改几行）

sundynix-shared/
  contract/
    voice.go                       ← 语音配置契约 VoiceConfig（新增）
```

### 5.2 Gateway `voice` 包设计

#### session.go — VoiceSession

```go
// VoiceSession 管理一次语音对话的完整生命周期：
//   1. 接收客户端音频帧 → 转发 ASR → 回传转写文字
//   2. 转写完成 → 组装 DSL → 调用现有任务提交
//   3. 订阅 token 流 → 攒句 → 喂 TTS → 回传音频帧
//   4. 支持打断：用户再次说话时中止当前 TTS
type VoiceSession struct {
    ws        *websocket.Conn    // 客户端连接
    asr       *ASRClient         // 火山 ASR
    tts       *TTSClient         // 火山 TTS
    buf       *SentenceBuffer    // 攒句器
    bus       *nats.Bus          // 复用现有 NATS bus
    submit    func(text, graph)  // 复用现有 SubmitTask 逻辑
    taskID    string             // 当前任务 ID
    mu        sync.Mutex
}

func (s *VoiceSession) Run(ctx context.Context)  // 主循环
func (s *VoiceSession) handleUpstream(ctx)       // 上行：音频→ASR→转写
func (s *VoiceSession) handleDownstream(ctx)     // 下行：token→攒句→TTS→音频
func (s *VoiceSession) interrupt()               // 打断 TTS
```

#### asr.go — 火山 ASR 客户端

```go
// ASRClient 封装火山引擎流式语音识别 WebSocket 连接。
// 协议：wss://openspeech.bytedance.com/api/v3/sauc/bigmodel
// 上行：音频帧（PCM 16kHz 16bit）
// 下行：JSON（partial/final 转写结果）
type ASRClient struct {
    conn   *websocket.Conn
    appid  string
    token  string
    cluster string
}

func NewASRClient(cfg VoiceConfig) (*ASRClient, error)
func (c *ASRClient) SendAudio(data []byte) error        // 发音频帧
func (c *ASRClient) Recv() (text string, isFinal bool, err error)  // 收转写
func (c *ASRClient) Close() error
```

#### tts.go — 火山 TTS 客户端

```go
// TTSClient 封装火山引擎双向流式语音合成 WebSocket 连接。
// 协议：wss://openspeech.bytedance.com/api/v3/tts/bidirection
// 上行：文字（可多次发送，流式喂入）
// 下行：音频帧（PCM/opus，流式返回）
type TTSClient struct {
    conn      *websocket.Conn
    appid     string
    token     string
    cluster   string
    voiceType string
}

func NewTTSClient(cfg VoiceConfig) (*TTSClient, error)
func (c *TTSClient) SendText(text string) error         // 喂一句文字
func (c *TTSClient) RecvAudio() (data []byte, done bool, err error)  // 收音频
func (c *TTSClient) Close() error
```

#### sentence_buffer.go — 攒句器

```go
// SentenceBuffer 把逐 token 的文字流攒成完整句子。
// 遇到断句符（，。！？；\n）时输出一个句子段，喂给 TTS。
// 设超时兜底：超过 2s 没遇到断句符也强制输出（防长无标点段卡住）。
type SentenceBuffer struct {
    buf     strings.Builder
    out     chan string    // 攒好的句子
    timeout time.Duration // 无标点强制输出超时（默认 2s）
}

func NewSentenceBuffer() *SentenceBuffer
func (b *SentenceBuffer) Feed(token string)   // 喂一个 token
func (b *SentenceBuffer) Flush()              // 强制输出剩余
func (b *SentenceBuffer) Sentences() <-chan string  // 读取攒好的句子
```

### 5.3 客户端设计

#### VoiceButton.tsx — 录音按钮

```
两种交互模式：
  A. 按住说话（Push-to-Talk）：按下录音、松开发送 — 适合短命令
  B. 点击切换（Toggle）：点一次开始录音、再点一次结束 — 适合长段落

录音参数：
  - MediaRecorder / AudioWorklet 采集
  - PCM 16kHz 16bit mono（火山 ASR 要求）
  - 每 100ms 切一帧发送（~3.2KB/帧）
```

#### VoicePlayer.tsx — 音频播放

```
- Web Audio API (AudioContext) 播放队列
- 收到 TTS 音频帧 → 解码 → 入队 → 顺序播放
- 支持打断：用户再次说话时清空队列、发 tts_interrupt
- 播放状态指示：🔊 动画
```

#### voice.ts — WebSocket 管理

```
- 建立/维护到 gateway /api/v1/voice/stream 的 WebSocket
- 区分 JSON 控制帧和 binary 音频帧
- 自动重连 + 心跳保活
- 暴露 hooks：useVoice() → { startRecording, stopRecording, isListening, transcript, isPlaying }
```

---

## 6. 与现有系统的集成点

### 6.1 改动清单（最小化）

| 文件 | 改动 | 行数 |
|---|---|---|
| `sundynix-gateway/internal/router/router.go` | 加一条 WebSocket 路由 | **+1 行** |
| `sundynix-gateway/internal/handler/voice.go` | 新增 handler（调 VoiceSession） | **新文件 ~80 行** |
| `sundynix-gateway/internal/voice/*.go` | 新增包（ASR/TTS/Session/Buffer/Config） | **新文件 ~500 行** |
| `sundynix-shared/contract/voice.go` | VoiceConfig 契约 | **新文件 ~30 行** |
| `sundynix-shared/bus/bus.go` | 加 ServeConfig/SubscribeConfig("voice",...) | **复用现有 config 模式，0 改动** |
| `sundynix-admin/.../DatasourcesPage.tsx` | 加语音配置表单 | **+~50 行** |
| `sundynix-desktop/frontend/...` | 新增 3 个文件 | **新文件 ~400 行** |
| **现有后端（Dispatcher/MCP/Eino/NATS）** | | **0 改动** |

### 6.2 路由变更

```go
// router.go 加一条：
api.GET("/voice/stream", h.VoiceStream)  // WebSocket 升级，须在 Auth 后
```

### 6.3 配置管理（复用现有控制面）

语音配置与模型配置走**完全相同的管道**：

```
Admin 控制台 → POST /admin/voice → Gateway 写 DB → NATS 广播 "voice" 配置
                                                    ↓
                                              Gateway 自身热更新 VoiceConfig
                                              （ASR/TTS 客户端用新配置重建）
```

契约：
```go
// contract/voice.go
type VoiceConfig struct {
    ASRAppID     string `json:"asr_appid"`
    ASRToken     string `json:"asr_token"`     // 密文（AES-256-GCM，复用现有 secrets）
    ASRCluster   string `json:"asr_cluster"`
    TTSAppID     string `json:"tts_appid"`
    TTSToken     string `json:"tts_token"`     // 密文
    TTSCluster   string `json:"tts_cluster"`
    TTSVoiceType string `json:"tts_voice_type"`
    TTSEncoding  string `json:"tts_encoding"`  // pcm / opus / mp3
    TTSRate      int    `json:"tts_rate"`       // 24000
    Enabled      bool   `json:"enabled"`
}
```

---

## 7. 实现步骤

### Phase 1：ASR（耳朵）— 3 天

```
目标：用户说话 → 屏幕上实时显示转写文字 → 手动提交为任务
```

| # | 任务 | 产出 |
|---|---|---|
| 1.1 | 火山引擎开通流式 ASR 服务，拿到 appid/token/cluster | 配置 |
| 1.2 | `voice/asr.go`：封装火山 ASR WebSocket 客户端 | 代码 |
| 1.3 | `voice/config.go`：读 env 配置 | 代码 |
| 1.4 | `voice/session.go`：VoiceSession 上行链路（音频→ASR→转写） | 代码 |
| 1.5 | `handler/voice.go` + `router.go`：WebSocket 端点 | 代码 |
| 1.6 | 客户端 `voice.ts` + `VoiceButton.tsx`：录音+WS+显示转写 | 代码 |
| 1.7 | 端到端验证：说话 → 实时转写 → 手动复制到输入框提交 | 验证 |

### Phase 2：语音直接触发任务 — 1 天

```
目标：说完自动提交任务，不用手动操作
```

| # | 任务 | 产出 |
|---|---|---|
| 2.1 | `session.go`：转写完成 → 组装默认 DSL → 调 SubmitTask | 代码 |
| 2.2 | 客户端：说完 → 自动提交 → 切到任务运行视图 | 代码 |
| 2.3 | 支持携带当前画布编排图（用户在 Studio 页说话时用画布图跑） | 代码 |

### Phase 3：TTS（嘴巴）— 3-4 天

```
目标：Agent 回答时语音朗读
```

| # | 任务 | 产出 |
|---|---|---|
| 3.1 | 火山引擎开通双向流式 TTS，选音色 | 配置 |
| 3.2 | `voice/tts.go`：封装火山 TTS WebSocket 客户端 | 代码 |
| 3.3 | `voice/sentence_buffer.go`：token 流攒句器 | 代码 + 单测 |
| 3.4 | `session.go`：下行链路（订阅 token 流→攒句→TTS→音频推送） | 代码 |
| 3.5 | 客户端 `VoicePlayer.tsx`：AudioContext 播放队列 | 代码 |
| 3.6 | 端到端验证：说话 → 任务执行 → Agent 边想边说 | 验证 |

### Phase 4：打断 + 连续对话 — 2 天

```
目标：自然对话体验
```

| # | 任务 | 产出 |
|---|---|---|
| 4.1 | 打断：用户再次说话时中止 TTS + 清空播放队列 | 代码 |
| 4.2 | 连续对话：上一轮完毕后自动重新激活麦克风 | 代码 |
| 4.3 | 会话历史串联：同一 session_id 下多轮对话共享上下文 | 代码 |
| 4.4 | 静音检测（VAD）：客户端 3s 无声自动结束录音 | 代码 |

### Phase 5：控制面 + 上线 — 2 天

```
目标：运维可管理，生产可用
```

| # | 任务 | 产出 |
|---|---|---|
| 5.1 | Admin 控制台加语音配置页（ASR/TTS appid/token/音色选择） | 代码 |
| 5.2 | `contract/voice.go` + token 密文存储（复用 secrets） | 代码 |
| 5.3 | 语音配置热更新（NATS 广播，复用 config 模式） | 代码 |
| 5.4 | 健康检查：`/admin/status` 加 ASR/TTS 连通性探测 | 代码 |
| 5.5 | 语音用量计量（ASR 秒数 + TTS 字数）→ 现有计费管道 | 代码 |
| 5.6 | `.env.example` 加语音配置项说明 | 文档 |

---

## 8. 性能与延迟分析

### 8.1 端到端延迟拆解

```
用户说完最后一个字 → 听到 Agent 第一个字的时间：

  ASR 尾部延迟          ~300ms   (火山 ASR final 结果延迟)
+ 任务提交 → NATS       ~10ms    (现有管道)
+ Dispatcher 消费       ~5ms     (现有管道)
+ LLM TTFT             ~500ms   (首 token 延迟，取决于模型)
+ 攒句（到第一个标点）    ~200ms   (模型每秒约 30-50 token，逗号很快出现)
+ TTS 首段合成          ~200ms   (火山 TTS 流式首包延迟)
─────────────────────────────────
  总计                  ~1.2s    ← 可接受（人类对话轮转间隔约 0.5-2s）
```

### 8.2 后续句子的延迟

首句之后，**TTS 与 LLM 推理流水线重叠**——LLM 在生成下一句时，上一句的 TTS 还在播放。用户感知是连续朗读，无等待。

### 8.3 音频带宽

```
上行（ASR）: PCM 16kHz 16bit mono = 32KB/s ≈ 256kbps  → 完全可接受
下行（TTS）: 
  - PCM 24kHz 16bit: 48KB/s
  - opus 编码后: ~6-12KB/s ≈ 48-96kbps  → 推荐用 opus 省带宽
```

---

## 9. 安全考量

| 维度 | 措施 |
|---|---|
| **ASR/TTS Token** | 复用现有 `secrets.Encrypt/Decrypt` (AES-256-GCM)，DB 存密文，NATS 过密文 |
| **WebSocket 鉴权** | 升级前经过 `middleware.Auth()`，未登录不可连 |
| **音频不落盘** | 语音帧只在内存中转，不存储不持久化 |
| **TTS 内容脱敏** | 复用现有 `harness/output.go` 的流式脱敏——脱敏后的文字再喂 TTS |
| **限流** | 语音连接数按用户限制（默认同时 1 个语音会话） |

---

## 10. 可观测性

| 指标 | 来源 |
|---|---|
| ASR 识别延迟 | Gateway OTel span `voice.asr` |
| TTS 合成延迟 | Gateway OTel span `voice.tts` |
| 语音会话数 | Prometheus gauge `sundynix_voice_sessions_active` |
| ASR 用量(秒) | 计入现有用量管道 |
| TTS 用量(字) | 计入现有用量管道 |
| 错误率 | span error + Prometheus counter |

---

## 11. 未来扩展（本期不做）

| 方向 | 说明 |
|---|---|
| **声纹识别** | 用声纹替代/辅助登录鉴权 |
| **多语种实时翻译** | ASR → 翻译 → TTS，三段流水线 |
| **自定义唤醒词** | "Hey Sundynix" 免点击启动 |
| **音色克隆** | 用户上传自己的声音，Agent 用用户喜欢的声音回答 |
| **Provider failover** | ASR/TTS 也做主备链（火山→讯飞），复用 LLM failover 模式 |

---

## 12. 总工期与资源

| 阶段 | 内容 | 工期 |
|---|---|---|
| Phase 1 | ASR（耳朵） | 3 天 |
| Phase 2 | 语音触发任务 | 1 天 |
| Phase 3 | TTS（嘴巴） | 3-4 天 |
| Phase 4 | 打断 + 连续对话 | 2 天 |
| Phase 5 | 控制面 + 上线 | 2 天 |
| **总计** | | **~2 周** |

**改动影响**：

```diff
+ 新增文件: ~10 个（Go 5 个 + TS 3 个 + 契约 1 个 + handler 1 个）
+ 新增代码: ~1,500 行（Go ~600 + TS ~400 + 测试 ~300 + 配置/文档 ~200）
~ 修改文件: 3 个（router.go +1行, DatasourcesPage.tsx +50行, .env.example +8行）
  不动文件: Dispatcher / MCP-Go / MCP-Py / Eino / NATS bus / shared 核心 = 0 改动
```

---

*本文档描述语音交互功能的设计方案；实现时以本文档为准，如有重大变更需更新本文档。*
