diff --git a/chat-openapi.md b/chat-openapi.md new file mode 100644 index 0000000..e03a1a1 --- /dev/null +++ b/chat-openapi.md @@ -0,0 +1,229 @@ +# MIS-Paw 开放 API 使用文档 + +> 面向外部接入系统的开发者。当前提供文件上传和 Agent 对话两个接口。 +> +> API 根地址示例:`https://misagent.lcfuturecenter.com` + +## 1. 快速开始 + +外部系统只需要使用 MIS-Paw 管理页面创建的完整 API Key。API Key 会唯一定位一个 Agent,因此请求中不需要传 `agentId`。 + +对外接口不要求登录态,也不要求 `Authorization`、`Clientid` 或 `Subsystem`。两个接口都必须携带: + +```http +X-Paw-Api-Key: <完整 API Key> +``` + +API Key 必须通过 HTTPS 传输,不要写入日志、前端源码、URL 查询参数或错误信息。管理页面列表中的 Key 可能被掩码显示,调用时请复制完整值。 + +## 2. 接口总览 + +| 方法 | 路径 | 用途 | 请求类型 | 成功响应 | +|---|---|---|---|---| +| `POST` | `/api/files/upload` | 上传 Agent 对话附件 | `multipart/form-data` | JSON | +| `POST` | `/api/shareChat` | 调用 Agent 对话 | `application/json` | SSE | + +网关和服务部署在带有统一前缀的环境时,将前缀拼接到上述路径前。例如实际地址可能是 `/paw/api/shareChat`;请以部署环境提供的 API 根地址为准。 + +## 3. 文件上传:`POST /api/files/upload` + +### 3.1 请求 + +请求头: + +| Header | 必填 | 值 | +|---|---:|---| +| `X-Paw-Api-Key` | 是 | 当前 Agent 的完整 API Key | +| `Content-Type` | 自动 | `multipart/form-data`,由 HTTP 客户端自动生成 boundary | + +表单字段: + +| 字段 | 必填 | 类型 | 说明 | +|---|---:|---|---| +| `file` | 是 | Binary | 要上传的文件 | + +示例: + +```bash +curl --fail-with-body -X POST "https://misagent.lcfuturecenter.com/api/files/upload" \ + -H "X-Paw-Api-Key: <完整 API Key>" \ + -F "file=@./demo.txt" +``` + +不要手动设置 `Content-Type: multipart/form-data`,否则可能缺少 boundary;让 curl、浏览器或 SDK 自动设置。 + +### 3.2 成功响应 + +```http +HTTP/1.1 200 OK +Content-Type: application/json +``` + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "url": "/root/output/paw15004/.qwenpaw/workspaces/9U5Y2t5/media/1b3e01157eb74bb39c0329dc47d6235c_demo.txt", + "fileName": "demo.txt", + "fileSize": 84757 + } +} +``` + +`data.url` 是 QwenPaw 当前 Agent Workspace `media` 目录中的文件引用。它是不透明值,调用方必须完整保存并在对话请求中原样传回,不要拼接、截断、URL 解码后重组或自行构造本地路径。 + +文件上传调用不依赖缓存头完成业务处理;部署环境如配置了响应缓存策略,应将该响应设置为 `Cache-Control: no-store`。 + +上传接口不创建 Session,也不返回 `X-Paw-Session-Id`。文件真正被对话使用后,才会按 QwenPaw 原生机制进入聊天文件记录。 + +## 4. Agent 对话:`POST /api/shareChat` + +### 4.1 请求头 + +| Header | 必填 | 说明 | +|---|---:|---| +| `X-Paw-Api-Key` | 是 | 定位 Agent 并完成 API Key 鉴权 | +| `X-Paw-Session-Id` | 否 | 续聊时传上一次响应中的值;首次请求可省略 | +| `Accept` | 否 | 推荐 `text/event-stream`;缺少时默认为 SSE。当前仅支持流式,不支持 `application/json` | +| `Content-Type` | 是 | `application/json` | + +本接口不要求 `Authorization`、`Clientid`、`Subsystem`。不要把 API Key 或 Session ID 放在 URL 查询参数中。 + +### 4.2 请求体 + +```json +{ + "message": "这个文件内容是什么", + "files": [ + { + "url": "/root/output/paw15004/.qwenpaw/workspaces/9U5Y2t5/media/1b3e01157eb74bb39c0329dc47d6235c_demo.txt", + "fileName": "demo.txt", + "fileSize": 84757 + } + ] +} +``` + +字段说明: + +| 字段 | 必填 | 类型 | 说明 | +|---|---:|---|---| +| `message` | 是 | String | 用户消息;去除首尾空白后不能为空,即使只提问文件也必须填写 | +| `files` | 否 | Array | 文件引用列表;不传等同于空数组 | +| `files[].url` | 是(每个文件) | String | `/api/files/upload` 成功响应中的 `data.url`,必须原样传回 | +| `files[].fileName` | 是(每个文件) | String | 上传响应中的 `data.fileName` | +| `files[].fileSize` | 是(每个文件) | Long | 上传响应中的 `data.fileSize`,单位为字节 | + +对外 DTO 不接收 `agentId`、`userId`、`sessionId`、`channel`、`stream` 或 QwenPaw Runtime 私有字段。 + +## 5. 流式对话(SSE) + +### 5.1 首次请求 + +省略 `X-Paw-Session-Id`,服务端会按 QwenPaw Console 规则生成 Session ID,并在响应头返回: + +```bash +curl -N --fail-with-body -X POST "https://misagent.lcfuturecenter.com/api/shareChat" \ + -H "X-Paw-Api-Key: <完整 API Key>" \ + -H "Accept: text/event-stream" \ + -H "Content-Type: application/json" \ + -d '{"message":"你好","files":[]}' +``` + +成功响应头: + +```http +Content-Type: text/event-stream;charset=UTF-8 +Cache-Control: no-cache, no-transform +X-Paw-Session-Id: 1788156264286 +``` + +响应体是现有 QwenPaw Console Chat 的 SSE 事件流,事件顺序和结束语义保持一致。客户端应按标准 SSE 读取 `data:` 事件,不要假设每一帧都是完整的最终答案。 + +### 5.2 续聊 + +保存首次响应的 `X-Paw-Session-Id`,后续请求用同一个 API Key 和同一个 Session ID: + +```bash +curl -N --fail-with-body -X POST "https://misagent.lcfuturecenter.com/api/shareChat" \ + -H "X-Paw-Api-Key: <完整 API Key>" \ + -H "X-Paw-Session-Id: 1788156264286" \ + -H "Accept: text/event-stream" \ + -H "Content-Type: application/json" \ + -d '{"message":"继续说明","files":[]}' +``` + +Session ID 是会话上下文标识,不是 API Key,也不是登录凭证。接入系统应按自己的用户或业务会话保存它;不同 API Key 不要主动共享同一个 Session ID。同一个 Session 同时只能有一个进行中的对话请求,否则可能返回 `409 SESSION_BUSY`。 + +## 6. 错误处理 + +建连前的错误通常返回 MIS 统一 JSON 错误结构: + +```json +{ + "code": 401, + "msg": "API Key 无效或已过期", + "data": null, + "errorCode": "API_KEY_INVALID" +} +``` + +常见状态码: + +| HTTP | 场景 | +|---:|---| +| `400` | `message` 为空、文件元数据缺失或 Session 格式不合法 | +| `401` | 缺少、无效或已过期的 `X-Paw-Api-Key` | +| `403` | API Key 已停用,或文件不属于该 Key 定位的 Agent Workspace | +| `406` | `Accept` 不支持 | +| `409` | 同一个 Agent/Session 已有进行中的 Chat | +| `413` | 文件超过配置的大小限制 | +| `422` | Agent 创建人的模型 Key 不可用 | +| `503` | Agent 或 QwenPaw 实例不可用 | + +如果 SSE 已经开始,之后发生的 Agent 错误仍以 SSE 事件返回,不会中途切换成 JSON。客户端需要同时处理 HTTP 建连错误和 SSE 错误事件。 + +## 7. 文件+对话完整流程 + +1. 使用 `X-Paw-Api-Key` 调用 `/api/files/upload`。 +2. 保存响应中的 `data.url`、`data.fileName`、`data.fileSize`。 +3. 调用 `/api/shareChat`,将这三个值放入 `files`,并填写 `message`。 +4. 保存响应头 `X-Paw-Session-Id`。 +5. 后续续聊时使用同一个 API Key,并回传保存的 Session ID。 + +```bash +# 1. 上传文件 +curl -sS -X POST "https://misagent.lcfuturecenter.com/api/files/upload" \ + -H "X-Paw-Api-Key: <完整 API Key>" \ + -F "file=@./demo.txt" + +# 2. 使用上传返回的 url 对话 +curl -N -X POST "https://misagent.lcfuturecenter.com/api/shareChat" \ + -H "X-Paw-Api-Key: <完整 API Key>" \ + -H "Accept: text/event-stream" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "这个文件内容是什么", + "files": [{ + "url": "<上一步 data.url>", + "fileName": "demo.txt", + "fileSize": 84757 + }] + }' +``` + +## 8. 浏览器跨域调用 + +如果由浏览器直接调用,预检请求不需要 API Key,但实际 `POST` 必须携带。前端需要能够读取 `X-Paw-Session-Id`,服务端跨域配置应允许以下请求头并暴露 Session 响应头: + +```text +Allowed-Headers: Content-Type, Accept, X-Paw-Api-Key, X-Paw-Session-Id +Exposed-Headers: X-Paw-Session-Id, Content-Type, Cache-Control +``` + +不要在浏览器端把完整 API Key 固化到公开前端代码中;更适合由受控的后端接入系统代理调用。 + +## 9. 重试与费用提示 + +一期没有 HTTP 请求级幂等键。客户端在未收到完整响应时重试,可能重新启动一次 Agent 对话并产生新的模型费用;只有同一 Session 尚未结束时,才可能收到 `409 SESSION_BUSY`。请由调用方控制超时、重试次数和同一 Session 的并发请求。