Files
synapse/docs/v0/04-caller-protocol.md
2026-06-27 22:17:15 +08:00

504 lines
12 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.

# P2A 协议(Person/Program-to-Agent Protocol)
> 版本:1.0.0
> 状态:草案
> 类型:实现规范
> 基于:[灵隙原始协议(Synapse Raw Protocol) v1.0.0](./01-a2a-raw-protocol.md)
---
## 1. 概述
P2A(Person/Program-to-Agent)调用协议定义了**非 Agent 调用方**(如普通后端服务、前端应用、第三方系统、人类用户)如何调用 Agent 能力的规范。
本协议将 A2A 协议的复杂性封装起来,提供简洁的 RESTful API,使调用方无需了解 A2A 协议细节即可使用 Agent 能力。
### 1.1 适用场景
- 前端应用直接调用 Agent 能力
- 后端业务系统集成 Agent 服务
- 第三方开发者通过 API 接入
- 无需实现完整 A2A 协议的调用方
### 1.2 设计原则
- **简单易用**:标准 RESTful API,JSON 格式
- **两种模式**:回调模式 + 轮询模式,调用方按需选择
- **认证简单**:API Key 认证,无需 HMAC 签名
- **文件支持**:支持 multipart/form-data 上传文件
- **错误友好**:清晰的错误码和错误信息
### 1.3 与 A2A 协议的关系
```
外部调用方 ──P2A 协议──▶ External API Layer ──A2A 协议──▶ Agent
```
P2A 协议是 A2A 协议的"简化入口",所有请求最终会转换为 灵隙消息发送给 Agent。
---
## 2. 认证方式
### 2.1 API Key 认证
- 在 HTTP Header 中传递:`X-API-Key: {api_key}`
- 或在 URL Query 中传递:`?api_key={api_key}`
- 如果服务端未配置 API Key,则跳过认证
### 2.2 回调验证(可选)
如果调用方提供了 `callback_token`,则服务端在回调时会在 Header 中带上 `X-Callback-Token`,用于调用方验证回调来源。
---
## 3. API 端点
所有端点默认前缀:`/api/v1/synapse`
### 3.1 端点清单
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/task` | 提交任务(JSON) |
| POST | `/task/multipart` | 提交任务(带文件上传) |
| GET | `/task/{task_id}` | 获取任务详情 |
| GET | `/task/{task_id}/status` | 获取任务状态(简化版) |
| GET | `/tasks` | 获取任务列表 |
| POST | `/task/{task_id}/cancel` | 取消任务 |
| GET | `/capabilities` | 获取能力清单 |
| POST | `/callback` | 接收回调(调用方实现) |
---
## 4. 任务提交
### 4.1 提交任务(JSON)
**请求:**
```http
POST /api/v1/synapse/task
Content-Type: application/json
X-API-Key: your-api-key
{
"task_type": "text_generation",
"payload": {
"prompt": "写一首诗",
"style": "古典"
},
"external_task_id": "my-task-001",
"priority": "normal",
"callback_url": "https://your-domain.com/callback",
"callback_token": "your-callback-token"
}
```
**请求字段说明:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `task_type` | string | 是 | 任务类型,如 `video_generation`, `image_generation` |
| `payload` | object | 是 | 任务参数,具体结构取决于 task_type |
| `external_task_id` | string | 否 | 调用方的任务 ID,用于关联 |
| `priority` | string | 否 | 优先级:`low`, `normal`, `high`, `urgent`,默认 `normal` |
| `callback_url` | string | 否 | 回调 URL,不提供则需轮询 |
| `callback_token` | string | 否 | 回调验证 token |
**响应:**
```json
{
"success": true,
"task_id": "task-abc123",
"status": "received",
"message": "任务已接收"
}
```
**响应字段说明:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 是否成功 |
| `task_id` | string | 服务端生成的任务 ID |
| `status` | string | 初始状态,通常为 `received` |
| `message` | string | 提示信息 |
| `error` | string | 错误信息(失败时) |
### 4.2 提交任务(Multipart 带文件)
**请求:**
```http
POST /api/v1/synapse/task/multipart
Content-Type: multipart/form-data
X-API-Key: your-api-key
------WebKitFormBoundary
Content-Disposition: form-data; name="task_type"
image_generation
------WebKitFormBoundary
Content-Disposition: form-data; name="payload"
{"prompt":"一只猫","style":"写实"}
------WebKitFormBoundary
Content-Disposition: form-data; name="priority"
normal
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="reference.jpg"
Content-Type: image/jpeg
[二进制数据]
------WebKitFormBoundary--
```
**表单字段:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `task_type` | string | 是 | 任务类型 |
| `payload` | string(JSON) | 是 | 任务参数(JSON 字符串) |
| `external_task_id` | string | 否 | 外部任务 ID |
| `priority` | string | 否 | 优先级 |
| `callback_url` | string | 否 | 回调 URL |
| `callback_token` | string | 否 | 回调 token |
| `file` | file | 否 | 上传的文件(可多个) |
**响应:** 同 JSON 提交方式
---
## 5. 任务查询
### 5.1 获取任务详情
**请求:**
```http
GET /api/v1/synapse/task/{task_id}
X-API-Key: your-api-key
```
**响应:**
```json
{
"success": true,
"task": {
"id": "task-abc123",
"type": "text_generation",
"status": "completed",
"progress": 100,
"message": "任务已完成",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:01:00Z",
"completed_at": "2026-01-01T00:01:00Z",
"eta": "2026-01-01T00:01:00Z",
"result": {
"text": "生成的文本...",
"metadata": { "tokens": 1024 }
},
"error": null,
"external_task_id": "my-task-001"
}
}
```
**任务状态:**
| 状态 | 说明 |
|------|------|
| `received` | 已接收 |
| `processing` | 处理中 |
| `completed` | 已完成 |
| `failed` | 已失败 |
| `cancelled` | 已取消 |
### 5.2 获取任务状态(简化版)
**请求:**
```http
GET /api/v1/synapse/task/{task_id}/status
X-API-Key: your-api-key
```
**响应:**
```json
{
"success": true,
"task_id": "task-abc123",
"status": "processing",
"progress": 50
}
```
### 5.3 获取任务列表
**请求:**
```http
GET /api/v1/synapse/tasks?status=processing&limit=20&offset=0
X-API-Key: your-api-key
```
**查询参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `status` | string | 否 | 按状态过滤 |
| `limit` | int | 否 | 每页数量,默认 20 |
| `offset` | int | 否 | 偏移量,默认 0 |
**响应:**
```json
{
"success": true,
"tasks": [
{
"id": "task-abc123",
"type": "text_generation",
"status": "completed",
"progress": 100,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:01:00Z"
}
],
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
```
---
## 6. 任务取消
**请求:**
```http
POST /api/v1/synapse/task/{task_id}/cancel
X-API-Key: your-api-key
```
**响应:**
```json
{
"success": true,
"task_id": "task-abc123",
"status": "cancelled",
"message": "任务已取消"
}
```
---
## 7. 能力查询
**请求:**
```http
GET /api/v1/synapse/capabilities
X-API-Key: your-api-key
```
**响应:**
```json
{
"success": true,
"capabilities": {
"agent_id": "my-agent",
"agent_name": "我的Agent",
"system_id": "my-system",
"protocol_version": "1.0.0",
"supported_task_types": [
{
"type": "text_generation",
"name": "文本生成",
"description": "生成各种类型的文本内容",
"estimated_time": "30s",
"input_schema": "...",
"output_schema": "..."
}
],
"supported_transport_modes": ["callback", "polling"],
"max_file_size": 104857600,
"max_concurrent_tasks": 10,
"support_progress_updates": true,
"support_streaming": false,
"support_hil": true,
"support_groups": true
}
}
```
---
## 8. 回调机制
如果调用方提供了 `callback_url`,服务端会在任务状态变化时主动回调。
### 8.1 回调请求
```http
POST {callback_url}
Content-Type: application/json
X-Callback-Token: {callback_token}
{
"task_id": "task-abc123",
"status": "completed",
"progress": 100,
"message": "任务已完成",
"result": {
"text": "生成的文本..."
},
"error": null,
"timestamp": "2026-01-01T00:01:00Z"
}
```
### 8.2 回调类型
| 触发时机 | 说明 |
|---------|------|
| 任务开始处理 | `status=processing`, `progress=0` |
| 进度更新 | `status=processing`, `progress=N` |
| 任务完成 | `status=completed`, `progress=100`, 包含 result |
| 任务失败 | `status=failed`, 包含 error |
| 任务取消 | `status=cancelled` |
### 8.3 回调响应
调用方应返回 2xx 状态码表示成功接收。如果返回非 2xx,服务端会重试(指数退避,最多 5 次)。
---
## 9. 错误处理
### 9.1 错误响应格式
```json
{
"success": false,
"error": "invalid_task_type",
"message": "不支持的任务类型"
}
```
### 9.2 错误码列表
| 错误码 | HTTP 状态码 | 说明 |
|--------|------------|------|
| `unauthorized` | 401 | API Key 无效或缺失 |
| `invalid_request` | 400 | 请求格式无效 |
| `invalid_task_type` | 400 | 任务类型不支持 |
| `invalid_params` | 400 | 参数无效 |
| `task_not_found` | 404 | 任务不存在 |
| `task_already_completed` | 409 | 任务已完成,无法取消 |
| `file_too_large` | 413 | 文件过大 |
| `rate_limited` | 429 | 请求过于频繁 |
| `internal_error` | 500 | 服务内部错误 |
| `service_unavailable` | 503 | 服务不可用 |
---
## 10. SDK 客户端接口
为方便调用方集成,提供 SDK 客户端。
### 10.1 SDK 初始化
```go
client := sdk.NewClient(sdk.ClientConfig{
BaseURL: "https://agent-api.example.com",
APIKey: "your-api-key",
Timeout: 30 * time.Second,
})
```
### 10.2 SDK 方法清单
| 方法 | 说明 |
|------|------|
| `SubmitTask(ctx, req)` | 提交任务(JSON) |
| `SubmitTaskWithFiles(ctx, req, files)` | 提交任务(带文件) |
| `GetTask(ctx, taskID)` | 获取任务详情 |
| `GetTaskStatus(ctx, taskID)` | 获取任务状态 |
| `ListTasks(ctx, status, limit, offset)` | 获取任务列表 |
| `CancelTask(ctx, taskID)` | 取消任务 |
| `GetCapabilities(ctx)` | 获取能力清单 |
| `WaitForTask(ctx, taskID, interval)` | 等待任务完成(轮询) |
### 10.3 数据结构
```go
type TaskRequest struct {
TaskType string
Payload map[string]any
ExternalTaskID string
Priority string
CallbackURL string
CallbackToken string
}
type TaskInfo struct {
ID string
Type string
Status string
Progress int
Message string
CreatedAt string
UpdatedAt string
CompletedAt string
ETA string
Result map[string]any
Error *TaskError
ExternalTaskID string
}
```
**完整 SDK 实现:** [sdk/client.go](../sdk/client.go)
---
## 11. 参考实现
本协议的参考实现:
| 模块 | 文件路径 | 说明 |
|------|---------|------|
| 服务端 | [externalapi/handler.go](../externalapi/handler.go) | External API Handler |
| 客户端 SDK | [sdk/client.go](../sdk/client.go) | Go 语言 SDK |
---
## 附录 A:调用模式选择
### 回调模式 vs 轮询模式
| 对比项 | 回调模式 | 轮询模式 |
|--------|---------|---------|
| 实时性 | 高,状态变化即时通知 | 低,取决于轮询间隔 |
| 实现复杂度 | 调用方需提供公网可访问的回调接口 | 简单,只需调用 GET 接口 |
| 网络要求 | 调用方需要公网可达 | 只需调用方能访问服务端 |
| 适用场景 | 生产环境、需要实时通知 | 开发测试、内网环境 |
### 选择建议
- **有公网服务器**:使用回调模式
- **本地开发 / 内网环境**:使用轮询模式
- **长时间任务**:建议回调模式,避免频繁轮询
- **短任务(<10s)**:可直接同步等待或高频轮询
---
## 附录 B:从 A2A 协议到 P2A 协议的映射
| 灵隙概念 | P2A 对应 | 说明 |
|---------|---------|------|
| `p2p:task_request` | `POST /task` | 任务提交 |
| `p2p:task_status_update` | 回调 / GET /task | 状态更新 |
| `p2p:task_complete` | 回调(status=completed) | 任务完成 |
| `p2p:task_failed` | 回调(status=failed) | 任务失败 |
| `p2p:task_cancel` | `POST /task/{id}/cancel` | 任务取消 |
| `p2p:capability_query` | `GET /capabilities` | 能力查询 |
| Agent 身份 | API Key | 简化认证 |
| HMAC 签名 | Callback Token | 简化验证 |