Skip to main content
一个团队要在某一件任务上把模型做好,需要的每一块在这个平台上都已经有了 —— 而这正是问题。一个 recipe、一个环境、两个 benchmark pack、一份 rubric、一套工具链、一种数据形状,是分散在六个地方的 七个对象,各自都没错;把它们拼成「我们是这样做 RTL 修复的」,是每个团队都要从头再做一遍的活。 他们没法互相抄的,恰恰是最花时间的那一块:验收协议 —— 对哪个基线、怎么留出测试集、至少多少道 题、好多少才算更好。 工程方案(Solution)就是一份声明:点名那七个,并把第八个写下来。

工程方案不运行任何东西

它不含奖励函数、不含 harness、不含训练代码。里面每一个字段都是一个名字,在安装它的那个部署上 解析,平台从不执行包里的任何东西。这条边界和平台其他地方是同一条:控制面负责解析、校验、存储与调 度,作业里跑什么属于你的项目或某个插件。 一个把 rubric 正文嵌进去的方案,就是那份 rubric 的第二个副本,会和训练真正打分用的那份越走越远。 解析不到的名字会被报成缺失,那是运维能据以行动的事实;漂移了的内嵌副本根本无法被发现。
solution.yaml
既不点名 recipe、也不点名环境的清单会被拒:那样用户就没有任何可以起步的东西。不在九种之内的 data_format 会被拒,并附上完整列表。

每一个官方方案都对着 prompt 基线比

acceptance.baseline 接受一个模型引用,或者字符串 prompt —— 在同一个基座模型上只用提示词的基 线。四个随附方案用的都是 prompt,这是刻意的。
如果在基座模型上认真写提示词就已经够用,正确的做法是把它发出去并量出来,而不是跑一次训练。 没有 prompt 基线的协议永远不会让这种情况浮出水面,于是训练任务照样被立项。
协议其余部分的判断标准是一样的:提前老老实实定下来很便宜,事后再老老实实定则不可能。 min_delta 不能为负。「越小越好」的指标用 direction: lower 表达,而不是写一个负的 delta。 每个方案都至少声明一个 min_delta: 0.0 的护栏指标。一个在 RTL 通过率上涨、却悄悄丢掉指令跟随的 模型并没有变好;它只是把一种能力换成了另一种,而且没有说出来。

随附的四个

rtl-repair 从「模型答了」到「有工具说它能用」的路径最短,所以在一个新部署上它是第一个值得试 的。pass@1 必须比 prompt 基线高 0.05;syntax_passinst_level_strict_acc 不许退步;至少 120 道题;按 design 切分。 testbench-generation 训练模型写 bench 而不是写设计。它那两个指标故意往相反方向拉 —— 一份 bench 既要接受正确的设计,要拒绝坏掉的设计,而 assert(1) 单看前一项就能满分。 eda-script-assistant 是公开数据最少、私有数据最多的那一个。它那两个 pack 是护栏、不是度量: 它真正被判的是团队自己脚本组成的私有题集,那种东西不可能随官方方案一起发布,只能由安装它的部署自 己声明。human_review 在这里是承重的 —— 能跑的脚本不等于对的脚本,它可能悄悄约束错了时钟。 eda-log-triage 不涉及仿真器、也不声明工具链,所以它是这里唯一一个没有 EDA 工具链的部署也能 跑的工作流。它按 case 而不是 design 切分:同一个故障被报了两次,是一件事实。

训练之前先读协议

show 会打印这个方案引用了什么、它的数据形状,然后按人必须做决定的顺序打印协议:
在第一次运行之前把它冻住。这个字段的全部价值,就在于它是先写下来的。

把它搭进你的项目

