从代码里调它:命令行、SDK、REST
同一个 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 小。
用 curl 只校验一个不合格的申请;再把 options 去掉、真的执行,比较两次的 HTTP 状态和返回。
做一个 requests.json,第二个请求故意不合格:两个客户是不是都没登记?把它改对再跑一次。
小测
选一个答案,马上看解析。
Q1SDK 里执行一个不合格的申请,applyAction 会怎样?
只有「只校验」不通过才正常返回;真的执行时不通过就是一次失败的请求,抛错。
Q2拿着成员(member)的 Key,用 aidc semantic apply 会得到什么?
成员的 Key 走应用:aidc app call。开发者 Key 才能直接调语义层的接口。
Q3批量的第 2 个请求校验不通过,第 1 个请求呢?
批量先全部校验,再在一个事务里执行;返回的信息会写明是第几个请求。