docs: 更新 Agent 协议文档与部署配置
- 更新 Agent API 端点文档 - 更新 SSE 事件与输入输出文档 - 新增 deploy/.env.prod.example 配置模板
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Agent API Endpoints
|
||||
|
||||
本文档列出所有 Agent 相关的 API 端点。
|
||||
本文档以当前后端实现为准,描述 `/api/v1/agent` 的 HTTP 接口契约。
|
||||
|
||||
Base URL: `/api/v1/agent`
|
||||
|
||||
@@ -8,353 +8,220 @@ Base URL: `/api/v1/agent`
|
||||
|
||||
## 端点清单
|
||||
|
||||
| 方法 | 路径 | 描述 |
|
||||
|------|------|------|
|
||||
| POST | `/runs` | 发起 Agent 运行 |
|
||||
| GET | `/runs/{thread_id}/events` | SSE 事件流 |
|
||||
| GET | `/history` | 获取对话历史快照 |
|
||||
| POST | `/attachments` | 上传附件 |
|
||||
| GET | `/attachments/signed-url` | 生成附件签名 URL |
|
||||
| POST | `/transcribe` | 语音转文字 (ASR) |
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| POST | `/runs` | 创建一次 agent run(异步入队) |
|
||||
| GET | `/runs/{thread_id}/events` | 订阅 SSE 事件流 |
|
||||
| GET | `/history` | 获取历史快照(按天分页) |
|
||||
| POST | `/attachments` | 上传用户图片附件 |
|
||||
| GET | `/attachments/signed-url` | 获取附件临时签名链接 |
|
||||
| POST | `/transcribe` | WAV 音频转写 |
|
||||
|
||||
---
|
||||
|
||||
## 1. POST /runs
|
||||
## 1) POST `/runs`
|
||||
|
||||
发起一个 Agent 运行任务。
|
||||
发起一次运行请求,后端会先持久化用户消息,再将命令放入异步队列。
|
||||
|
||||
### Request
|
||||
|
||||
Request Body: `RunAgentInput`
|
||||
|
||||
详细数据结构见 [run-agent-input.md](./run-agent-input.md)
|
||||
- Body: `RunAgentInput`
|
||||
- 详细结构见 `docs/protocols/agent/run-agent-input.md`
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
`202 Accepted`
|
||||
|
||||
```ts
|
||||
{
|
||||
taskId: string, // 任务 ID
|
||||
threadId: string, // 会话 ID
|
||||
runId: string, // 运行 ID
|
||||
created: string // ISO-8601 时间戳
|
||||
taskId: string;
|
||||
threadId: string;
|
||||
runId: string;
|
||||
created: boolean; // 是否新建了会话
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
### 错误码
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.example.com/api/v1/agent/runs \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"runId": "run-001",
|
||||
"state": {},
|
||||
"messages": [
|
||||
{
|
||||
"id": "msg-001",
|
||||
"role": "user",
|
||||
"content": "帮我查一下北京今天的天气"
|
||||
}
|
||||
],
|
||||
"tools": [],
|
||||
"context": [],
|
||||
"forwardedProps": {}
|
||||
}'
|
||||
```
|
||||
|
||||
### Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"taskId": "task-abc123",
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"runId": "run-001",
|
||||
"created": "2026-03-16T10:00:00Z"
|
||||
}
|
||||
```
|
||||
- `401` 未认证
|
||||
- `422` 请求结构校验失败
|
||||
- `429` 超过 run 请求速率限制
|
||||
|
||||
---
|
||||
|
||||
## 2. GET /runs/{thread_id}/events
|
||||
## 2) GET `/runs/{thread_id}/events`
|
||||
|
||||
获取 SSE 事件流,用于实时接收 Agent 运行过程中的事件。
|
||||
订阅指定 thread 的实时事件流。
|
||||
|
||||
### Path Parameters
|
||||
### Path
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|------|------|------|
|
||||
| thread_id | string | 会话 ID |
|
||||
| 参数 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `thread_id` | string | 会话 ID |
|
||||
|
||||
### Query Parameters
|
||||
### Query
|
||||
|
||||
| 参数 | 类型 | 默认值 | 描述 |
|
||||
|------|------|--------|------|
|
||||
| Last-Event-ID | string | - | 可选,用于断点续传的事件 ID |
|
||||
| idle_limit | integer | 300 | 最大空闲轮询次数 (1-3600) |
|
||||
| 参数 | 类型 | 默认 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `idle_limit` | integer | `300` | 最大空闲轮询次数(1-3600) |
|
||||
|
||||
### Headers
|
||||
|
||||
| 参数 | 描述 |
|
||||
|------|------|
|
||||
| Last-Event-ID | 可选的事件 ID,用于从指定位置恢复 |
|
||||
| Header | 必填 | 说明 |
|
||||
|---|---|---|
|
||||
| `Accept: text/event-stream` | 否 | 建议显式设置 |
|
||||
| `Last-Event-ID` | 否 | 从指定游标断点续流 |
|
||||
|
||||
### Response
|
||||
|
||||
SSE (Server-Sent Events) 流,Content-Type: `text/event-stream`
|
||||
- `200 OK`
|
||||
- `Content-Type: text/event-stream`
|
||||
- 事件类型与字段见 `docs/protocols/agent/sse-events.md`
|
||||
- 空闲时会发送 keep-alive 注释行 `: keep-alive`
|
||||
|
||||
事件类型详情见 [sse-events.md](./sse-events.md)
|
||||
### 错误码
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const eventSource = new EventSource(
|
||||
'https://api.example.com/api/v1/agent/runs/550e8400-e29b-41d4-a716-446655440000/events'
|
||||
);
|
||||
|
||||
eventSource.addEventListener('run.started', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
console.log('Started:', data);
|
||||
});
|
||||
|
||||
eventSource.addEventListener('text.delta', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
console.log('Delta:', data.data.delta);
|
||||
});
|
||||
|
||||
eventSource.addEventListener('run.finished', (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
console.log('Finished:', data);
|
||||
});
|
||||
```
|
||||
- `401` 未认证
|
||||
- `403` 非会话所有者
|
||||
- `422` `Last-Event-ID` 非法
|
||||
- `429` 超过 SSE 连接数限制
|
||||
|
||||
---
|
||||
|
||||
## 3. GET /history
|
||||
## 3) GET `/history`
|
||||
|
||||
获取对话历史快照。
|
||||
返回历史快照(`HistorySnapshotResponse`),不是 SSE 包装事件。
|
||||
|
||||
### Query Parameters
|
||||
### Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 描述 |
|
||||
|------|------|------|------|
|
||||
| threadId | string | 否 | 会话 ID,不指定则返回最新会话 |
|
||||
| before | date | 否 | 日期格式 `YYYY-MM-DD`,返回该日期之前的快照 |
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `threadId` | string | 否 | 指定会话,不传则取当前用户最近会话 |
|
||||
| `before` | `YYYY-MM-DD` | 否 | 返回该日期之前最近一天的快照 |
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
{
|
||||
scope: "history_day",
|
||||
threadId: string | null,
|
||||
day: string | null, // ISO date format "YYYY-MM-DD"
|
||||
hasMore: boolean,
|
||||
messages: HistoryMessage[]
|
||||
scope: "history_day";
|
||||
threadId: string | null;
|
||||
day: string | null; // YYYY-MM-DD
|
||||
hasMore: boolean;
|
||||
messages: Array<{
|
||||
id: string;
|
||||
seq: number;
|
||||
role: "user" | "assistant" | "tool";
|
||||
content: string;
|
||||
url?: string | null; // user 附件签名链接
|
||||
ui_schema?: object | null; // assistant/tool 的编译后 UI
|
||||
timestamp: string; // ISO-8601
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
详细数据结构见 [run-agent-input.md](./run-agent-input.md)
|
||||
### 说明
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl "https://api.example.com/api/v1/agent/history?threadId=550e8400-e29b-41d4-a716-446655440000&before=2026-03-15"
|
||||
```
|
||||
|
||||
### Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"scope": "history_day",
|
||||
"threadId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"day": "2026-03-15",
|
||||
"hasMore": false,
|
||||
"messages": [
|
||||
{
|
||||
"id": "msg-001",
|
||||
"seq": 1,
|
||||
"role": "user",
|
||||
"content": "帮我创建一个日程",
|
||||
"url": null,
|
||||
"timestamp": "2026-03-15T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "msg-002",
|
||||
"seq": 2,
|
||||
"role": "assistant",
|
||||
"content": "好的,我来帮您创建日程。",
|
||||
"uiSchema": {
|
||||
"version": "2.0",
|
||||
"locale": "zh-CN",
|
||||
"status": "success",
|
||||
"theme": "default",
|
||||
"root": {
|
||||
"type": "stack",
|
||||
"appearance": "card",
|
||||
"children": [
|
||||
{"type": "text", "content": "日程已创建", "role": "title"},
|
||||
{"type": "badge", "label": "SUCCESS", "status": "success"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"timestamp": "2026-03-15T10:00:05Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
- 若用户没有任何会话:返回
|
||||
- `threadId = null`
|
||||
- `day = null`
|
||||
- `hasMore = false`
|
||||
- `messages = []`
|
||||
|
||||
---
|
||||
|
||||
## 4. POST /attachments
|
||||
## 4) POST `/attachments`
|
||||
|
||||
上传附件到存储。
|
||||
上传图片附件,返回可直接用于 `RunAgentInput.messages[].content[].url` 的签名链接。
|
||||
|
||||
### Form Data
|
||||
### Request
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|------|------|------|
|
||||
| threadId | string | 会话 ID |
|
||||
| file | file | 要上传的文件 |
|
||||
- `multipart/form-data`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `threadId` | string | 会话 ID |
|
||||
| `file` | file | 附件文件 |
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
{
|
||||
attachment: {
|
||||
bucket: string,
|
||||
path: string,
|
||||
mimeType: string,
|
||||
size: number,
|
||||
url: string // 临时访问 URL
|
||||
}
|
||||
bucket: string;
|
||||
path: string;
|
||||
mimeType: string;
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
### 错误码
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.example.com/api/v1/agent/attachments \
|
||||
-F "threadId=550e8400-e29b-41d4-a716-446655440000" \
|
||||
-F "file=@/path/to/image.png"
|
||||
```
|
||||
|
||||
### Limits
|
||||
|
||||
- 最大文件大小: 5MB
|
||||
- 支持的文件类型: 见后端配置
|
||||
- `401` 未认证
|
||||
- `403` 非会话所有者
|
||||
- `413` 附件超过大小限制
|
||||
- `422` 文件类型不支持/空文件等
|
||||
- `503` 存储服务不可用
|
||||
|
||||
---
|
||||
|
||||
## 5. GET /attachments/signed-url
|
||||
## 5) GET `/attachments/signed-url`
|
||||
|
||||
生成附件的签名 URL,用于直接访问存储中的文件。
|
||||
对已有存储对象重新签名。
|
||||
|
||||
### Query Parameters
|
||||
### Query
|
||||
|
||||
| 参数 | 类型 | 必填 | 描述 |
|
||||
|------|------|------|------|
|
||||
| bucket | string | 是 | 存储桶名称 |
|
||||
| path | string | 是 | 文件路径 |
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `bucket` | string | 是 | 存储桶 |
|
||||
| `path` | string | 是 | 对象路径 |
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
{
|
||||
bucket: string,
|
||||
path: string,
|
||||
url: string // 签名 URL
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl "https://api.example.com/api/v1/agent/attachments/signed-url?bucket=agent-inputs&path=user-123/image.png"
|
||||
```
|
||||
|
||||
### Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"bucket": "agent-inputs",
|
||||
"path": "user-123/image.png",
|
||||
"url": "https://storage.example.com/agent-inputs/user-123/image.png?signature=abc123..."
|
||||
bucket: string;
|
||||
path: string;
|
||||
url: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. POST /transcribe
|
||||
## 6) POST `/transcribe`
|
||||
|
||||
语音转文字 (ASR)。
|
||||
WAV 音频转写。
|
||||
|
||||
### Request
|
||||
|
||||
Form Data:
|
||||
- `multipart/form-data`
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|------|------|------|
|
||||
| audio | file | 音频文件 (WAV 格式) |
|
||||
|
||||
### Headers
|
||||
|
||||
| 参数 | 描述 |
|
||||
|------|------|
|
||||
| content-length | 文件大小 |
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `audio` | file | WAV 文件 |
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
{
|
||||
transcript: string, // 转录文本
|
||||
language: string, // 检测到的语言
|
||||
duration: number // 音频时长 (秒)
|
||||
transcript: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
### 限制
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.example.com/api/v1/agent/transcribe \
|
||||
-F "audio=@/path/to/audio.wav"
|
||||
```
|
||||
|
||||
### Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"transcript": "今天天气真不错",
|
||||
"language": "zh-CN",
|
||||
"duration": 3.5
|
||||
}
|
||||
```
|
||||
|
||||
### Limits
|
||||
|
||||
- 支持格式: `audio/wav`, `audio/x-wav`, `audio/wave`
|
||||
- 最大文件大小: 10MB
|
||||
- 速率限制: 20 次/分钟/用户
|
||||
- 内容类型:`audio/wav` / `audio/x-wav` / `audio/wave`
|
||||
- 文件大小:最大 10MB
|
||||
- 速率限制:20 次/分钟/用户
|
||||
|
||||
---
|
||||
|
||||
## 错误响应
|
||||
## 通用错误
|
||||
|
||||
所有端点可能返回以下错误:
|
||||
|
||||
| 状态码 | 描述 |
|
||||
|--------|------|
|
||||
| 400 | 请求参数错误 |
|
||||
| 401 | 未认证 |
|
||||
| 403 | 无权限 |
|
||||
| 404 | 资源不存在 |
|
||||
| 413 | 请求体过大 |
|
||||
| 422 | 数据验证失败 |
|
||||
| 429 | 速率限制 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
### Error Response Format
|
||||
当前实现的错误主体为 FastAPI `detail` 字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "错误详情信息"
|
||||
"detail": "..."
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user