12 KiB
Python 后端 API 文档
Base URL:
http://localhost:3001所有来自 java-mock 的请求须附加内部服务签名 Header(见内部鉴权协议)。
/api/chat_callback由火山引擎 RTC 平台直接回调,走独立 API Key 鉴权。
目录
接口总览
| 方法 | 路径 | 调用方 | 鉴权方式 | 说明 |
|---|---|---|---|---|
| POST | /getScenes |
java-mock | 内部签名 | 获取场景列表 & RTC 配置 |
| POST | /proxy |
java-mock | 内部签名 | 转发 StartVoiceChat / StopVoiceChat 到火山引擎 |
| POST | /api/session/history |
java-mock | 内部签名 | 写入房间历史上下文 |
| POST | /api/chat_callback |
火山引擎 RTC 平台 | API Key | 自定义 LLM 回调,返回 SSE 流 |
| POST | /debug/chat |
开发调试 | 无 | 直接测试 LLM 对话 |
| GET | /debug/rag |
开发调试 | 无 | 测试 RAG 知识库检索 |
一、场景接口
1.1 获取场景列表
POST /getScenes
鉴权: 内部签名(java-mock 调用)
请求体: {} 或空
成功响应 200:
{
"ResponseMetadata": {
"Action": "getScenes"
},
"Result": {
"scenes": [
{
"scene": {
"id": "Custom",
"botName": "BotUser001",
"isInterruptMode": true,
"isVision": false,
"isScreenMode": false,
"isAvatarScene": false,
"avatarBgUrl": null
},
"rtc": {
"AppId": "6xxxxxxx",
"RoomId": "550e8400-e29b-41d4-a716-446655440000",
"UserId": "user-xyz",
"Token": "AQBhMGI3Zm...",
"TaskId": "task-001"
}
}
]
}
}
场景字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 场景唯一标识,后续接口的 SceneID 取此值 |
| botName | string | AI Bot 在 RTC 房间中的 UserId |
| isInterruptMode | boolean | 是否开启打断模式(InterruptMode === 0) |
| isVision | boolean | 是否开启视觉能力 |
| isScreenMode | boolean | 是否为屏幕共享模式 |
| isAvatarScene | boolean | 是否为数字人场景 |
| avatarBgUrl | string|null | 数字人背景图 URL |
RTC 字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| AppId | string | 火山引擎 RTC AppId |
| RoomId | string | 本次会话分配的房间 ID(UUID) |
| UserId | string | 用户在 RTC 房间中的 UserId |
| Token | string | RTC 入房 Token |
| TaskId | string | 语音任务 ID,StopVoiceChat 时需要 |
副作用: 该接口会将
RoomId / UserId / TaskId写入服务端 Session,供后续/proxy?Action=StartVoiceChat自动取用,无需客户端传递。
失败响应:
{
"ResponseMetadata": {
"Action": "getScenes",
"Error": {
"Code": -1,
"Message": "错误描述"
}
}
}
二、RTC 代理接口
2.1 开始 / 停止语音对话
POST /proxy?Action=<action>&Version=<version>
鉴权: 内部签名(java-mock 调用)
Query 参数:
| 字段 | 必填 | 默认值 | 说明 |
|---|---|---|---|
| Action | ✅ | — | StartVoiceChat 或 StopVoiceChat |
| Version | ❌ | 配置文件值 | 火山引擎 OpenAPI 版本,如 2024-12-01 |
请求体(JSON):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| SceneID | string | ✅ | 场景 ID(从 getScenes 的 scene.id 获取) |
StartVoiceChat
请求示例:
{
"SceneID": "Custom"
}
内部处理逻辑:
- 从 Session 取回
getScenes时生成的RoomId / UserId / TaskId - 将
room_id附加到 LLM 回调 URL(?room_id=xxx),使/api/chat_callback能关联历史上下文 - 带 SigV4 签名转发到火山引擎
https://rtc.volcengineapi.com
成功响应 200:
{
"ResponseMetadata": {
"RequestId": "2024xxxxxxxxxx",
"Action": "StartVoiceChat",
"Version": "2024-12-01",
"Service": "rtc"
},
"Result": {
"Message": "success"
}
}
StopVoiceChat
请求示例:
{
"SceneID": "Custom"
}
内部处理逻辑:
- 从 Session 取回
RoomId / TaskId - 清除该房间的历史上下文缓存(
room_history) - 带 SigV4 签名转发到火山引擎
成功响应 200:
{
"ResponseMetadata": {
"RequestId": "2024xxxxxxxxxx",
"Action": "StopVoiceChat",
"Version": "2024-12-01",
"Service": "rtc"
},
"Result": {
"Message": "success"
}
}
通用失败响应:
{
"ResponseMetadata": {
"Action": "StartVoiceChat",
"Error": {
"Code": "InvalidParameter",
"Message": "SceneID 不能为空,SceneID 用于指定场景配置"
}
}
}
三、会话历史接口
3.1 写入历史上下文
在
StartVoiceChat之前调用,将历史对话注入该房间的上下文缓存。后续/api/chat_callback会自动将其 prepend 到每次 LLM 请求的 messages 前。
POST /api/session/history
鉴权: 内部签名(java-mock 调用)
请求体(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": "今天出勤率 90%" }
]
}
成功响应 200:
{
"code": 200
}
失败响应 401:
{
"code": 401,
"message": "鉴权失败"
}
四、LLM 回调接口
4.1 自定义 LLM 回调(SSE)
由火山引擎 RTC 平台在用户发言后自动回调。返回 OpenAI 兼容格式的 SSE 流。
POST /api/chat_callback?room_id=<room_id>
鉴权: Authorization: Bearer <CUSTOM_LLM_API_KEY>(Header 或 Query 参数)
Query 参数:
| 字段 | 必填 | 说明 |
|---|---|---|
| room_id | ❌ | 房间 ID。传入时自动从缓存取历史上下文并 prepend 到 messages |
请求体(JSON):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| messages | array | ✅ | 对话消息列表,最后一条必须是 user 角色 |
| temperature | float | ❌ | 采样温度 |
| max_tokens | int | ❌ | 最大生成 token 数 |
| top_p | float | ❌ | Top-P 采样 |
messages 中每条消息:
| 字段 | 类型 | 说明 |
|---|---|---|
| role | string | "user" / "assistant" / "system" |
| content | string | 消息文本 |
请求示例:
{
"messages": [
{ "role": "user", "content": "今天办公室出勤情况咋样" }
],
"temperature": 0.7,
"max_tokens": 1024
}
处理逻辑:
- 验证 API Key
- 过滤掉
content === "欢迎语"的触发词消息(RTC 平台自动发送,非真实用户输入) - 若有
room_id,从缓存取历史并 prepend 到 messages 前 - 调用本地 LLM 服务(工具调用 / RAG 按需触发)
- 以 SSE 流返回结果
成功响应 200(text/event-stream):
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"delta":{"content":"今"},...}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"delta":{"content":"天"},...}]}
data: [DONE]
失败响应(SSE 格式,HTTP 状态码对应):
data: {"error":{"code":"AuthenticationError","message":"API Key 无效"}}
data: [DONE]
| HTTP 状态码 | code | 触发场景 |
|---|---|---|
| 401 | AuthenticationError |
API Key 无效 |
| 400 | BadRequest |
messages 为空 / 最后一条不是 user |
| 500 | InternalError |
LLM 初始化失败 / 请求解析失败 |
五、调试接口
仅供本地开发使用,无鉴权。
5.1 调试聊天
POST /debug/chat
直接发消息给 LLM,响应为纯文本流(非 SSE)。完成后在服务端终端输出可复用的 history JSON 结构。
请求体(JSON):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| history | array | ❌ | 历史消息列表,格式同 messages,默认空 |
| question | string | ✅ | 本次用户提问 |
请求示例:
{
"history": [
{ "role": "assistant", "content": "你好,有什么可以帮你?" }
],
"question": "今天办公室有多少人打卡?"
}
成功响应 200(text/plain 流式):
今天办公室一共九人,目前出勤率为 100%。
5.2 调试 RAG 检索
GET /debug/rag?query=<query>
测试知识库检索,返回检索到的原始上下文内容。
Query 参数:
| 字段 | 必填 | 说明 |
|---|---|---|
| query | ✅ | 检索问题 |
成功响应 200:
{
"query": "今天出勤情况",
"retrieved_context": "#### 今天出勤数据\n办公室共 9 人...",
"length": 128,
"status": "success"
}
无结果时 status 为 "no_results_or_error",retrieved_context 为 null。
内部鉴权协议
/getScenes、/proxy、/api/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 编码的用户显示名 |
X-User-Sex |
性别 |
X-User-Is-Driver |
"true" / "false" |
X-User-Dept-Id |
部门 ID |
X-User-Dept-Name |
URL 编码的部门名称 |
X-User-Role-List |
URL 编码的角色列表 JSON |
签名算法:
message = "java-gateway:{userId}:{毫秒时间戳}"
signature = HMAC-SHA256(INTERNAL_SERVICE_SECRET, message) // hex
Python 接收方验证逻辑(security/internal_auth.py):
INTERNAL_SERVICE_SECRET未配置 → 直接放行(开发环境兼容)- 校验 4 个必要字段是否存在,
X-Internal-Service必须为java-gateway - 时间窗口:
abs(now_ms - timestamp) ≤ 5分钟(防重放) - 重新计算 HMAC,用
hmac.compare_digest常量时间比较(防时序攻击)
通用错误结构
内部接口(getScenes / proxy / session 系列) 返回火山引擎风格:
{
"ResponseMetadata": {
"Action": "xxx",
"Error": {
"Code": "InvalidParameter",
"Message": "SceneID 不能为空"
}
}
}
chat_callback 返回 SSE 格式错误:
data: {"error":{"code":"BadRequest","message":"messages 不能为空"}}
data: [DONE]
环境变量
| 变量名 | 必填 | 说明 |
|---|---|---|
INTERNAL_SERVICE_SECRET |
✅ | 内部服务签名密钥,与 java-mock 侧保持一致 |
CUSTOM_LLM_API_KEY |
✅ | chat_callback 接口的鉴权 Key,配置到火山引擎 RTC 场景中 |
OPENAI_API_KEY |
✅(或同类) | 接入 LLM 所需的 API Key |
OPENAI_BASE_URL |
❌ | 自定义 LLM Base URL(接入本地模型时使用) |
LLM_MODEL |
❌ | 指定模型名称 |
RAG_* |
❌ | 知识库相关配置(详见 utils/env.py) |