Revamp documentation structure in mkdocs.yml by reorganizing navigation for improved accessibility. Remove outdated content from previous sections and introduce new topics including detailed guides on assistant management, configuration options, and tool integrations. Enhance API reference documentation with comprehensive error codes and WebSocket protocol details. Add new sections for automated testing, data analysis, and knowledge base management, ensuring a cohesive and user-friendly documentation experience.

This commit is contained in:
Xin Wang
2026-03-01 22:38:50 +08:00
parent 6a46ec69f4
commit 2418df80e5
33 changed files with 3664 additions and 693 deletions

View File

@@ -0,0 +1,88 @@
# 错误码
本文档列出 AI Video Assistant API 的所有错误码及其说明。
## 协议错误
| 错误码 | 说明 | 解决方案 |
|---|---|---|
| `protocol.invalid_json` | JSON 格式错误 | 检查发送的 JSON 是否合法 |
| `protocol.invalid_message` | 消息格式错误 | 检查消息结构是否符合协议 |
| `protocol.order` | 消息顺序错误 | 确保先发送 `session.start` |
| `protocol.assistant_id_required` | 缺少 `assistant_id` query 参数 | 在连接 URL 中添加 `assistant_id` 参数 |
| `protocol.invalid_override` | metadata 覆盖字段不合法 | 检查 overrides 字段是否在白名单内 |
## 助手错误
| 错误码 | 说明 | 解决方案 |
|---|---|---|
| `assistant.not_found` | 助手不存在 | 检查 `assistant_id` 是否正确 |
| `assistant.config_unavailable` | 助手配置不可用 | 确认助手已正确配置并发布 |
## 音频错误
| 错误码 | 说明 | 解决方案 |
|---|---|---|
| `audio.invalid_pcm` | PCM 数据无效 | 检查音频格式是否为 `pcm_s16le` |
| `audio.frame_size_mismatch` | 音频帧大小不匹配 | 确保帧长度是 640 字节的整数倍 |
## 服务器错误
| 错误码 | 说明 | 解决方案 |
|---|---|---|
| `server.internal` | 服务端内部错误 | 查看服务端日志排查问题 |
## 错误响应格式
所有错误都通过 `error` 事件返回:
```json
{
"type": "error",
"timestamp": 1730000000000,
"sessionId": "sess_xxx",
"data": {
"code": "protocol.invalid_json",
"message": "Invalid JSON format",
"details": {}
}
}
```
## HTTP API 错误
REST API 使用标准 HTTP 状态码:
| 状态码 | 说明 |
|--------|------|
| 200 | 请求成功 |
| 201 | 创建成功 |
| 400 | 请求参数错误 |
| 401 | 未授权(缺少或无效的认证信息) |
| 403 | 禁止访问(权限不足) |
| 404 | 资源不存在 |
| 422 | 请求实体无法处理 |
| 500 | 服务器内部错误 |
### HTTP 错误响应示例
```json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": {
"field": "name",
"reason": "required"
}
}
}
```
## 错误处理最佳实践
1. **始终检查错误响应** - 不要假设请求一定成功
2. **实现重试机制** - 对于临时性错误(如网络问题)实现指数退避重试
3. **记录错误日志** - 保存错误详情用于问题排查
4. **友好的用户提示** - 将技术错误转换为用户可理解的提示

View File

