rtc-voice-chat/backend/API.md
2026-04-02 20:15:15 +08:00

12 KiB
Raw Blame History

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 本次会话分配的房间 IDUUID
UserId string 用户在 RTC 房间中的 UserId
Token string RTC 入房 Token
TaskId string 语音任务 IDStopVoiceChat 时需要

副作用: 该接口会将 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 StartVoiceChatStopVoiceChat
Version 配置文件值 火山引擎 OpenAPI 版本,如 2024-12-01

请求体JSON

字段 类型 必填 说明
SceneID string 场景 IDgetScenesscene.id 获取)

StartVoiceChat

请求示例:

{
  "SceneID": "Custom"
}

内部处理逻辑:

  1. 从 Session 取回 getScenes 时生成的 RoomId / UserId / TaskId
  2. room_id 附加到 LLM 回调 URL?room_id=xxx),使 /api/chat_callback 能关联历史上下文
  3. 带 SigV4 签名转发到火山引擎 https://rtc.volcengineapi.com

成功响应 200

{
  "ResponseMetadata": {
    "RequestId": "2024xxxxxxxxxx",
    "Action": "StartVoiceChat",
    "Version": "2024-12-01",
    "Service": "rtc"
  },
  "Result": {
    "Message": "success"
  }
}

StopVoiceChat

请求示例:

{
  "SceneID": "Custom"
}

内部处理逻辑:

  1. 从 Session 取回 RoomId / TaskId
  2. 清除该房间的历史上下文缓存(room_history
  3. 带 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 房间 IDgetScenes 返回的 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
}

处理逻辑:

  1. 验证 API Key
  2. 过滤掉 content === "欢迎语" 的触发词消息RTC 平台自动发送,非真实用户输入)
  3. 若有 room_id,从缓存取历史并 prepend 到 messages 前
  4. 调用本地 LLM 服务(工具调用 / RAG 按需触发)
  5. 以 SSE 流返回结果

成功响应 200text/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": "今天办公室有多少人打卡?"
}

成功响应 200text/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_contextnull


内部鉴权协议

/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

  1. INTERNAL_SERVICE_SECRET 未配置 → 直接放行(开发环境兼容)
  2. 校验 4 个必要字段是否存在,X-Internal-Service 必须为 java-gateway
  3. 时间窗口:abs(now_ms - timestamp) ≤ 5分钟(防重放)
  4. 重新计算 HMAChmac.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