JVS Crew API 文档
概述
JVS Crew 是阿里云无影团队开发的 AI 智能助手平台。通过JVS Crew API,可以将 JVS Crew 的 AI 对话能力集成到自有应用中。
API 分为四大类:
会话交互——获取令牌、发起对话、上传文件
会话管理——列举/查看/删除历史会话
定时任务——创建/管理/监控定时执行任务
计费查询——查看用量和消耗明细
快速开始
集成 JVS Crew 最少只需两步:
获取令牌——使用 AK/SK 调用 GetAccessToken,获取 AccessToken。
发起对话——携带 AccessToken 调用 Chat,通过 SSE 流接收回复。
完整 Python 示例参见使用示例章节。
基础信息
协议:HTTPS
Base URL:
https://wuyingai.cn-shanghai.aliyuncs.comAPI 版本:
2026-03-11(所有接口的x-acs-version或 POPVersion参数)
认证方式
本文档的 API 采用两种认证方式:
认证方式 | 适用 API | 说明 |
AK/SK 签名 | GetAccessToken、GetChatFileUploadUrl、SyncContext、GetBillingOverview、ListUserConsumption | 使用阿里云 AccessKey 进行 POP V1 签名,详见使用示例 |
JWT 令牌 | Chat、ListSessions、ListSessionHistory、StopSession、DeleteSession、GetSandboxInfo、CreateScheduledTask、UpdateScheduledTask、GetScheduledTask、ListScheduledTasks、DeleteScheduledTask、ListScheduledTaskRuns | 先调用 GetAccessToken 获取 AccessToken,放入 Query 参数 |
通用请求格式
两种认证方式的请求格式不同:
AK/SK 签名接口:所有参数(包括 Action、业务参数、签名参数)均通过 Query String 拼接在 URL 中,使用 POST 方法发送。
POST https://wuyingai.cn-shanghai.aliyuncs.com/?Action=GetAccessToken&ExternalUserId=user-38764&Signature=...&其他签名参数JWT 令牌接口:Authorization 放在 Query String 中,操作名称通过 x-acs-action Header 指定,业务参数放在 JSON Body 中。
POST https://wuyingai.cn-shanghai.aliyuncs.com/?Authorization=Bearer%20<token>
Headers: x-acs-action: ListSessions, x-acs-version: 2026-03-11, x-acs-date: <UTC 时间>
Body: {"ExternalUserId": "user-38764"}Chat 接口的 URL 路径为 /api/agent/chat(非根路径 /),其余 JWT 接口均使用根路径。
API 一览
API | 分类 | 认证 | 说明 |
会话交互 | AK/SK | 获取 JWT 访问令牌 | |
会话交互 | JWT | 流式对话(SSE) | |
会话交互 | AK/SK | 获取文件上传地址 | |
会话交互 | AK/SK | 同步文件到沙箱 | |
会话管理 | JWT | 列举会话列表 | |
会话管理 | JWT | 获取会话历史 | |
会话管理 | JWT | 中止正在执行的对话 | |
会话管理 | JWT | 删除对话记录 | |
会话管理 | JWT | 获取沙箱信息 | |
计费查询 | AK/SK | 租户当月计费概览 | |
计费查询 | AK/SK | 按用户查询消耗明细 | |
定时任务 | JWT | 创建定时任务 | |
定时任务 | JWT | 更新定时任务 | |
定时任务 | JWT | 查询单个任务详情 | |
定时任务 | JWT | 分页列举任务 | |
定时任务 | JWT | 删除任务 | |
定时任务 | JWT | 查询执行记录 |
会话交互接口
GetAccessToken - 获取对话令牌
接口描述
获取用户进行对话所需访问令牌(AccessToken),供后续调用 Chat 接口验证身份。
令牌格式:AccessToken 为 JWT,由 Header.Payload.Signature 三段经 Base64URL 编码后以 . 连接成一行;下表示例为脱敏示意,实际 RequestId、JWT 各段均更长。
令牌有效期:AccessToken 在一段时间内有效,过期后须重新调用本接口获取新令牌。
请求信息
认证方式:POP V1 签名(AK/SK),详见使用示例
Action:
GetAccessToken
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
ExternalUserId | string | 是 | 外部系统用户唯一标识 |
|
请求示例
params = {
"Format": "JSON",
"Version": "2026-03-11",
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": _now_utc(),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "GetAccessToken",
"RegionId": "cn-shanghai",
"ExternalUserId": "user-38764",
}
params["Signature"] = _sign_v1(params, sk)响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
AccessToken | string | JWT 访问令牌,用于 Chat 等接口的 Authorization 参数 |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
响应示例
成功:
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"AccessToken": "eyJhbGc****.eyJ********.****TCk"
}失败:
{
"Success": false,
"Code": "400",
"Message": "Invalid ExternalUserId",
"HttpStatusCode": 400
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
400 | InvalidParameter | 参数错误 | ExternalUserId 格式不正确 |
401 | Unauthorized | 未授权 | 缺少必要的认证信息 |
500 | InternalError | 服务内部错误 | 服务端异常,请稍后重试 |
Chat - 流式对话
接口描述
与 JVS Crew 发起流式对话,采用 Server-Sent Events(SSE) 协议实时推送对话内容。
特性:
实时流式响应,降低首字延迟
支持多模态输入(文本、图片、文件)
会话保持,支持多轮对话
事件驱动,精确控制消息状态
请求信息
请求方法:
POSTContent-Type:
application/json响应 Content-Type:
text/event-stream
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
TemplateId | string | 否 | Agent 模板 ID |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
Content-Type | string | 是 | 请求内容类型 |
|
Accept | string | 是 | 接受的响应类型 |
|
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
Cache-Control | string | 否 | 缓存控制 |
|
Connection | string | 否 | 连接类型 |
|
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
SessionId | string | 否 | 会话 ID,用于保持多轮对话上下文 |
|
ExternalUserId | string | 是 | 外部系统用户 ID |
|
Input | string | 否 | 消息列表 JSON 字符串,按时间顺序排列 |
|
RoutingKey | string | 否 | 路由键,指定后端实例 |
|
Input 结构说明
Input 参数是一个 JSON 字符串(非对象数组),包含 Message 数组,需先序列化为字符串再传递。
Message 结构(JSON 字符串内的数组元素):
名称 | 类型 | 必填 | 描述 | 示例值 | 枚举值 |
Role | string | 是 | 消息角色 |
|
|
Content | array | 否 | 内容块列表 | 见下方 Content 结构 | - |
Content 结构(Message 中的 Content 数组元素):
名称 | 类型 | 必填 | 描述 | 示例值 | 枚举值 |
Type | string | 是 | 内容类型 |
|
|
Text | string | 否 | 文本内容(Type=text) |
| - |
ImageUrl | string | 否 | 图片 URL 或 base64(Type=image) |
| - |
FileUrl | string | 否 | 文件路径或 URL(Type=file) |
| - |
请求示例
curl -N -X POST \
'https://wuyingai.cn-shanghai.aliyuncs.com/api/agent/chat?Authorization=Bearer%20<access_token>&TemplateId=<template_id>' \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'x-acs-version: 2026-03-11' \
-H 'x-acs-action: Chat' \
-H 'x-acs-date: 2026-03-18T06:21:31Z' \
-d '{
"Input": "[{\"Role\":\"user\",\"Content\":[{\"Type\":\"text\",\"Text\":\"你好\"}]}]",
"ExternalUserId": "test-user",
"SessionId": "test-session-001"
}-N参数用于禁用缓冲,实时接收 SSE 流。x-acs-date需要设置为当前 UTC 时间(ISO 8601 格式)。Input是 JSON 字符串,需要转义引号。<access_token>替换为实际的访问令牌,令牌过期(HTTP 401)时,需重新调用 GetAccessToken。
响应参数(SSE 事件)
SSE 响应格式为 data: <JSON>\n\n,每行为一个 JSON 事件对象。服务端定期发送 :ping 心跳行(无 data: 前缀)以保持连接,客户端忽略即可。
通用字段
名称 | 类型 | 描述 | 示例值 |
Object | string | 事件对象类型 |
|
Id | string | 消息唯一标识 |
|
SessionId | string | 会话 ID |
|
SequenceNumber | string | 事件序号,保证处理顺序 |
|
Response 事件字段
Object=response 事件标记整个回复的生命周期(开始与结束)。
名称 | 类型 | 描述 | 枚举值 |
Status | string | 回复状态 |
|
Message 事件字段
Object=message 事件表示一条具体消息,通过 Type 字段区分消息类型。
名称 | 类型 | 描述 | 枚举值 |
Role | string | 角色 |
|
Type | string | 消息类型 |
|
Status | string | 运行状态 |
|
Content | array | 内容块列表(仅 | 见下方 Content 结构 |
CreatedAt | string | 创建时间戳(Unix 秒) |
|
Content 结构(响应)
名称 | 类型 | 描述 | 示例值 |
Type | string | 内容类型 |
|
Status | string | 内容状态 |
|
Text | string | 文本内容 |
|
Data | object | 结构化数据(如工具调用) |
|
事件类型说明
事件类型 | Object | 描述 | 触发时机 |
回复创建 |
| Status= | SSE 流开始 |
回复进行中 |
| Status= | 开始生成内容 |
思考开始 |
| Type= | 模型开始推理 |
思考内容增量 |
| 思考阶段的文本片段(Status= | 每生成一段思考文本 |
思考完成 |
| Type= | 推理结束 |
消息开始 |
| Type= | 开始生成正式回复 |
消息内容增量 |
| 正式回复的文本片段(Status= | 每生成一段回复文本 |
消息内容完成 |
| 聚合后的完整文本(Status= | 正式回复文本生成完毕 |
消息完成 |
| Type= | 正式回复结束 |
回复完成 |
| Status= | SSE 流结束 |
错误 |
| 错误信息 | 发生错误时 |
心跳 |
| 保持长连接,客户端忽略即可 | 空闲时每隔数秒 |
思考阶段(reasoning)的 content 是模型内部推理过程,一般不向终端用户展示。客户端应根据当前 message 的 Type 来决定是否展示对应的 content。
SSE 响应示例
完整流程:
data: {"Object":"response","Status":"created","SequenceNumber":"0"}
data: {"Object":"response","Status":"in_progress","SequenceNumber":"1"}
: ping
data: {"Object":"message","Id":"msg_001","SessionId":"176405663****961","Type":"reasoning","Status":"in_progress","SequenceNumber":"2"}
data: {"Object":"content","Id":"msg_001","Type":"text","Status":"in_progress","Text":"用户在打招呼","SequenceNumber":"3"}
data: {"Object":"content","Id":"msg_001","Type":"text","Status":"in_progress","Text":",我简单回复即可","SequenceNumber":"4"}
data: {"Object":"message","Id":"msg_001","Type":"message","Status":"in_progress","SequenceNumber":"5"}
data: {"Object":"content","Id":"msg_001","Type":"text","Status":"in_progress","Text":"您好","SequenceNumber":"6"}
data: {"Object":"content","Id":"msg_001","Type":"text","Status":"in_progress","Text":"!","SequenceNumber":"7"}
data: {"Object":"content","Id":"msg_001","Type":"text","Status":"completed","Text":"用户在打招呼,我简单回复即可","SequenceNumber":"8"}
data: {"Object":"message","Id":"msg_001","Type":"reasoning","Status":"completed","SequenceNumber":"9"}
data: {"Object":"message","Id":"msg_001","Type":"message","Status":"completed","Content":[{"Type":"text","Text":"您好!"}],"SequenceNumber":"10"}
data: {"Object":"response","Status":"completed","SequenceNumber":"11"}SequenceNumber=3~4的 content 属于reasoning(思考)阶段,SequenceNumber=6~7的 content 属于message(正式回复)阶段。客户端应只展示message阶段的 content。SequenceNumber=8是Status=completed的聚合 content,包含某阶段的完整文本;它可能出现在后续阶段的增量事件之后(异步聚合),客户端应通过跟踪最近一个Object=message事件的Type来判定当前 content 归属。: ping是 SSE 协议注释行,浏览器 EventSource 和主流 SSE 库会自动忽略。
GetChatFileUploadUrl - 获取文件上传地址
接口描述
获取会话中文件上传 URL、沙箱内路径及 FileKey,用于将文件上传至 Agentbay 为用户提供的 Context 存储空间。文件上传分三步完成:
调用本接口获取
UploadUrl和FileKey使用 HTTP PUT 请求将文件内容上传到
UploadUrl(直传至对象存储,无需额外签名)使用该
FileKey调用 SyncContext 将文件同步到沙箱,同步后 Agent 才能使用该文件
请求信息
认证方式:POP V1 签名(AK/SK),与 GetAccessToken 相同
Action:
GetChatFileUploadUrl
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
FileName | string | 是 | 要上传的文件名称 |
|
ExternalUserId | string | 是 | 外部系统用户唯一标识 |
|
TemplateId | string | 否 | Agent 模板 ID |
|
请求示例
params = {
"Format": "JSON",
"Version": "2026-03-11",
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": _now_utc(),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "GetChatFileUploadUrl",
"RegionId": "cn-shanghai",
"FileName": "report.pdf",
"ExternalUserId": "user-38764",
"TemplateId": "template-abc123",
}
params["Signature"] = _sign_v1(params, sk)响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 错误码 |
|
HttpStatusCode | integer | 状态码 |
|
RequestId | string | 请求 ID |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
UploadUrl | string | 文件上传 URL,用于将文件上传至对象存储 |
|
UploadHeadersHint | string | 上传请求的 Header 提示信息 |
|
SandboxPath | string | 文件在沙箱内的路径 |
|
FileKey | string | 文件标识,调用 SyncContext 时传入。格式为 |
|
响应示例
成功:
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"UploadUrl": "https://oss-example.aliyuncs.com/upload/...",
"UploadHeadersHint": "...",
"SandboxPath": "/home/wuying/jvscrew/uploads/report_a1b2c3d4.pdf",
"FileKey": "uploads/report_a1b2c3d4.pdf"
}SyncContext - 同步 Context 的指定文件到沙箱
接口描述
同步指定用户的 Context 中指定文件内容到沙箱环境,使沙箱中的用户数据与 Context 保持同步。
请求信息
认证方式:POP V1 签名(AK/SK),与 GetAccessToken 相同
Action:
SyncContext
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
ExternalUserId | string | 是 | 外部系统用户唯一标识 |
|
FileKey | string | 是 | 文件标识,由 GetChatFileUploadUrl 返回 |
|
TemplateId | string | 否 | Agent 模板 ID |
|
请求示例
params = {
"Format": "JSON",
"Version": "2026-03-11",
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": _now_utc(),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "SyncContext",
"RegionId": "cn-shanghai",
"ExternalUserId": "user-38764",
"FileKey": "uploads/report_a1b2c3d4.pdf",
"TemplateId": "template-abc123",
}
params["Signature"] = _sign_v1(params, sk)响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 错误码 |
|
HttpStatusCode | integer | 状态码 |
|
RequestId | string | 请求 ID |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
响应示例
成功:
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C"
}会话管理接口
ListSessions - 列举对话列表
接口描述
列举指定用户的会话列表。每个元素包含 SessionId,可用于查询历史、中止或删除会话。
请求信息
请求方法:
GET(也接受POST)
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
TemplateId | string | 否 | Agent 模板 ID,用于筛选 |
|
ExternalUserId | string | 是 | 外部系统用户唯一标识 |
|
Channel | string | 否 | 按渠道筛选 |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
Chats | array | 会话基本信息列表 | 见下方 |
AccessDeniedDetail | string | 鉴权失败详情 |
|
Chats 数组元素:
名称 | 类型 | 描述 | 示例值 |
Id | string | 会话 ID |
|
Name | string | 会话标题 |
|
SessionId | string | 会话标识,用于删除/停止等操作 |
|
UserId | string | 用户 ID |
|
Channel | string | 渠道名称 |
|
CreatedAt | string | 会话创建时间(ISO 8601) |
|
UpdatedAt | string | 会话最后更新时间(ISO 8601) |
|
Meta | map | 扩展元数据 |
|
响应示例
成功:
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"Chats": [
{
"Id": "4bd0****02f",
"Name": "你好",
"SessionId": "curl-test-session-********",
"UserId": "u-open-************",
"Channel": "console",
"CreatedAt": "2026-03-26T03:51:42.071603Z",
"UpdatedAt": "2026-03-26T03:52:03.000000Z",
"Meta": {}
}
]
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
401 | Unauthorized | 未授权 | AccessToken 无效或已过期 |
ListSessionHistory - 列举对话历史明细
接口描述
根据 SessionId 获取指定会话的历史消息列表,包含用户消息和 AI 回复。
请求信息
请求方法:
GET(也接受POST)
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
TemplateId | string | 否 | Agent 模板 ID |
|
SessionId | string | 是 | 要获取历史的会话 ID |
|
ExternalUserId | string | 是 | 外部系统用户唯一标识 |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
Messages | array | 会话消息列表 | 见下方 |
AccessDeniedDetail | string | 鉴权失败详情 |
|
Messages 数组元素:
名称 | 类型 | 描述 | 示例值 |
Id | string | 消息唯一标识 |
|
Role | string | 消息角色 |
|
Type | string | 消息类型 |
|
Object | string | 对象类型 |
|
Status | string | 消息状态 |
|
Error | string | 错误信息(如有) |
|
SequenceNumber | string | 序号 |
|
Content | array | 内容块列表 | 见下方 |
Metadata | map | 扩展元数据 |
|
Content 数组元素:
名称 | 类型 | 描述 | 示例值 |
Object | string | 对象类型 |
|
Status | string | 状态 |
|
Error | string | 错误信息 |
|
MsgId | string | 所属消息 ID |
|
Text | string | 文本内容 |
|
Data | string | 结构化数据(工具调用等) |
|
SequenceNumber | string | 序号 |
|
响应示例
成功:
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "123***456",
"Messages": [
{
"Id": "msg_5e8d****aa1d",
"Role": "user",
"Type": "message",
"Object": "message",
"Status": "completed",
"Error": null,
"SequenceNumber": null,
"Content": [
{
"Object": "content",
"Status": "completed",
"Error": null,
"MsgId": "msg_5e8d****aa1d",
"Text": "你好",
"Data": null,
"SequenceNumber": null
}
],
"Metadata": {
"OriginalId": "msg_20e8****8ff3",
"OriginalName": "user"
}
},
{
"Id": "msg_8574****0563",
"Role": "assistant",
"Type": "message",
"Object": "message",
"Status": "completed",
"Error": null,
"SequenceNumber": null,
"Content": [
{
"Object": "content",
"Status": "completed",
"Error": null,
"MsgId": "msg_8574****0563",
"Text": "你好,小伙伴!有什么我可以帮你的吗?",
"Data": null,
"SequenceNumber": null
}
],
"Metadata": {
"OriginalId": "dXRT****MUV",
"OriginalName": "JVSCrewAgent"
}
}
]
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
401 | Unauthorized | 未授权 | AccessToken 无效或已过期 |
StopSession - 中止对话
接口描述
中止正在执行的 Agent 对话任务。调用后 Agent 将立即停止推理和工具执行,不再产生新的 Token 输出。适用于主动取消长时间运行的任务,或需要立即终止 Agent 的场景。
中止机制:服务端取消 Agent 执行任务,断开与大模型的连接,确保不再产生 Token。已完成的对话历史保留不变,后续可在同一 SessionId 下继续对话。
请求信息
请求方法:
POST(也接受GET)Content-Type:
application/json
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
TemplateId | string | 否 | Agent 模板 ID |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
Content-Type | string | 是 | 请求内容类型 |
|
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
SessionId | string | 是 | 要中止的会话 ID |
|
请求体示例
{
"SessionId": "test-session-001"
}响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
Stopped | boolean | 是否成功中止了正在运行的任务。 |
|
响应示例
成功(任务已中止):
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"Stopped": true
}成功(当前无运行中任务):
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "FA23****-****-****-****-****D4B",
"Stopped": false
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
401 | Unauthorized | 未授权 | AccessToken 无效或已过期 |
503 | ServiceUnavailable | 服务不可用 | Task tracker 未初始化 |
DeleteSession - 删除对话
接口描述
根据 SessionId 删除对话记录,包括对话元数据和会话状态文件。删除后该会话的历史消息清空且无法恢复。
请求信息
请求方法:
POSTContent-Type:
application/json
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
TemplateId | string | 否 | Agent 模板 ID |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
Content-Type | string | 是 | 请求内容类型 |
|
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
SessionId | string | 是 | 要删除的会话 ID |
|
请求体示例
{
"SessionId": "test-session-001"
}响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
Deleted | boolean | 是否成功删除 |
|
响应示例
成功:
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"Deleted": true
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
401 | Unauthorized | 未授权 | AccessToken 无效或已过期 |
500 | InternalError | 会话不存在或删除失败 | 指定的 SessionId 未找到对应的对话记录,或服务端异常 |
GetSandboxInfo - 获取沙箱会话信息
接口描述
获取当前用户沙箱会话状态与资源地址。可判断沙箱是否已激活,并获取沙箱的资源访问 URL 和会话标识。
请求信息
请求方法:
GET(也接受POST)
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
请求参数
无额外请求参数。用户身份通过 JWT 令牌自动携带。
响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
ResourceUrl | string | 沙箱流化画面访问 URL |
|
SandboxSessionId | string | 沙箱会话 ID |
|
SessionActive | string | 沙箱会话是否激活 |
|
响应示例
成功(沙箱已激活):
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"ResourceUrl": "https://jvscrew.example.com/resource/...",
"SandboxSessionId": "session-abc123",
"SessionActive": "true"
}成功(沙箱未激活):
{
"Success": true,
"Code": "200",
"HttpStatusCode": 200,
"RequestId": "FA23****-****-****-****-****D4B",
"ResourceUrl": null,
"SandboxSessionId": null,
"SessionActive": "false"
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
401 | Unauthorized | 未授权 | AccessToken 无效或已过期 |
计费查询接口
计费查询接口使用 AK/SK 签名认证(与 GetAccessToken 相同),无需先获取 AccessToken。
GetBillingOverview - 获取计费概览
接口描述
获取租户当月计费概览,包含消耗积分、会话数和平均消耗等指标。
请求信息
认证方式:POP V1 签名(AK/SK),与 GetAccessToken 相同
Action:
GetBillingOverview
请求参数
无额外请求参数。租户身份通过 AK/SK 自动识别。
请求示例
params = {
"Format": "JSON",
"Version": "2026-03-11",
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": _now_utc(),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "GetBillingOverview",
"RegionId": "cn-shanghai",
}
params["Signature"] = _sign_v1(params, sk)响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
MonthlyCredit | float | 当月已消耗积分(Credit) |
|
MonthlySessions | integer | 当月会话总数 |
|
AvgCreditPerSession | float | 单会话平均消耗 |
|
CycleStart | string | 账单周期起始日(ISO 8601) |
|
CycleEnd | string | 账单周期结束日(ISO 8601) |
|
响应示例
成功:
{
"Success": true,
"Code": "ok",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"MonthlyCredit": 125.50,
"MonthlySessions": 42,
"AvgCreditPerSession": 2.99,
"CycleStart": "2026-04-01T00:00:00Z",
"CycleEnd": "2026-04-30T23:59:59Z"
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
401 | Unauthorized | 未授权 | AK/SK 无效 |
500 | InternalError | 服务内部错误 | 服务端异常,请稍后重试 |
ListUserConsumption - 查询用户消耗明细
接口描述
按用户查询当月消耗明细,支持分页和按外部用户 ID 过滤。
请求信息
认证方式:POP V1 签名(AK/SK),与 GetAccessToken 相同
Action:
ListUserConsumption
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
ExternalUserIds | string | 否 | 按外部用户 ID 过滤,多个用逗号分隔 |
|
PageSize | integer | 否 | 每页数量,默认 20,最大 100 |
|
PageNumber | integer | 否 | 页码,从 1 开始,默认 1 |
|
请求示例
params = {
"Format": "JSON",
"Version": "2026-03-11",
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": _now_utc(),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "ListUserConsumption",
"RegionId": "cn-shanghai",
"ExternalUserIds": "alice,bob",
"PageSize": "20",
"PageNumber": "1",
}
params["Signature"] = _sign_v1(params, sk)响应参数
名称 | 类型 | 描述 | 示例值 |
Success | boolean | 是否成功 |
|
Code | string | 业务状态码 |
|
Message | string | 错误详情(失败时返回) |
|
HttpStatusCode | integer | HTTP 状态码 |
|
RequestId | string | 请求唯一标识 |
|
AccessDeniedDetail | string | 鉴权失败详情 |
|
Users | array | 用户消耗明细列表 | 见下方 |
TotalCount | integer | 总用户数 |
|
PageSize | integer | 每页数量 |
|
PageNumber | integer | 当前页码 |
|
Users 数组元素:
名称 | 类型 | 描述 | 示例值 |
UserId | string | 用户内部标识 |
|
ExternalUserId | string | 外部用户标识(无则回退为 UserId) |
|
InstanceId | string | 实例 ID(用于售卖侧对账) |
|
MonthlyCredit | float | 当月消耗积分 |
|
MonthlySessions | integer | 当月会话数 |
|
MonthlyDurationHours | float | 当月使用时长(小时) |
|
MonthlyDurationMinutes | float | 当月使用时长(分钟) |
|
响应示例
成功:
{
"Success": true,
"Code": "ok",
"HttpStatusCode": 200,
"RequestId": "EA12****-****-****-****-****E5C",
"Users": [
{
"UserId": "u-open-abc123",
"ExternalUserId": "alice",
"InstanceId": "jvscrew-u-open-abc123",
"MonthlyCredit": 28.50,
"MonthlySessions": 12,
"MonthlyDurationHours": 3.25,
"MonthlyDurationMinutes": 195.00
},
{
"UserId": "u-open-def456",
"ExternalUserId": "bob",
"InstanceId": "jvscrew-u-open-def456",
"MonthlyCredit": 15.00,
"MonthlySessions": 8,
"MonthlyDurationHours": 1.50,
"MonthlyDurationMinutes": 90.00
}
],
"TotalCount": 2,
"PageSize": 20,
"PageNumber": 1
}错误码
HttpCode | Error Code | 错误信息 | 说明 |
400 | InvalidPageSize | 参数错误 | PageSize 不能为负数 |
401 | Unauthorized | 未授权 | AK/SK 无效 |
500 | InternalError | 服务内部错误 | 服务端异常,请稍后重试 |
定时任务接口
定时任务 API 使用 JWT 令牌认证,与 Chat、ListSessions 等接口相同:先调用 GetAccessToken 获取 AccessToken,放入 Query 参数 Authorization=Bearer <token>。
CreateScheduledTask - 创建定时任务
接口描述
创建定时任务,支持 cron 表达式和固定间隔调度。
请求信息
认证方式:JWT 令牌(
AuthorizationQuery 参数)Action:
CreateScheduledTask
Query 参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Authorization | string | 是 | GetAccessToken 返回的 JWT,格式为 |
|
请求头(Header)
名称 | 类型 | 必填 | 描述 | 示例值 |
Content-Type | string | 是 | 请求内容类型 |
|
x-acs-version | string | 是 | API 版本 |
|
x-acs-action | string | 是 | API 操作名称 |
|
x-acs-date | string | 是 | 请求时间(ISO 8601 格式) |
|
请求参数
名称 | 类型 | 必填 | 描述 | 示例值 |
Name | string | 是 | 任务名称 |
|
Instruction | string | 是 | 任务指令,Agent 按此指令执行 |
|
TemplateId | string | 否 | 模板 ID |
|
Schedule | object | 是 | 调度规则,见 Schedule 对象 | - |
Sinks | array | 否 | 推送渠道,见 Sinks 对象 | - |
请求示例
curl -X POST \
'https://wuyingai.cn-shanghai.aliyuncs.com/?Authorization=Bearer%20<access_token>' \
-H 'Content-Type: application/json' \
-H 'x-acs-version: 2026-03-11' \
-H 'x-acs-action: CreateScheduledTask' \
-H 'x-acs-date: 2026-04-22T06:00:00Z' \
-d '{
"Name": "每日技术简报",
"Instruction": "帮我总结今天的技术新闻",
"Schedule": {"Type": "cron", "Expr": "0 9 * * *", "Timezone": "Asia/Shanghai"},
"Sinks": [{"Sink": "im_push", "Channel": "dingtalk", "ChannelInstanceId": "", "TargetUserId": "<user>", "TargetSessionId": "", "Meta": {}}]
}'
响应参数(Task 对象)
所有返回 Task 的接口(Create / Update / Get)共用以下结构:
名称 | 类型 | 描述 |
TaskId | string | 任务唯一标识 |
TemplateId | string | 模板 ID |
ExternalUserId | string | 外部用户 ID |
Name | string | 任务名称 |
Status | string | 任务状态( |
Instruction | string | 任务指令 |
Schedule | object | 调度配置 |
Sinks | array | 推送渠道配置 |
NextRunAt | string | 下次执行时间(ISO 8601) |
LastRunAt | string | 上次执行时间(新创建时为 null) |
LastError | string | 最近错误信息(新创建时为 null) |
CreatedAt | string | 创建时间(ISO 8601) |
UpdatedAt | string | 更新时间(ISO 8601) |
POP 网关自动过滤值为 null 的字段,因此 LastRunAt 和 LastError 在新创建的任务响应中可能不出现。
响应示例
{
"TaskId": "bd0f7607-538c-47b4-9b1e-380e12947640",
"TemplateId": "template-zc9ecvdf",
"ExternalUserId": "verify-schedule-user",
"Name": "每日技术简报",
"Status": "active",
"Instruction": "帮我总结今天的技术新闻",
"Schedule": {"Type": "cron", "Expr": "0 9 * * *", "Timezone": "Asia/Shanghai"},
"Sinks": [],
"NextRunAt": "2026-04-22T09:00:00",
"CreatedAt": "2026-04-21T23:32:53",
"UpdatedAt": "2026-04-21T23:32:53"
}UpdateScheduledTask - 更新定时任务
接口描述
更新指定定时任务的配置。
请求信息
认证方式:JWT 令牌(
AuthorizationQuery 参数),与 CreateScheduledTask 相同Action:
UpdateScheduledTask
Query 参数和请求头与 CreateScheduledTask 相同,x-acs-action 改为 UpdateScheduledTask。
请求参数
名称 | 类型 | 必填 | 描述 |
TaskId | string | 是 | 要更新的任务 ID |
Name | string | 是 | 新的任务名称 |
Instruction | string | 是 | 新的任务指令 |
TemplateId | string | 否 | 模板 ID |
Schedule | object | 是 | 新的调度规则 |
Sinks | array | 否 | 新的推送渠道配置 |
响应参数
同 CreateScheduledTask 响应(Task 对象)。
GetScheduledTask - 查询任务详情
接口描述
根据 TaskId 查询定时任务详情。
请求信息
认证方式:JWT 令牌(
AuthorizationQuery 参数),与 CreateScheduledTask 相同Action:
GetScheduledTask
Query 参数和请求头与 CreateScheduledTask 相同,x-acs-action 改为 GetScheduledTask。
请求参数
名称 | 类型 | 必填 | 描述 |
TaskId | string | 是 | 任务 ID |
TemplateId | string | 否 | 模板 ID |
响应参数
同 CreateScheduledTask 响应(Task 对象)。
ListScheduledTasks - 分页列举任务
接口描述
分页列举当前用户的定时任务。
请求信息
认证方式:JWT 令牌(
AuthorizationQuery 参数),与 CreateScheduledTask 相同Action:
ListScheduledTasks
Query 参数和请求头与 CreateScheduledTask 相同,x-acs-action 改为 ListScheduledTasks。
请求参数
名称 | 类型 | 必填 | 描述 |
TemplateId | string | 否 | 按模板过滤 |
PageNumber | integer | 否 | 页码,默认 1 |
PageSize | integer | 否 | 每页条数,默认 20,最大 100 |
响应参数
名称 | 类型 | 描述 |
Tasks | array | 任务列表,每个元素为 Task 对象 |
TotalCount | integer | 总数 |
PageNumber | integer | 当前页码 |
PageSize | integer | 每页条数 |
POP 网关过滤值为 0 或 null 的字段,空列表时 TotalCount、PageNumber、PageSize 可能不出现。
响应示例
{
"Tasks": [
{
"TaskId": "bd0f7607-538c-47b4-9b1e-380e12947640",
"Name": "每日技术简报",
"Status": "active",
"NextRunAt": "2026-04-22T09:00:00"
}
],
"TotalCount": 1,
"PageNumber": 1,
"PageSize": 20
}DeleteScheduledTask - 删除任务
接口描述
删除指定的定时任务。
请求信息
认证方式:JWT 令牌(
AuthorizationQuery 参数),与 CreateScheduledTask 相同Action:
DeleteScheduledTask
Query 参数和请求头与 CreateScheduledTask 相同,x-acs-action 改为 DeleteScheduledTask。
请求参数
名称 | 类型 | 必填 | 描述 |
TaskId | string | 是 | 要删除的任务 ID |
响应参数
名称 | 类型 | 描述 |
Deleted | boolean | 是否删除成功 |
响应示例
{"Deleted": true}ListScheduledTaskRuns - 查询执行记录
接口描述
查询定时任务的执行记录列表,支持游标分页。
请求信息
认证方式:JWT 令牌(
AuthorizationQuery 参数),与 CreateScheduledTask 相同Action:
ListScheduledTaskRuns
Query 参数和请求头与 CreateScheduledTask 相同,x-acs-action 改为 ListScheduledTaskRuns。
请求参数
名称 | 类型 | 必填 | 描述 |
TaskId | string | 否 | 按任务 ID 过滤 |
Since | string | 否 | 起始时间戳(毫秒),仅返回之后的记录 |
Cursor | string | 否 | 分页游标,来自上一次响应的 NextCursor |
PageSize | integer | 否 | 每页条数,默认 50,最大 200 |
响应参数
名称 | 类型 | 描述 |
Runs | array | 执行记录列表 |
NextCursor | string | 下一页游标,为 null 时表示无更多数据 |
Runs 数组元素:
名称 | 类型 | 描述 |
RunId | string | 执行记录唯一标识 |
TaskId | string | 所属任务 ID |
TemplateId | string | 模板 ID |
Status | string | 执行状态: |
ResultPayload | string | 执行结果内容(仅 succeeded 时有值) |
ErrorMessage | string | 错误信息(仅 failed 时有值) |
PushSink | string | 推送渠道类型 |
PushStatus | string | 推送状态: |
StartedAt | string | 开始时间 |
FinishedAt | string | 结束时间 |
CreatedAt | string | 记录创建时间 |
响应示例
{
"Runs": [
{
"RunId": "run-abc123",
"TaskId": "bd0f7607-538c-47b4-9b1e-380e12947640",
"TemplateId": "template-zc9ecvdf",
"Status": "succeeded",
"ResultPayload": "今日技术要闻:...",
"PushStatus": "succeeded",
"StartedAt": "2026-04-22T09:00:01",
"FinishedAt": "2026-04-22T09:02:35",
"CreatedAt": "2026-04-22T09:00:00"
}
],
"NextCursor": null
}定时任务数据结构
Schedule 对象
字段 | 类型 | 描述 |
Type | string | 调度类型: |
Expr | string | 调度表达式,格式取决于 Type |
Timezone | string | 时区,如 |
Type 与 Expr 对照表:
Type | Expr 格式 | 示例 | 说明 |
cron | 标准 cron 表达式 |
| 每天早上 9 点 |
cron | 标准 cron 表达式 |
| 工作日早上 9 点 |
interval | 数字+单位 |
| 每 10 分钟 |
interval | 数字+单位 |
| 每 2 小时 |
Sinks 对象
字段 | 类型 | 描述 |
Sink | string | 推送方式,当前支持 |
Channel | string | 渠道类型,如 |
ChannelInstanceId | string | 渠道实例 ID |
TargetUserId | string | 目标用户 ID |
TargetSessionId | string | 目标会话 ID |
Meta | object | 渠道扩展元数据 |
未配置 Sinks 时,任务仍正常执行,结果通过 ListScheduledTaskRuns 的 ResultPayload 字段拉取。
Run 状态流转
running → succeeded(执行成功)
→ failed(执行失败)推送状态(PushStatus)
状态 | 说明 |
pending | 等待推送 |
succeeded | 推送成功 |
failed | 推送失败 |
skipped | 未配置 Sinks,跳过推送 |
定时任务错误码
HttpCode | 说明 | 排查建议 |
400 | 请求参数错误 | 检查必填参数、Schedule/Sinks 格式 |
401 | 认证失败 | 检查 Bearer Token 是否有效或已过期 |
404 | 资源不存在 | 确认 TaskId 是否正确 |
使用示例
Python
完整的示例代码请参考:
#!/usr/bin/env python3
""" JVS Crew Chat 示例 - 使用 POP V1 签名
使用前需要提供以下信息:
1. 阿里云 AK/SK(必需)
- 获取方式:阿里云 RAM 控制台 → AccessKey 管理 → 创建 AccessKey
- 配置方式:在项目根目录 .env 文件中添加:
ALIBABA_CLOUD_ACCESS_KEY_ID=你的 AK
ALIBABA_CLOUD_ACCESS_KEY_SECRET=你的 SK
- 注意:建议使用 RAM 子用户的 AK/SK,避免使用主账号
2. 可选配置项(修改下方代码中的常量)
- ENDPOINT: API 端点地址,默认 cn-shanghai
- REGION_ID: 地域 ID,默认 cn-shanghai
- EXTERNAL_USER_ID: 外部用户 ID,用于标识对话用户
- USER_MESSAGE: 要发送的消息内容
运行方式:
pip install requests python-dotenv
python jvscrew_chat_example.py
"""
import base64
import hashlib
import hmac
import json
import os
import time
import urllib.parse
import uuid
from datetime import datetime, timezone
import requests
from dotenv import load_dotenv
# 加载当前目录的 .env 文件
load_dotenv()
# ============ 配置 ============
ENDPOINT = "https://wuyingai.cn-shanghai.aliyuncs.com"
API_VERSION = "2026-03-11"
REGION_ID = "cn-shanghai"
EXTERNAL_USER_ID = "test-user-example"
USER_MESSAGE = "你好"
# ============ V1 签名实现 ============
def _pct(s: str) -> str:
"""RFC 3986 URL 编码"""
return urllib.parse.quote(str(s), safe="-_.~")
def _now_utc() -> str:
"""UTC 时间戳"""
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
def _sign_v1(params: dict, sk: str) -> str:
"""计算阿里云 POP V1 签名"""
# 1. 参数排序 + URL 编码
pairs = [
f"{_pct(k)}={_pct(str(v))}"
for k, v in sorted(params.items())
if k != "Signature"
]
canonical = "&".join(pairs)
# 2. 构造待签名字符串
string_to_sign = f"POST&{_pct('/')}&{_pct(canonical)}"
# 3. HMAC-SHA1 签名
key = (sk + "&").encode("utf-8")
signature = base64.b64encode(
hmac.new(key, string_to_sign.encode("utf-8"), hashlib.sha1).digest()
).decode("ascii")
return signature
def get_access_token(ak: str, sk: str, external_user_id: str) -> str:
"""获取 AccessToken(使用 V1 签名)"""
params = {
"Format": "JSON",
"Version": API_VERSION,
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": _now_utc(),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "GetAccessToken",
"RegionId": REGION_ID,
"ExternalUserId": external_user_id,
}
# 计算签名
params["Signature"] = _sign_v1(params, sk)
# 发送请求
url = f"{ENDPOINT}/?{urllib.parse.urlencode(params)}"
resp = requests.post(
url, headers={"Accept": "application/json"}, timeout=60)
resp.raise_for_status()
data = resp.json()
if not data.get("Success") and data.get("Code") not in ("200", "Success", None):
raise RuntimeError(f"GetAccessToken failed: {data}")
token = data.get("AccessToken")
if not token:
raise RuntimeError(f"No AccessToken in response: {data}")
return token
def chat_sse(jwt: str, external_user_id: str, session_id: str, text: str):
"""发起 Chat SSE 对话"""
url = f"{ENDPOINT}/api/agent/chat?Authorization={urllib.parse.quote(f'Bearer {jwt}')}"
payload = {
"ExternalUserId": external_user_id,
"SessionId": session_id,
"Input": json.dumps(
[{"Role": "user", "Content": [{"Type": "text", "Text": text}]}],
ensure_ascii=False,
),
}
headers = {
"Content-Type": "application/json",
"Accept": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"x-acs-version": API_VERSION,
"x-acs-action": "Chat",
"x-acs-date": _now_utc(),
}
resp = requests.post(url, json=payload, headers=headers,
stream=True, timeout=300)
resp.raise_for_status()
# 处理 SSE 流
# current_phase 用于区分 reasoning(思考)和 message(正式回复)阶段
current_phase = None # "reasoning" 或 "message"
for line in resp.iter_lines():
if not line:
continue
line = line.decode("utf-8")
if not line.startswith("data:"):
continue
raw = line[5:].strip()
if raw == "[DONE]":
break
try:
ev = json.loads(raw)
except json.JSONDecodeError:
continue
if not isinstance(ev, dict):
continue
obj = ev.get("Object") or ev.get("object")
typ = ev.get("Type") or ev.get("type")
status = ev.get("Status") or ev.get("status")
# 跟踪当前阶段:reasoning(思考)或 message(正式回复)
if obj == "message" and typ in ("reasoning", "message"):
current_phase = typ
# 只输出正式回复阶段的增量 content,跳过 reasoning 内容
if obj == "content" and typ == "text" and status == "in_progress":
if current_phase == "message":
text_content = ev.get("Text") or ev.get("text") or ""
print(text_content, end="", flush=True)
elif obj == "error":
print(f"\n错误: {json.dumps(ev, ensure_ascii=False)}")
break
elif obj == "response" and status == "completed":
print("\n对话完成")
break
print()
def main():
# 从环境变量读取 AK/SK
ak = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID", "").strip()
sk = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET", "").strip()
if not ak or not sk:
raise RuntimeError(
"请设置环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET\n"
"或在项目根目录 .env 文件中配置"
)
print(f"使用 AK: {ak[:8]}...")
print(f"ExternalUserId: {EXTERNAL_USER_ID}")
print(f"发送消息: {USER_MESSAGE}")
print("-" * 50)
# 1. 获取 Token
print("正在获取 AccessToken...")
token = get_access_token(ak, sk, EXTERNAL_USER_ID)
print(f"Token 获取成功")
# 2. 发起对话
session_id = f"session-{int(time.time() * 1000)}"
print(f"SessionId: {session_id}")
print("-" * 50)
print("AI 回复:")
chat_sse(token, EXTERNAL_USER_ID, session_id, USER_MESSAGE)
if __name__ == "__main__":
main()文件上传完整示例
将本地文件上传到 Context 存储并同步到沙箱,需要依次完成三步:获取上传地址 → PUT 上传文件 → 同步到沙箱。
import hashlib
import hmac
import base64
import urllib.parse
import uuid
import requests
from datetime import datetime, timezone
def _pct(s: str) -> str:
return urllib.parse.quote(str(s), safe="-_.~")
def _now_utc() -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
def _sign_v1(params: dict, sk: str) -> str:
pairs = [
f"{_pct(k)}={_pct(str(v))}"
for k, v in sorted(params.items())
if k != "Signature"
]
canonical = "&".join(pairs)
string_to_sign = f"POST&{_pct('/')}&{_pct(canonical)}"
key = (sk + "&").encode("utf-8")
return base64.b64encode(
hmac.new(key, string_to_sign.encode("utf-8"), hashlib.sha1).digest()
).decode("ascii")
ENDPOINT = "https://wuyingai.cn-shanghai.aliyuncs.com"
API_VERSION = "2026-03-11"
REGION_ID = "cn-shanghai"
def get_chat_file_upload_url(ak, sk, file_name, external_user_id, template_id=""):
"""步骤一:获取文件上传地址"""
params = {
"Format": "JSON", "Version": API_VERSION, "AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1", "Timestamp": _now_utc(),
"SignatureVersion": "1.0", "SignatureNonce": str(uuid.uuid4()),
"Action": "GetChatFileUploadUrl", "RegionId": REGION_ID,
"FileName": file_name, "ExternalUserId": external_user_id,
}
if template_id:
params["TemplateId"] = template_id
params["Signature"] = _sign_v1(params, sk)
url = f"{ENDPOINT}/?{urllib.parse.urlencode(params)}"
resp = requests.post(url, headers={"Accept": "application/json"}, timeout=60)
resp.raise_for_status()
data = resp.json()
if not data.get("Success"):
raise RuntimeError(f"GetChatFileUploadUrl failed: {data}")
return data
def upload_file_to_oss(upload_url, file_path):
"""步骤二:将文件 PUT 上传到预签名 URL"""
with open(file_path, "rb") as f:
file_content = f.read()
resp = requests.put(upload_url, data=file_content, timeout=120)
resp.raise_for_status()
def sync_context(ak, sk, external_user_id, file_key, template_id=""):
"""步骤三:同步文件到沙箱"""
params = {
"Format": "JSON", "Version": API_VERSION, "AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1", "Timestamp": _now_utc(),
"SignatureVersion": "1.0", "SignatureNonce": str(uuid.uuid4()),
"Action": "SyncContext", "RegionId": REGION_ID,
"ExternalUserId": external_user_id, "FileKey": file_key,
}
if template_id:
params["TemplateId"] = template_id
params["Signature"] = _sign_v1(params, sk)
url = f"{ENDPOINT}/?{urllib.parse.urlencode(params)}"
resp = requests.post(url, headers={"Accept": "application/json"}, timeout=60)
resp.raise_for_status()
data = resp.json()
if not data.get("Success"):
raise RuntimeError(f"SyncContext failed: {data}")
return data
def upload_and_sync(ak, sk, local_file_path, external_user_id, template_id=""):
"""完整的文件上传流程,返回文件在沙箱中的路径"""
file_name = local_file_path.split("/")[-1]
print(f"正在获取文件上传地址: {file_name}")
upload_info = get_chat_file_upload_url(ak, sk, file_name, external_user_id, template_id)
upload_url = upload_info["UploadUrl"]
file_key = upload_info["FileKey"]
sandbox_path = upload_info["SandboxPath"]
print(f"FileKey: {file_key}, SandboxPath: {sandbox_path}")
print(f"正在上传文件到对象存储...")
upload_file_to_oss(upload_url, local_file_path)
print("文件上传完成")
print(f"正在同步文件到沙箱...")
sync_context(ak, sk, external_user_id, file_key, template_id)
print(f"文件已同步到沙箱路径: {sandbox_path}")
return sandbox_path
if __name__ == "__main__":
import os
ak = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID", "").strip()
sk = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET", "").strip()
sandbox_path = upload_and_sync(
ak=ak, sk=sk, local_file_path="/path/to/report.pdf",
external_user_id="user-38764", template_id="template-abc123",
)
print(f"文件已就绪,沙箱路径: {sandbox_path}")