输入:schema、子命令、文件参数、action 归一
什么时候读:设计
schema.json、声明子命令、接收文件、或技能以action分发多种操作时。
目录
- input_schema 规则
- 必填校验语义
- 子命令(cli_commands)
- 文件参数与附件引用
- prompt 字段(force_raw_prompt)
- 动作型技能入参归一(必读,漂移是系统性的)
- 身份字段不可信
- 平台读的 schema 扩展键(action.enum / x-options-from / x-keys-from / x-output-schema / x-output-paths)
1. input_schema 规则
标准 JSON Schema,放 schema.json 或代码内常量,schema.json 优先。
平台取 schema 的顺序(/skills/schema/{name}):技能目录 schema.json(整个文件即 input schema)→ 注册时的
input_schema → skill_meta.json / skill.json 的 input_schema / inputSchema / parameters →
handler.py 里的 INPUT_SCHEMA / OUTPUT_SCHEMA 常量。最后这条用 ast.literal_eval 读,常量必须是纯字面量
(不能引用变量、拼接、调函数),否则静默读不到。
{
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "标的代码,如 BTC / AAPL,大写"},
"image": {"type": "string", "x-input-type": "image"},
"limit": {"type": "integer", "default": 100, "description": "返回条数,1~1000"}
},
"required": ["symbol"]
}
properties的值必须是对象。"symbol": "string"这种裸字符串会被平台修正,但不同 provider 的元校验可能直接拒绝整批工具——一个技能写错,全部工具消失。additionalProperties/items只能是布尔或对象。description是模型填参的唯一依据。写取值范围、格式、例子,不要只写字段名。- 属性名避开
key token secret password credential auth子串,否则被当凭证从 schema 摘除(见 config-secrets.md)。
2. 必填校验语义
缺字段和传空值("" / [] / {} / 纯空白)都判为未提供;0 和 false 是合法值。
校验不通过时平台把错误回给模型自纠,不会静默补默认值。
3. 子命令
声明 cli_commands: {子命令: schema}。数量在 1~45 之间时,平台把技能扇出成多个工具名
<skill>__<sub>;执行前还原为 skill + input["_subcommand"],参数校验改用该子命令的 schema。
CLI 型技能的 _subcommand 放到 argv[0]。
子命令 vs action 字段:子命令让每个操作有独立 schema 和独立 description,模型选得准; action 字段一个 schema 管所有操作,description 要写得更长。操作间参数差异大的用子命令。
4. 文件参数与附件引用
路径归一。以下字段名的值被平台解析成绝对路径:
input output file path video audio image src dst
inputs files videos images clips sources paths bgm input_file file_path
- 绝对路径原样保留;相对路径只取 basename 挂到会话工作区(模型拼的目录前缀一律丢弃)。
output/dst/output_path/out视为待生成文件,无条件落到工作区。- 其余字段文件不存在时保留原值,让报错更清楚。
附件引用。模型看到的素材清单里每项带引用 ID(img_1 / file_1)。平台执行前:
- 字段值或数组项精确等于引用 ID → 替换成真实
local_path。 code/command/script/cmd/instruction/shell/bash字段内的子串引用也替换,路径转 posix 正斜杠,含空格自动补引号。- 数组字段自动去重。
技能内直接用拿到的路径,不要再拼目录。
5. prompt 字段
生成类技能声明 force_raw_prompt: true,平台用用户本轮原文覆盖 schema 第一个必填字段。
委托场景(上游产出而非用户直给)不覆盖。
6. 动作型技能入参归一
以 action 分发多种操作的技能,模型填参会系统性漂移:中文动作名翻成英文、参数键翻成英文、
「确认」翻成 confirmed: true、把用户整句「确认初始化」塞进 action。文档写再清楚也挡不住,
归一必须在技能侧做。
6.1 action 别名归一
大小写、下划线/连字符、英文同义词、中文夹字,统一映射到 dispatch 里的规范 action。
别名表的值集合必须 ⊆ 规范 action 集合,加自检断言。归一发生时回写 action_note: "initialize → 初始化"。
ACTIONS = {"初始化", "拉数据", "查询", "更新"}
ALIASES = {"initialize": "初始化", "init": "初始化", "fetch": "拉数据", "pull": "拉数据",
"query": "查询", "search": "查询", "update": "更新"}
assert set(ALIASES.values()) <= ACTIONS
def norm_action(raw):
s = str(raw or "").strip().lower().replace("-", "_")
if s in ACTIONS: return s, None
if s in ALIASES: return ALIASES[s], f"{raw} → {ALIASES[s]}"
for a in ACTIONS:
if s.startswith("确认" + a): return a, f"{raw} → {a}(含确认前缀)"
return None, None
6.2 参数键别名归一
record/row/values → data、filter → filters、order_by → sort、confirm/approve/确定 → 确认。
dispatch 前统一归口,同样回显。
6.3 无 action 一律拒绝
返回 need_param=action + 支持的 action 清单。不得按入参形状默认成某个写动作。
更新即使幂等也是写动作;定时任务必须显式传 action。
入口先拆包:payload / input / args 包了一层也要能读到 action。
6.4 确认只能来自用户原话
写动作采用「试算/预演 → 确认 → 执行」三段时,确认=true 只接受两种来源:
- 模型按用户指示显式传入;
action以「确认」开头(去前缀归一到写动作并补确认=true)。
技能不得自行补确认,不得把「预演成功」视为确认。
6.5 预演返回回显收到的参数
写明「缺 确认=true 所以只预演」。同一动作同样参数连续 3 次一模一样的预演卡片,说明参数没翻对。回显让模型不用猜。
6.6 给用户的「下一步」不用指令式措辞
「下一步:说拉数据」会被模型当成自己的指令执行。改为「可继续的操作:…」并标 for_user。
6.7 其它容错(踩坑档案)
- 每个数组/对象参数过一遍「可能是 JSON 字符串」的掰形函数。
- 多选字段解析要认得字符串
"[]"。 - 标的大写归一、周期别名归一,客户端再过滤一次。
7. 身份字段不可信
工号、角色、组织、团队角色一律取 runtime_context。input_data 中的同名字段视为模型可伪造,必须忽略。
8. 平台读的 schema 扩展键
| 键 | 放哪 | 谁读 | 作用 |
|---|---|---|---|
properties.action.enum | action 字段 | 页面网关 /skills/invoke(_declared_actions) | 页面动作白名单:声明了就挡掉不在其中的动作(40404);不声明则任何动作都透传。带面板的技能必须写,见 ui-panel.md §4 |
x-options-from: {"call": "<action>"} | 任意字段(可嵌在 items / properties 里) | 控制台参数表单 /skills/options-query | 单值下拉的动态选项来源 |
x-keys-from: {"call": "<action>"} | 同上 | 同上 | 多列选择 / 映射(filter-builder、column-mapping、metric-builder)的选项来源 |
x-output-schema | schema.json 顶层 | /skills/schema 返回 output_schema;链编辑器校验 $steps.x.字段 | 输出结构声明,见 chain.md |
x-output-paths | schema.json 顶层 | /skills/schema 原样返回 output_paths | 输出路径提示(前端用) |
x-cli-positional / x-subcommand | 字段 / 顶层 | 子进程 argv 拼装 | 见 code-facts.md §3.3 |
x-input-type | 字段 | 前端 | 输入控件类型提示(如 image) |
/skills/options-query 的规则:整棵 schema 递归收集所有 x-options-from / x-keys-from 里的 call,
只放行这些 call(其余 40403,一个都没声明则全部拒绝);执行时入参为 {"action": call, **params},
并把服务端算出的 org_id setdefault 进入参(技能仍以 ctx 为准);channel web_admin、无会话身份。
所以 call 必须是 handler 真能处理的只读动作,返回结构要能被表单当选项读。
x-actions(含 invocable_from / structural):当前平台没有任何地方读它。保留无害,但不要把它当权限控制。