PyPTO-Pro 需求规格化实战:用 SPEC 机器合同冻结算子语义、接口与 P0 验收基线
【免费下载链接】pypto-gymPyPTO-Gym 是基于 PyPTO 编程框架构建的算子与模型样例仓库项目地址: https://gitcode.com/cann/pypto-gym
PyPTO-Pro 是 CANN 生态中面向 PyPTO 编程框架的算子/模型开发流程,本篇文章讲解其 Stage 1 核心技能pypto-pro-intent-understand:如何把自然语言、官方 API、论文或用户代码中的算子需求,整理为可执行、可机器校验的custom/<op>/SPEC.md。读完本文,你将掌握最小语义合同的提取方法、事实置信度分级与歧义处理规则、machine-contract JSON 的逐字段填写约束,以及如何用仓库自带的validate_spec.py校验器守住"公式、接口、验收规格"三道冻结线。
技能定位:只回答"算什么、接口是什么、怎样算正确"
pypto-pro-intent-understand在 PyPTO-Pro 精简流程中承担 Stage 1 的需求澄清与规格化职责。它的任务边界非常明确(见 SKILL.md):
- 负责:回答"算什么、接口是什么、怎样算正确",即冻结需求语义、公开接口合同与验收规格;
- 不负责:选择 PyPTO-Pro API、计算拓扑、Module、tile、同步或 kernel 写法——这些分别属于 material-explore 和 Stage 3/4。
在 pypto-pro-op-plan/SKILL.md 定义的 Stage 1 串行流程中,本技能是第一步"冻结需求语义"的执行者:同一 agent session 内加载本技能生成并验证SPEC.md,不 dispatch 子代理、不重做确认流程。而 orchestration.md 进一步说明:Stage 1 由 planner 子代理串行加载本技能(生成 SPEC.md)与 material-explore(产出 EXPLORE_REPORT.md + PRO_MATERIAL_INDEX.md),随后由 verifier 以stage1-check模式执行门禁快检,PASS 后才能complete_stage(1)推进到 Stage 2。也就是说,本技能产出的SPEC.md是整个 5 阶段流水线的"契约原点",后续 golden、设计、实现与验收全部以它为基准。
输入与输出合同
- 输入:用户陈述,以及用户明确给出的公式、代码、测试、论文或官方 API 引用;
- 输出:
custom/<op>/SPEC.md,必须使用 SPEC 模板; - 文件冲突:若
SPEC.md已存在,不得静默覆盖——交互模式先让用户确认覆盖;无人值守任务中保留原文件并返回blocked。
按输入形态恢复事实,不改变同一证据标准:
| 输入形态 | 处理方式 |
|---|---|
| 标准 API | 以目标版本官方定义为准 |
| 外部 URL | 必须先读取原文;读取失败时只形成低置信度待确认草稿 |
| 代码/测试 | 按实际签名和控制流提取 |
| 自定义描述 | 缺公式或最小输入输出合同时直接列出缺失项 |
核心红线:不要把模型记忆升级成外部材料证据。
事实与决策规则:五级优先级 + 三级置信度
按以下优先级采用事实:
- 用户明确陈述及用户提供的测试;
- 项目已经批准的接口合同;
- 目标版本官方文档或标准 API;
- 用户提供的论文、源码或参考实现;
- 模型知识只可形成待确认草稿,不可冒充已确认事实。
为每项非显然结论记录来源和置信度:
✓ 高:用户事实、已批准合同或目标版本官方资料;⚠ 中:从论文、源码或用户代码分析得到;❓ 低:推断,只能等待确认或按无人值守规则披露。
不得静默为公式、输入输出、shape、dtype、optional 参数、动态轴或边界语义填值——这是需求规格化最严格的纪律。
工作流:四个步骤冻结最小语义合同
步骤 1:提取最小语义合同
识别并整理公开接口的 rank、shape、dtype、动态轴和语义:
- 合法算子名:小写字母开头,只含小写字母、数字和下划线(即
lower_snake_case); - 数学公式或等价的逐步算法;
- 每个公开输入、输出及可选参数的名称、rank、shape、dtype、动态轴和语义;
- 每个输出 shape/dtype 相对输入与参数的推导关系;rank-0 tensor 的 shape 明确写
[]; - machine-contract 的每个输入/输出都写可解析的闭区间
value_range: [min, max];界限必须有语义依据且为有限数,供 Stage 3 做强制数值安全分析,未知时不得猜测或用模板示例替代; - 零值、极值、NaN/Inf、空维度及尾部元素的数学行为;
- 精度标准、功能优先级和至少一组可执行 P0 典型配置。
两个容易被忽略的语义要点:
- 辅助 tensor 的预展开/预广播:公开接口是否要求辅助 tensor 由调用方预展开/预广播,属于输入 shape 关系,必须在这里保留;kernel 内如何据此 broadcast、切 tile 或索引属于 Stage 3,不能提前设计。
- 编号算法步骤:公式不能表达分块、循环、递推、在线更新或状态依赖时,补充带编号的算法步骤。算法描述只定义数学过程,不提前规定 tile 或硬件实现。
步骤 2:识别会改变公开语义的特性
只列当前算子实际涉及的特性,例如 mask、量化、融合、动态 shape、混合精度、随机性、稀疏性或数值稳定策略。每项记录四要素:
- 是否需要;
- 来源与置信度;
- P0/P1/P2/P3 优先级;
- 对公式、接口或验收的影响。
优先级规则:P0/P1 必须进入首个版本;P2 可选;P3 明确暂缓。本技能不判断 PyPTO-Pro 实现复杂度或 API 支持度——那交给 material-explore。
对 optional 参数执行四项语义分析:
- 在公式中的位置(输入预处理/核心计算/输出后处理);
- 计算作用(条件分支/数值缩放/数据选择);
- 与其他参数的依赖/互斥;
- 省略时的默认语义。
不要把 kernel 实现方式混入这项分析。
步骤 3:集中处理歧义
三种处理模式:
- 交互模式:一次展示数据流摘要、规格清单、关键歧义及拟采用默认值,整体确认;最多两轮;
- 用户输入已完整:直接展示确认稿,不机械追问已给出的事实;
- 无人值守模式(用户明确要求不提问或持续执行):仅对非阻塞字段使用可追溯默认,并在 SPEC"自动决策"中记录采用值、来源、理由和影响。
若数学语义或最小输入输出合同仍无法确定,不猜测,返回blocked和缺失项。允许使用的默认值必须先披露再持久化;shape、dtype 和动态轴只有在目标标准接口确有默认或用户确认后才可采用,没有依据时保持未决并阻断,不能用示例模板值替代。
步骤 4:生成并自检 SPEC
复制 SPEC 模板,逐项替换占位符;删除不适用的可选行,禁止把模板占位符或示例值留在成品中。json machine-contractfenced block 是唯一机器事实源;正文只解释公式、接口语义、边界和证据,不重复 shape、dtype、容差或 P0 字段值。各字段规则:
op_name:对应算子名,lower_snake_case;formula:用等式或编号伪代码步骤定义每个公开输出;复杂算法仍须让每个输出成为赋值或箭头目标,正文只解释符号与依据;supported_dtypes:按首次出现顺序列出本 SPEC 公开输入输出实际使用的全部 canonical dtype;同一接口的另一组 dtype 组合拆为独立 class/SPEC,避免下游静默丢失 index、mask 或量化辅助 tensor 的 dtype;inputs/outputs:按公开签名顺序完整记录 name、shape、dtype、有限 value_range;p0_cases:逐案记录 name、params、input_shapes、output_shapes;校验器会从第一项导出只供旧调用方使用的内存字段p0_shapes,SPEC 不再双写该字段;default_params:只包含公开签名中已确认的标量默认参数;没有则写{};tolerance、动态轴范围、shape 约束和性能目标:直接记录已确认裁定。
性能目标单一来源规则:只有用户明确给出且可复算的数值目标时,才把该值写入perf_target,并在 SPEC"P0 与性能目标依据"中记录用户来源。用户未指定数值目标时,perf_target写null,并在"自动决策"中说明 Stage 5 将使用逐 P0 case 的默认理想参考golden_reference_ratio >= 1.0;不得把这一系统默认值写成用户要求或交付硬门禁。
P0 一致性约束:所有 P0 的映射 key 与顺序分别等于default_params、inputs、outputs;具体 shape 必须等于把本 case 输入/参数代入合同 shape 表达式后的结果。rank-0 tensor 写[]。tile/kernel shape 仍由 Stage 3 决定。每个动态 shape 符号须在至少一个输入维中单独出现,保证 P0 具体 shape 能确定地绑定该符号;其他输入/输出可使用由它组成的表达式。
运行模板旁的校验器,非零退出时修复后重跑:
python "$CANNBOT_CONFIG_ROOT/skills/pypto-pro-intent-understand/scripts/validate_spec.py" \ custom/<op>/SPEC.md说明:
$CANNBOT_CONFIG_ROOT是 skill 安装态的资源配置根;在当前仓库中,对应源码位于 scripts/validate_spec.py。校验器同样被 Stage 1 收尾自检脚本 validate_stage1.py 以及 pypto-pro-golden-generate 的 golden 脚手架复用——后者的规则是:没有已校验 SPEC 时先加载本技能创建并校验 SPEC,信息不足时由本技能澄清或返回blocked,不猜测合同。
SPEC 模板与 machine-contract 结构详解
模板 spec-template.md 由"机器合同"与"语义说明"两部分构成。机器合同是唯一的机器事实源:
{ "schema_version": 1, "op_name": "{{OP_NAME}}", "formula": "{{FORMULA_OR_NUMBERED_STEPS}}", "supported_dtypes": [], "inputs": [], "outputs": [], "default_params": {}, "tolerance": { "atol": null, "rtol": null }, "dynamic_axes_ranges": {}, "shape_constraints": [], "p0_cases": [], "perf_target": null }填写约束(模板"填写约束"小节):
supported_dtypes按首次出现顺序列出本 SPEC 公开输入输出实际使用的全部 canonical dtype;同一接口的另一组 dtype 组合拆为独立 class/SPEC;formula用一个 JSON 字符串定义每个公开输出;简单算子写可审查的等式,复杂递推写编号伪代码步骤(换行转义为\n),且每个输出都必须是赋值或箭头目标,不要只写自然语言标签;inputs/outputs按公开签名顺序填写,每项严格包含name、shape、dtype、value_range;rank-0 shape 写[],闭区间值域写有限数值[min, max];- shape 维度只使用正整数,或由符号、整数、
+ - * //和括号构成的表达式;每个动态符号须在至少一个输入 shape 中作为独立维度出现,并在dynamic_axes_ranges中给出正整数闭区间; default_params只放公开签名中的标量默认参数,顺序与签名一致;无默认参数时写{};p0_cases至少一项,每项严格包含name、params、input_shapes、output_shapes;所有映射均按合同声明顺序覆盖全量字段;首项params等于default_params,每个 shape 都是公式代入后的具体整数数组;- 不适用的可选字段使用空数组、空对象或
null,不要保留示例值或另建第二份机器表格。
机器合同之后是 12 个编号语义小节:功能与分类、公式符号与依据、算法描述、数据流说明、接口语义、功能与可选参数依据、精度语义、动态 Shape 与约束依据、边界条件处理、P0 与性能目标依据、参考与来源、自动决策。末尾标注生成时间与确认状态。正文只解释语义与证据,不复制机器字段值。
校验器源码解析:机器合同如何被逐字段审查
validate_spec.py 是整个规格化流程的"守门员",约 480 行、零第三方依赖(仅用标准库argparse/ast/json/logging/re),可直接运行。它把校验拆成一系列原子检查:
结构层检查
BLOCK_RE:SPEC.md 中必须恰好一个```json machine-contract fenced block,多一个、少一个都报错(exactly one);PLACEHOLDER_RE:任何残留的{{...}}模板占位符都会导致失败(unresolved template placeholder);- JSON 解析使用
object_pairs_hook=_unique_object拒绝重复键,parse_constant拒绝NaN/Infinity等非有限数值字面量。
头部与命名检查
schema_version必须等于 1;op_name必须匹配^[a-z][a-z0-9_]*$(NAME_RE),即lower_snake_case。
dtype 词表与顺序一致性
supported_dtypes必须非空、无重复,且全部落在DTYPE_VOCAB:bfloat16, float16, float32, float64, int8, uint8, int16, int32, int64, bool;- 关键约束:
supported_dtypes必须恰好等于 inputs+outputs 中 dtype 的首次出现顺序(_validate_tensor_dtypes),防止声明与实现漂移。
tensor 检查(inputs/outputs)
- 每项严格包含
name/shape/dtype/value_range四个字段,无多余、无缺失; - name 唯一且为
lower_snake_case; - shape 的每个维度必须是正整数,或由
+ - * //与括号组成的符号表达式(_check_shape_syntax用ast做白名单语法校验,不允许幂、位运算等); value_range必须是二元有限数闭区间[min, max]且min <= max;- inputs 与 outputs 的 name 集合不得相交。
shape 符号与动态轴闭环
- 收集所有 shape 表达式中的符号(
_shape_symbols); dynamic_axes_ranges的键必须恰好等于全部 shape 符号集合(多一个、少一个都报exactly match shape symbols);- 每个符号必须作为独立维度出现在至少一个输入 shape 中(
_input_anchors+_validate_dynamic_symbols),防止出现"输出维度绑定了未锚定的符号"; - 每个符号的闭区间必须是正整数区间
[positive_min, max]。
p0_cases 全量一致性
p0_cases必须非空,case name 唯一且为lower_snake_case;- 每个 case 严格包含
name/params/input_shapes/output_shapes四字段; params的键名与顺序必须等于default_params,且首项的 params 必须等于 default_params;input_shapes/output_shapes的键名与顺序必须分别等于 contract 中 inputs/outputs 的声明顺序;- 每个 shape 必须是具体整数数组(
concrete=True时禁止符号); - 校验器会用 case 的 params 和 input_shapes 构造符号环境(
_case_environment),再把合同 shape 表达式求值,逐一比对 case 的 input/output shape 是否等于公式代入结果(_validate_case_expected_shapes,报错形如shape [31, 16] does not equal [32, 16]); - 若符号在该 case 中绑定具体值,还须落在
dynamic_axes_ranges的闭区间内(_validate_case_ranges)。
tolerance 与 perf_target
tolerance严格含atol、rtol两个字段,且必须是非负有限数;perf_target只允许null或正有限数(_validate_perf_target),把 SKILL.md 的"单一来源规则"落成机器可查的约束。
兼容字段p0_shapes:校验通过后,_validate返回的字典会附加p0_shapes = 首个 case 的 input_shapes 列表,供旧调用方(如 Stage 2 golden 脚手架)直接消费,SPEC 文件本身不双写该字段。
CLI 行为:python validate_spec.py <spec.md>成功打印PASS: SPEC JSON machine contract is valid并返回退出码 0;任何失败打印FAIL: <原因>并返回退出码 1。
用回归测试理解"合法"与"非法"边界
test_validate_spec.py 是一份可直接当"正反示例教材"的回归测试。它内置的合法合同demo_op(y = x,输入输出["N", 16]float32,N ∈ [1,128],两个 P0 case)是理解 machine-contract 最小形态的最佳起点:
{ "schema_version": 1, "op_name": "demo_op", "formula": "y = x", "supported_dtypes": ["float32"], "inputs": [{"name": "x", "shape": ["N", 16], "dtype": "float32", "value_range": [-4, 4]}], "outputs": [{"name": "y", "shape": ["N", 16], "dtype": "float32", "value_range": [-4, 4]}], "default_params": {}, "tolerance": {"atol": 0.001, "rtol": 0.002}, "dynamic_axes_ranges": {"N": [1, 128]}, "shape_constraints": [], "perf_target": null, "p0_cases": [ {"name": "small", "params": {}, "input_shapes": {"x": [8, 16]}, "output_shapes": {"y": [8, 16]}}, {"name": "large", "params": {}, "input_shapes": {"x": [32, 16]}, "output_shapes": {"y": [32, 16]}} ] }测试覆盖的"必拒"场景,正是写 SPEC 时的高频错误清单:
| 场景 | 报错关键字 |
|---|---|
| JSON 重复键 | duplicate JSON key |
| 残留模板占位符 | unresolved template placeholder |
supported_dtypes为空 | canonical dtypes |
| P0 输出 shape 与公式代入不符 | does not equal |
| formula 缺失/空串/非字符串 | missing fields: formula/non-empty string |
| 两个 machine-contract block | exactly one |
| 未知字段 | unknown fields |
perf_target为字符串/布尔/0/负数/对象/NaN | perf_target |
未知 dtype(如banana) | canonical dtypes |
| 动态符号范围缺失或多余 | exactly match shape symbols |
符号未作为输入独立维度出现(如["2*N", 16]) | standalone dimension |
另有两条正向用例值得注意:test_preserves_mixed_public_tensor_dtypes验证"同一接口混合 dtype(如 index 用 int32、数据用 float32)时,supported_dtypes按首次出现顺序原样保留",这正是 SKILL.md 要求"不丢失 index/mask/量化辅助 tensor 的 dtype"的机器化保障;test_valid_contract_and_compatibility_field验证p0_shapes从首个 case 正确导出。
完成条件:一张可勾选的验收清单
生成 SPEC 后必须逐项满足(对应 SKILL.md"完成条件"):
- 算子名、数学语义和最小输入输出合同均已确定;
- shape、dtype、动态轴、optional 参数和边界行为已确认或按无人值守规则留有证据;
- 复杂算子含可恢复的算法步骤;
- 所有功能均标优先级,P0/P1 没有遗漏;
- 所有 P0 配置均可供 golden 构造输入,且输出 shape 与机器合同公式一致;
- 所有机器合同输入/输出均有有依据、可解析的有限
value_range; - SPEC 恰有一个严格 JSON machine-contract、正文没有重复机器字段、无占位符或未披露默认值;
- 用户性能目标或 Stage 5 默认 Golden 1.0 理想参考的来源已按规则明确记录;
validate_spec.py通过。
与下游的交接:kernel 契约补充与 Stage 1 门禁
SPEC 冻结后并非直接进入设计。根据 pypto-pro-op-plan/SKILL.md,Stage 1 会在SPEC.md末尾追加"kernel 契约补充"小节,记录通用需求模板不表达的边界——辅助张量语义(公开输入/模型参数/内部临时量)、cast 边界链(输入、累加、后处理、输出各段的语义 dtype)、累加/写回语义(覆盖写/跨块累加/原子累加)、目标设备(未指定默认 A5 并标注为默认假设)、以及"由 Stage 3 设计"的 topology/tile/同步标记。若这些字段会改变数学语义或公开接口,必须回到本技能修订并重新确认;若只是硬件实现选择,留给 Stage 3。
整条链路最后落到机器门禁:Stage 1 收尾运行validate_stage1.py,它会复用本技能的validate_spec.py作为 canonical SPEC 校验器(见 validate_stage1.py 中对pypto-pro-intent-understand/scripts/validate_spec.py的引用),再经 verifier 的stage1-check门禁与complete_stage(1)状态推进。也就是说,一份通过校验的 SPEC.md,既是需求语义的权威记录,也是后续 Stage 2–5 所有阶段可引用的机器可读契约——这就是"需求规格化"在 PyPTO-Pro 流水线中的价值所在。
【免费下载链接】pypto-gymPyPTO-Gym 是基于 PyPTO 编程框架构建的算子与模型样例仓库项目地址: https://gitcode.com/cann/pypto-gym
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考