从代码里调它:命令行、SDK、REST

第 5 课 · 共 7 课 约 6 分钟

同一个 Action 的三种调法;校验不通过时抛什么、状态码怎么读;批量一个事务;把结果读回来。

本课目标

读完这一课,你将能够

  • 用命令行、SDK 和 REST 调同一个 Action
  • 分清校验不通过在三种调法里各是什么样子,按状态码处理出错
  • 批量执行一个事务,并把改动读回来

命令行:给人,也给智能体

前两课已经在用:aidc semantic apply <Action> --param 名=值。参数多了,或者值里有特殊字符,就整体给一份 JSON:

aidc semantic apply submit-seat-request \
  --params '{"customer":"acme-east","seats":35,"reason":"新开两个仓库"}' \
  --validate-only        # 去掉它才真的执行;--return-edits 把改动一起返回
  • 输出:不是终端时(管道、脚本、智能体)缺省就是 JSON;失败时是 { ok: false, error: { code, message, status, details } }。
  • 退出码:0 成功,2 参数或提交条件不通过,3 没登录,4 没权限,5 不存在,6 冲突(例如主键已存在),7 限流,8 上游或网络故障,其余错误是 1。
  • 执行时校验不通过,和「只校验」不通过一样,退出码都是 2;智能体据此决定是改参数还是停下来问人。

SDK:在脚本或应用里

