Script
设想您经营一家服装网店。每次上架商品时,都要一条条写出吸引人的详细说明,实在麻烦。于是您希望只要填入商品名和关键词,就让 AI 代您写好详细说明。可是,要调用那个 AI 写作服务,需要一把密钥(access token,外部服务凭它确认“是不是付过费的用户”)。如果把这把密钥放进客人看到的网站(浏览器)里,任何人都能把它取出来,于是就泄露了。别人拿着泄露的密钥,就可能随意使用这项服务,费用却要您来承担。
因此,您需要这样一个东西:它把密钥藏在客人看不到的地方,代替网站去调用 AI,再把结果填进商品里。Script 就是它。Script 就是把要做的事按顺序写下来,比如“用这把密钥调用 AI,把得到的文字填进这件商品的详细说明里”。它不是用代码,而是用一种固定格式(JSON,一种用花括号来书写条目和值的数据记法)来书写。网站只需通过互联网调用这个 Script 即可,而密钥藏在 Script 内部,客人是看不到的。
可以把它比作把事先写好的菜谱挂在厨房里。客人点了那道菜时(网站调用 Script 时),厨房(WEEGLOO)就照着菜谱上的顺序做好,把完成的菜端出来。店主只是把菜谱写好挂在那里,并不需要每来一单就亲自下厨。本页先来看 Script 是什么、长什么样、调用后会返回什么,然后以服装店的“填充商品说明” Script 为例,看看它的样子。最后,还会看看如何把这个 Script 接起来,让商品一上架它就自动执行。
Script 代劳的工作
哪怕只是填充一条商品说明,背后要做的事也有好几样。它要确认调用方是否有权限,检查发来的值是否正确,用藏起来的密钥去调用外部 AI 服务,把得到的结果放进想要的位置(商品的详细说明),再把响应返回。以前,做这些事的居中程序得您亲手打造、部署到服务器上并加以维护。Script 的目标,就是把这些事不用代码、集中写在一处,交由它来代办。
- 一个 Script 就是一个调用入口。 网站可以通过互联网调用的一个入口,就对应一个 Script。调用时所用的方式(
method)决定要执行哪个 Script。 - 要做的事从上到下依次排列。 Script 里按顺序写下要执行的动作。它们自上而下逐条执行,后一个动作会承接前一个动作的结果。
- 从预设的动作中挑选并组合。 它并不是让您塞进任意代码,而是从预先备好的动作(创建、读取、修改、删除资源,调用外部服务,暂存值,条件判断,循环等)中挑选出来,逐条排列。
用来写明该做什么的定义
一个 Script 由一份确定了三样东西的“定义”构成。
- 调用方式(
method):调用这个 Script 时所用的方式。取Get、Post、Put、Patch、Delete之一,调用时凭这个值来判定是哪个 Script。 - 要做的事(
statements):从上到下依次执行的动作列表。至少要有一个。 - 输入校验(
payloadSchema,可选):用来在执行前核对调用时随附发送的输入的格式。一旦设定,不符合格式的输入就不会执行,而是被退回。
下面以服装店的“填充商品说明” Script 为例。这个 Script 处理的,是一件包含商品名和关键词的商品。从网站传来的输入(在后面会看到的自动执行中,被上架的商品会原样传入)是这样的形状。
{
"sys": { "id": "3trmXRMKq7bd0Prbef1... (商品编号)" },
"fields": {
"productName": { "zh-CN": "不锈钢保温杯 500ml" },
"keywords": { "zh-CN": "保温、轻便、露营" }
}
}下面是接收这件商品、用外部 AI 生成详细说明,并填充该商品的详细说明(body)的 Script 定义。
{
"method": "Post",
"statements": [
{ "type": "Http", "method": "POST",
"url": "https://api.ai-writer.example.com/v1/generate",
"headers": [
{ "key": "Authorization", "value": "Bearer <秘密 access token>", "secret": true }
],
"body": {
"product": "{ /payload/fields/productName/zh-CN }",
"keywords": "{ /payload/fields/keywords/zh-CN }"
},
"name": "gen" },
{ "type": "ResourcePatch", "resource": "Content",
"target": { "sys": { "id": "{ /payload/sys/id }" } },
"fields": { "body": { "zh-CN": "{ /gen/body/text }" } },
"publish": true },
{ "type": "Return", "value": { "id": "{ /payload/sys/id }" }, "statusCode": 200 }
]
}- 第一个动作(
Http)用藏起来的密钥去调用外部 AI 服务。在装有密钥的请求头上加上secret: true,那个值就不会显示给客人,只在调用前的一刻才被解开。得到的结果被暂存到名为gen的地方。 - 第二个动作(
ResourcePatch)用前面得到的文字({ /gen/body/text })只填充该商品的详细说明(body),商品的其余值不会被触动。 - 使用把值传递到下一步的占位符
{ /… }。{ /payload/fields/productName/zh-CN }指向传入商品的名称,{ /payload/sys/id }指向该商品的编号,{ /gen/body/text }指向 AI 返回的文字。 - 最后一个动作(
Return)返回已填充说明的商品编号。 - 为什么 Content 的值要像
{ "zh-CN": … }这样按语言分别书写、statements中可以放入的动作的全部种类、以及占位符和条件、计算的语法,都在 值表达式 和 Statement 目录 中介绍。
调用后会返回什么
Script 在最后会把 Return 动作的值返回给调用方。返回的响应中包含以下内容。
requestId:指向本次执行的识别编号。durationMs:执行所花费的时间(毫秒)。statusCode:所到达的Return的状态码(不另行指定时为 200)。return或error:Return返回的值。通常放在return中;若把该值标记为错误,则放在error中。两者不会同时出现。
“填充商品说明”被调用后也是在当场执行,上面那样的响应会立即返回。只是其中含有调用外部 AI 的动作,因此在响应到来之前可能要等上几秒。一次执行可用的时间,在下文 留给执行的时间 中介绍。返回的响应是这样的形状。
{
"requestId": "3trmXRMZ8kqLb2Prdf1eYc0axWnKv",
"durationMs": 1840,
"statusCode": 200,
"return": { "id": "3trmXRMKq7bd0Prbef1... (商品编号)" }
}网站可以凭这个 return 中的 id 定位刚刚填好说明的商品,把新的详细说明展示给客人。
如果 Script 没有到达 Return 就结束了,那么 return 和 error 都不会有,只会返回 statusCode 为 200。关于用 Return 决定响应正文和状态码的详细规则,在 Statement 目录中的 Return 中介绍。
留给执行的时间
Script 在被调用的当场执行。调用方会直接以响应的形式拿到这次执行的结果。并没有“稍后再去查询结果”这样的流程。
一次执行可用的时间有预算。默认是 30 秒。如果其中含有调用外部服务的动作,预算就会按为那个动作定好的等待时间相应增加。这样增加也最多到 180 秒。
重复某件事的动作会大量占用预算。因为它是按循环内部动作定好的等待时间乘以循环次数来计算的。把循环次数定得越大,预算也就算得越大。
超过定好的时间,那次执行就会在那里中断。“填充商品说明”只调用外部 AI 一次,所以这个 Script 的预算就是默认的 30 秒再加上那一次的等待时间。
每个动作各占多少预算,以及执行上的其他约束,在 执行语义、约束与安全 中介绍。
Script 由谁来创建
与其让人一条条手写复杂的动作,Script 从设计上就是交给 AI 智能体或程序来创建的。只要用一句话拜托 AI 智能体“帮我做一个填充商品说明的入口”,智能体就会替您做出前面看到的那种定义。相当于一句话,就在网站背后多出一个干活的入口。
用 AI 智能体创建 Script 的详细流程,在 用一句话打造后端 中介绍。
创建好的 Script,由人在管理画面(内容工作室)中查看和管理。查看它的名称和定义,必要时进行修改或删除。实际调用 Script 的,是客人看到的网站或应用(前端)。以在产品中注册的会员(ServiceUser)身份,只能执行 Script,不能创建或修改。
与 Webhook 有何不同
Script 和 Webhook 都是与外部相连的装置,但调用的方向相反。
- Webhook 在预定的变化发生时(比如商品被上架)会自动作出反应。即使无人调用,只要事件发生就会自动行动。不过,它不会把结果返回给调用方。
- Script 是网站在需要时直接调用的入口。要调用才会执行,并会当即拿回这次执行的结果。
“店主一按下‘填充说明’,就调用 AI 取回详细说明并填入”,这是调用方在等待结果的事,所以适合用 Script;“商品一上架,就自动发生某件事”,这是对事件作出反应的事,所以适合用 Webhook。而且这两者可以搭配使用。下一节马上就会看到。
只要上架,说明就自动填好
到目前为止,都是店主按下“填充说明”按钮,亲自调用 Script。再往前一步,即使不按按钮,也可以让 Script 在上架商品的那一刻自动执行。因为 Webhook 会捕捉那个事件,代为调用我们的 Script。
流程是这样的。
- 店主上架商品。这时只填写商品名和关键词,详细说明留空。
- Webhook 察觉到有新商品被上架这一事件。
- Webhook 把刚上架的商品原样传给我们的“填充商品说明” Script 并执行。
- Script 用外部 AI 生成详细说明,填充该商品的详细说明(
body)。 - 稍过片刻,商品的详细说明就自动填好了。
这里用的 Script 与前面完全相同。改变的只是调用的契机。不再是按钮,而是“商品被上架”这一事件来调用。由于被上架的商品会原样成为 Script 的输入,Script 便用 { /payload/sys/id } 取到那件商品,填充其详细说明。
在 Webhook 一侧要设定的有三样:对什么事件作出反应(有新商品被上架时)、只对哪些商品作出反应(限定为某类商品),以及要做什么(不是向外部地址发送通知,而是调用我们的 Script)。
您也许会担心:Script 填好的详细说明,会不会又引发“商品被改动”这一事件,从而无休止地循环下去。不会的。除非另行开启,Script 的写入不会引发新的事件,平台也会阻止无休止的循环。
有些 Script 可以像这样只允许通过 Webhook 执行,而阻止从外部用地址直接调用。这样一来,那个 Script 就只会对预定的事件作出反应,直接调用则会被拒绝。设置方法在 Script 资源与端点 中介绍。
这样连接的详细设置,在 Webhook 中介绍。
Script 特别有用的场景
如果只是要向外部通知一声“发生了这样的事”,那么一个 Webhook 就足够了。但如果在调用外部服务之后,还要根据它返回的结果继续判断和处理,就需要一个把整个流程汇集到一处的 Script。
下面以一项付费生成 AI 图像的功能为例。当客人请求生成图像时,接下来这些事情需要按顺序发生。
- 确认客人的额度是否充足。如果不足,就在这里停下,并告知“额度不足”。
- 如果充足,就先按费用扣除相应的额度。
- 调用外部 AI 服务来生成图像。
- 把生成好的图像保存为 Content。
- 如果第 3 步或第 4 步出了问题,就把刚刚扣除的额度退还回去。
Webhook 虽然能向外部通知“有请求进来了”,却无法像这样根据结果来扣除额度,也无法在失败时回退。把多个步骤按条件衔接起来、并在失败时回退前面的步骤,这类工作则由 Script 来承担。Script 特别能发挥作用的场景如下。
- 需要根据结果继续处理时:根据外部服务返回的响应,当场判断是要保存、扣除,还是回退。
- 即使同时进来也不能出错时:同一位客人在很短的时间内请求两次,也不能把额度扣除两次。Script 会在读取值之后、就要保存之前,用版本号确认“这期间是否有别的请求改动过这个值”,一旦对不上就停下。
- 需要调用方本身没有的权限时:客人并没有权限自己直接修改额度余额。即便如此,扣除仍能安全地进行,是因为 Script 受托于创建者的权限来执行。对调用方,只需授予执行 Script 的权限即可。这一委托,下文 执行和管理的权限 会详细介绍。
至于如何把这个例子写成实际的 Script 定义,Cookbook 中会通过确认、扣除、退还额度的示例来介绍。
执行和管理的权限
要执行或管理 Script,角色(SpaceRole)中必须具备相应的权限。
- 执行:要调用 Script,角色中必须有 Script 的执行权限(Execute)。没有就无法执行。
- 管理:要创建、修改、删除 Script,分别需要创建、修改、删除权限。
执行 Script 时要确认的,只有一件:调用方是否具备执行权限(Execute)。Script 内部排列的各个动作,在执行的那一刻并不会另行确认权限。这就像调用一个已获准执行的程序时,只看是否有权执行这个程序,而不会对它内部所做的每一件事都逐一征得许可。
作为替代,各个动作的权限并不是在执行时确认,而是在 Script 保存时就预先确认。创建者必须实际拥有该 Script 内部动作所涉及的 Content、Media 操作权限,才能保存。例如“填充商品说明” Script 会修改商品 Content 的详细说明,因此如果创建者没有修改商品的权限,保存就会被退回。含有无权限动作的 Script,从一开始就无法保存。
这样看来,执行 Script 就相当于受托于创建者的权限、代为执行。即便是调用方自己并不具备的操作,只要是创建者能做的操作,就会通过 Script 照样发生。因此在创建 Script 时,必须慎重决定其中放入哪些动作。创建者的权限,就界定了那个 Script 能做的事的范围。
如何把权限装入角色,在 角色与权限 中介绍。
需要了解的事项
- 没有发布这一步。 Script 并不是那种通过发布来传递给访问者的资源,而是在管理画面中创建好、供网站调用的入口。因此与 Content、Media 不同,它没有发布、取消发布的状态,一创建就能立即使用。每修改一次,版本号就加一;删除时也无需取消发布这类前置步骤,可以直接删除。
- 数量有上限。 Script 属于计费对象,因此一个 Organization 能拥有的数量按套餐分别设定(Free 10 个、Basic 30 个、Pro 100 个、Enterprise 无限制)。达到上限后就无法创建新的 Script,删除不用的 Script 就会空出一个名额。
在内容工作室中管理
创建好的 Script,在内容工作室的 Script 画面中查看和管理。在左侧菜单点击 Script,就会以列表形式列出至今创建的 Script。列表的每一行会显示名称、Endpoint(调用方式和地址会一起显示)、是否允许 匿名调用、更新时间和更新者。

