> ## Documentation Index
> Fetch the complete documentation index at: https://dingguoliang.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 端侧语音 Agent 智控平台

> 脱敏全案：一天怎么用、一次对话怎么走、三层地图与三个深挖点。

近半年主线是一套 **端侧语音 Agent 智控平台**：网页里运营设备与智能体，设备侧跑实时语音对话，两边靠配置契约连成闭环。功能已基本打通，进入上线阶段。

案例已脱敏——不写公司名、产品品牌和客户细节；写的是系统怎么拆、一次对话怎么走、以及几处真正难的地方。

***

## 先看这一天在干什么

可以把系统想成两条线，同时转：

**运营线（人在电脑前）**<br />登录智控台 → 管理设备与绑定 → 给智能体选模型、音色、插件和知识库 → 配团队权限 → 配置下发到对应设备。业务接口还能按区域切换，账号体系相对固定。

**会话线（人在设备前）**<br />设备连上语音服务 → 按「这台设备」的配置装配能力 → 用户说话 → 系统听清、思考、必要时查知识或调工具 → 把话播出来 → 用户打断时，上一轮声音必须立刻停干净。

若两条线各干各的：现场只能改本地文件；助手停在单轮闲聊；多团队时数据边界含糊。这半年做的事，就是把它们收成一条能运营、能降级的闭环。

***

## 一次对话怎么走完

下面按时间顺序走一遍（经典语音路径）。括号里是人话解释。

1. **建连**<br />设备通过 WebSocket 连上语音服务，一带上设备身份。一设备一连接，会话状态挂在这条连接上。
2. **拉配置**<br />若走智控台模式：先拿基座配置，再按设备拉「这一台」的智能体、模型、插件等差异项。模块没就绪前，不急着处理用户语音，避免半初始化乱答。本地开发也可以不连智控台，用本地配置跑通。
3. **听（VAD）**<br />从连续音频里判断「用户是不是在说话、说完没有」。这是后面一切的门闩。
4. **识（ASR）**<br />把语音打成文字。本地识别与云端识别在资源占用上不一样：有的可以多连接共享，有的必须每连接隔离。
5. **想 / 办事（LLM + 工具）**<br />模型根据上下文决定直接回答，还是先调工具（查知识、设备能力、外部 MCP 等）。工具不是散落在代码各处的 if，而是收成统一目录再分发。
6. **说（TTS）**<br />文字合成语音流式回传。理想情况是模型还没说完整段，设备已经开始播，体感才不像卡死。
7. **打断**<br />用户说「停」或重新说话时：停止采集只是第一步；还在飞的生成、播报、字幕必须标成「过期」丢掉，否则会出现幽灵播报——旧句子冷不丁冒出来。长耗时工具也要有开始/结束状态，打断时把界面收干净。

另有一条 **端到端语音路径**（不经经典 ASR→LLM→TTS 级联）。同一连接里两条主路径只能活一条，否则会抢音频和状态。默认仍保证经典路径可运行，再扩端到端。

***

## 系统怎么拆

```text theme={null}
智控台前端 (Vue)
    ↕ HTTP（业务可按区域切换）
智控台后端 (Java / Spring)
  · 设备 / 智能体 / 模型 / 知识库
  · 登录权限 + 团队数据隔离
  · 向设备侧下发配置（服务身份鉴权，和用户登录不是一路）
    ↕ 配置拉取
设备侧语音服务 (Python)
  · WebSocket 会话
  · VAD → ASR → LLM → TTS（或端到端）
  · 工具 / 插件 / MCP
  · OTA、视觉等配套 HTTP
```

***

## 三层模块地图

我覆盖全链路，下面按层列能力——这是这半年「面」上做了什么。

### 智控台前端

* 设备、智能体、模型、知识库、音色/克隆等管理界面
* 路由与按钮级权限（和后端权限字符串对齐）
* 团队上下文由具体业务请求显式带上，而不是全局偷偷注入（写错团队的代价很高）
* 账号域相对固定；业务 API 可按数据中心/区域切换

### 智控台后端

* 设备绑定与生命周期、智能体与模型配置、知识库运营入口
* **系统功能权限**（菜单/角色）与 **团队数据权限**（资源归属）分开建模
* 读操作可在授权团队范围内聚合；写操作必须有明确团队上下文
* 关键查询侧带团队过滤，不只靠前端藏按钮
* 知识库通过适配器对接外部检索/向量引擎，业务层不绑死一家
* 给设备侧的配置接口用服务身份保护，和运营人员的登录会话分离；基座配置可缓存

