集成与上线

API 与 Webhook

一个端点即可从你自己的代码里运行集群:POST /api/swarm/run。配套限定范围的密钥、幂等重试,以及针对慢于一次请求的场景的签名回调。

API 密钥

从该集群的 部署 对话框创建。密钥形如 sk_swarm_… ,而密文只显示 一次 ——它以哈希形式存储,无法恢复,只能轮换。

属性取值说明
scopesrun, read_runs默认为 ['run']。数据库约束会拒绝其他任何取值,因此拼写错误在写入时就失败,而不是静默地什么都不授权。
expires_attimestamp / null可选的过期时间。为某个特定集成用的密钥设一个。
revoked_attimestamp / null撤销立即生效——下一次请求即失败拒绝。
rotated_from密钥 id设在替代密钥上,这样你能看出是谁取代了谁。
last_used_iptext最近一次请求的源 IP——闲置的密钥一眼可辨,被盗的密钥可追溯。
reject_approvalsboolean设置后,遇到审批节点的运行会直接失败,而不是挂在那里等一个并没有在看的人。
webhook_secrettext用于给回调签名——见下文。
callback_urlurl该密钥的默认回调地址;可按请求覆盖。

POST /api/swarm/run

请求头

请求头必填说明
Authorization: Bearer sk_swarm_…是—
Content-Type: application/json是—
Idempotency-Key否由客户端指定。让重试返回原始结果,而不是重新运行一次。

请求体

字段类型用途
inputstring集群输入节点的自由文本输入。
inputsobject对于输入节点声明了结构化表单的集群:每个字段名对应一个键。
history{role, content}[]此前的对话轮次(user / assistant)。正是它把一个集群变成多轮聊天机器人。
asyncboolean设为 true 会立即返回,并把结果投递到回调地址。
callback_urlurl为本次运行覆盖该密钥的默认回调地址。

同步运行

bash
curl -X POST https://your-instance.example.com/api/swarm/run \
  -H "Authorization: Bearer $ZENSTUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-48213-summary" \
  -d '{
        "input": "Summarise ticket 48213 and suggest a reply",
        "inputs": { "priority": "high" }
      }'
200 响应
{
  "output": "The customer reports a faulty hinge …",
  "runId": "5f1c0f0e-…"
}

异步运行

bash
curl -X POST https://your-instance.example.com/api/swarm/run \
  -H "Authorization: Bearer $ZENSTUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "input": "Produce the weekly summary",
        "async": true,
        "callback_url": "https://api.example.com/hooks/zenstudio"
      }'
202 响应
{
  "accepted": true,
  "callback_url": "https://api.example.com/hooks/zenstudio"
}

凡是耗时超出一次请求应有时长的场景都用异步——长图、审批关卡、大文档。

状态码

代码含义该怎么办
200运行已完成(同步)读取 output 和 runId。
202已接受(异步)等待回调。
401密钥缺失、无效、已停用或已过期检查密钥;不要盲目重试。
402超出预算上限触到消费上限——参见 预算.
404找不到该集群该密钥对应的集群已被删除。
409使用该 Idempotency-Key 的运行仍在进行中退避后重试;不要发起第二次运行。
422同一个 Idempotency-Key 配了不同的请求体这是客户端的缺陷——要么复用完全相同的请求体,要么换一个新键。
429超出速率限制放慢速度后重试。

幂等性

发送一个 Idempotency-Key ,之后用同一个键重试会返回原始结果,而不是再跑一遍集群。

为什么这样设计

网络往往是在服务端已经把活干完之后才出问题。没有幂等性时,你的重试逻辑加上平台照跑不误的态度,会让一个客户事件触发三次模型运行——三倍成本,三份互相矛盾的输出。请从你正在处理的那个对象派生出键(order-48213-summary),绝不要每次尝试都用一个随机值,否则每次重试都是一次全新的运行。
情形结果
同键、同请求体,首次调用已完成返回 200 及此前保存的原始响应
同键、同请求体,首次调用仍在运行返回 409——不要发起第二次运行
同键、请求体不同返回 422——明确拒绝,而不是返回一个对不上的结果

幂等记录只保留一段有限的时间窗,之后会被清理。

限额

上限用途
速率限制每个密钥每个时间窗内的请求数,超出返回 429。
并发每个密钥的并发运行数——这一项保护的是你的提供商配额。
运行超时挂钟时间上限,这样带环的图不会永远跑下去。
预算上限每个密钥的消费上限,超出返回 402。参见 预算.

这些限制在所有实例间统一生效

速率限制和并发槽位在 Postgres 里计数,而不是在各个应用进程里,因此无论你的负载均衡后面有多少实例,配置的数就是实际生效的数。如果数据库短时不可达,实例会退回本地计数并记录这一点——那一刻限制会变弱,但不会消失。

Webhook 回调

每次投递都会带上以下请求头:

请求头取值
X-ZenStudio-Eventswarm.run.completed
X-ZenStudio-TimestampUnix 秒级时间戳,包含在签名内容中
X-ZenStudio-Signaturesha256=<hex> ——对 <timestamp>.<body> 做 HMAC-SHA256,使用该密钥的 Webhook 密钥

投递最多重试 3 次,每次尝试超时 15 秒。

校验签名

javascript
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, headers, secret) {
  const ts  = headers["x-zenstudio-timestamp"];
  const sig = headers["x-zenstudio-signature"]; // "sha256=<hex>"

  // Reject old timestamps FIRST — this is what stops a captured
  // delivery being replayed at you weeks later.
  const age = Math.abs(Date.now() / 1000 - Number(ts));
  if (!Number.isFinite(age) || age > 300) return false;

  const expected =
    "sha256=" + createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");

  const a = Buffer.from(expected);
  const b = Buffer.from(sig ?? "");
  // Constant-time: a plain === leaks the answer through timing.
  return a.length === b.length && timingSafeEqual(a, b);
}
  • 签名要针对 原始 请求体,在任何 JSON 解析之前——重新序列化会改变字节内容,签名就对不上了。
  • 尽快返回 2xx,把实际工作异步处理;响应慢的端点会被重试。
  • 把你的处理逻辑写成幂等的——重试可能把同一个结果投递两次。

出网安全

回调 URL 在投递前会被校验:私有地址、回环地址和链路本地地址——包括云元数据端点——都会被拒绝。同一套防护覆盖平台代你发出的每一个出站请求,包括 web_browse、集群 HTTP 节点和 MCP 端点,因此由模型选定的 URL 无法被用来探入你的内网。

遇到审批节点的运行

带有 审批节点 的集群会等人。对无人值守的集成来说那就是卡住,所以请在密钥上设置 reject_approvals ,让这类运行改为快速失败。无论哪种情况,审批都是失败即拒绝——运行绝不会因为超时而越过某个关卡。

查看发生了什么

每次由 API 触发的运行都会产生一条完整追踪,归属到触发它的那个密钥,可在此查看: 追踪记录,成本归属可在此查看: 分析。某个集成行为异常时,先从那里查,而不是先翻自己的日志——追踪会显示解析后的提示词和每一次工具调用。

调用笔记本而不是集群

位于 开发者工作区 的笔记本可以用同样的方式发布:在笔记本上点击 发布 生成一个 nbk_… 密钥,然后 POST /api/notebook/run ,带上 {"inputs": {…}}。请求体会到达笔记本的入口函数,其返回值作为响应返回;长时间运行会交回一个 runId ,可在此轮询: /api/notebook/run/status。当逻辑本来就是笔记本里已经跑通的 Python、且没必要先改造成集群时,用它。