init 把方案的 template/ 目录复制到 <into>/<name>,然后就结束了。它不提交、不配置部署,也不 写下任何随后归平台所有的东西。文件落在你的仓库里、归你改;没有任何东西被上传,模板在你的容器里运 行,信任级别和你自己写的任何代码一样。 目标目录已存在时是拒绝而不是合并 —— 一个覆盖了一半的脚手架比两种结果都糟 —— 所以 --force 是你 表示「我就是要这么做」的方式。
随附的四个方案都没有带 template/ 目录。 对它们中任何一个执行 tp solution init 都会打印 solution '<name>' ships no template 并以 1 退出。在某个方案带上模板之前,内置方案能用的是 listshow,而 init 是给你自己部署发布的方案用的。

这个部署能不能跑某个方案

一个名字只有在有人核对它解析得到才值得发布,而这件核对恰恰是 SDK 做不到的 —— 它知道清单写了什么, 却完全不知道这里有哪些。两个只读接口做这件事:
列表给出 ready 以及没解析到的那些引用 —— 是点名而不是计数,因为人接下来要做的正是把这些装上。 详情再加上每个引用的种类和说明,以及方案声明的那份验收协议。 ready 的意思是每一个名字都解析得到。少一个 benchmark pack 的方案不是「基本就绪」:验收协议 点名了那个 pack,所以缺它跑出来的结果是对着别的东西量的。 两个路由都是只读。工程方案的安装走的是所有声明式包共用的插件接口,在这里再开一条创建路径,就是给 同一个对象搞出第二套摘要和鉴权规则。
这个构建里 Toolchain Profile 还不是一个独立对象。 方案的 toolchain 引用是对着部署配置的 sandbox 镜像解析的,引用上会带一条说明。配了 sandbox 镜像的部署能跑需要工具链的方案,没配的不 能。

写你自己的

工程方案是一个 kind: solution 插件 —— 声明式包,所以平台只解析、从不运行它:
plugin.yaml
三条规则,在两个不同的地方被检查:
  • template/ 之外不许有可执行文件,发布时拒绝。根目录下的 .py 意味着有人期待平台去 import 它,而这正是声明式包绝不能制造的期待。要交给用户的脚手架放在 template/ 下,在用户自己的环境 里运行。
  • 目录名必须等于 name,加载目录时拒绝。目录叫 rtl-flow、清单里写 name: our-rtl-flow, 加载不进去。
  • 内置方案不可被遮蔽。 内置先加载、先写入者胜,所以一个叫 rtl-repair 的包不会替换随附的那 个。两个人跑「同一个」方案却拿到不同协议,对验收协议来说比对 recipe 更糟,因为不一样的那个 东西是结果的定义本身。
已发布的包安装在 $TUNEPLANE_HOME/solutions/<owner>/<name>/ —— 没设 TUNEPLANE_HOME 时就是 ~/.tuneplane —— 并以 <owner>/<name> 引用;内置的保留裸名字。开发用的 checkout 可以用 TUNEPLANE_SOLUTION_PATH 追加目录,在 Linux 和 macOS 上用 : 分隔。

工程方案不做什么

在依赖它之前,把边界说清楚。
  • 验收协议是一份记录,不是一道门禁。 平台不会拿一次运行去和声明的 baseline 比、不会按 sample_min 数题目、也不会因为没达到 min_delta 就拒绝晋级。真正起强制作用的是 spec.evaluation.gates 里按作业声明的评测门禁 —— 见运行评测。 工程方案是团队把协议写下来的地方;遵守它仍然是团队自己的事。
  • split_by 是一个意图声明。 它点名你的切分应当尊重哪个字段。平台不会在提交时替你算泄漏 —— 哪些通了、哪些没通,见数据形状与切分
  • 控制台还没有工程方案页面。 tp solution 和那两个 API 路由就是全部的界面。
  • 这里没有任何东西在真实硬件上端到端打过分。 面向硬件的那几个方案指向的工具链镜像从未在 CI 里 构建过,指向的评测器也没有任何本项目的 runner 跑得起来; RTL 评测写明了哪些没有被证明。

下一步

tp solution 命令参考 · RTL 评测 · 数据形状与切分 · Benchmark pack · 插件