openydt-skill-maker — openydt 自定义 Skill 制作器
CRITICAL:开始前 MUST 先用 Read 工具读取
../openydt-shared/SKILL.md,掌握 openydt 的配置 / profile / 签名(v2/v3) / 响应包络与状态码 / 限速 / 写操作安全规则。所有你新建的 skill 都要复用这套基座,不要在新 skill 里重复这些内容。
本技能是「制作其它 openydt skill」的元技能,对标飞书 lark-skill-maker:当用户想把 openydt 的某个接口(原子封装)或某条多步业务流程(编排)固化成可复用 Skill 时,按本指南产出一个符合规范的 SKILL.md。
何时用本技能
- 用户要新建一个 openydt 域技能(如「在场车 / 月票 / 黑名单」域)。
- 用户要把某个
openydt api <cmd>或某条「查费 → 缴费」式业务链路封装成可复用 Skill。 - 用户要把已有 SKILL.md 规范化(补 frontmatter、整理命令表、给写操作加
--yes)。
不属于本技能:实际调用业务接口(用对应域技能或 openydt api)、改 Go 命令代码(改 cmd/gen 须先改抽取器/codegen,而非手写)。
目录结构
每个 skill 是 skills/<skill-name>/ 下的一个目录,至少含 SKILL.md;正文较长或有大块参考资料时,把按需内容拆到 references/:
skills/
openydt-shared/SKILL.md # 共享基座(所有 skill 都先 Read 它)
openydt-<域>/
SKILL.md # 主入口:frontmatter + 正文(必须精简,常驻上下文)
references/ # 可选:按需加载的大块内容
<topic>.md # 如字段字典、完整枚举表、长业务流程
命名约定:技能目录名用 openydt-<域或场景>(kebab-case),与 frontmatter 的 name 一致。
frontmatter 字段说明(同规范)
frontmatter 必须与现有 openydt 技能一致:
---
name: openydt-<域> # 必填,与目录名一致,kebab-case
version: 1.0.0 # 必填,语义化版本
description: "<一句话职责>。<触发词富集>。" # 必填,见下方要求
metadata:
requires:
bins: ["openydt"] # 必填,声明依赖 openydt 二进制
cliHelp: "openydt <域> --help" # 建议:让使用者快速看到真实子命令
---
description是技能能否被正确召回的关键,写法对标 Anthropic skill-creator:一句 WHAT(本域职责 + 读/写边界)+ 一句 WHEN(典型触发场景),整体精简到约 100–150 字,给 3–6 个有区分度的代表场景即可,不要堆砌同义词。- 为什么不堆砌:把「读写动词 × 业务名词」笛卡尔积式铺开,会与兄弟域抢同一个词(如「查费/缴费」曾被 5 个技能同时认领)、稀释判别信号、撑大常驻 token,反而降低召回准确度。判别力来自边界而非数量。
- 同名跨域场景要加一句边界,例如 record 注明「历史账单/缴费记录(实时算费请用 trade 域)」。具体归属见下方「触发词去冲突」。
- 触发是否准确,按本技能「制作步骤」用 skill-creator 的触发 eval 客观验收,而非靠「词够不够多」的主观判断。
cliHelp填该域真实的帮助命令,便于人类核对子命令是否存在。
触发词去冲突(每个触发短语只归一个 owner 域)
skill-creator 的首要扣分项是「与兄弟技能触发词冲突」。openydt 是单一平台下的多域技能库,最容易撞车。规则:每个裸触发短语只归一个 owner 域,其余域改用限定词 + 在 description 写一句边界;读 vs 写同名场景按「主操作」归属。新技能上线前,必须与既有域的 description 做一次触发词去重。
已知裁决表(务必遵守,新增域据此对齐):
| 触发词 | owner(独占裸词) | 其余域改法 |
|---|---|---|
| 查费 / 算费 / 缴费 / 在线缴费 | billing(trade) 实时算费 | record→「查缴费记录/账单明细」;monthticket→「月票缴费/扣费记录」;park 仅「车场收费标准查询」;coupon 不认领 |
| 屏显 / 语音播报 | device(下发:推屏显/喊话/播报) | park→「查屏显内容/应显示什么」 |
| 在场车 | record(明细) | data→「实时在场数量/在场统计」 |
| 查账单 | record =「缴费记录/账单明细」 | data =「账单汇总/经营报表」 |
| 电子券 / 优惠券 | coupon(查/发/收闭环) | park→「车辆优惠券记录(只读)」;monthticket→「车场协议同步扫码」 |
| 特殊车辆类型 / specialCarTypeId / VIP分组 | monthticket(创建/查询) | list 仅「作入参引用」,不认领「创建」 |
| 泛词「查车」 | —(禁用泛词,拆成限定短语) | record「查在场车/进出记录」、monthticket「查车主身份/是否 VIP」、park「查车场信息」 |
正文结构约定
正文按固定骨架写,从上到下:
- CRITICAL 先读 shared:正文第一句必须是醒目提示,要求开始前先 Read
../openydt-shared/SKILL.md,不在本技能重复签名/状态码/安全规则。 - 何时用本技能 + 意图路由:说清楚本域负责什么,并给出「这类诉求请改用 X 域」的路由(避免技能越界)。
- 可用命令表:用表格列出本域命令,列为「中文名 | 命令 | 读/写 | 关键参数」。
命令列写真实可执行的openydt <域> <use>。读/写列标明读还是写;所有写命令在表内与示例里都要标注「需--yes」。关键参数标必填项(用*或「必填」),数组/对象型字段说明须用--bodyJSON 传入。
- 业务流程(仅当有多步链路时):描述需要回填上一步响应的链路(如「查费 → 计费测算」「建券 → 售券 → 发券」),强调字段必须取自上一步响应、不可臆造。无强依赖链则写明「各命令为独立查询」。
- 示例:给 2-4 个可直接复制运行的命令,至少含一个读示例;若有写命令,必须先给一条
--dry-run预览签名请求、再给一条--yes实发两步序列,让「先预演后执行」可直接照抄。示例卫生(硬约束):parkCode 必须用共享基座文档化的测试车场(1ZS7H5PQH9/PTD2YBBZ),时间参数用当前/相对时间或中性占位——不要照抄 catalogsampleBody里 2016–2019 的历史值,否则用户复制即撞 904/911 或空结果。 - 错误自愈速查表(必含):每域给「现象 | 含义 | 恢复动作(可执行下一步)」三列表(参照 [[openydt-flow-park-access]] 风格),并指向 [[openydt-shared]] 的
../openydt-shared/references/result-reading-sop.md。 - 写操作幂等(若本域有写):点名各写命令的幂等键(
billCode/thirdBillCode/uniqNo等)、复述「重试复用首次键、907=幂等命中」,指向../openydt-shared/references/write-idempotency.md;无显式键的写要求「重发前先查」。 - 结果解读要点(必含):金额单位(元 / 时间券分钟)、
status=1但data空、0 条≠无——域内点名相关字段,细则指向../openydt-shared/references/result-reading-sop.md。
why 约定:每条 MUST/NEVER/CRITICAL 配一句 why(如「先读 shared——因签名/状态码不在本技能重复,漏读会用错签名版本」),避免空洞硬规则被强模型 rationalize 掉。
references/ 按需加载约定
- SKILL.md 主体要短(常驻上下文,控制 token):正文控制在 500 行以内,命中即拆。把大块、低频内容下沉到
references/<topic>.md,并在主体里用相对链接指明「需要 X 时再 Read」。 - 适合放 references 的内容:完整字段字典 / 长枚举表(如券类型、车辆类型全集)、超过两步的完整业务流程、错误码到处置动作的详表。
- 在主体里写清触发条件,例如:「处理建券 → 售券 → 发券完整链路前,先 Read
references/<topic>.md(示例占位,非真实文件)」,让模型按需加载而非默认全读。
命令必须真实存在
- 命令表里的每条
openydt <域> <use>必须真实存在,来源只有两类,二选一核对:- 域一等命令:以
cmd/gen/<域>.go的真实子命令为准(这些由 codegen 生成),或运行openydt <域> --help核对。 - catalog 接口:以
catalog/catalog.json中included: true的interfaces[]为准,每条含cmd(业务编码) /domain/readwrite/params/sampleBody,可据此推断命令名、读写属性与示例参数。
- 域一等命令:以
- 不要臆造命令名或参数。
included:false的接口(标excludeReason)属于越界范围,不要为它建技能。 - 若目标接口尚无域一等命令,可在技能里用通用兜底
openydt api <cmd> --body '{...}'调用(见 shared 的三层命令模型),但仍要确认该cmd在 catalog 中存在且可调用。
写操作标 --yes
- catalog 中
readwrite: "write"(或任何会改变平台状态的操作:缴费、开闸、发券、开通月票、加/移黑名单、设置车位等)一律为写命令。 - 写命令在命令表的「读/写」列标「写(需
--yes)」,并在示例中实际带上--yes,必要时建议先--dry-run预览签名请求。这条与 shared 的安全规则一致,新技能不得弱化。
制作步骤
- 确定域/场景与目标接口,去
catalog/catalog.json(included:true)或openydt <域> --help核对真实命令、读写属性、必填参数、sampleBody。 - 新建
skills/openydt-<名>/SKILL.md,按上面 frontmatter 与正文骨架填写;description 富集中文触发词。 - 命令表逐条核对真实性与读写标注:读/写须与 catalog
readwrite逐条一致,写命令标--yes;只读域不得混入 write 命令(如确有平台契约标 write 的「伪写」统计接口,须在 description/正文显式说明「该接口契约标 write,调用需 --yes」)。 - 大块内容下沉
references/,主体留按需加载指引。 - 顺带核对盲区:去 catalog 看本域有没有「有 endpoint、
included:false但direction:callable」的接口(常见排除理由 appointment/authorize/certificate/tag 等多是「功能未一等化」而非废弃)。这类接口无专属命令,应在正文加一句「用openydt api <cmd>调用,详见 api-explorer」的指路,而非漏掉。 - 自检(客观优先于主观):命令是否都真实存在、读写标注是否与 catalog 一致、写操作是否都标
--yes且示例含--dry-run、是否在开头要求先读 shared、触发词是否与既有域去重(对照「触发词去冲突」表)。触发是否准确,用路由触发评测客观验收:构造正例(应召回本域)与反例(易误召回的兄弟域场景),写入evals/routing-evals.json,用tools/eval/routing-eval.workflow.mjs(subagent 路由评测,非 nested)跑验收,baseline 见tools/eval/ROUTING-BASELINE.md;确认本域命中、冲突域不误召回,达标再上线。
最小模板
统一渲染规约(所有 openydt 技能对齐)
- 命令表列名固定:
中文名 | 命令 | 读/写 | 关键参数。 - 写操作读/写列统一写
写(需 --yes)(不混用「写」「写(--yes)」等)。 - 必填统一用
*后缀(不混用「必填」「(必填)」)。 - 关键参数统一用 flag 式(
--xxx),数组/对象注明「用--body」。 - 跨技能引用统一
[[openydt-<域>]]wiki-link(不用裸命令名/相对路径 prose)。 - 正文标点统一全角;写示例必须含
--dry-run预览行再--yes。 - CRITICAL 头、「何时用+意图路由」、「可用命令表」、「业务流程」、「错误自愈表」、「示例」、「命令归属 [[links]]」按此固定顺序。
Pre-ship Checklist(上线前逐项勾)
- 命令表每条
openydt <域> <use>经--help/catalog 核对真实存在(零幻觉) - 读/写标注与 catalog
readwrite逐条一致;写命令标--yes且示例含--dry-run - description WHAT+WHEN、约 100-150 字、与兄弟域触发去冲突(对照裁决表)
- 含错误自愈表 / 写幂等(若有写)/ 结果解读要点三块
- 示例用文档化测试 parkCode + 当前/相对时间(不照抄历史 sampleBody)
- 跨域引用用 [[wiki-link]];未一等化 callable 有 api 兜底指路
- 每条硬规则配 why
- 跑路由触发评测:正例/反例数据集在各技能
evals/routing-evals.json,runner 为tools/eval/routing-eval.workflow.mjs(subagent 路由评测),baseline 见tools/eval/ROUTING-BASELINE.md;确认本域正例命中、冲突域不误召回
把下面整段复制为新技能的 SKILL.md 起点,替换尖括号占位后逐项核对:
---
name: openydt-<域>
version: 1.0.0
description: "<一句 WHAT:本域负责 X,含读/写边界>。<一句 WHEN:典型触发场景,3–6 个有区分度的代表说法,勿堆砌同义词;与兄弟域同名场景加一句边界>。"
metadata:
requires:
bins: ["openydt"]
cliHelp: "openydt <域> --help"
---
# openydt-<域> — <中文域名>
> **CRITICAL:开始前 MUST 先用 Read 工具读取 [`../openydt-shared/SKILL.md`](../openydt-shared/SKILL.md)**(认证 / profile / 签名 / 状态码 / 限速 / 安全规则)。未读共享基座不要执行任何命令。
## 何时用本技能
<本域负责什么>。意图路由:
- <这类诉求> → 留在本域。
- <那类诉求> → 改用 `openydt <其它域> --help`。
## 可用命令
`<use>` 为命令真实 kebab 名,调用形如 `openydt <域> <use>`。数组/对象型字段用 `--body '<json>'` 传入。
| 中文名 | 命令 | 读/写 | 关键参数 |
| --- | --- | --- | --- |
| <查询某资源> | `openydt <域> <use-read>` | 读 | `--xxx`*(必填) |
| <修改某资源> | `openydt <域> <use-write>` | 写(需 `--yes`) | `--xxx`*、`yyyList`*(用 `--body`) |
> 标 `*` 为必填。
## 业务流程
<若有需回填上一步响应的链路,在此描述,强调字段取自上一步响应、不可臆造;否则写「各命令为独立查询,拿到必填参数即可直接调用」。>
## 示例
1) 读示例:
```bash
openydt <域> <use-read> --xxx <值>
- 写示例(写操作必须加
--yes,必要时先--dry-run):
openydt <域> <use-write> --yes --body '{"xxx":"...","yyyList":[{...}]}'
## workflow(编排)型技能模板(用于跨域 / 多步业务流程)
上面的「最小模板」是**原子 / 域技能**(包装一个域的命令)。当一个**业务结果**需要把多个命令(常跨域)串成固定管道、且步骤间要回填上一步响应字段时,做成 **workflow(编排)型技能**,对标飞书 `lark-workflow-*`。
| | 原子 / 域技能 | workflow 技能 |
| --- | --- | --- |
| 触发 | API/域级意图(「查在场车」) | 业务结果(「出一份车场经营日报」「缴费后对账」) |
| 正文 | 命令表 + 独立查询 | 固定多步管道 + 步骤间数据回填 |
| 组合 | 自包含 | 组合多个域命令 |
| 命名 | `openydt-<域>` | `openydt-workflow-<场景>` |
额外约定:
- 触发写「业务结果」而非「调某接口」,触发词用结果名(经营日报 / 对账 / 催缴),**不与被组合的域技能抢词**。
- 正文用 **ASCII 管道图**画清数据流与回填字段(哪个字段取自上一步响应)。
- 含写的步骤:**先 `--dry-run` 预览、确认后再 `--yes`**;批量写注意限速(见 shared,约 4/s)。
- 仅当「跨域 / 需多步回填 / 需汇总」才独立成 workflow——单域已能在正文写全的闭环不必重复成技能。
管道图示意(放进 workflow 技能的「## 流程」节):
{parkCode} ─► openydt parking get-park-on-site-car ──► 确认在场 ─► openydt trade get-park-fee ──► 取 chargeBillNumber / shouldPayValue └─► openydt trade pay-park-fee --dry-run → 确认 → --yes (写) └─► openydt parking get-pay-bill ──► 反查金额是否一致