omk 术语规范
范围: 这是 omk 维护者的内部设计决策归档(为什么 artifact 不叫 evaluand、为什么 v0.16 起废
--variants、qualityScore → judgeScore 迁移路径等)。不是新用户入门文档——日常用法看 README 即可。中英双版并存(docs/specs/英文 /docs/zh/specs/中文),术语本身全是英文,源码为命名的事实来源。
一、目标
这份规范用于统一 omk 后续迭代中的对外文案、命令示例、数据结构与代码命名。
目标有三条:
- 对齐行业与开源社区常见说法,尽量减少 omk 私有术语
- 把"被评测对象"、"运行环境"、"实验分组"与"实验角色"四层拆开,避免混用
- 为未来扩展到 skill、agent、workflow、agent team 等载体保留统一抽象
二、标准术语
1. Artifact
artifact 是 omk 对"被评测对象"的统一标准术语。
它表示在实验中被拿来比较、注入、运行或观测的对象,可以是:
baselineskillpromptagentworkflow- 未来的
team或其他新型知识载体
规则:
- 对外文档优先使用
artifact - 对内核心类型、请求结构、任务结构优先使用
artifact
2. Artifact Kind
artifact kind 是 artifact 的具体类别。
当前支持:
baselineskillpromptagentworkflow
规则:
baseline表示空 artifact,也就是不注入任何显式 artifact;对大多数使用者来说,可以直接理解为"什么都没有"skill、agent、workflow是 artifact 的子类,不是顶层总称- 新增载体时,优先扩展
artifact kind,不要另起一套平行抽象
3. Variant
variant 是一次实验中的一条对比臂的表达式,不是领域对象本身。
例如:
baselineprd/path/to/SKILL.md(runtime context 的 cwd 单独声明,不编码进表达式)
规则:
- variant 表达式解析后得到 artifact 与 runtime context
- 每个 variant 都必须绑定一个 experiment role(control 或 treatment),见第 4 节
- CLI 层按 experiment role 声明 variant(
--control/--treatment),不再使用扁平的--variants参数
4. Experiment Role
experiment role 是 variant 在当次实验中扮演的角色,采用统计学标准术语。
枚举:
control— 对照组,提供基线测量treatment— 干预组(实验组),对比 control 看变化
规则:
- role 是 variant 的 run-time 属性,不是 artifact 的固有属性;同一个 artifact 在不同 run 可以扮演不同 role
- CLI 层通过
--control <expr>和--treatment <v1,v2,...>两个独立参数声明 - 报告中以 control/treatment 标签展示,不再从
artifactKind === 'baseline'反推角色 baseline是 artifact kind 术语,不是 experiment role 术语;参见第三节边界
5. Runtime Context
runtime context 是运行时上下文,当前最核心的是 cwd。
它表示模型或 agent 在什么环境里运行,而不是"被评测对象"本身。
在项目型 agent 场景下,runtime context 就直接包含这些会影响行为的环境因素:
- 项目目录
CLAUDE.md- 本地 skills
- 仓库文件
- 工具可见范围
规则:
cwd归属于 runtime context,单独声明(CLI 的--control-cwd/--treatment-cwd,或 eval.yaml 的结构化cwd:字段),不编码进 variant 表达式- 如果要表达"空 artifact + 指定 runtime context",用自描述标签作 artifact、cwd 单独给,例如
--treatment project-env --treatment-cwd /path/to/project - 不要把项目目录、项目级 runtime context、显式 artifact 注入混成一个概念
6. Sample / 用例
sample 是评测的一条用例(test case)记录。
规则:
- 代码 / API / 文件名 / CLI flag 继续用
sample:Sample类型、sample_id字段、eval-samples.json文件名、--samplesflag——这些是开源 API + 英文圈 LLM eval 通用术语,不动 - user-facing 中文文案默认用「用例」,不用「样本」:CLI 输出、报告 UI、错误信息、文档正文、commit message 中文部分。包括"用例数"/"用例难度"/"用例不足"/"跨用例散度"等组合
- 理由:omk 的
eval-samples是开发者手挑的测试用例,不是从某分布随机抽样的统计样本。「样本」会暗示"再多跑就能扩大样本量",误导用户——实际是要补设计、补用例。「用例」是工程语境(test case),与用户写测评时的心智一致("我设计了 5 个用例") - 例外:统计学术语场景保留「样本」——Cohen's d / Hedges' g 的"小样本修正"、"样本均值"、"样本方差"、"样本量"、bootstrap "重采样" 等,这些是 stats 领域的固定提法(对应英文 small-sample correction / sample mean / sample variance / sample size / resampling),硬翻成「用例」反而让懂统计的读者多一拍。判定准则:这个词指的是"对总体的一次随机抽样"统计概念(那就是样本),还是**"开发者手挑的一条测试用例"**(那就是用例)。两者不混用、上下文清晰
6.1 Sample 元数据字段
Sample schema 含 4 个可选元数据字段,纯文档 / 诊断用,不参与 grading / judge / verdict。详见 docs/zh/specs/sample-design-spec.md。
capability?: string[]— 该 sample 测试的能力维度(可多个)。归一时大小写 / 短横线 / 驼峰 / 下划线不敏感。difficulty?: 'easy' | 'medium' | 'hard'— 难度分层(强枚举)。construct?: string— 该 sample 测的 construct 类型。Suggested:'necessity'(测必要性,baseline-vs-skill)/'quality'(测 skill 写得好不好)/'capability'(测某具体能力)。Free-form string 允许自定义。provenance?: 'human' | 'llm-generated' | 'production-trace'— 数据来源。
construct 跟 capability 区别(用户最常混淆的两个字段):
- construct = 这个 sample 测哪类事(necessity / quality / capability)。是实验设计的层面 — 你跑 baseline-vs-skill 是测必要性,跑 skill-v1-vs-skill-v2 是测质量。
- capability = 这个 sample 测哪些具体能力(api-selection / error-diagnosis / fallback)。是被测对象的能力维度。
7. Task
task 是一次具体执行单元:
一个 sample × 一个 artifact × 一个 runtime context
规则:
- 任务层不直接代表实验结论
- 任务是执行与评分的最小单位
8. Trace
trace 是一次执行过程中产生的过程数据,包括:
- turns
- tool calls
- timing
- token / cost / cache 等执行指标
规则:
- trace 属于运行结果
- trace 用于解释 agent 行为差异,不用于命名被评测对象
三、术语边界
1. baseline 就是"什么都没有"
baseline 的标准含义是:
- 不做显式 artifact 注入
- 不额外附带项目级 runtime context
对大多数使用者来说,baseline 就可以直接理解为"什么都没有"。
如果要单独观察项目级 runtime context,推荐显式写成:
- artifact 用自描述标签
project-env,cwd 用--treatment-cwd /path/to/project(或 eval.yaml 的cwd:字段)
这里的 project-env 只是实验分组标签,真正的语义是"空 artifact + 指定 runtime context"。
2. skill 不是总称
skill 只在对象确实是 skill 文件、skill 目录或 skill 风格 system prompt 时使用。
以下场景不要用 skill 做总称:
- 比较多个不同类型对象
- 描述 CLI 通用变体语法
- 描述未来 agent team、workflow 等对象
3. agent 不是总称
agent 用于描述具有 agent 运行特征的 artifact 或运行形态,例如:
- 有工具调用
- 有多轮轨迹
- 依赖运行时环境
但 agent 不应替代 artifact 成为通用术语。
4. baseline kind 和 control role 不是一回事
baseline 是 ArtifactKind 枚举中的一员,表示"空 artifact"(不注入任何显式 artifact)。 control 是 experimentRole 的取值,表示"这个 variant 在本次实验里扮演对照角色"。
两者正交:
- 一个
baselinekind 的 artifact 通常扮演controlrole,但这不是定义 - 两个都是
skillkind 的 artifact(v1 vs v2)比较时,其中一个被显式声明为control——此时 control role 和 baseline kind 没有任何关系 - 报告与代码都应以
experimentRole作为判定对照组的唯一来源,不从artifactKind === 'baseline'反推
5. CI 在 omk 里只指 Confidence Interval
omk 里 CI 永远只指置信区间(Confidence Interval),不指 Continuous Integration。这条避免与统计学外的 "CI" 含义混淆。
规则:
- 持续集成场景的内部 helper 一律用 "gate":
omk eval的 gate 路径 /evaluateLayerGates/gateThreshold/LayerGateResult - 置信区间场景一律用 "CI":
bootstrap CI/diff CI/bootstrapCI字段 / "95% CI" - 文档 / 注释 / commit message 提到 "CI" 时不必加澄清 — 单一含义,读者不需上下文判断
6. 稳定性 = 跨重复运行(test-retest),不是跨用例散度
稳定性(stability)的概念对齐 psychometrics 的 test-retest reliability——同一对象在重复运行下的分数一致性。omk 采用 CV(变异系数,工程领域相对离散度指标)作主指标;它与 psychometrics 严格意义的 test-retest reliability(通常用 ICC 或 Pearson r)不完全等价,不是 psychometrics 标准下的 reliability 测量,而是同类概念下的工程化近似。
omk 的具体实现:--repeat N 让同一 (variant × sample) 跑 N 次,report.variance.perVariant[v] 存多次运行的分数序列。稳定性主指标 CV = σ / mean(变异系数,无量纲相对散度),副指标 σ + 95% CI。阈值 <5% / 5~15% / >15% 为 1-5 分数量纲下的经验值,不是学术文献引用值。
什么不是稳定性:
- 跨用例 min~max 分数范围不是稳定性。同一 variant 在多个用例上的分数差异,大部分来自用例难度本身不同(eval-samples 通常有意覆盖多种任务),不是 variant 内在波动。把这个 range 叫稳定性是误读——读者看到"100%"会错以为 variant 很稳定,实际可能只是用例集太窄。
- **成功率(success rate)**不是稳定性。成功率反映的是"任务有没有完成"(执行健康度),和"分数在重复测时抖动多大"(测量稳定性)是两个独立概念。成功率 < 100% 时在副区 alert,不作为稳定性主指标。
UI 约定:
- 六维对比表"稳定性"列主值:有 variance 数据时显示
CV X.X%,没有(单轮评测 / 无--repeat)时显示—+ 副区需 --repeat ≥ 2。诚实交代测不到什么。 - 行业对照:Anthropic / OpenAI eval docs、Braintrust、Langfuse 等都把多次运行之间的 variance 作为稳定性核心指标,不用跨用例散度。
7. 三层评分:事实 / 行为 / LLM 评价
LayeredScores 把 composite(合成分)拆成三个正交层,字段依次 factScore / behaviorScore / judgeScore,UI 分别展示为 "事实" / "行为" / "LLM 评价"。
| 层 | 字段 | 来源 | 本质 |
|---|---|---|---|
| 事实 | factScore | 事实类断言通过率(contains / json_schema / fact_check 等) | 规则可验证 · 客观 |
| 行为 | behaviorScore | 行为类断言通过率(tools_called / tool_output_contains / turns_max 等) | 规则可验证 · 客观 |
| LLM 评价 | judgeScore | LLM judge 基于 rubric 的主观评分(= results.llmScore) | 模型评委 · 主观 |
"LLM 评价"不叫"质量"的原因:
composite合成分 = 三层算术平均;外部推广采用基础四维框架(质量 / 成本 / 效率 / 准确性),"质量"指代 composite 合成分这一维- 如果把
judgeScore也叫"质量层",同一份报告里就会有表头"质量 3.85"与 detail"质量层: 4"两个语义完全不同的数字,读者无法区分 - "LLM 评价"明示来源是 LLM 评委,和"事实 / 行为"的规则验证形成语义对比,三层并列无歧义
judge作为字段名与已有术语judgeExecutor/judgeModel对齐
代码约定:
- 对外文档、UI label、变更记录提及这一层时用 "LLM 评价"(中文)/ "LLM judge"(英文)
- 代码字段、类型、枚举值统一使用
judge/judgeScore/avgJudgeScore - 不要在新代码里再出现
qualityScore/avgQualityScore(属 v0.15 遗留命名,v0.16 已废除)
四、对外表达规范
1. 文档
对外文档采用以下优先级:
- 顶层总称:
artifact - 实验分组:
variant - 实验角色:
control/treatment - 运行环境:
runtime context - 具体对象类型:
skill/agent/workflow
2. 命令示例
命令示例中:
- 使用
--control <expr>+--treatment <v1,v2,...>按 experiment role 声明 variant - variant 表达式解析为 artifact 与 runtime context
- 示例对象尽量写具体路径或具体名称,不用泛化占位代替所有场景
- 复杂实验配置推荐用
--config eval.yaml,CLI 参数只承担简单场景
3. 报告与验收
报告、验收文档应优先回答:
- 这次比较的 artifact 是什么
- 它们运行在什么 runtime context 中
- 谁是 control、谁是 treatment
- 差异来自 artifact 本身,还是来自 runtime context
五、对内实现规范
1. 类型与字段
新代码优先使用:
ArtifactArtifactKindartifactstask.artifactartifactHashesVariantConfig.experimentRole(新增字段,枚举'control' | 'treatment')
2. 去兼容策略
omk 当前仍处于 0-1 阶段,用户规模很小,因此不主动保留历史兼容层。
规则:
- 新实现直接收敛到 artifact 术语
- 旧命名如果会造成长期歧义,应直接删除,而不是继续挂兼容别名
- 破坏性调整优先在现在完成,不向后滚雪球
- v0.16 起
--variants直接移除(不打 deprecation warning),用户迁移到--control/--treatment
3. 命名原则
- 通用抽象用
artifact - 具体子类用
skill/agent/workflow - 实验编排用
variant - 实验角色用
control/treatment(不用baseline/experiment) - 运行环境用
runtime context/cwd
4. 裸 kind 留给 ArtifactKind
在 omk 的产品语义里,裸 kind 留给 Artifact.kind(ArtifactKind:baseline / skill / prompt / agent / workflow)。baseline 表示 eval 里的空 artifact;实验角色仍然看 control / treatment。命令行设计同理:未来如果出现 --kind,它也应该表示 artifact kind,而不是安装目标、report 类型或 observe event 类型。
其它判别字段如果是新字段,或能安全改名,就用限定名。已经落盘的既有 kind 字段保持原样,除非单独做 migration:
report.kind→reportKind/documentKindevent.kind→eventKindexecutorRuntime.kind→runtimeKindstandard.kind→standardKind
两条注意:
- 持久化判别字段冻结。 任何已经序列化进 report / observe / doctor / diagnosis JSON 的
kind都是落盘格式里的字段名:改名会破坏反序列化磁盘上已有的文件,所以要单独走数据 / schema 迁移(本轮不做)。这是序列化向后兼容,不是统计可比性 —— 改字段名不改任何测量数字。(report.kind另外还在 Report schema 不变量清单里,改它按常规 schema 谨慎处理。) - 内部非持久字段的改名是渐进式的 —— 改到那块代码时顺手做,不搞一次性大扫除。一个 CI 护栏冻结当前裸
kind声明点的集合,防止新的不加限定的kind混进来。
六、术语映射
| 旧术语 | 新标准术语 | 说明 |
|---|---|---|
| evaluand | artifact | 被评测对象的统一总称 |
| EvaluandSpec | Artifact | 核心对象类型 |
| EvaluandKind | ArtifactKind | 对象类别 |
| evaluands | artifacts | 请求中的对象列表 |
| task.evaluand | task.artifact | 单个任务绑定的对象 |
| evaluandHashes | artifactHashes | artifact 内容哈希 |
| skillHashes | artifactHashes | report 中的统一对象哈希 |
| skill 作为总称 | artifact | skill 退回为具体子类 |
| agent 作为总称 | artifact / agent runtime | 视语义选择 |
--variants CLI 参数 | --control / --treatment | 按 experiment role 声明 variant,废除扁平列表 |
从 artifactKind === 'baseline' 推断对照组 | 显式读 experimentRole === 'control' | 对照组由用户声明,不从 artifact kind 反推 |
LayeredScores.qualityScore | LayeredScores.judgeScore | UI 展示为 "LLM 评价" / "LLM judge";避免与表头"质量"(composite) 重名 |
VariantSummary.avgQualityScore | VariantSummary.avgJudgeScore | 同上 |
VarianceLayerKey: 'quality' | VarianceLayerKey: 'judge' | 同上 |
七、Skill Isolation(v0.22 新增)
1. 问题背景
omk 跑 baseline-vs-skill 评测时,baseline variant 默认通过三条 channel 拿到 ~/.claude/skills/ 里的所有 skill,导致 baseline 实际不是"裸模型"——construct invalidity:
- SDK skill auto-discovery:Claude Agent SDK 默认扫
~/.claude/skills/把 skill 列表注入 main session system prompt - subagent Skill 工具:即便 main session 没 skill,SDK 内置 task subagent 调
Skill(...)仍会按需加载 skill 内容 - cwd 文件系统访问:baseline 默认 cwd 是用户评测工作目录,该目录通常有
skills/<name>/symlink 给 treatment 用,baseline 用 plainGlob/Read工具就能顺 symlink 直接读SKILL.md
三条 channel 都堵掉之后,baseline 才真的"裸"。任何一条没堵,baseline 都会绕过其他堵点拿到 skill 内容,verdict / Δ 反映的是污染基线 vs treatment,而不是真实"无知识 vs 有知识"。
2. 术语
allowedSkills(per-variant 字段,新加在Artifact/VariantConfig/EvalConfigVariant上):undefined→ SDK 默认行为(全发现~/.claude/skills/)[]→ 完全隔离:options.skills = []+options.disallowedTools = ['Skill'],main session 不发现任何 skill,subagent 也无法调 Skill 工具[name1, name2]→ 白名单:options.skills = [name1, name2],只载入指定 skill。subagent 走独立 channel,白名单场景 v1 不强制 subagent 跟随(follow-up)
--strict-baselineflag(default true):对所有kind === 'baseline'的 artifact 自动设allowedSkills = [];--no-strict-baseline关掉(显式 opt-out)meta.skillIsolation(report meta 新字段):variantName → allowedSkills 快照,跨报告对比 verdict / Δ 时校验
3. 默认值与优先级
eval.yaml variant.allowedSkills (显式)
> CLI --strict-baseline / --no-strict-baseline (批量)
> default (strictBaseline = true)baseline-kind 默认 [](strict),其他 kind 默认 undefined(SDK 全发现)。
4. 隔离覆盖范围
| Channel | 覆盖? | 机制 |
|---|---|---|
| Main session skills | ✅ | options.skills = [] |
| SDK 内置 task subagent 调 Skill 工具 | ✅(allowedSkills=[] 时) | options.disallowedTools = ['Skill'] |
| cwd 文件系统(baseline 走 cwd → skills/ symlink → SKILL.md) | ✅(strict + 用户没显式 cwd 时) | baseline cwd 切到 ~/.oh-my-knowledge/isolated-cwd/ 空目录 |
| MCP servers | ✅(已默认堵) | SDK settingSources 默认 [],omk 不传 mcpServers |
AgentDefinition.skills 白名单精确控制 | ❌(known hole, v1 不做) | follow-up:omk 加 agents option |
| script executor | ❌ | stderr warn,用户自定义不参与 isolation |
为什么 cwd 这条 channel 单独列出:仅堵 SDK 两条 channel(skills:[] + disallowedTools:['Skill'])后,baseline 的 Skill 工具调用确实降到 0,但 baseline 仍能用 plain Glob / Read 顺 cwd 下的 skills/<name>/ symlink 读到 SKILL.md,完全绕过 SDK 隔离。根因:omk 默认 baseline.cwd === null → SDK fallback 到 process.cwd() = 用户评测工作目录,那里通常有 skills/<name>/ symlink 给 treatment 用。修法是 baseline 默认 cwd 切到 ~/.oh-my-knowledge/isolated-cwd/(空目录)。用户显式给 baseline 设 cwd 时不动(显式 cwd = 用户负责该目录干净)。
注:isolated-cwd 不是 sandbox,baseline 仍可 Read 任意 absolute path。但模型不会主动猜用户私有路径(没 system prompt 暗示)。如果评测场景里 baseline 会被 prompt 引导去读绝对路径,需要再加层 sandbox 保护(out-of-scope)。
5. cache key 版本
cache key 当前为 v4: prefix,含 allowedSkills、executor 名和 executor runtime 指纹入键 — 切换 strict / non-strict、跨 executor 或 binary / SDK 版本变化都不会误命中旧输出。
6. executor 兼容
| Executor | undefined | [] | [name] |
|---|---|---|---|
claude-sdk | 默认全发现 | skills:[] + disallowedTools:[Skill] | skills:[name] |
claude-cli | 默认 | --disable-slash-commands --disallowedTools Skill | throw(用户改 sdk) |
script | 默认 | stderr warn,不阻塞(无效) | stderr warn,不阻塞(无效) |
claude-cli executor 用 --disable-slash-commands(文档:"Disable all skills")+ --disallowedTools Skill 双堵,跟 SDK 等价,只缺 partial whitelist 能力——白名单 [name] 需求必须走 claude-sdk(SDK skills option 直接支持白名单语义)。script executor 用户自定义,无法保证遵循 isolation,只 warn。
八、落地判断标准
后续新增功能、文档或接口时,如果遇到命名选择,按下面顺序判断:
- 它是在描述被评测对象吗?如果是,用
artifact - 它是在描述实验分组吗?如果是,用
variant - 它是在描述实验角色吗?如果是,用
control/treatment - 它是在描述运行目录或环境吗?如果是,用
runtime context - 它是在描述具体对象类型吗?如果是,用
skill/agent/workflow - 如果一个词同时混合了对象、环境或角色语义,就要拆开重写