定义通常由 AI 智能体代为创建,不过您也可以在这个画面中亲手创建。新的 Script 通过列表右上角的 创建 按钮来创建。
- 点击列表右上角的 创建 按钮。
- 在 名称 栏中输入
填充商品说明。 - 将 HTTP 方法 选为调用这个 Script 的方式(这里是
POST)。 - 在 Statement 栏中填入写明该做什么的定义。把上面“填充商品说明”示例的定义原样填入即可。
创建画面上还有这些栏目:允许直接调用(关掉后就无法通过调用 URL 来调用,只能通过 Webhook 或 Scheduler 执行。默认为开启)、允许匿名调用(开启后会一并生成一个匿名调用地址,没有 Weegloo 登录的第三方也能通过它调用。默认为关闭),以及 调用 URL(分为 标准调用 和 匿名调用 两行,要保存之后才会定下来,所以现在是空的)。

如果想在执行前核对调用时随附发送的输入,就打开 Payload Schema 中的 Payload 校验,并写下要核对的格式。全部填好后,点击右上角的 创建 按钮。
在列表中点击某一个 Script,就会打开详情画面。详情画面分为 执行日志 和 设置 两个选项卡,初次打开时显示的是 执行日志。在 设置 选项卡中查看名称和定义,右侧则一并显示这个 Script 的编号(ID)、版本 和 变更记录(创建时间、创建者、更新时间、更新者)。修改定义后 保存,版本号就会加一。不再使用的 Script,用 删除 删掉。

执行日志 选项卡中,这个 Script 实际执行过的记录会一行一行累积起来。每一行会显示 执行时间、是什么启动了这次执行(触发方式)、结果、耗时,以及指向这次执行的 请求 ID。用上方的 结果 栏可以只挑出成功的或只挑出失败的,点击 刷新日志 就会把刚刚执行的记录也重新读取进来。
记录不会保留很久。成功的执行会在 1 小时后、失败的执行会在 3 天后自动删除。成功的一方会先消失,因此有时列表看起来只剩下失败记录。

接下来要做的事
- Script 概览:介绍构成 Script 的定义的顶层结构、执行规则以及语法文档集。
- Statement 目录:介绍
statements中可以放入的动作(创建、读取、修改、删除资源,调用外部服务,条件、循环等)的种类和字段。 - Webhook:介绍如何像“商品一上架 Script 就自动执行”那样,在预定的变化发生时自动作出反应。