应用里,semantic.ontology() 自动取应用所在的公司。脚本里没有应用,要自己说清楚:取一份 SDK,存成 .mjs(curl -o aidc.mjs https://www.ai-dc.ai/developer/sdk/v1/aidc.js),用 configure 给出地址和公司。密钥不用另外给:aidc login 存在 ~/.aidc/config.json 里的 Key,Node 20.16 以上会自动读到;更老的 Node 和无人值守的地方(CI、服务器)设环境变量 AIDC_API_KEY。把下面的脚本存成 call.mjs:

// 用 SDK 从脚本里调 Action(Node 20.16 以上;更老的 Node 设环境变量 AIDC_API_KEY)。先取一份 SDK,存成 .mjs:
//   curl -o aidc.mjs https://www.ai-dc.ai/developer/sdk/v1/aidc.js
// 运行:node call.mjs。先 aidc login:Node 20.16 以上会自动用它存在 ~/.aidc/config.json 里的 Key;无人值守(CI、服务器)就设环境变量 AIDC_API_KEY=aidc-dk-…
import { configure, semantic } from "./aidc.mjs";

configure({ apiBase: "https://www.ai-dc.ai", namespace: "cell-acme" }); // 换成你的公司代码
const client = semantic.ontology();
const args = { customer: "acme-east", seats: 3 };

// 1. 先校验:不写入。校验不通过不会抛错,看 validation.result
const check = await client.action("submit-seat-request").applyAction(args, { $validateOnly: true });
console.log(check.validation.result, check.validation.submissionCriteria.map((c) => c.configuredFailureMessage ?? c.result));

// 2. 直接执行一个不合格的:会抛 AidcError(HTTP 422),失败信息在 err.message,逐项结果在 err.details.validation
try {
  await client.action("submit-seat-request").applyAction(args, { $returnEdits: true });
} catch (err) {
  console.log(err.name, err.status, err.code, "|", err.message);
}

// 3. 合格的:执行并拿回改动
const done = await client.action("submit-seat-request").applyAction({ customer: "acme-east", seats: 50, reason: "SDK 试跑" }, { $returnEdits: true });
console.log(done.operationId, done.edits.addedObjectCount, done.edits.edits[0].objectType);
INVALID [ '申请的座位数要比现在的多', 'VALID' ]
AidcError 422 action_validation_failed | 申请的座位数要比现在的多
ri.actions.aidc.action.cmuni… 1 seatRequest

注意前两步的差别。只校验不通过,请求本身是成功的,applyAction 正常返回,你自己看 validation.result;执行时不通过,applyAction 抛出 AidcError:status 是 422,code 是 action_validation_failed,message 是第一条失败信息,逐项的结果在 err.details.validation 里。界面上「先校验、再确认执行」,正是用这个差别。

REST:任何语言都行

命令行和 SDK 都只是包了一层 REST。路径和请求体照 Palantir 的 Apply Action:

export AIDC_API_KEY=$(node -p 'JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.aidc/config.json","utf8")).apiKey')   # 取出 aidc login 存的 Key

curl -i -X POST https://www.ai-dc.ai/api/v1/ontologies/cell-acme/actions/submit-seat-request/apply \
  -H "Authorization: Bearer $AIDC_API_KEY" -H "Content-Type: application/json" \
  -d '{"parameters":{"customer":"acme-east","seats":3},"options":{"mode":"VALIDATE_ONLY"}}'
{ "ok": true,
  "data": { "validation": { "result": "INVALID",
    "submissionCriteria": [{ "result": "INVALID", "configuredFailureMessage": "申请的座位数要比现在的多" }, { "result": "VALID" }],
    "parameters": { … } } },
  "meta": { "requestId": "req_…", … } }

options.mode 缺省是执行(VALIDATE_AND_EXECUTE);options.returnEdits 设为 ALL 才把改动返回。出错时看 HTTP 状态和 error.code:

  • 422 action_validation_failed:执行时参数或提交条件不通过。message 是第一条失败信息,details.validation 是逐项结果。
  • 403 forbidden:你的角色不在 roles 里,或者是只读访问,或者拿的是成员 Key(成员 Key 只能调用应用)。
  • 404:Action 不存在。
  • 409:冲突,比如主键已存在(object_exists)。
  • 429 rate_limited:每个 Key 每分钟 60 次 apply / applyBatch(只校验也算);details.retryAfterSeconds 告诉你等多久。

批量与读回来

一次要做很多件同样的事,用批量:apply-batch(REST 是 applyBatch),最多 20 个,在一个事务里,任何一个校验不通过,整批都不写。

cat > requests.json <<'EOF'
[
  { "customerId": "acme-b1", "name": "ACME B1", "stage": "试点", "seats": 5, "members": 2 },
  { "customerId": "acme-b2", "name": "ACME B2", "stage": "试点", "seats": 0, "members": 2 }
]
EOF
aidc semantic apply-batch register-customer requests.json
# 422 第 2 个请求:座位数 要在 1–10000 之间   —— 两个客户都没有登记

把改动读回来,用对象集,不用另外的接口。命令行和 SDK 是同一种写法;subscribe 在数据一变时推给你,界面就是这样实时更新的:

aidc semantic objects seatRequest --where '{"status":"submitted"}' --order-by requestedAt:desc
aidc semantic objects customer --where '{"stage":"试点","seats":{"$gt":30}}' --select name,seats,members
aidc semantic subscribe seatRequest --where '{"status":"submitted"}'

要点

  • 命令行、SDK、REST 调的是同一个 Action,走同一份校验;命令行退出码 2 = 校验不通过。
  • 只校验不通过时请求成功、validation.result 是 INVALID;执行不通过时 SDK 抛 AidcError,HTTP 是 422。
  • 读状态码:422 是内容不对,403 是角色不对,409 是冲突,429 是太快了。
  • 批量最多 20 个、一个事务、整批成败;改动用对象集读回来,用 subscribe 实时看。

练一练

三种调法各跑一遍

在你自己的公司里做;REST 那一遍需要开发者 Key:aidc login 把它存在 ~/.aidc/config.json 的 apiKey 里(Key 是密钥,别贴进聊天、代码库或截图)。

取 SDK,存好 call.mjs,改成你的公司代码,aidc login 之后直接运行。第三步要合格,先确认 ACME East 现在的座位数比 50 小。

小测

选一个答案,马上看解析。

Q1SDK 里执行一个不合格的申请,applyAction 会怎样?

Q2拿着成员(member)的 Key,用 aidc semantic apply 会得到什么?

Q3批量的第 2 个请求校验不通过,第 1 个请求呢?

延伸阅读