@@ -0,0 +1,196 @@
# API 参考
本节提供 AI Video Assistant 的完整 API 文档。
## API 概览
AI Video Assistant 提供两种类型的 API
| API 类型 | 用途 | 协议 |
|---------|------|------|
| **REST API** | 管理助手、模型、知识库等资源 | HTTP |
| **WebSocket API** | 实时语音对话 | WebSocket |
## REST API
### 基础地址
```
http://localhost:8080/api/v1
```
### 认证
REST API 使用 Bearer Token 认证:
```bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:8080/api/v1/assistants
```
### 通用响应格式
**成功响应**
```json
{
"success": true,
"data": { ... }
}
```
**列表响应**
```json
{
"success": true,
"data": {
"items": [...],
"total": 100,
"page": 1,
"page_size": 20
}
}
```
**错误响应**
```json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "错误描述"
}
}
```
### 主要端点
#### 助手管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /assistants | 获取助手列表 |
| POST | /assistants | 创建助手 |
| GET | /assistants/{id} | 获取助手详情 |
| PATCH | /assistants/{id} | 更新助手 |
| DELETE | /assistants/{id} | 删除助手 |
#### 模型管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /llm | 获取 LLM 模型列表 |
| POST | /llm | 添加 LLM 模型 |
| GET | /asr | 获取 ASR 模型列表 |
| POST | /asr | 添加 ASR 模型 |
| GET | /voices | 获取语音列表 |
| POST | /voices | 添加语音配置 |
#### 知识库管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /knowledge-bases | 获取知识库列表 |
| POST | /knowledge-bases | 创建知识库 |
| POST | /knowledge-bases/{id}/documents | 上传文档 |
| DELETE | /knowledge-bases/{id}/documents/{doc_id} | 删除文档 |
#### 历史记录
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /history | 获取对话历史 |
| GET | /history/{id} | 获取对话详情 |
| GET | /history/stats | 获取统计数据 |
## WebSocket API
### 连接地址
```
ws://localhost:8000/ws?assistant_id=<assistant_id>
```
### 协议概述
WebSocket API 使用双向消息通信:
- **文本帧**JSON 格式的控制消息
- **二进制帧**PCM 音频数据
### 详细文档
- [WebSocket 协议](websocket.md) - 完整的消息格式和流程
- [错误码](errors.md) - 错误码列表和处理方式
## SDK
### JavaScript SDK
```bash
npm install @ai-video-assistant/sdk
```
```javascript
import { AIVideoAssistant } from '@ai-video-assistant/sdk';
const assistant = new AIVideoAssistant({
apiUrl: 'http://localhost:8080',
wsUrl: 'ws://localhost:8000'
});
// 创建助手
const result = await assistant.create({
name: '客服助手',
prompt: '你是一个友好的客服助手'
});
// 开始对话
const conversation = await assistant.connect(result.id);
conversation.on('response', (text) => {
console.log('助手回复:', text);
});
```
### Python SDK
```bash
pip install ai-video-assistant
```
```python
from ai_video_assistant import AIVideoAssistant
client = AIVideoAssistant(
api_url="http://localhost:8080",
ws_url="ws://localhost:8000"
)
# 创建助手
assistant = client.assistants.create(
name="客服助手",
prompt="你是一个友好的客服助手"
)
# 开始对话
async with client.connect(assistant.id) as conv:
response = await conv.send_text("你好")
print(f"助手回复: {response}")
```
## 速率限制
| 端点类型 | 限制 |
|---------|------|
| REST API | 100 请求/分钟 |
| WebSocket | 10 并发连接/用户 |
超出限制会返回 `429 Too Many Requests`
## 下一步
- [WebSocket 协议](websocket.md) - 实时对话协议详解
- [错误码](errors.md) - 错误处理参考
- [快速开始](../quickstart/api.md) - API 使用示例

View File

