Agent智能体 Open API 对接文档(第三方)
文档版本v1.6.0更新日期2026-08-12适用产品麦芽Agent智能体 Open API文档性质正式对接文档(与当前线上实现一致)1. 概述
1.1 能力说明
第三方业务系统可通过本 Open API,向已开通的Agent智能体助手提交用户咨询(支持附件 URL 传入)、查询任务进度与结果、下载 AI 产出文件,并接收平台终态回调。
#接口方向方法路径 / 地址说明0会话初始化三方 → 平台POST/api/open/session/init可选。提前创建 session_code 并异步预热 CLI,缩短首问冷启动;不创建任务1需求录入三方 → 平台POST/api/open/demand/create创建客服任务;默认异步 JSON,可选 sync=true SSE;可用 stream_output 控制文本是否增量落库2任务查询三方 → 平台POST/api/open/demand/query查询任务状态、动作流、成果3任务终止三方 → 平台POST/api/open/demand/stop终止未完成任务;终态后触发回调(与 query 一致)4文件下载三方 → 平台GET/api/open/demand/file/download凭短期 token 下载产出文件5结果回调平台 → 三方POST贵方配置的 callback_url任务终态后主动推送 TaskSnapshot接口 0~4 由贵方调用平台;接口 5 由平台调用贵方服务。六者共同构成完整对接面。
不调用会话初始化仍可直接demand/create(首问可能冷启动);调用 init 后首问须携带返回的session_code。
1.2 接入凭证
开通接入后,平台向贵方提供:
凭证说明third_party_id接入标识(写入请求体,须与 ACCESSKEY 归属一致)ACCESSKEY访问密钥,放在请求头 X-Access-KeySECRETKEY签名密钥,仅用于本地计算签名,禁止通过网络传输Base URL形如 https://{host}/api/open(以实际开通环境为准)可选配置(由平台侧维护):
- IP 白名单
- 回调地址
callback_url - 内容长度、是否允许附件、附件数量上限等(
message_input_config) - 测试环境是否允许 HTTP 附件 URL(
other_config.attachment_allow_http)
附件能力说明:
方向方式说明三方 → 平台(输入)create.attachments[].file_url录入时由平台拉取并挂载;须开通 allow_attachments=true平台 → 三方(输出)query/callback 的 outputs[].view_urlAI 生成文件后,凭 token GET 下载;与输入附件无关1.3 会话与任务
概念字段含义会话session_code多轮对话容器;不传则新建,传入则续聊任务demand_id单次提交对应的执行单元;查询/下载/回调的主键之一规则:
- 每次调用录入接口都会新建一条任务(
demand_id)。 - 不传
session_code→ 新建会话(首问可能冷启动)。 - 传入有效
session_code→ 在同一会话下续提新任务(须与biz_user_id匹配)。 - 推荐:打开客服页时先调
POST /session/init拿到session_code并后台预热;用户首问demand/create携带该码,可复用已启动的 CLI。biz_session_id可做三方侧幂等键。
(可选)POST /session/init → session_code + 后台预热
session_code
├── demand_id = 10001 (首问,传入 init 返回的 session_code)
└── demand_id = 10002 (追问,传入同一 session_code)2. 通用约定
2.1 协议与编码
项约定协议HTTPS(测试环境可能为 HTTP,以开通说明为准)字符编码UTF-8请求体JSON(Content-Type: application/json; charset=utf-8)成功业务码响应体 code = 2002.2 统一响应结构
JSON 接口(会话初始化 / 录入 / 查询)成功与失败均返回:
{
"code": 200,
"message": "success",
"data": {}
}字段类型说明codeint业务码;成功为 200,失败见 §10messagestring说明信息dataobject / null业务数据;失败时可能为 null 或附加信息HTTP 状态码与业务码对应关系见 §10。
文件下载接口成功时直接返回文件二进制流(非上述 JSON 包装);失败时返回纯文本错误信息。
2.3 时钟同步
签名依赖请求头中的 Unix 毫秒时间戳。请保证调用方服务器与标准时间偏差不超过 ±300 秒(5 分钟),否则返回 40004。
3. 鉴权与签名(HMAC-SHA256)
会话初始化、录入、查询、终止接口必须按本节签名。
文件下载接口使用查询结果中的短期 token,无需再带 HMAC 头(见 §8)。3.1 请求头
Header必填说明Content-Type是application/json; charset=utf-8X-Access-Key是ACCESSKEYX-Timestamp是Unix 毫秒时间戳字符串,如 1722757920123X-Nonce是随机串,长度 16~64;同一 ACCESSKEY 下短期内不可重复X-Signature是按 §3.2 计算的十六进制签名(小写)3.2 签名算法
算法:HMAC-SHA256
步骤
- 取 原始请求体字节(
raw body)。空 body 按空字节序列处理。
- 必须对即将发送的原始字节做哈希;不要先 parse 再重新序列化(字段顺序、空格变化会导致验签失败)。
- 计算 Body 摘要:
body_hash = HEX( SHA256(raw_body) )- 构造规范串(Canonical String),共 6 行,行之间以 单个换行符 `\n`(LF,0x0A) 连接,末尾不加多余换行:
HTTP_METHOD
PATH
ACCESS_KEY
TIMESTAMP
NONCE
BODY_HASH行取值规则HTTP_METHOD大写,如 POSTPATH对外公开路径,必须为 /api/open/session/init、/api/open/demand/create、/api/open/demand/query 或 /api/open/demand/stop(含 /api 前缀,不含 query string)ACCESS_KEY与 X-Access-Key 相同TIMESTAMP与 X-Timestamp 相同NONCE与 X-Nonce 相同BODY_HASH步骤 2 的十六进制小写字符串- 使用 SECRETKEY(UTF-8)对规范串做 HMAC-SHA256,输出十六进制小写字符串,写入
X-Signature:
signature = HEX( HMAC_SHA256(key=SECRETKEY, message=canonical_string) )3.3 签名示例
假设:
ACCESSKEY = AK_demo_001
SECRETKEY = SK_demo_secret
METHOD = POST
PATH = /api/open/demand/create
TIMESTAMP = 1722757920123
NONCE = a1b2c3d4e5f6789012345678abcdef01
BODY = {"third_party_id":"demo-tp","biz_user_id":"u1","content":"你好"}body_hash = SHA256(UTF8(BODY))的 hex- Canonical:
POST
/api/open/demand/create
AK_demo_001
1722757920123
a1b2c3d4e5f6789012345678abcdef01
<body_hash>X-Signature = HMAC_SHA256(SK_demo_secret, canonical)的 hex
3.4 代码示例(Python)
import hashlib
import hmac
import json
import time
import uuid
import requests
ACCESS_KEY = "AK_xxx"
SECRET_KEY = "SK_xxx"
BASE = "https://{host}/api/open"
def sign(method: str, path: str, access_key: str, timestamp: str, nonce: str, raw_body: bytes) -> str:
body_hash = hashlib.sha256(raw_body or b"").hexdigest()
canonical = "\n".join([
method.upper(),
path,
access_key,
timestamp,
nonce,
body_hash,
])
return hmac.new(
SECRET_KEY.encode("utf-8"),
canonical.encode("utf-8"),
hashlib.sha256,
).hexdigest()
def post_open(path_suffix: str, body: dict):
# path_suffix 例: "/demand/create"
path = f"/api/open{path_suffix}"
raw_body = json.dumps(body, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
ts = str(int(time.time() * 1000))
nonce = uuid.uuid4().hex # 32 位,满足 16~64
signature = sign("POST", path, ACCESS_KEY, ts, nonce, raw_body)
headers = {
"Content-Type": "application/json; charset=utf-8",
"X-Access-Key": ACCESS_KEY,
"X-Timestamp": ts,
"X-Nonce": nonce,
"X-Signature": signature,
}
url = f"{BASE.rstrip('/')}{path_suffix}"
return requests.post(url, data=raw_body, headers=headers, timeout=30)3.5 常见验签失败原因
现象常见原因40003 签名错误PATH 写成了 /open/... 或带了域名/query;body 被重新格式化;SECRETKEY 错误40004 请求已过期客户端时钟偏差超过 5 分钟;Timestamp 误用秒而非毫秒40005 重复请求同一 ACCESSKEY 下 Nonce 被重放(Nonce TTL 约 5 分钟)40002 ACCESSKEY 无效密钥停用、未生效或已过期40006 IP 不在白名单出口 IP 未登记40001 接入标识不一致Body 中 third_party_id 与 ACCESSKEY 所属接入不匹配4. 接口:会话初始化(可选)
提前创建会话并异步预热客服 CLI。不创建 demand。适合在打开客服页、用户尚未输入时调用,缩短首问等待。
- URL:
POST /api/open/session/init - 鉴权:§3 HMAC 签名(PATH=
/api/open/session/init)
4.1 请求体
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"biz_session_id": "optional-idempotency-key",
"display_name": "张三",
"title": "退款咨询",
"stream_output": true,
"ext": {}
}字段类型必填说明third_party_idstring是接入标识biz_user_idstring是三方用户 IDbiz_session_idstring否三方会话幂等键(≤64)。同一接入下重复调用复用同一 session_code 并再次触发预热display_namestring否展示名titlestring否会话标题stream_outputboolean否默认 true。须与后续首问 demand/create 保持一致(进预热指纹)。幂等重试未传时继承已有会话值;首问 create 未传时亦沿用 init 落库值extobject否扩展字段4.2 成功响应
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260810120000-x9y8z7w6",
"prewarm_status": "preparing",
"stream_output": true,
"created": true
}
}字段说明session_code后续 demand/create / 续聊须携带prewarm_statuspreparing / ready / failed(同进程瞬时状态;preparing 为常态,勿强依赖轮询)stream_output本次会话预热使用的流式开关createdtrue=新建会话;false=biz_session_id 命中已有会话4.3 推荐时序
打开客服页 → POST /session/init → 拿到 session_code
用户输入 → POST /demand/create(带同一 session_code、建议相同 stream_output)
追问 → 继续带同一 session_code预热为同进程 best-effort:失败不影响后续录入(自动冷启动)。多实例部署时需会话粘性/owner,否则首问仍可能冷启。
5. 接口一:需求录入
创建一条Agent智能体任务。默认异步执行;可选 sync=true 走 SSE 同步流式。
- URL:
POST /api/open/demand/create - 鉴权:§3 HMAC 签名
5.0 执行模式(sync / stream_output)
sync响应取结果方式终态 callback不传 / falseapplication/json(立即返回 demand_id)三方轮询 POST /demand/query会推送(若配置了 callback_url)truetext/event-stream(同连接推流)同一 POST 内收 created/action/finished不推送(结果已由 SSE 交付)stream_output含义不传 / true(默认)Agent 文本按增量(delta)写入 action,SSE/query 可更快看到首字falseAgent 关闭增量流式,文本整段落库后再可见(首字更晚,action 条数更少)sync/stream_output必须为 JSON boolean。字符串"true"会返回40007。
二者独立:sync控制 HTTP 是否 SSE 同连接推送;stream_output控制模型文本是否增量落库。
增加字段会改变 Body,须对新原始字节重新签名。
SSE 断开不会取消后台任务;请用首个created事件中的demand_id+session_code调用 query 兜底。
建议同步模式带上 biz_demand_id,便于断线重试对账(当前版本不自动幂等)。5.1 请求体
新会话:
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"content": "我想咨询退款流程",
"title": "退款咨询",
"display_name": "张三",
"biz_demand_id": "biz-order-001",
"ext": {
"order_id": "ORD-20260801"
}
}续聊(传入上次返回的 `session_code`):
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"session_code": "CS-S-20260805101200-x9y8z7w6",
"content": "那退款大概多久能到账?",
"title": "退款咨询-追问"
}带附件(三方提供 HTTPS 临时下载链接):
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"content": "请阅读附件并总结退款条款",
"attachments": [
{
"file_url": "https://partner-cdn.example.com/tmp/contract.pdf",
"file_name": "合同.pdf",
"mime_type": "application/pdf"
}
]
}平台会在录入时拉取file_url并注册为任务附件,AI 在工作区resources/目录读取。须在接入配置中开启message_input_config.allow_attachments=true。单文件默认最大 20MB;数量以max_attachment_count为准(默认 5)。PDF 等二进制文件由 AI 通过 Skill / 命令行工具解析,请勿假设平台会原样转发文件内容。
附件相关接入配置示例(平台侧):
{
"message_input_config": {
"allow_attachments": true,
"max_attachment_count": 5,
"max_content_length": 32000
},
"other_config": {
"attachment_allow_http": false
}
}字段类型必填说明third_party_idstring是接入标识,须与 ACCESSKEY 一致biz_user_idstring是贵方用户唯一 IDcontentstring是本轮用户输入;默认最大长度 32000(以接入配置为准)session_codestring否不传=新会话;传入=/session/init 返回或续聊码(须属于该 biz_user_id)titlestring否任务标题;缺省自动生成display_namestring否用户展示名biz_demand_idstring否贵方侧业务单号,最长 64attachmentsarray否附件列表;受接入配置 message_input_config 约束attachments[].file_urlstring条件附件下载 URL(HTTPS;测试环境可在 other_config.attachment_allow_http=true 时允许 HTTP)attachments[].file_namestring否文件名;缺省从 URL 推断attachments[].mime_typestring否MIME 类型,可选extobject否扩展字段;平台会关联存储。另:stream_output 会合并写入任务侧 ext_json 供 Job 读取(顶层字段优先于 ext.stream_output)syncboolean否默认 false。true 时响应改为 SSE 同步流式(§5.3)stream_outputboolean否默认 true。控制客服 Job 是否增量流式写入文本 action;与 sync 独立5.2 成功响应(异步,sync=false)
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345,
"status": 0,
"status_name": "pending",
"created_at": "2026-08-05T09:12:00",
"sync": false,
"stream_output": true
}
}字段说明session_code会话编码;续聊时带回demand_id本次任务 ID;查询/对账使用status / status_name初始一般为 0 / pendingcreated_at创建时间(ISO 风格本地时间字符串)sync回显请求中的 sync(异步一般为 false)stream_output回显本次任务实际使用的流式开关异步任务请通过 查询接口 或 回调 获取最终结果,勿在录入 JSON 响应中期待完整答复。
5.3 成功响应(同步 SSE,sync=true)
- HTTP:
200 - Content-Type:
text/event-stream - 响应头:
Cache-Control: no-cache、X-Accel-Buffering: no(请代理关闭缓冲并拉长读超时,建议 ≥ 15 分钟) - 最大连接时长:15 分钟;超时发送
stream_error后关闭,任务继续执行
请求示例:
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"content": "请总结退款流程",
"sync": true,
"stream_output": true,
"biz_demand_id": "biz-order-001"
}事件顺序: created → action* → finished(或 stream_error)
id: created:12345
event: created
data: {"request_id":"...","session_code":"CS-S-...","demand_id":12345,"status":0,"status_name":"pending","created_at":"..."}
id: action:788001
event: action
data: {"id":788001,"action_name":"text","action_type":"unified_demand_action","action_detail":{"execution_result":"..."},"create_time":"..."}
: ping
id: finished:12345
event: finished
data: {"session_code":"...","demand_id":12345,"status":20,"status_name":"completed","finished":true,"result_summary":"...","outputs":[],"..."}事件说明created建单成功后立即发送;含 demand_id/session_code,断线后用于 queryaction一条公开 action 一帧;白名单与 query 一致:thinking/text/interaction_question/interaction_replyfinished终态(20/90/99);字段对齐 TaskSnapshot,不含完整 actions 数组stream_error流传输/超时等;不表示任务已失败,请改用 query注释 : ping约每 15 秒心跳,保持代理连接流前错误(验签/参数等):仍返回普通 JSON + HTTP 4xx/5xx,不会进入 SSE。
curl 联调:
curl -N -X POST 'http://HOST/api/open/demand/create' \
-H 'Content-Type: application/json; charset=utf-8' \
-H 'X-Access-Key: ...' \
-H 'X-Timestamp: ...' \
-H 'X-Nonce: ...' \
-H 'X-Signature: ...' \
-d '{"third_party_id":"...","biz_user_id":"...","content":"...","sync":true}'5.4 录入场景示例
场景 A:纯文本新会话(无附件)
请求:
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"content": "我想咨询退款流程",
"title": "退款咨询"
}响应:
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345,
"status": 0,
"status_name": "pending",
"created_at": "2026-08-05T09:12:00"
}
}场景 B:带附件新会话(输入附件)
贵方先将文件上传至 OSS/CDN,生成 HTTPS 临时链接(建议 5~15 分钟有效),再调用录入:
请求:
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"content": "请阅读附件,用三句话总结文档内容",
"title": "合同摘要",
"attachments": [
{
"file_url": "https://partner-cdn.example.com/tmp/contract.pdf",
"file_name": "合同.pdf",
"mime_type": "application/pdf"
}
]
}响应: 与场景 A 结构相同(仅 demand_id / session_code 不同)。附件是否拉取成功在录入阶段即确定;拉取失败返回 40009,不会创建任务。
附件拉取失败示例:
{
"code": 40009,
"message": "当前接入配置不允许上传附件",
"data": null
}
{
"code": 40009,
"message": "下载附件失败",
"data": null
}场景 C:续聊(同 session,无新附件)
请求:
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"session_code": "CS-S-20260805101200-x9y8z7w6",
"content": "那退款大概多久能到账?",
"title": "退款咨询-追问"
}响应: 返回同一 session_code、新的 demand_id(每次录入均新建任务)。
场景 D:续聊并补充新附件
请求:
{
"third_party_id": "agent-maiya-prod-xxxx",
"biz_user_id": "user_10086",
"session_code": "CS-S-20260805101200-x9y8z7w6",
"content": "请再看一下这份补充材料",
"attachments": [
{
"file_url": "https://partner-cdn.example.com/tmp/supplement.txt",
"file_name": "补充说明.txt"
}
]
}每一轮 demand_id 独立挂载附件;历史轮次的附件不会自动带入新一轮,除非用户在续聊中再次传入。6. 接口二:任务查询
按录入返回的 session_code + demand_id 查询该次任务的执行快照。
- URL:
POST /api/open/demand/query - 鉴权:§3 HMAC 签名
6.1 请求体
{
"third_party_id": "agent-maiya-prod-xxxx",
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345
}字段类型必填说明third_party_idstring是接入标识session_codestring是录入返回的会话编码demand_idint是录入返回的任务 ID6.2 成功响应(data = TaskSnapshot)
以下按典型场景分别示例。查询请求体在各场景中相同(见 §6.1)。
场景 A:执行中(无终态、无产出)
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345,
"status": 10,
"status_name": "running",
"finished": false,
"error_code": null,
"error_message": null,
"result_summary": null,
"actions": [
{
"id": 90001,
"action_name": "text",
"action_type": "unified_demand_action",
"action_detail": {
"execution_result": "您好,正在为您查询退款政策..."
},
"create_time": "2026-08-05T09:12:18"
}
],
"outputs": []
}
}场景 B:已完成 — 纯文本答复(无输出文件)
常见于咨询类,或「阅读输入附件后文字总结」(create 有附件,但 AI 未生成可下载文件):
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805164503-5573652c",
"demand_id": 37412,
"status": 20,
"status_name": "completed",
"finished": true,
"error_code": null,
"error_message": null,
"result_summary": "该附件文档内容非常简短……(三句话总结正文)",
"actions": [
{
"id": 782271,
"action_name": "text",
"action_type": "unified_demand_action",
"action_detail": {
"execution_result": "1. 文件性质:这是一份测试文档……"
},
"create_time": "2026-08-05T16:49:30"
}
],
"outputs": []
}
}场景 C:已完成 — 含 AI 产出文件(需下载)
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345,
"status": 20,
"status_name": "completed",
"finished": true,
"result_summary": "已为您生成退款流程说明文档。",
"actions": [
{
"id": 90001,
"action_name": "text",
"action_type": "unified_demand_action",
"action_detail": {
"execution_result": "已为您整理退款流程,详见附件 PDF。"
},
"create_time": "2026-08-05T09:15:28"
}
],
"outputs": [
{
"output_type": "file",
"output_id": 32019,
"output_detail": {
"file_name": "退款流程说明.pdf",
"file_type": "pdf",
"view_url": "https://{host}/api/open/demand/file/download?token=eyJ...",
"expires_at": "2026-08-05T10:15:30+08:00"
}
}
]
}
}场景 D:已完成 — 失败终态
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805163303-69e817db",
"demand_id": 37408,
"status": 99,
"status_name": "failed",
"finished": true,
"error_code": "SESSION_CONTEXT_CORRUPTED",
"error_message": "系统无法继续读取当前会话,是否清空上下文后继续执行。",
"result_summary": "系统无法继续读取当前会话,是否清空上下文后继续执行。",
"actions": [],
"outputs": []
}
}场景对照速查
场景create 附件finishedoutputs主要阅读字段纯文本咨询无true[]result_summary / actions阅读附件后文字答复有true[]result_summary / actionsAI 生成文件可有可无true非空outputs[].view_url + result_summary执行中可有可无false[]actions(进度)失败可有可无true[]error_code / error_message6.3 TaskSnapshot 字段
字段类型说明session_codestring会话编码demand_idint任务 IDthird_party_idstring接入标识statusint状态码,见 §6.4status_namestring状态名finishedbool是否终态biz_user_idstring贵方用户 IDassistant_idint执行助手 IDcreated_at / updated_atstring时间error_code / error_messagestring / null失败时错误信息result_summarystring / null结果摘要actionsarray公开动作流(未完成时也会返回)outputsarray文件成果;仅 `finished=true` 且本次 `demand_id` 有登记产出时有值,否则 []6.4 任务状态
statusstatus_namefinished说明0pendingfalse排队中10runningfalse执行中11analyzingfalse分析中12processingfalse处理中16resumingfalse恢复中20completedtrue成功完成90interruptedtrue中断99failedtrue失败6.5 actions 说明
仅返回公开白名单动作:
action_nameaction_detail 公开字段thinkingexecution_result(文本,最长约 8000 字符)textexecution_resultinteraction_questiontitle, contentinteraction_replyresponse.text / selected_label / selected_labels内部工具调用、绝对路径、密钥等不会出现在公开 action_detail 中。
6.6 outputs 说明
字段说明output_type固定 fileoutput_id产出记录 IDoutput_detail.file_name文件名output_detail.file_type扩展名(如 pdf)output_detail.view_url文件下载地址(含短期 token),见 §8output_detail.expires_attoken 过期时间(ISO8601,含时区)注意:
- 未完成任务:
outputs恒为[](即便后台已生成文件)。 - 输入附件(create 传入)不在
outputs中返回;outputs仅含 AI 产出 的可下载文件。 - 按任务隔离:
outputs只返回本次 `demand_id` 登记的文件,不包含同session_code下其他轮次(其他demand_id)的产出。续聊时请分别 query 各demand_id获取对应文件。 - 同一
demand_id若产出多个文件,outputs为数组,每项对应一个可下载文件。 view_url每次查询重新签发,请勿长期缓存;过期后重新调用本接口刷新。- 不会返回服务器本地绝对路径。
7. 接口三:任务终止
按录入返回的 session_code + demand_id 终止该次任务。终止成功后任务进入终态 status=90(interrupted),平台会异步触发 §9 结果回调(若已配置 callback_url);sync=true 的 SSE 连接也会收到终态事件。
- URL:
POST /api/open/demand/stop - 鉴权:§3 HMAC 签名
7.1 请求体
{
"third_party_id": "agent-maiya-prod-xxxx",
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345
}字段类型必填说明third_party_idstring是接入标识session_codestring是录入返回的会话编码demand_idint是录入返回的任务 ID7.2 成功响应
{
"code": 200,
"message": "success",
"data": {
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345,
"status": 90,
"status_name": "interrupted",
"finished": true
}
}7.3 业务规则
规则说明可终止状态pending / running / processing / resuming 等非终态不可终止已完成(20)、已中断(90)、失败(99)→ 返回 40011权限须与 query 相同:session_code + demand_id 须属于当前 third_party_id执行中任务SSE(sync=true)检测到 90 后立刻推送 finished 并结束,不再继续推 action;Job 仍会在数秒内收尾排队任务尚未被 Job 领取的任务会立即变为 interrupted,并触发回调8. 接口四:文件下载
任务完成后,通过查询(或回调)得到的 view_url 直接下载文件。
- URL:
GET /api/open/demand/file/download?token={token} - 鉴权:无需 HMAC 头;凭 query 参数
token鉴权 - 成功响应:文件二进制流
Content-Type:按文件类型推断(未知则为application/octet-stream)Content-Disposition: attachment; filename="..."
7.1 请求参数
参数位置必填说明tokenQuery是由平台在 outputs[].output_detail.view_url 中签发示例:
GET /api/open/demand/file/download?token=eyJ2IjoxLCJkZW1hbmRfaWQiOjEyMzQ1...<sig> HTTP/1.1
Host: {host}浏览器、curl、HTTP 客户端均可直接 GET,无需额外签名头。
下载成功: HTTP 200,响应体为文件二进制流。
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="退款流程说明.pdf"
<binary data>下载失败示例:
HTTP/1.1 401 Unauthorized
Content-Type: text/plain; charset=utf-8
token 已过期7.2 Token 规则
项说明有效期默认 3600 秒(1 小时)绑定信息demand_id、session_code、接入配置、file_name签名使用接入配置当前有效 SECRETKEY 做 HMAC-SHA256(平台签发,贵方无需自行构造)刷新过期后重新调用 任务查询,使用新的 view_url7.3 失败响应
下载失败时返回 纯文本(非 JSON),常见情况:
HTTP含义400token 无效 / 参数不完整 / 文件名非法401token 签名校验失败或已过期403无权访问该任务文件404任务或文件不存在500服务内部错误7.4 安全说明
- Token 具备时效与归属绑定,请勿公开传播长期有效的下载链接。
- 服务端校验任务归属,并限制仅能下载该会话产出目录内文件,禁止路径穿越。
- 响应中不会暴露服务器磁盘路径。
9. 接口五:结果回调(平台 → 第三方)
任务进入终态后,平台主动将结果推送到贵方服务。这是正式对接接口之一,方向与录入/查询相反。
项说明方向平台 → 第三方方法POSTURL接入配置中的 callback_url(由平台侧开通时登记)Content-Typeapplication/json; charset=utf-8触发条件demand.status ∈ {20, 90, 99},且该任务尚未同步成功触发时机终态写入成功后立即异步 POST 一次数据体与 §6 任务查询的 data(TaskSnapshot)完全一致8.1 前置配置
开通时向平台提供可公网访问的 HTTPS 回调地址,例如:
https://partner.example.com/hooks/mai/customer-service要求:
- 建议 HTTPS;若确需 HTTP,须由平台侧显式放行。
- 地址须可被平台服务器访问(注意防火墙 / 专线)。
- 未配置
callback_url时,平台视为无需投递(不影响录入与查询)。
8.2 回调请求头
Header必填说明Content-Type是application/json; charset=utf-8X-MAI-Access-Key是接入配置当前有效 ACCESSKEYX-MAI-Timestamp是Unix 毫秒时间戳X-MAI-Nonce是随机串X-MAI-Signature是对原始回调 Body 的 HMAC-SHA256 签名(算法同 §3.2)注意:回调头前缀为 `X-MAI-`,与贵方调用平台时使用的 X-Access-Key 等命名不同,请勿混用。8.3 回调请求体
外层结构固定;data 与 §6 查询的 TaskSnapshot 完全一致(含各场景差异)。
通用结构:
字段类型说明eventstring固定 task.finishedtimestampint回调发出时间(Unix 毫秒)dataobjectTaskSnapshot,见 §6.3~§6.6回调场景 A:成功 + 有产出文件(outputs 非空)
对应 §6.2 场景 C。贵方收到后应下载 data.outputs[].output_detail.view_url:
{
"event": "task.finished",
"timestamp": 1722758772000,
"data": {
"session_code": "CS-S-20260805101200-x9y8z7w6",
"demand_id": 12345,
"status": 20,
"status_name": "completed",
"finished": true,
"result_summary": "已为您生成退款流程说明文档。",
"outputs": [
{
"output_type": "file",
"output_id": 32019,
"output_detail": {
"file_name": "退款流程说明.pdf",
"file_type": "pdf",
"view_url": "https://{host}/api/open/demand/file/download?token=eyJ...",
"expires_at": "2026-08-05T10:15:30+08:00"
}
}
]
}
}回调场景 B:成功 + 仅文字答复(含「阅读输入附件」)
对应 §6.2 场景 B。create 时可能传了输入附件,但 `outputs` 仍为空:
{
"event": "task.finished",
"timestamp": 1722758976000,
"data": {
"session_code": "CS-S-20260805164503-5573652c",
"demand_id": 37412,
"status": 20,
"status_name": "completed",
"finished": true,
"result_summary": "该附件文档内容非常简短……(三句话总结)",
"outputs": []
}
}回调场景 C:失败终态
{
"event": "task.finished",
"timestamp": 1722758850000,
"data": {
"session_code": "CS-S-20260805163303-69e817db",
"demand_id": 37408,
"status": 99,
"status_name": "failed",
"finished": true,
"error_code": "SESSION_CONTEXT_CORRUPTED",
"error_message": "系统无法继续读取当前会话,是否清空上下文后继续执行。",
"outputs": []
}
}回调仅在终态触发一次;data.actions可能为空数组(与查询接口一致,以result_summary/outputs/error_*为准)。
8.4 贵方验签步骤(强烈建议)
算法与 §3.2 完全相同,区别仅在于 Header 名称与 PATH 取值:
- 读取原始请求 Body 字节(不要先 parse 再序列化)。
body_hash = HEX(SHA256(raw_body))- 构造规范串:
POST
{callback_url 的 path}
{X-MAI-Access-Key}
{X-MAI-Timestamp}
{X-MAI-Nonce}
{body_hash}示例:若 callback_url = https://partner.example.com/hooks/mai/customer-service,则 PATH = /hooks/mai/customer-service(不含域名与 query)。
expected = HEX(HMAC_SHA256(SECRETKEY, canonical))- 与
X-MAI-Signature做常量时间比较;并校验 Timestamp 偏差不超过 5 分钟。
Python 验签示例:
import hashlib
import hmac
from urllib.parse import urlparse
def verify_mai_callback(secret_key: str, callback_url: str, headers: dict, raw_body: bytes) -> bool:
access_key = headers.get("X-MAI-Access-Key", "")
timestamp = headers.get("X-MAI-Timestamp", "")
nonce = headers.get("X-MAI-Nonce", "")
signature = (headers.get("X-MAI-Signature") or "").lower()
path = urlparse(callback_url).path or "/"
body_hash = hashlib.sha256(raw_body or b"").hexdigest()
canonical = "\n".join(["POST", path, access_key, timestamp, nonce, body_hash])
expected = hmac.new(
secret_key.encode("utf-8"),
canonical.encode("utf-8"),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)8.5 贵方响应约定
建议返回:
{
"code": 0,
"message": "ok"
}平台判定成功条件:
- HTTP 状态码为 2xx;且
- 若响应体为 JSON 且包含
code字段,则code须为 `0` 或 `200`。
不满足上述条件视为本次回调失败。
8.6 投递语义与幂等
项行为成功标记该demand_id 已同步,不再重复推送失败不自动重试;仅记录尝试次数;sync_status 保持未同步幂等贵方须按 data.demand_id 幂等处理(网络超时可能导致贵方已收、平台判失败)超时默认约 10 秒(以接入配置为准)与查询关系回调失败不影响贵方继续调用 §6 查询拉取结果10. 错误码
codeHTTP说明200200成功40001403接入标识不存在/已停用,或与 ACCESSKEY 不一致40002401ACCESSKEY 无效或已过期40003401签名错误40004401请求已过期(时间戳偏差过大)40005401重复请求(Nonce 重放)40006403IP 不在白名单40007400参数校验失败40008404demand_id 不存在或无权访问40009400附件不符合要求(未开启、数量/大小/类型/URL 不合法或下载失败)40010400session 校验失败:session_code 不存在或无权访问;session_code / biz_session_id 与 biz_user_id 不匹配40011400需求状态不允许终止(已完成/已中断/失败)50001500服务内部错误示例:
{
"code": 40003,
"message": "签名错误",
"data": null
}11. 推荐对接流程
10.1 纯文本咨询(无附件、无产出文件)
推荐(预热首问):
1. POST /session/init → 保存 session_code(stream_output 与后续保持一致)
2. POST /demand/create(带 session_code,无 attachments)
3. POST /demand/query 轮询至 finished=true
4. 读取 result_summary / actions(outputs 为 [])
5. (可选)收到 callback,data 与 query 一致兼容(不预热,首问可能冷启动):
1. POST /demand/create(无 session_code、无 attachments)
2. POST /demand/query 轮询至 finished=true
3. 读取 result_summary / actions(outputs 为 [])
4. (可选)收到 callback,data 与 query 一致10.2 带输入附件(三方传 file_url)
1. 贵方 OSS 生成 HTTPS 临时链接
2. POST /demand/create(带 attachments[])
└─ 失败 40009 → 检查 allow_attachments / URL 可达性
3. POST /demand/query 轮询
4. finished=true 且 outputs=[] → 文字结论在 result_summary(常见)
5. finished=true 且 outputs 非空 → 另有 AI 生成文件,GET view_url 下载10.3 要求 AI 生成文件(输出附件)
1. POST /demand/create,content 中明确说明「请生成 PDF/文档给我」
2. 轮询或等 callback
3. finished=true 且 outputs[].view_url 非空
4. GET view_url 下载(§8);token 过期则重新 query 刷新10.4 续聊
1. 再次 POST /demand/create,带同一 session_code + biz_user_id
2. 得到新 demand_id;每轮 attachments 独立,不自动继承历史附件
3. 分别 query 各 demand_id10.5 同步 SSE(sync=true)
1. POST /demand/create,Body 含 "sync": true
2. 解析 text/event-stream:created → action* → finished
3. 若中途断开:用 created 中的 demand_id/session_code 调 query 兜底
4. 本模式不会发送终态 callback取结果方式:
- 异步:回调为主 + 查询兜底。
- 同步 SSE:同连接收流;断线用 query 兜底。
12. 联调检查清单
- [ ] 可选:打开页先调
/session/init,首问携带返回的session_code,stream_output与 init 一致 - [ ] 签名 PATH 使用
/api/open/session/init、/api/open/demand/create或/api/open/demand/query - [ ] 对原始发送字节计算 SHA256,避免 JSON 二次序列化改变内容
- [ ] Timestamp 为 毫秒
- [ ] Nonce 长度 16~64,且不重放
- [ ] Body 含正确
third_party_id - [ ] 出口 IP 已加入白名单(若已启用)
- [ ] 异步 create 后轮询或等 callback;勿在 JSON 响应中期待完整答复
- [ ]
sync=true时按 SSE 解析,代理关闭缓冲并用curl -N验证 - [ ] 按需传
stream_output(默认 true);与sync独立,改 Body 后须重签 - [ ] SSE 断线后可用 query 兜底;同步模式不依赖 callback
- [ ] 接入已开启
allow_attachments=true(若需传输入附件) - [ ] 输入附件使用 HTTPS 临时 URL;平台服务器须能访问
- [ ] 区分输入附件(create)与输出文件(outputs);后者才需下载
- [ ] 查询时同时传
session_code与demand_id - [ ] 仅在
finished=true时期待outputs非空 - [ ] 下载使用完整
view_url;过期后重新 query - [ ] 已配置可访问的
callback_url(仅异步模式需要) - [ ] 回调验签使用
X-MAI-*头,PATH 取回调 URL 的 path - [ ] 回调按
demand_id幂等;成功响应 HTTP 2xx 且code为 0 或 200
13. 修订记录
版本日期说明v1.6.02026-08-12新增POST /demand/stop 任务终止接口;错误码 40011v1.5.22026-08-10明确 outputs 按 demand_id 隔离,续聊各轮 query 仅返回本轮产出文件v1.5.12026-08-10文档与实现对齐:session/init 鉴权说明、create 响应字段、40010/移除 40011、推荐流程与 Postman 签名 PATHv1.52026-08-10新增可选 POST /session/init 会话预热;首问可携带 init 返回的 session_codev1.42026-08-06create 支持 stream_output(默认 true)透传客服 Job include_partial_messagesv1.32026-08-06create 支持 sync=true SSE 同步流式;同步模式不发送终态 callbackv1.22026-08-05支持输入附件(file_url);补充多场景请求/响应示例;区分输入附件与输出文件v1.12026-08-05将结果回调提升为正式接口四;补充请求头、验签示例、投递语义v1.02026-08-05首版:录入、查询、文件下载与签名说明