13 KiB
Python 后端 API 文档
Base URL:
http://localhost:3001/v1所有路径均挂载在
/v1前缀下,完整路径如POST http://localhost:3001/v1/getScenes。来自 java-mock 的请求须附加 内部签名 Header。
/chat_callback由火山引擎 RTC 平台直接回调,走独立 API Key 鉴权。
接口总览
| 方法 | 路径 | 调用方 | 鉴权 | 说明 |
|---|---|---|---|---|
| POST | /getScenes |
java-mock | 内部签名 | 获取场景列表 & RTC 入房参数 |
| POST | /proxy?Action=xxx |
java-mock | 内部签名 | 开始/停止语音对话 |
| POST | /session/history |
java-mock | 内部签名 | 写入房间历史上下文 |
| POST | /chat_callback |
火山引擎 RTC | Bearer Token | 自定义 LLM 回调(SSE 流式) |
| POST | /debug/chat |
开发调试 | 无 | 调试 LLM 对话 |
| GET | /debug/rag |
开发调试 | 无 | 调试 RAG 检索 |
调用时序
前端 → java-mock → Python 后端
1. POST /getScenes ← 获取场景 + RTC 入房参数
2. POST /session/history ← (可选) 注入历史上下文
3. POST /proxy?Action=StartVoiceChat ← 启动语音对话
4. 火山引擎 RTC → POST /chat_callback ← 平台回调(自动,非 java-mock)
5. POST /proxy?Action=StopVoiceChat ← 结束语音对话
一、获取场景列表
POST /v1/getScenes
返回所有已配置场景的信息和对应的 RTC 入房参数。每次调用会重新生成 RoomId/UserId/Token/TaskId 并写入服务端 Session,供后续 StartVoiceChat 自动取用。
请求
Headers(内部签名):
| Header | 必填 | 说明 |
|---|---|---|
X-Internal-Service |
✅ | 固定 java-gateway |
X-Internal-User-Id |
✅ | 当前登录用户 ID |
X-Internal-Timestamp |
✅ | 毫秒时间戳(字符串) |
X-Internal-Signature |
✅ | HMAC-SHA256 签名(hex),算法见内部鉴权协议 |
Body: 无({} 或空均可)
成功响应 200
{
"ResponseMetadata": {
"Action": "getScenes"
},
"Result": {
"scenes": [
{
"scene": {
"id": "Custom",
"name": "小块",
"icon": "https://lf3-rtc-demo.volccdn.com/obj/rtc-aigc-assets/DoubaoAvatar.png",
"botName": "agent-user-001",
"isInterruptMode": true,
"isVision": false,
"isScreenMode": false,
"isAvatarScene": false,
"avatarBgUrl": ""
},
"rtc": {
"AppId": "6xxxxxxx",
"RoomId": "550e8400-e29b-41d4-a716-446655440000",
"UserId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"Token": "001xxxxxxAQBhMGI3Zm...",
"TaskId": "e5f6a7b8-1234-5678-9abc-def012345678"
}
}
]
}
}
Result.scenes[*].scene 字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 场景唯一标识,后续 /proxy 接口的 SceneID 取此值 |
name |
string | 场景显示名称 |
icon |
string | 场景头像 URL |
botName |
string | AI Bot 在 RTC 房间中的 UserId |
isInterruptMode |
boolean | 是否开启用户打断模式 |
isVision |
boolean | 是否开启视觉理解能力 |
isScreenMode |
boolean | 是否为屏幕共享模式(视觉输入来自屏幕流) |
isAvatarScene |
boolean | 是否为数字人场景 |
avatarBgUrl |
string|null | 数字人背景图 URL,非数字人场景为空 |
Result.scenes[*].rtc 字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
AppId |
string | 火山引擎 RTC AppId |
RoomId |
string | 本次生成的房间 ID(UUID),前端入房和后续接口都需要 |
UserId |
string | 本次生成的用户 ID(UUID),前端入房使用 |
Token |
string | RTC 入房 Token,24 小时有效 |
TaskId |
string | 语音任务 ID,StopVoiceChat 时需要 |
注意: 每次调用
getScenes都会重新生成RoomId/UserId/Token/TaskId。必须在getScenes之后、StartVoiceChat之前使用同一套参数。
失败响应
鉴权失败 401:
{
"code": 401,
"message": "鉴权失败"
}
配置错误(缺少环境变量等):
{
"ResponseMetadata": {
"Action": "getScenes",
"Error": {
"Code": -1,
"Message": "Custom 场景缺少以下环境变量: CUSTOM_ACCESS_KEY_ID, CUSTOM_SECRET_KEY"
}
}
}
二、开始/停止语音对话
POST /v1/proxy?Action={Action}&Version={Version}
带 SigV4 签名转发到火山引擎 RTC OpenAPI。内部会自动从 Session 取回 getScenes 分配的房间参数。
请求
Headers(内部签名): 同 getScenes
Query 参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
Action |
string | ✅ | — | StartVoiceChat 或 StopVoiceChat |
Version |
string | ❌ | 环境变量 RTC_OPENAPI_VERSION,兜底 2025-06-01 |
火山引擎 OpenAPI 版本 |
Body(JSON):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
SceneID |
string | ✅ | 场景 ID,取 getScenes 返回的 scene.id(当前固定为 "Custom") |
请求示例:
{
"SceneID": "Custom"
}
StartVoiceChat 处理逻辑
- 从 Session 取回
getScenes时生成的RoomId、UserId、TaskId - 将
room_id追加到 LLM 回调 URL(?room_id={RoomId}),使/chat_callback能关联历史上下文 - 使用 AK/SK 对请求做 SigV4 签名
- 转发到
https://rtc.volcengineapi.com?Action=StartVoiceChat
StartVoiceChat 成功响应 200
{
"ResponseMetadata": {
"RequestId": "2025070100000000000000000000abcd",
"Action": "StartVoiceChat",
"Version": "2025-06-01",
"Service": "rtc"
},
"Result": {
"Message": "success"
}
}
StopVoiceChat 处理逻辑
- 从 Session 取回
RoomId、TaskId - 清除该房间的历史上下文缓存(
session/history写入的数据) - 使用 AK/SK 签名后转发到火山引擎
StopVoiceChat 成功响应 200
{
"ResponseMetadata": {
"RequestId": "2025070100000000000000000000efgh",
"Action": "StopVoiceChat",
"Version": "2025-06-01",
"Service": "rtc"
},
"Result": {
"Message": "success"
}
}
失败响应
鉴权失败 401:
{
"code": 401,
"message": "鉴权失败"
}
参数/配置错误(HTTP 200,但包含 Error):
{
"ResponseMetadata": {
"Action": "StartVoiceChat",
"Error": {
"Code": -1,
"Message": "SceneID 不能为空,SceneID 用于指定场景配置"
}
}
}
| 错误场景 | Error.Message |
|---|---|
| Action 为空 | Action 不能为空 |
| SceneID 为空 | SceneID 不能为空,SceneID 用于指定场景配置 |
| 场景不存在 | {SceneID} 不存在,请先配置对应场景。 |
| AK/SK 缺失 | Custom 场景的 AccountConfig.accessKeyId 不能为空 |
| 火山引擎接口报错 | 透传火山引擎原始错误信息 |
三、写入历史上下文
POST /v1/session/history
在 StartVoiceChat 之前调用,将上一次的对话历史注入该房间的上下文缓存。后续火山引擎 RTC 回调 /chat_callback 时,会自动将这些历史消息 prepend 到每次 LLM 请求的 messages 前面,实现跨会话的上下文延续。
请求
Headers(内部签名): 同 getScenes
Body(JSON):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
room_id |
string | ✅ | RTC 房间 ID,取 getScenes 返回的 rtc.RoomId |
messages |
array | ✅ | 历史消息列表,按时间正序排列 |
messages[*] 字段说明:
| 字段 | 类型 | 必填 | 可选值 | 说明 |
|---|---|---|---|---|
role |
string | ✅ | "user" | "assistant" |
消息发送方角色 |
content |
string | ✅ | — | 消息文本内容 |
请求示例:
{
"room_id": "550e8400-e29b-41d4-a716-446655440000",
"messages": [
{ "role": "assistant", "content": "你好,我是小块,有什么需要帮忙的吗?" },
{ "role": "user", "content": "今天出勤情况咋样" },
{ "role": "assistant", "content": "今天全部门出勤率百分之九十五,共二十三人到岗。" }
]
}
成功响应 200
{
"code": 200
}
失败响应
鉴权失败 401:
{
"code": 401,
"message": "鉴权失败"
}
Body 校验失败 422(FastAPI 自动校验):
{
"detail": [
{
"type": "missing",
"loc": ["body", "room_id"],
"msg": "Field required"
}
]
}
注意:
- 每次调用会覆盖该
room_id下已有的历史,不是追加StopVoiceChat时会自动清除该房间的历史缓存- 如果不需要上下文延续(新对话),可以跳过此接口
四、自定义 LLM 回调(SSE)
此接口由火山引擎 RTC 平台自动回调,不经过 java-mock。
POST /v1/chat_callback?room_id={room_id}
鉴权: Authorization: Bearer <CUSTOM_LLM_API_KEY>
Query 参数:
| 参数 | 必填 | 说明 |
|---|---|---|
room_id |
❌ | 房间 ID,由 StartVoiceChat 自动追加到回调 URL 中 |
Body(JSON):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
messages |
array | ✅ | 对话消息列表,最后一条必须是 user 角色 |
temperature |
float | ❌ | 采样温度 |
max_tokens |
int | ❌ | 最大生成 token 数 |
top_p |
float | ❌ | Top-P 采样 |
成功响应 200(text/event-stream):
data: {"id":"chatcmpl-xxx","choices":[{"delta":{"content":"今"}}]}
data: {"id":"chatcmpl-xxx","choices":[{"delta":{"content":"天"}}]}
data: [DONE]
失败响应:
| HTTP 状态码 | Error.Code | 触发场景 |
|---|---|---|
| 401 | AuthenticationError |
API Key 无效 |
| 400 | BadRequest |
messages 为空 / 最后一条不是 user |
| 500 | InternalError |
LLM 初始化失败 / 请求解析失败 |
五、调试接口
仅供本地开发,无鉴权。
5.1 调试聊天
POST /v1/debug/chat
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
history |
array | ❌ | 历史消息列表(role + content),默认空 |
question |
string | ✅ | 本次用户提问 |
响应: 200 text/plain 流式文本
5.2 调试 RAG 检索
GET /v1/debug/rag?query={query}
| 参数 | 必填 | 说明 |
|---|---|---|
query |
✅ | 检索问题 |
响应 200:
{
"query": "今天出勤情况",
"retrieved_context": "检索到的知识文本...",
"length": 128,
"status": "success"
}
内部鉴权协议
/getScenes、/proxy、/session/history均启用此鉴权。
java-mock 发送方在请求头附加:
| Header | 必填 | 说明 |
|---|---|---|
X-Internal-Service |
✅ | 固定值 java-gateway |
X-Internal-User-Id |
✅ | 当前登录用户 ID |
X-Internal-Timestamp |
✅ | 毫秒级 Unix 时间戳(字符串) |
X-Internal-Signature |
✅ | HMAC-SHA256 签名(hex) |
X-User-Name |
❌ | URL 编码的用户显示名(透传,Python 侧暂未使用) |
X-User-Sex |
❌ | 性别 |
X-User-Dept-Name |
❌ | URL 编码的部门名称 |
签名算法:
message = "java-gateway:{userId}:{毫秒时间戳}"
signature = HMAC-SHA256(INTERNAL_SERVICE_SECRET, message) → hex 编码
Python 接收方验证逻辑:
INTERNAL_SERVICE_SECRET未配置 → 直接放行(开发环境兼容)- 校验
X-Internal-Service必须为java-gateway,且 4 个必要 Header 非空 - 时间窗口校验:
|当前时间 - timestamp| ≤ 5 分钟(防重放) - 重新计算 HMAC,用
hmac.compare_digest常量时间比较(防时序攻击)
通用错误结构
内部接口(getScenes / proxy / session/history) 返回火山引擎风格:
{
"ResponseMetadata": {
"Action": "操作名",
"Error": {
"Code": -1,
"Message": "错误描述"
}
}
}
chat_callback 返回 JSON 格式错误(非 SSE):
{
"Error": {
"Code": "BadRequest",
"Message": "messages 不能为空"
}
}
环境变量
| 变量名 | 必填 | 说明 |
|---|---|---|
INTERNAL_SERVICE_SECRET |
✅ | 内部服务签名密钥,需与 java-mock 侧一致 |
CUSTOM_LLM_API_KEY |
❌ | /chat_callback 的 Bearer Token,留空则跳过鉴权 |
LOCAL_LLM_API_KEY |
✅ | 方舟 LLM API Key |
LOCAL_LLM_MODEL |
✅ | 方舟端点 ID |
LOCAL_LLM_BASE_URL |
✅ | 方舟 API 地址 |
完整变量列表见 .env.example。