Files
fire-safety-ymd/docs/specs/fire-safety-ymd-dashscope-compatible-chat-v1.md
T
2026-09-05 15:46:37 +08:00

144 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DashScope 风格兼容对话 API v1 Spec
| 项 | 内容 |
| --- | --- |
| 状态 | Implemented |
| 日期 | 2026-09-05 |
| 负责人 | fire-safety-ymd 后端 |
| 需求来源 | 复用既有客户端的 `/api/v1/apps/{app_id}/completion`、`xtoken` 与 `event: result` 契约 |
## 1. 背景
既有用户端按照 DashScope Application HTTP 形式调用固定应用路径,并以 SSE `result` 事件读取 `output.session_id`、`finish_reason` 和 `text`。本项目原生 `/api/chat` 的请求体与事件名称不同。为避免客户端一次性重写,本 checkpoint 在同一 Chat Service 之上增加一个受限兼容适配层,并保留原生接口。
本契约参考阿里云官方 Application API 的路径、`input.prompt`、`input.session_id` 和 SSE 结果外形,但不是 DashScope 全量代理或完整复刻。
## 2. 目标
- 新增可选的 `POST /api/v1/apps/{app_id}/completion`。
- 接收既有客户端的 `xtoken`、`input.prompt`、可选 `input.session_id` 和 `parameters` 空对象。
- 返回 `event: result` SSE;首个事件提供会话 ID,严格成功事件以 `finish_reason: "stop"` 终止。
- 复用 `/api/chat` 的会话容量、TTL、同会话并发排斥、SuperAgent 严格完成判定和错误分类。
- Nginx 只终止 TLS、限制路径、限流并反代本 Go 服务,不保存或注入任何应用 Secret。
## 3. 非目标与兼容边界
- 不移除或改变原生 `POST /api/chat`。
- 不实现 DashScope 的 `messages`、`biz_params`、文件、图像、知识库、思考过程或任意 `parameters`。
- 不代理到 DashScope,也不把兼容 `app_id` 当成真正的 SuperAgent Profile ID。
- 不向客户端暴露 Provider Session、Run、Trace、工具参数/结果或半截回答。
- 不提供非流式 JSON 模式;即使请求未带 `X-DashScope-SSE: enable`,本兼容路径也始终返回 SSE,以匹配现有客户端。
- `parameters.incremental_output` 仅为输入兼容而接受。v1 只有严格完成后的一个正文结果,因此 `true` 与 `false` 不改变正文分片方式。
- 静态 `xtoken` 只用于受控联调,不是最终用户身份或动态授权。
## 4. 配置与路由
| 环境变量 | 默认值 | 说明 |
| --- | --- | --- |
| `FIRE_SAFETY_CHAT_COMPAT_APP_ID` | 空 | 非空时注册兼容路径;1 至 128 个 ASCII 字母、数字、下划线或连字符 |
| `FIRE_SAFETY_CHAT_AUTH_TOKEN` | 空 | 兼容路径期望的 `xtoken`,仍必须与 SuperAgent Key、MCP Token 不同 |
兼容路径只有在 `FIRE_SAFETY_CHAT_ENABLED=true` 且 App ID 非空时注册。App ID 是用于路径匹配的公开标识,不是 Secret;不匹配的路径返回 404。
## 5. 请求契约
```http
POST /api/v1/apps/fire-safety-public-app/completion
xtoken: <FIRE_SAFETY_CHAT_AUTH_TOKEN>
Content-Type: application/json
Accept: text/event-stream
{
"input": {
"prompt": "杨家盘瞭望哨 3 公里内的水源?"
},
"parameters": {}
}
```
后续轮次把前一轮成功响应的 `output.session_id` 放回 `input`:
```json
{
"input": {
"prompt": "再说明这些候选的限制",
"session_id": "conv_..."
},
"parameters": {
"incremental_output": true
},
"debug": {}
}
```
约束:
- `input.prompt` 必填,非空,并服从现有消息大小上限。
- `input.session_id` 只能是本服务此前返回的本地会话 ID;服务端仍负责映射 Provider Session。
- `parameters` 可省略、为空对象,或只包含布尔型 `incremental_output`。
- `debug` 可省略或只能是空对象。
- 未知字段、`null`、错误类型、尾随 JSON 和超大请求体均拒绝。
- 兼容 DTO 不接收用户身份、角色、区域、租户、Provider Session 或 metadata。
## 6. 成功 SSE
Prepare 成功后先发送会话事件。`finish_reason` 的初始值按官方示例使用字符串 `"null"`,不是 JSON `null`:
```text
id: 1
event: result
:HTTP_STATUS/200
data: {"output":{"session_id":"conv_...","finish_reason":"null"},"usage":{},"request_id":"..."}
```
只有 SuperAgent Adapter 同时验证最终内容、成功 `run.completed` 和顶层 `end` 后,才发送终止事件:
```text
id: 2
event: result
:HTTP_STATUS/200
data: {"output":{"session_id":"conv_...","finish_reason":"stop","text":"..."},"usage":{"models":[{"input_tokens":12,"output_tokens":34,"model_id":"qwen-plus-latest"}]},"request_id":"..."}
```
- 两个事件的 `session_id` 和 `request_id` 必须相同。
- `session_id` 是本地随机会话 ID,不是 Provider Session。
- `model_id` 在上游未提供有效模型名时省略;token 数量是当前 Provider 返回的单轮聚合值。
- 等待期间每 15 秒可发送不含业务数据的 SSE comment heartbeat。
- 客户端只有看到 `event: result` 且 `output.finish_reason == "stop"` 才能把本轮视为成功。
## 7. 错误
SSE 开始前使用 HTTP 状态和 DashScope 风格安全 JSON:
```json
{"code":"CHAT_AUTH_INVALID","message":"Chat authentication failed.","request_id":"..."}
```
SSE 开始后的失败发送 `event: error`,只包含稳定 code、通用 message、request ID 和本地 session ID;不发送 `finish_reason: "stop"`,也不返回任何已接收的部分回答。
沿用原生 Chat 的主要状态:400 输入错误、401 token 错误、403 Origin 错误、404 App/会话不存在、409 会话忙、503 容量不足,以及 502/504 上游失败或超时。
## 8. CORS、Nginx 与 Secret
- 浏览器 Origin 必须精确出现在 `FIRE_SAFETY_CHAT_ALLOWED_ORIGINS`;不允许 `*` 或 credentials。
- 预检只允许 `POST` 以及 `Content-Type`、`xtoken`、`X-DashScope-SSE`、`X-Request-ID`。
- Nginx 示例只公开精确兼容路径、`/mcp` 和可选 `/health`,其余路径返回 404。
- Nginx 不比较或注入 `xtoken`、SuperAgent Open API Key、MCP Bearer 或数据库凭证;Header 原样交给 Go 验证。
- 对话 SSE 必须关闭代理缓冲、缓存、gzip 和上游自动重试,并让代理超时覆盖 Chat 总运行时限。
## 9. 验收标准
- Given App ID 未配置,When 请求兼容路径,Then 路由返回 404,原生 `/api/chat` 行为不变。
- Given App ID 或 `xtoken` 错误,When 请求,Then 在读取问题和调用 SuperAgent 前拒绝。
- Given 首轮请求成功,When 读取 SSE,Then 先收到字符串 `"null"` 会话事件,再收到同会话 `"stop"` 最终正文。
- Given 后续请求携带成功返回的 `session_id`,When 调用,Then 复用同一服务端会话映射。
- Given Provider 流失败,When SSE 已开始,Then 收到安全 `error`,不收到部分正文或 `stop`。
- Given Nginx 配置生效,When 请求未列出的路径,Then 不会转发到 Go 或外部 DashScope。
## 10. 协议来源
- [Alibaba Cloud Model Studio Application API reference](https://www.alibabacloud.com/help/en/model-studio/application-api-reference)
- [Call a Model Studio application by using an API](https://www.alibabacloud.com/help/en/model-studio/application-calling-guide)
外部文档会演进;本项目以本 Spec 和自动化测试定义的受限兼容子集为准。