@@ -0,0 +1,853 @@
# WebSocket 协议
WebSocket 端点提供双向实时语音对话能力,支持音频流输入输出和文本消息交互。
## 连接地址
```
ws://<host>/ws?assistant_id=<assistant_id>
```
- `assistant_id` 为必填 query 参数,用于从数据库加载该助手的运行时配置。
## 传输规则
- **文本帧**JSON 格式控制消息
- **二进制帧**PCM 音频数据(`pcm_s16le`, 16kHz, 单声道)
- 帧长度必须是 640 字节的整数倍20ms 音频 = 640 bytes
---
## 消息流程
```
Client -> session.start
Server <- session.started
Server <- config.resolved
Client -> (binary pcm frames...)
Server <- input.speech_started / transcript.delta / transcript.final
Server <- assistant.response.delta / assistant.response.final
Server <- output.audio.start
Server <- (binary pcm frames...)
Server <- output.audio.end
Client -> session.stop
Server <- session.stopped
```
---
## 客户端 -> 服务端消息
### 1. Session Start: `session.start`
客户端连接后发送的第一个消息,用于启动对话会话。
```json
{
"type": "session.start",
"audio": {
"encoding": "pcm_s16le",
"sample_rate_hz": 16000,
"channels": 1
},
"metadata": {
"channel": "web",
"source": "web_debug",
"history": {
"userId": 1
},
"overrides": {
"systemPrompt": "你是简洁助手",
"greeting": "你好,我能帮你什么?",
"output": {
"mode": "audio"
}
},
"dynamicVariables": {
"customer_name": "Alice",
"plan_tier": "Pro"
}
}
}
```
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | string | 是 | 固定为 `"session.start"` |
| `audio` | object | 否 | 音频格式描述 |
| `audio.encoding` | string | 否 | 固定为 `"pcm_s16le"` |
| `audio.sample_rate_hz` | number | 否 | 固定为 `16000` |
| `audio.channels` | number | 否 | 固定为 `1` |
| `metadata` | object | 否 | 运行时配置 |
**metadata 支持的字段**
- `channel` - 渠道标识
- `source` - 来源标识
- `history.userId` - 历史记录用户 ID
- `overrides` - 可覆盖字段(仅限安全白名单)
- `dynamicVariables` - 动态变量(支持 `{{variable}}` 占位符)
**`metadata.overrides` 白名单字段**
- `systemPrompt`
- `greeting`
- `firstTurnMode`
- `generatedOpenerEnabled`
- `output`
- `bargeIn`
- `knowledgeBaseId`
- `knowledge`
- `tools`
- `openerAudio`
**限制**
- `metadata.workflow` 会被忽略(不触发 workflow 事件)
- 禁止提交 `metadata.services`
- 禁止提交 `assistantId` / `appId` / `app_id` / `configVersionId` / `config_version_id`
- 禁止提交包含密钥语义的字段(如 `apiKey` / `token` / `secret` / `password` / `authorization`
---
### 2. Text Input: `input.text`
发送文本输入,跳过 ASR 识别,直接触发 LLM 回复。
```json
{
"type": "input.text",
"text": "你能做什么?"
}
```
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | string | 是 | 固定为 `"input.text"` |
| `text` | string | 是 | 用户文本内容 |
---
### 3. Response Cancel: `response.cancel`
请求中断当前回答。
```json
{
"type": "response.cancel",
"graceful": false
}
```
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `type` | string | 是 | - | 固定为 `"response.cancel"` |
| `graceful` | boolean | 否 | `false` | `false` 立即打断 |
---
### 4. Tool Call Results: `tool_call.results`
回传客户端执行的工具结果。
```json
{
"type": "tool_call.results",
"results": [
{
"tool_call_id": "call_abc123",
"name": "weather",
"output": { "temp_c": 21, "condition": "sunny" },
"status": { "code": 200, "message": "ok" }
}
]
}
```
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | string | 是 | 固定为 `"tool_call.results"` |
| `results` | array | 否 | 工具结果列表 |
| `results[].tool_call_id` | string | 是 | 工具调用 ID |
| `results[].name` | string | 是 | 工具名称 |
| `results[].output` | any | 否 | 工具输出 |
| `results[].status` | object | 是 | 执行状态 |
| `results[].status.code` | number | 是 | HTTP 状态码200-299 表示成功) |
| `results[].status.message` | string | 是 | 状态描述 |
---
### 5. Session Stop: `session.stop`
结束对话会话。
```json
{
"type": "session.stop",
"reason": "client_disconnect"
}
```
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | string | 是 | 固定为 `"session.stop"` |
| `reason` | string | 否 | 结束原因 |
---
### 6. Binary Audio
`session.started` 之后可持续发送二进制 PCM 音频。
- **格式**`pcm_s16le`
- **采样率**16000 Hz
- **声道**1单声道
- **帧长**20ms = 640 bytes
---
## 服务端 -> 客户端事件
### 事件包络
所有 JSON 事件都包含统一包络字段:
```json
{
"type": "event.name",
"timestamp": 1730000000000,
"sessionId": "sess_xxx",
"seq": 42,
"source": "asr",
"trackId": "audio_in",
"data": {}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `type` | string | 事件类型 |
| `timestamp` | number | 事件时间戳Unix 毫秒) |
| `sessionId` | string | 会话 ID |
| `seq` | number | 递增序号(用于重放/恢复) |
| `source` | string | 事件来源:`asr` / `llm` / `tts` / `tool` / `system` / `client` / `server` |
| `trackId` | string | 事件轨道:`audio_in` / `audio_out` / `control` |
| `data` | object | 业务数据(可选) |
**轨道 ID 说明**
| trackId | 说明 | 相关事件 |
|---------|------|---------|
| `audio_in` | ASR/VAD 输入侧事件 | `input.*`, `transcript.*` |
| `audio_out` | 助手输出侧事件 | `assistant.*`, `output.audio.*`, `response.interrupted`, `metrics.ttfb` |
| `control` | 会话控制事件 | `session.*`, `error`, `config.resolved`, `heartbeat` |
---
### 会话控制类事件
#### `session.started`
会话启动成功,客户端收到此事件后可以开始发送音频。
```json
{
"type": "session.started",
"timestamp": 1730000000000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 1,
"trackId": "control",
"tracks": {
"audio_in": "audio_in",
"audio_out": "audio_out",
"control": "control"
},
"audio": {
"encoding": "pcm_s16le",
"sample_rate_hz": 16000,
"channels": 1
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `sessionId` | string | 会话唯一标识符 |
| `trackId` | string | 固定为 `"control"` |
| `tracks` | object | 可用轨道列表 |
| `tracks.audio_in` | string | 输入轨道 ID |
| `tracks.audio_out` | string | 输出轨道 ID |
| `tracks.control` | string | 控制轨道 ID |
| `audio` | object | 音频格式配置 |
| `audio.encoding` | string | 编码格式 |
| `audio.sample_rate_hz` | number | 采样率 |
| `audio.channels` | number | 声道数 |
---
#### `config.resolved`
服务端最终配置快照,在 `session.started` 后立即发送。
```json
{
"type": "config.resolved",
"timestamp": 1730000000001,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 2,
"trackId": "control",
"config": {
"assistantId": "asst_abc123",
"configVersionId": "ver_xyz789",
"output": {
"mode": "audio"
},
"services": {
"llm": {
"provider": "openai",
"model": "gpt-4"
},
"asr": {
"provider": "sensevoice",
"model": "paraformer"
},
"tts": {
"provider": "aliyun",
"model": "xiaoyun",
"enabled": true
}
},
"tools": ["weather", "calculator"]
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"control"` |
| `config` | object | 已解析的运行时配置 |
| `config.assistantId` | string | 助手 ID |
| `config.configVersionId` | string | 配置版本 ID |
| `config.output` | object | 输出配置 |
| `config.output.mode` | string | 输出模式:`"audio"` / `"text"` |
| `config.services` | object | 服务配置(不包含密钥) |
| `config.tools` | array | 可用工具列表 |
---
#### `heartbeat`
保活心跳事件,默认每 50 秒发送一次。
```json
{
"type": "heartbeat",
"timestamp": 1730000050000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 10
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `timestamp` | number | 心跳时间戳 |
---
#### `session.stopped`
会话结束确认。
```json
{
"type": "session.stopped",
"timestamp": 1730000100000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 50,
"reason": "client_requested"
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `reason` | string | 结束原因:`"client_requested"` / `"timeout"` / `"error"` |
---
### ASR 识别事件
#### `input.speech_started`
检测到语音开始VAD
```json
{
"type": "input.speech_started",
"timestamp": 1730000010000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 5,
"source": "asr",
"trackId": "audio_in",
"probability": 0.95
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_in"` |
| `probability` | number | 语音检测置信度0-1 |
---
#### `input.speech_stopped`
检测到语音结束VAD
```json
{
"type": "input.speech_stopped",
"timestamp": 1730000012000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 8,
"source": "asr",
"trackId": "audio_in",
"probability": 0.92
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_in"` |
| `probability` | number | 静音检测置信度0-1 |
---
#### `transcript.delta`
ASR 增量识别文本(实时转写)。
```json
{
"type": "transcript.delta",
"timestamp": 1730000011000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 6,
"source": "asr",
"trackId": "audio_in",
"text": "你好",
"data": {
"text": "你好",
"turn_id": "turn_001",
"utterance_id": "utt_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_in"` |
| `text` | string | 增量识别文本 |
| `data.text` | string | 增量识别文本(同 `text` |
| `data.turn_id` | string | 当前对话轮次 ID |
| `data.utterance_id` | string | 当前语句 ID |
**节流说明**:服务端默认每 300ms 合并一次 delta 事件。
---
#### `transcript.final`
ASR 最终识别文本(语句结束)。
```json
{
"type": "transcript.final",
"timestamp": 1730000012500,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 9,
"source": "asr",
"trackId": "audio_in",
"text": "你好,请问今天天气怎么样",
"data": {
"text": "你好,请问今天天气怎么样",
"turn_id": "turn_001",
"utterance_id": "utt_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_in"` |
| `text` | string | 最终识别文本 |
| `data.text` | string | 最终识别文本(同 `text` |
| `data.turn_id` | string | 当前对话轮次 ID |
| `data.utterance_id` | string | 当前语句 ID |
---
### LLM/TTS 输出事件
#### `assistant.response.delta`
助手增量文本输出(流式生成)。
```json
{
"type": "assistant.response.delta",
"timestamp": 1730000013000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 12,
"source": "llm",
"trackId": "audio_out",
"text": "今天天气",
"data": {
"text": "今天天气",
"turn_id": "turn_001",
"response_id": "resp_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `source` | string | 固定为 `"llm"` |
| `text` | string | 增量文本内容 |
| `data.text` | string | 增量文本内容(同 `text` |
| `data.turn_id` | string | 当前对话轮次 ID |
| `data.response_id` | string | 当前回复 ID |
**节流说明**:服务端默认每 80ms 合并一次 delta 事件。
---
#### `assistant.response.final`
助手完整文本输出(回复结束)。
```json
{
"type": "assistant.response.final",
"timestamp": 1730000015000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 18,
"source": "llm",
"trackId": "audio_out",
"text": "今天天气晴朗气温25度适合外出。",
"data": {
"text": "今天天气晴朗气温25度适合外出。",
"turn_id": "turn_001",
"response_id": "resp_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `source` | string | 固定为 `"llm"` |
| `text` | string | 完整回复文本 |
| `data.text` | string | 完整回复文本(同 `text` |
| `data.turn_id` | string | 当前对话轮次 ID |
| `data.response_id` | string | 当前回复 ID |
---
#### `assistant.tool_call`
工具调用通知,通知客户端 LLM 请求调用工具。
```json
{
"type": "assistant.tool_call",
"timestamp": 1730000014000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 14,
"source": "llm",
"trackId": "audio_out",
"tool_call_id": "call_abc123",
"tool_name": "weather",
"arguments": {
"city": "北京"
},
"executor": "server",
"timeout_ms": 30000,
"data": {
"tool_call": {
"id": "call_abc123",
"name": "weather",
"arguments": "{\"city\":\"北京\"}"
},
"turn_id": "turn_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `source` | string | 固定为 `"llm"` |
| `tool_call_id` | string | 工具调用唯一 ID |
| `tool_name` | string | 工具名称 |
| `arguments` | object | 工具参数(已解析的 JSON |
| `executor` | string | 执行方:`"server"` 服务端执行 / `"client"` 客户端执行 |
| `timeout_ms` | number | 超时时间(毫秒) |
| `data.tool_call` | object | 原始工具调用信息 |
| `data.tool_call.id` | string | 工具调用 ID |
| `data.tool_call.name` | string | 工具名称 |
| `data.tool_call.arguments` | string | 工具参数JSON 字符串) |
| `data.turn_id` | string | 当前对话轮次 ID |
**注意**:当 `executor = "client"` 时,客户端需要执行工具并返回 `tool_call.results`
---
#### `assistant.tool_result`
工具执行结果通知。
```json
{
"type": "assistant.tool_result",
"timestamp": 1730000014500,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 15,
"source": "server",
"trackId": "audio_out",
"tool_call_id": "call_abc123",
"tool_name": "weather",
"tool_display_name": "天气查询",
"ok": true,
"error": null,
"result": {
"tool_call_id": "call_abc123",
"name": "weather",
"output": {
"temperature": 25,
"condition": "晴",
"humidity": 40
},
"status": {
"code": 200,
"message": "ok"
}
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `source` | string | 执行方:`"server"` / `"client"` |
| `tool_call_id` | string | 工具调用 ID |
| `tool_name` | string | 工具名称 |
| `tool_display_name` | string | 工具显示名称 |
| `ok` | boolean | 执行是否成功(状态码 200-299 为 true |
| `error` | object \| null | 错误信息(`ok=false` 时存在) |
| `error.code` | number | 错误状态码 |
| `error.message` | string | 错误描述 |
| `error.retryable` | boolean | 是否可重试 |
| `result` | object | 原始执行结果 |
| `result.output` | any | 工具返回数据 |
| `result.status` | object | 执行状态 |
| `result.status.code` | number | HTTP 状态码 |
| `result.status.message` | string | 状态描述 |
---
#### `output.audio.start`
TTS 音频播放开始标记。
```json
{
"type": "output.audio.start",
"timestamp": 1730000015500,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 19,
"source": "tts",
"trackId": "audio_out",
"data": {
"tts_id": "tts_001",
"turn_id": "turn_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `source` | string | 固定为 `"tts"` |
| `data.tts_id` | string | TTS 播放段 ID |
| `data.turn_id` | string | 当前对话轮次 ID |
**说明**:此事件后服务端将发送二进制 PCM 音频帧。
---
#### `output.audio.end`
TTS 音频播放结束标记。
```json
{
"type": "output.audio.end",
"timestamp": 1730000018000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 25,
"source": "tts",
"trackId": "audio_out",
"data": {
"tts_id": "tts_001",
"turn_id": "turn_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `source` | string | 固定为 `"tts"` |
| `data.tts_id` | string | TTS 播放段 ID |
| `data.turn_id` | string | 当前对话轮次 ID |
---
#### `response.interrupted`
回答被打断(用户插话)。
```json
{
"type": "response.interrupted",
"timestamp": 1730000016000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 20,
"source": "system",
"trackId": "audio_out",
"data": {
"turn_id": "turn_001",
"response_id": "resp_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `data.turn_id` | string | 被打断的对话轮次 ID |
| `data.response_id` | string | 被打断的回复 ID |
---
#### `metrics.ttfb`
首包音频时延指标Time To First Byte
```json
{
"type": "metrics.ttfb",
"timestamp": 1730000015600,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 21,
"source": "system",
"trackId": "audio_out",
"latencyMs": 1520,
"data": {
"latencyMs": 1520,
"turn_id": "turn_001"
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `trackId` | string | 固定为 `"audio_out"` |
| `latencyMs` | number | 首包音频时延(毫秒) |
| `data.latencyMs` | number | 首包音频时延(同 `latencyMs` |
| `data.turn_id` | string | 当前对话轮次 ID |
**说明**:从用户输入结束到第一个音频包发送的时间。
---
### 错误事件
#### `error`
统一错误事件。
```json
{
"type": "error",
"timestamp": 1730000020000,
"sessionId": "ea34e1ca-b417-4a57-b03e-f752cb82e97d",
"seq": 30,
"sender": "server",
"code": "llm.timeout",
"message": "LLM request timeout",
"stage": "llm",
"retryable": true,
"trackId": "audio_out",
"data": {
"error": {
"stage": "llm",
"code": "llm.timeout",
"message": "LLM request timeout",
"retryable": true
}
}
}
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `sender` | string | 错误来源:`"server"` / `"client"` |
| `code` | string | 错误码 |
| `message` | string | 错误描述 |
| `stage` | string | 错误阶段:`"protocol"` / `"asr"` / `"llm"` / `"tts"` / `"tool"` / `"audio"` |
| `retryable` | boolean | 是否可重试 |
| `trackId` | string | 错误关联的轨道 |
| `data.error` | object | 结构化错误信息 |
| `data.error.stage` | string | 错误阶段 |
| `data.error.code` | string | 错误码 |
| `data.error.message` | string | 错误描述 |
| `data.error.retryable` | boolean | 是否可重试 |
**trackId 约定**
- `audio_in`ASR/音频输入相关错误
- `audio_out`LLM/TTS/工具相关错误
- `control`:协议/会话控制相关错误
---
## 关联 ID 说明
事件中的关联 ID 用于追踪对话流程:
| ID 类型 | 说明 | 生命周期 |
|---------|------|---------|
| `turn_id` | 对话轮次 ID | 一次用户-助手交互 |
| `utterance_id` | 语句 ID | 一次 ASR 最终识别结果 |
| `response_id` | 回复 ID | 一次助手回复生成 |
| `tool_call_id` | 工具调用 ID | 一次工具调用 |
| `tts_id` | TTS 播放段 ID | 一段语音合成播放 |
---
## 心跳与超时
- **心跳间隔**:默认 50 秒(`heartbeat_interval_sec`
- **空闲超时**:默认 60 秒(`inactivity_timeout_sec`
- 客户端应持续发送音频或轻量消息避免被判定闲置
## 事件节流
为保持客户端渲染和服务端负载稳定v1 协议对部分事件进行节流:
| 事件 | 默认节流间隔 | 说明 |
|------|-------------|------|
| `transcript.delta` | 300ms | ASR 增量文本 |
| `assistant.response.delta` | 80ms | LLM 增量文本 |
## 错误处理
详细错误码请参考 [错误码](errors.md)。