### 设备侧语音服务

* 连接生命周期：握手、后台初始化、绑定/未绑定分支
* 按配置装配 VAD/ASR/LLM/TTS/记忆/意图等可替换模块
* 文本消息按类型路由（hello、打断、监听、IoT、MCP、视觉等），避免全堆在连接主逻辑里
* 统一工具调度：服务端插件、服务端/设备 MCP、设备 IoT 等
* 会话内按需检索知识（短超时，失败要说人话）
* 日志按模块打标，并带设备/会话上下文；配置日志脱敏

***

## 三个深挖点

### 1. 配置：既要统一运营，又要能本地调试

最早如果只认本地文件，运维根本管不住现场；如果一切必须走云端，联调又慢得难受。后来定成：

* 有控制面地址 → 以云端基座为主，建连后再拉「这一台设备」的差异配置
* 默认可提交的结构 vs 密钥/现场覆盖分开，密钥不进默认模板
* 留少量本地可覆盖项，方便排障或灰度换模块，但优先级写清楚
* 字段名两边必须同一套；改契约就当改接口，双边一起动

联调里踩过最冤的，是同一含义两边各起一个字段名——改半天发现设备根本没读到新值。现在更在意契约纪律，而不是「再加一个开关」。

更深一层见 [配置与控制面](/notes/config-control-plane)。

### 2. 会话：双路径互斥，打断必须「死干净」

语音产品里，用户感知几乎等于「我说完有没有声音、我说停停不停」。

* **双路径**：经典级联和端到端不要并行抢同一路音频；入口就互斥
* **打断**：用轮次标记作废过期的生成/播报/字幕；只停麦不够
* **别堵事件循环**：阻塞初始化、重计算丢线程池；记忆预热之类不挡首轮
* **扩展往外挂**：新协议、新工具走独立处理与可替换模块，连接核心保持瘦

幽灵播报这类 bug 复现不稳定，没有「这一通会话装了哪套模块、卡在哪一段」的日志，线上只能重启。可观测性在这里不是加分项，是排障前提。

更深一层见 [会话与打断](/notes/voice-session-interrupt)。

### 3. 权限与工具：能进后台 ≠ 能看全部；能说话 ≠ 能办事

多团队共用控制台时，只做登录和菜单，列表接口仍可能扫到不该看的数据。所以：

* 系统层管「能不能进功能」
* 团队层管「碰得到哪些资源」；写必须带团队上下文
* 查询侧强制范围；前端团队头显式传递

工具侧则是另一件事：来源一多（插件、MCP、设备能力），若各写各的，模型一失败就容易空转重试。做法是统一目录分发，短超时与可理解错误，长任务有开始/结束，打断时收尾。知识检索也按「会话内工具」挂上，而不是写死在语音主循环里——控制面管知识运营，对话里按需查。

***

## 坏了的时候长什么样

上线前更在意失败形态，而不是只演示 Happy Path。

| 情况 | 期望 |
| - | - |
| 未绑定 / 拉配置失败 | 进受限引导，而不是连接直接被踢 |
| 某个 TTS 实现挂了 | 有占位回落，管线仍能起来 |
| 知识检索超时 | 短超时；告诉模型/用户失败，不拖死整轮 |
| 工具跑到一半用户打断 | 生命周期收尾，界面不一直转圈 |
| 控制面抖动 | 拉配置有限重试；本地模式仍可开发 |

更多短复盘见 [经验总结](/notes/lessons-learned)。

***

## 技术栈

| 层 | 技术 |
| - | - |
| 智控台前端 | Vue、权限指令、多区域业务 API |
| 智控台后端 | Java、Spring Boot、MySQL、Redis |
| 设备侧服务 | Python、asyncio、WebSocket |
| 检索 | 外部知识/向量引擎（适配接入）+ 会话内按需检索 |
| 多模态 | ASR / TTS / 端到端语音、视觉相关能力 |

***

## 相关阅读

<CardGroup cols={2}>
  <Card title="配置与控制面" icon="sliders" href="/notes/config-control-plane">
    双模式、按设备配置、契约与鉴权分层。
  </Card>

  <Card title="会话与打断" icon="waveform-lines" href="/notes/voice-session-interrupt">
    走读加深、双路径、轮次作废与线程边界。
  </Card>

  <Card title="经验总结" icon="lightbulb" href="/notes/lessons-learned">
    跨主题短复盘。
  </Card>

  <Card title="项目概览" icon="folder" href="/projects/overview">
    项目区入口。
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.