oh-my-knowledge 0.24.0 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +85 -22
  2. package/README.zh.md +82 -22
  3. package/dist/src/analysis/saturation.d.ts +2 -2
  4. package/dist/src/analysis/saturation.js +2 -2
  5. package/dist/src/authoring/evolver.d.ts +7 -4
  6. package/dist/src/authoring/evolver.d.ts.map +1 -1
  7. package/dist/src/authoring/evolver.js +15 -7
  8. package/dist/src/authoring/evolver.js.map +1 -1
  9. package/dist/src/cli/i18n-dict.d.ts +1 -1
  10. package/dist/src/cli/i18n-dict.d.ts.map +1 -1
  11. package/dist/src/cli/i18n-dict.js +213 -40
  12. package/dist/src/cli/i18n-dict.js.map +1 -1
  13. package/dist/src/cli/index.js +188 -87
  14. package/dist/src/cli/index.js.map +1 -1
  15. package/dist/src/cli/parse-run-config.d.ts +32 -9
  16. package/dist/src/cli/parse-run-config.d.ts.map +1 -1
  17. package/dist/src/cli/parse-run-config.js +76 -21
  18. package/dist/src/cli/parse-run-config.js.map +1 -1
  19. package/dist/src/cli/parse-strict.d.ts +20 -0
  20. package/dist/src/cli/parse-strict.d.ts.map +1 -0
  21. package/dist/src/cli/parse-strict.js +25 -0
  22. package/dist/src/cli/parse-strict.js.map +1 -0
  23. package/dist/src/doctor/index.d.ts +19 -0
  24. package/dist/src/doctor/index.d.ts.map +1 -0
  25. package/dist/src/doctor/index.js +182 -0
  26. package/dist/src/doctor/index.js.map +1 -0
  27. package/dist/src/doctor/preflight.d.ts +32 -0
  28. package/dist/src/doctor/preflight.d.ts.map +1 -0
  29. package/dist/src/doctor/preflight.js +32 -0
  30. package/dist/src/doctor/preflight.js.map +1 -0
  31. package/dist/src/doctor/renderer.d.ts +13 -0
  32. package/dist/src/doctor/renderer.d.ts.map +1 -0
  33. package/dist/src/doctor/renderer.js +69 -0
  34. package/dist/src/doctor/renderer.js.map +1 -0
  35. package/dist/src/doctor/rules.d.ts +30 -0
  36. package/dist/src/doctor/rules.d.ts.map +1 -0
  37. package/dist/src/doctor/rules.js +216 -0
  38. package/dist/src/doctor/rules.js.map +1 -0
  39. package/dist/src/eval-core/bootstrap.d.ts +1 -1
  40. package/dist/src/eval-core/bootstrap.js +1 -1
  41. package/dist/src/eval-core/comparability.d.ts.map +1 -1
  42. package/dist/src/eval-core/comparability.js +82 -57
  43. package/dist/src/eval-core/comparability.js.map +1 -1
  44. package/dist/src/eval-core/dependency-checker.js +1 -1
  45. package/dist/src/eval-core/dependency-checker.js.map +1 -1
  46. package/dist/src/eval-core/evaluation-execution.d.ts +20 -7
  47. package/dist/src/eval-core/evaluation-execution.d.ts.map +1 -1
  48. package/dist/src/eval-core/evaluation-execution.js +29 -5
  49. package/dist/src/eval-core/evaluation-execution.js.map +1 -1
  50. package/dist/src/eval-core/evaluation-job.d.ts +2 -4
  51. package/dist/src/eval-core/evaluation-job.d.ts.map +1 -1
  52. package/dist/src/eval-core/evaluation-job.js +1 -3
  53. package/dist/src/eval-core/evaluation-job.js.map +1 -1
  54. package/dist/src/eval-core/evaluation-reporting.d.ts.map +1 -1
  55. package/dist/src/eval-core/evaluation-reporting.js +12 -14
  56. package/dist/src/eval-core/evaluation-reporting.js.map +1 -1
  57. package/dist/src/eval-core/schema.d.ts.map +1 -1
  58. package/dist/src/eval-core/schema.js +7 -2
  59. package/dist/src/eval-core/schema.js.map +1 -1
  60. package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts +6 -4
  61. package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts.map +1 -1
  62. package/dist/src/eval-workflows/batch-evaluation-workflow.js +14 -12
  63. package/dist/src/eval-workflows/batch-evaluation-workflow.js.map +1 -1
  64. package/dist/src/eval-workflows/evaluation-pipeline.d.ts +2 -2
  65. package/dist/src/eval-workflows/evaluation-pipeline.d.ts.map +1 -1
  66. package/dist/src/eval-workflows/evaluation-pipeline.js +39 -34
  67. package/dist/src/eval-workflows/evaluation-pipeline.js.map +1 -1
  68. package/dist/src/eval-workflows/evaluation-preparation.d.ts +5 -20
  69. package/dist/src/eval-workflows/evaluation-preparation.d.ts.map +1 -1
  70. package/dist/src/eval-workflows/evaluation-preparation.js +2 -21
  71. package/dist/src/eval-workflows/evaluation-preparation.js.map +1 -1
  72. package/dist/src/eval-workflows/run-evaluation.d.ts +11 -10
  73. package/dist/src/eval-workflows/run-evaluation.d.ts.map +1 -1
  74. package/dist/src/eval-workflows/run-evaluation.js +123 -16
  75. package/dist/src/eval-workflows/run-evaluation.js.map +1 -1
  76. package/dist/src/grading/assertions.js +4 -4
  77. package/dist/src/grading/assertions.js.map +1 -1
  78. package/dist/src/grading/gold-cli.js +4 -4
  79. package/dist/src/grading/gold-cli.js.map +1 -1
  80. package/dist/src/grading/human-gold.d.ts +1 -1
  81. package/dist/src/grading/human-gold.js +1 -1
  82. package/dist/src/grading/index.d.ts +20 -15
  83. package/dist/src/grading/index.d.ts.map +1 -1
  84. package/dist/src/grading/index.js +29 -16
  85. package/dist/src/grading/index.js.map +1 -1
  86. package/dist/src/grading/judge.d.ts +1 -1
  87. package/dist/src/grading/judge.js +1 -1
  88. package/dist/src/inputs/eval-config.js +65 -7
  89. package/dist/src/inputs/eval-config.js.map +1 -1
  90. package/dist/src/renderer/html-renderer.d.ts.map +1 -1
  91. package/dist/src/renderer/html-renderer.js +32 -12
  92. package/dist/src/renderer/html-renderer.js.map +1 -1
  93. package/dist/src/renderer/summary.js +1 -1
  94. package/dist/src/renderer/summary.js.map +1 -1
  95. package/dist/src/types/doctor.d.ts +95 -0
  96. package/dist/src/types/doctor.d.ts.map +1 -0
  97. package/dist/src/types/doctor.js +2 -0
  98. package/dist/src/types/doctor.js.map +1 -0
  99. package/dist/src/types/eval.d.ts +36 -17
  100. package/dist/src/types/eval.d.ts.map +1 -1
  101. package/dist/src/types/executor.d.ts +33 -0
  102. package/dist/src/types/executor.d.ts.map +1 -1
  103. package/dist/src/types/index.d.ts +1 -0
  104. package/dist/src/types/index.d.ts.map +1 -1
  105. package/dist/src/types/index.js +1 -0
  106. package/dist/src/types/index.js.map +1 -1
  107. package/dist/src/types/judge.d.ts +11 -0
  108. package/dist/src/types/judge.d.ts.map +1 -1
  109. package/dist/src/types/report.d.ts +21 -52
  110. package/dist/src/types/report.d.ts.map +1 -1
  111. package/package.json +6 -6
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # oh-my-knowledge
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/oh-my-knowledge.svg)](https://www.npmjs.com/package/oh-my-knowledge)
4
+ [![npm weekly downloads](https://img.shields.io/npm/dw/oh-my-knowledge.svg)](https://www.npmjs.com/package/oh-my-knowledge)
4
5
  [![CI](https://github.com/lizhiyao/oh-my-knowledge/actions/workflows/ci.yml/badge.svg)](https://github.com/lizhiyao/oh-my-knowledge/actions/workflows/ci.yml)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
7
  [![Node.js Version](https://img.shields.io/node/v/oh-my-knowledge.svg)](https://nodejs.org)
@@ -10,7 +11,7 @@
10
11
  **omk** — The knowledge you give your LLM — what's it actually worth?
11
12
  omk answers with objective data, not gut feeling.
12
13
 
13
- **Fix the model, vary the knowledge artifact.**
14
+ **Evaluation framework for LLM knowledge inputs** — prompts, RAG corpora, skills, agent workflows. Fix the model, vary the artifact.
14
15
 
15
16
  <a id="statistical-rigor"></a>
16
17
  > Built-in: Bootstrap CI · Krippendorff α (judge ↔ human) · length-debias · saturation curves · construct-validity isolation. [Why these matter →](docs/statistical-rigor.md)
@@ -37,23 +38,39 @@ omk bench run --dry-run
37
38
 
38
39
  # run the evaluation (auto-discovers everything under skills/)
39
40
  omk bench run # → HTML report with verdict in 5 minutes
41
+ # (omk doctor + LLM connectivity check both run as mandatory gates;
42
+ # --skip-connectivity available for connectivity, doctor is unconditional)
40
43
 
41
44
  # CLI output language: zh (default) / en — flag wins over env
42
45
  omk bench run --lang en
43
46
  OMK_LANG=en omk bench report
44
47
  ```
45
48
 
46
- ## Use inside Claude Code
49
+ ## Use inside AI Coding Agents
47
50
 
48
- After installing omk, talk to it in natural language from Claude Code:
51
+ ### Use inside Claude Code
49
52
 
50
- ```
53
+ When the `omk` skill is available in Claude Code, you can invoke it directly like this:
54
+
55
+ ```bash
51
56
  /omk eval # evaluate the artifact(s) in the current project
52
57
  /omk evolve # auto-iterate to improve an artifact
53
58
  /omk gen-samples # generate test cases
54
59
  ```
55
60
 
56
- You can also just say "compare v1 vs v2 for me" or "improve this artifact" omk picks the right command.
61
+ You can also just say "compare v1 vs v2 for me" or "improve this artifact" and omk picks the right command.
62
+
63
+ ### Use inside Codex
64
+
65
+ Codex does not support Claude Code style `/omk ...` slash commands by default. In Codex, the usual pattern is to ask the agent to run the `omk` CLI directly, for example:
66
+
67
+ ```bash
68
+ omk bench run
69
+ omk bench evolve
70
+ omk bench gen-samples skills/my-skill.md
71
+ ```
72
+
73
+ You can also describe the goal in natural language, such as "compare v1 vs v2" or "generate test cases for this skill".
57
74
 
58
75
  ## Why this tool
59
76
 
@@ -61,6 +78,7 @@ Teams doing knowledge engineering produce lots of knowledge artifacts (skills to
61
78
 
62
79
  ## Key features
63
80
 
81
+ - **Pre-evaluation health check** — `omk doctor` runs as a mandatory gate before `bench run` / `bench gate`; checks skill readability, metadata, dependencies, samples contract — pure static, zero LLM calls (like lint + typecheck for knowledge artifacts). Executor / judge connectivity is a separate phase, controllable via `--skip-connectivity`
64
82
  - **Controlled-variable offline bench** — fix the model and samples, vary only the artifact; works with Claude Code skills, CLAUDE.md prompts, RAG knowledge bases, or any markdown-based instruction
65
83
  - **Six-dimension scoring** — separate signals for Fact / Behavior / LLM-judge / Cost / Efficiency / Stability, so a regression in one axis isn't hidden by gains in another
66
84
  - **Production session observability** — parse Claude Code session JSONL traces, measure per-skill failure rate, latency, token cost, and knowledge-gap signals on real user sessions
@@ -376,7 +394,9 @@ options:
376
394
  samples + variants + model + executor in one file; CLI
377
395
  flags override config fields when both are provided
378
396
  --model <name> task execution model (default: sonnet)
379
- --judge-model <name> judge model (default: haiku)
397
+ --judge-models <list> judge config; 1 entry = single judge (default
398
+ claude:haiku), ≥ 2 entries = ensemble. Format:
399
+ `executor:model[,executor:model]`
380
400
  --output-dir <path> output dir (default: ~/.oh-my-knowledge/reports/)
381
401
  --no-judge skip the LLM judge
382
402
  --no-cache disable result cache (on by default; identical inputs reuse)
@@ -386,7 +406,10 @@ options:
386
406
  --timeout <sec> per-task executor timeout (default: 120)
387
407
  --repeat <n> repeat N times for variance analysis (default: 1)
388
408
  --executor <name> executor (default: claude); supports custom commands
389
- --skip-preflight skip evaluation model reachability check
409
+ --skip-connectivity skip the LLM connectivity check (doctor still runs;
410
+ doctor is mandatory and has no skip flag).
411
+ Auto-applied on --resume (the original run already
412
+ verified connectivity).
390
413
  --mcp-config <path> MCP config for fetching private-doc URLs via MCP Server
391
414
  (default: .mcp.json in cwd)
392
415
  --no-serve don't auto-start the report server after the run
@@ -394,8 +417,6 @@ options:
394
417
  --batch batch mode: evaluate each artifact independently vs baseline
395
418
  requires {name}.eval-samples.json paired with each artifact
396
419
  --judge-repeat <n> run the LLM judge N times per (sample × dimension) and report stddev
397
- --judge-models <list> multi-judge ensemble: "executor1:model1,executor2:model2"
398
- ≥ 2 judges enables ensemble + inter-judge agreement output
399
420
  --bootstrap enable distribution-free CIs: bootstrap CI per variant +
400
421
  pairwise diff CI (CI containing 0 = not significant)
401
422
  --bootstrap-samples N bootstrap resample count (default 1000)
@@ -414,6 +435,29 @@ options:
414
435
 
415
436
  **eval.yaml budget**: declare `budget: { totalUSD?, perSampleUSD?, perSampleMs? }` (all optional, must be ≥ 0). CLI flags of the same name override the config values.
416
437
 
438
+ **eval.yaml experiment-design fields**: the same flags above can be set in `eval.yaml` for reproducible experiment configuration (CLI > eval.yaml > default):
439
+
440
+ ```yaml
441
+ samples: ./eval-samples.yaml
442
+ model: sonnet
443
+ repeat: 5 # multi-run variance, ≥ 1
444
+ judgeRepeat: 3 # per (sample × dim) judge self-consistency, ≥ 1
445
+ bootstrap: true # distribution-free CI per variant
446
+ bootstrapSamples: 2000 # default 1000, ≥ 100
447
+ goldDir: ./gold # post-run α / κ / Pearson against human anchor
448
+ lengthDebias: true # default; set false to reproduce pre-v0.21 hash
449
+ strictBaseline: true # default; set false to disable skill isolation
450
+ noJudge: false # default; set true to skip LLM judge entirely
451
+ judgeModels: # 1 entry = single judge; ≥ 2 = ensemble
452
+ - { executor: claude, model: opus }
453
+ - { executor: openai-api, model: gpt-4o }
454
+ variants:
455
+ - { name: baseline, role: control, artifact: baseline }
456
+ - { name: my-skill, role: treatment, artifact: ./skills/my-skill.md }
457
+ ```
458
+
459
+ **Field entry points**: `bench run` reads every field above. `bench gate` goes through `parseRunConfig` and picks up the shared subset (`variants` / `executor` / `model` / `judgeModels` — both single-judge and ensemble — / `noJudge` / `noCache` / `blind` / `strictBaseline` / `budget` / `mcpConfig` / `variantAllowedSkills`); the experiment-design fields handled by `handleRun` (`repeat` / `judgeRepeat` / `bootstrap` / `bootstrapSamples` / `goldDir` / `lengthDebias`) are intentionally not read by `gate` and can be extended later. Other subcommands (`evolve` / `verdict` / `diff` / `analyze` / …) do not read `eval.yaml`.
460
+
417
461
  **Difference from `cost_max` / `latency_max` assertions**: assertions are **per-sample scoring rules** (exceeding the cap fails that one assertion, the run continues); budget caps are **workflow-level hard limits** (`totalUSD` overrun aborts the run and persists a partial report; per-sample overruns fail the offending sample but the run continues). Assertions answer "is quality acceptable?"; budgets answer "are cost/time within the envelope?".
418
462
 
419
463
  ### `omk bench run --batch` (batch mode)
@@ -501,6 +545,26 @@ omk bench gate [options]
501
545
  independently to fact / behavior / judge
502
546
  ```
503
547
 
548
+ ### `omk doctor` (pre-evaluation health check)
549
+
550
+ Pure static / zero-LLM checks — analogous to lint + typecheck in the SE toolchain. Runs as a mandatory gate before `bench run` / `bench gate` so a typo'd YAML or missing dependency aborts with an actionable error instead of producing a garbage-in verdict. Also runnable standalone for local iteration or CI.
551
+
552
+ ```bash
553
+ omk doctor # batch check every skill in current dir / ./skills
554
+ omk doctor skills/v1.md # single file
555
+ omk doctor skills/ --json # JSON output for CI consumption
556
+ omk doctor --gate; echo $? # silent mode — exit 1 if any fatal check fails
557
+ ```
558
+
559
+ What `doctor` checks:
560
+
561
+ - **skill readable** — file exists, content non-empty, has minimum length
562
+ - **skill metadata** — front-matter (if present) is valid YAML; directory-skills have `SKILL.md`
563
+ - **dependencies present** — referenced CLI tools, files, env vars all available (reuses `preflightDependencies`)
564
+ - **samples ↔ skill contract** — when samples are provided, validate they're non-empty and have prompt fields (warn-level)
565
+
566
+ Executor / judge connectivity is verified by a separate evaluation preflight phase, not by doctor — clean boundary: doctor is static, eval is dynamic. `bench run` / `bench gate` abort with `exit 1` and stderr `doctor failed:` prefix when doctor fails. **Doctor is mandatory and not skippable** (static checks have no cost reason to skip); LLM connectivity is separately controllable via `--skip-connectivity` (auto-skipped on `--resume`).
567
+
504
568
  ### `omk bench report`
505
569
 
506
570
  Start the report server to browse historical reports, submit feedback, and delete reports.
@@ -545,7 +609,7 @@ Re-judges every (sample × variant) of an existing report with the OPPOSITE leng
545
609
  ```bash
546
610
  omk bench debias-validate length <reportId> [options]
547
611
  --variant <name> check a single variant only
548
- --judge-model <id> override the report's judge model
612
+ --judge-models <executor:model> override the report's judge (single-judge only)
549
613
  --bootstrap-samples N bootstrap iterations (default 1000)
550
614
  --seed N deterministic seed
551
615
  ```
@@ -601,8 +665,7 @@ When 14 of 50 samples failed, reading them one by one is slow. This command send
601
665
 
602
666
  ```bash
603
667
  omk bench failures <reportId> [options]
604
- --judge-executor <name> executor (default: claude)
605
- --judge-model <id> clustering model (default: from report.meta.judgeModel)
668
+ --judge-models <executor:model> clustering judge (default: from report.meta.judgeModels[0]; single-judge only)
606
669
  --max-clusters <n> maximum clusters (default 5)
607
670
  --threshold <num> failure score threshold (default 3)
608
671
  --max-feed <n> max failures fed to LLM (default 50; takes the worst)
@@ -675,7 +738,7 @@ The command writes `~/.oh-my-knowledge/analyses/<timestamp>-skill-health.json`.
675
738
 
676
739
  API-direct executors support custom base URLs via env: `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`.
677
740
 
678
- Codex construct-validity notes: (1) `codex` uses the `codex` binary on `PATH`; `codex-sdk` uses the bundled `@openai/codex` binary resolved by `@openai/codex-sdk`. Reports persist per-variant `meta.executorRuntimes` plus `meta.executorRuntime` / `meta.judgeRuntime` fingerprints (binary or SDK version + capability snapshot), and `bench diff` / `bench verdict` warn when strict comparability cannot be audited. If runtime fingerprints differ, treat results as an executor-runtime comparison, not only prompt/template behavior. (2) Both executors isolate user-level config: `codex` passes `--ephemeral` + `--ignore-user-config`; `codex-sdk` redirects `$CODEX_HOME` to a per-process tmp dir (auth.json symlinked through). User-level `~/.codex/config.toml` does not leak into eval runs in either case.
741
+ Codex construct-validity notes: (1) `codex` uses the `codex` binary on `PATH`; `codex-sdk` uses the bundled `@openai/codex` binary resolved by `@openai/codex-sdk`. Reports persist per-variant `meta.executorRuntimes`, `meta.executorRuntime`, and per-judge `meta.judgeModels[].runtime` fingerprints (binary or SDK version + capability snapshot), and `bench diff` / `bench verdict` warn when strict comparability cannot be audited. If runtime fingerprints differ, treat results as an executor-runtime comparison, not only prompt/template behavior. (2) Both executors isolate user-level config: `codex` passes `--ephemeral` + `--ignore-user-config`; `codex-sdk` redirects `$CODEX_HOME` to a per-process tmp dir (auth.json symlinked through). User-level `~/.codex/config.toml` does not leak into eval runs in either case.
679
742
 
680
743
  ### Custom executor
681
744
 
@@ -861,25 +924,25 @@ omk bench run \
861
924
  export OPENAI_API_KEY="your Zhipu API key"
862
925
  export OPENAI_BASE_URL="https://open.bigmodel.cn/api/paas/v4"
863
926
  omk bench run --executor openai-api --model glm-4-plus \
864
- --judge-model glm-4-plus --no-cache
927
+ --judge-models openai-api:glm-4-plus --no-cache
865
928
 
866
929
  # Qwen (Alibaba)
867
930
  export OPENAI_API_KEY="your Qwen API key"
868
931
  export OPENAI_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
869
932
  omk bench run --executor openai-api --model qwen-plus \
870
- --judge-model qwen-plus
933
+ --judge-models openai-api:qwen-plus
871
934
 
872
935
  # DeepSeek
873
936
  export OPENAI_API_KEY="your DeepSeek API key"
874
937
  export OPENAI_BASE_URL="https://api.deepseek.com"
875
938
  omk bench run --executor openai-api --model deepseek-chat \
876
- --judge-model deepseek-chat
939
+ --judge-models openai-api:deepseek-chat
877
940
 
878
941
  # Moonshot (Kimi)
879
942
  export OPENAI_API_KEY="your Moonshot API key"
880
943
  export OPENAI_BASE_URL="https://api.moonshot.cn/v1"
881
944
  omk bench run --executor openai-api --model moonshot-v1-8k \
882
- --judge-model moonshot-v1-8k
945
+ --judge-models openai-api:moonshot-v1-8k
883
946
  ```
884
947
 
885
948
  **Ollama local model:**
@@ -889,11 +952,11 @@ omk bench run --executor "python examples/custom-executor/ollama-executor.py" \
889
952
  --model llama3 --no-judge
890
953
  ```
891
954
 
892
- **About the judge model:**
955
+ **About the judge:**
893
956
 
894
- - `--judge-model` picks the model used by the LLM judge (default `haiku`)
895
- - `--judge-executor` picks the executor the judge uses (defaults to `--executor`)
896
- - If you don't have Claude, point `--judge-executor` and `--judge-model` at whatever model you have
957
+ - `--judge-models <list>` picks the LLM judge(s). Format: `executor:model[,executor:model]`. Default: `${executor}:haiku` (or claude:haiku when no `--executor` set)
958
+ - 1 entry = single judge; 2 entries = multi-judge ensemble + inter-judge agreement
959
+ - If you don't have Claude, point `--judge-models` at whatever you have, e.g. `--judge-models openai-api:glm-4-plus`
897
960
  - Add `--no-judge` to skip the LLM judge and rely on assertions alone
898
961
 
899
962
  ## Environment variables
@@ -926,4 +989,4 @@ This tool is designed for **local trusted environments** (dev machines, CI pipel
926
989
 
927
990
  ---
928
991
 
929
- See [CHANGELOG](./CHANGELOG.md) for release notes. Contributions welcome — see [CONTRIBUTING](./CONTRIBUTING.md).
992
+ See [GitHub Releases](https://github.com/lizhiyao/oh-my-knowledge/releases) for release notes. Contributions welcome — see [CONTRIBUTING](./CONTRIBUTING.md).
package/README.zh.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # oh-my-knowledge
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/oh-my-knowledge.svg)](https://www.npmjs.com/package/oh-my-knowledge)
4
+ [![npm weekly downloads](https://img.shields.io/npm/dw/oh-my-knowledge.svg)](https://www.npmjs.com/package/oh-my-knowledge)
4
5
  [![CI](https://github.com/lizhiyao/oh-my-knowledge/actions/workflows/ci.yml/badge.svg)](https://github.com/lizhiyao/oh-my-knowledge/actions/workflows/ci.yml)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
7
  [![Node.js Version](https://img.shields.io/node/v/oh-my-knowledge.svg)](https://nodejs.org)
@@ -10,7 +11,7 @@
10
11
  **omk** — 你给 LLM 的知识,价值在哪里?
11
12
  omk 帮你用客观数据回答,而不是凭感觉。
12
13
 
13
- **固定模型,只变知识载体。**
14
+ **面向 LLM 知识输入(prompt / RAG / skill / agent)的评测框架** —— 固定模型,只变知识载体。
14
15
 
15
16
  <a id="statistical-rigor"></a>
16
17
  > 默认带:Bootstrap 置信区间 · Krippendorff α(评委 ↔ 人工)· 长度去偏 · 饱和曲线 · 用例隔离(construct validity)。[这些为什么重要 →](docs/zh/statistical-rigor.md)
@@ -37,17 +38,21 @@ omk bench run --dry-run
37
38
 
38
39
  # 运行评测(自动发现 skills/ 目录下的所有 artifact)
39
40
  omk bench run # → 5 分钟出 HTML 报告 + verdict
41
+ # (omk doctor 和 LLM 连通性检测都是强制前置门禁;
42
+ # --skip-connectivity 可跳连通性,doctor 无 skip flag)
40
43
 
41
44
  # CLI 输出语言: zh (默认) / en — flag 优先级高于环境变量
42
45
  omk bench run --lang en
43
46
  OMK_LANG=en omk bench report
44
47
  ```
45
48
 
46
- ## 在 Claude Code 中使用
49
+ ## 在 AI Coding Agent 中使用
47
50
 
48
- 安装 omk 后,在 Claude Code 中直接用自然语言交互:
51
+ ### Claude Code 中使用
49
52
 
50
- ```
53
+ 当 `omk` skill 已在 Claude Code 中可用时,可以直接这样调用:
54
+
55
+ ```bash
51
56
  /omk eval # 评测当前项目的 artifact
52
57
  /omk evolve # 自动迭代改进 artifact
53
58
  /omk gen-samples # 生成测试用例
@@ -55,12 +60,25 @@ OMK_LANG=en omk bench report
55
60
 
56
61
  或直接说"帮我评测 v1 和 v2 的差异"、"改进一下这个 artifact",omk 会自动理解意图并调用对应命令。
57
62
 
63
+ ### 在 Codex 中使用
64
+
65
+ Codex 默认不支持 `/omk ...` 这种 Claude Code 风格的 slash command。通常直接让 agent 执行 `omk` CLI,例如:
66
+
67
+ ```bash
68
+ omk bench run
69
+ omk bench evolve
70
+ omk bench gen-samples skills/my-skill.md
71
+ ```
72
+
73
+ 也可以直接用自然语言描述目标,例如"比较 v1 和 v2 的评测差异"、"为这个 skill 生成测试用例"。
74
+
58
75
  ## 为什么需要这个工具
59
76
 
60
77
  做知识工程的团队会产出大量知识载体(当前常见是 skill,也包括 prompt、agent、workflow 等)。当被问到"v2 比 v1 好在哪"时,需要客观数据而非主观判断。`oh-my-knowledge` 通过控制变量实验解决这个问题:相同模型、相同测试用例,只改变知识载体。
61
78
 
62
79
  ## 核心能力
63
80
 
81
+ - **评测前置健康检查** — `omk doctor` 在 `bench run` / `bench gate` 之前**强制**运行,检查 skill 可读性、元数据合法性、依赖完整性、samples 契约——纯静态零 LLM 调用,类比 SE 工具栈的 lint + typecheck。executor / judge 连通性是独立阶段,可用 `--skip-connectivity` 单独跳过
64
82
  - **控制变量离线评测** — 固定模型和用例,只变知识载体;兼容 Claude Code skill、CLAUDE.md prompt、RAG 知识库等任何 markdown 形式的指令
65
83
  - **六维独立打分** — Fact / Behavior / LLM-judge / Cost / Efficiency / Stability 分别出信号,单一维度的回退不会被其他维度的收益掩盖
66
84
  - **线上 session 观测** — 解析 Claude Code session JSONL,在真实用户会话上测量各 skill 的失败率、耗时、token 成本和知识缺口信号
@@ -374,7 +392,8 @@ omk bench run [选项]
374
392
  --config <路径> YAML/JSON 配置文件(evaluation-as-code);在一个文件里声明
375
393
  samples + variants + model + executor;CLI 参数会覆盖 config
376
394
  --model <名称> 被测模型(默认:sonnet)
377
- --judge-model <名称> 评委模型(默认:haiku
395
+ --judge-models <list> 评委配置;1 条 = 单评委 (默认 claude:haiku),
396
+ ≥ 2 条 = ensemble。格式 `executor:model[,executor:model]`
378
397
  --output-dir <路径> 输出目录(默认:~/.oh-my-knowledge/reports/)
379
398
  --no-judge 跳过 LLM 评分
380
399
  --no-cache 禁用结果缓存(默认开启,相同输入自动复用)
@@ -384,7 +403,8 @@ omk bench run [选项]
384
403
  --timeout <秒> 单个任务的执行器超时时间(默认:120)
385
404
  --repeat <n> 重复 N 次做方差分析(默认:1)
386
405
  --executor <名称> 执行器(默认:claude),支持自定义命令
387
- --skip-preflight 跳过评测前的模型连通性检查
406
+ --skip-connectivity 跳过评测前 LLM 连通性检测(doctor 仍然强制执行,无 skip flag)。
407
+ --resume 时自动跳过(原 run 已验过连通性)。
388
408
  --mcp-config <路径> MCP 配置文件,用于通过 MCP Server 获取私有文档 URL 内容
389
409
  (默认:当前目录的 .mcp.json)
390
410
  --no-serve 评测完成后不自动启动报告服务
@@ -392,8 +412,6 @@ omk bench run [选项]
392
412
  --batch 批量评测:每个 artifact 独立和 baseline 对比
393
413
  需要每个 artifact 配对 {name}.eval-samples.json
394
414
  --judge-repeat <n> 每条 sample × dimension 跑 LLM 评委 N 次,输出 stddev (评委自一致性)
395
- --judge-models <list> 多评委 ensemble: "executor1:model1,executor2:model2"
396
- ≥ 2 个 judge 触发 ensemble + inter-judge agreement 输出
397
415
  --bootstrap 启用 distribution-free CI:每个 variant 加 bootstrap CI,
398
416
  pairwise diff CI 含 0 = 不显著
399
417
  --bootstrap-samples N bootstrap 重采样次数 (默认 1000)
@@ -409,6 +427,29 @@ omk bench run [选项]
409
427
 
410
428
  **eval.yaml 预算字段**: `budget: { totalUSD?, perSampleUSD?, perSampleMs? }`,所有字段可选且必须 ≥ 0。CLI 同名 flag 覆盖配置值。
411
429
 
430
+ **eval.yaml 实验设计字段**: 上面 CLI flag 同样可以写到 `eval.yaml` 让实验配置可复现 (CLI > eval.yaml > 默认):
431
+
432
+ ```yaml
433
+ samples: ./eval-samples.yaml
434
+ model: sonnet
435
+ repeat: 5 # 多轮方差分析, ≥ 1
436
+ judgeRepeat: 3 # 每条 (sample × dim) 评委自一致性次数, ≥ 1
437
+ bootstrap: true # 每 variant distribution-free CI
438
+ bootstrapSamples: 2000 # 默认 1000, ≥ 100
439
+ goldDir: ./gold # 跑完自动对比 human anchor 算 α / κ / Pearson
440
+ lengthDebias: true # 默认; 设 false 复现 v0.21 之前的 hash
441
+ strictBaseline: true # 默认; 设 false 关掉 skill 隔离
442
+ noJudge: false # 默认; 设 true 完全跳过 LLM 评委
443
+ judgeModels: # 1 条 = 单评委; ≥ 2 条 = ensemble
444
+ - { executor: claude, model: opus }
445
+ - { executor: openai-api, model: gpt-4o }
446
+ variants:
447
+ - { name: baseline, role: control, artifact: baseline }
448
+ - { name: my-skill, role: treatment, artifact: ./skills/my-skill.md }
449
+ ```
450
+
451
+ **字段入口**: `bench run` 完整支持上述全部字段; `bench gate` 通过 `parseRunConfig` 共享 variants / executor / model / `judgeModels`(单评委 + ensemble 都生效)/ noJudge / noCache / blind / strictBaseline / budget / mcpConfig / variantAllowedSkills,但 `handleRun` 自己处理的实验设计字段(`repeat` / `judgeRepeat` / `bootstrap` / `bootstrapSamples` / `goldDir` / `lengthDebias`)gate 不读,后续按需扩展到 gate。其他子命令(`evolve` / `verdict` / `diff` / `analyze` 等)完全不读 eval.yaml。
452
+
412
453
  **和 `cost_max` / `latency_max` 断言的区别**: 断言是**单样本评分维度**(超出直接打 0 分,run 继续);budget 是**工作流级硬阈值**(`totalUSD` 超出整个 run abort 保留 partial report,per-sample 超出该样本失败但 run 继续)。一个回答"质量是否达标",一个回答"花钱/时间是否在预算内"。
413
454
 
414
455
  ### `omk bench run --batch`(批量评测)
@@ -496,6 +537,26 @@ omk bench gate [选项]
496
537
  fact / behavior / judge 三层
497
538
  ```
498
539
 
540
+ ### `omk doctor`(评测前置健康检查)
541
+
542
+ 纯静态 / 零 LLM 调用,类比 SE 工具栈的 lint + typecheck。`bench run` / `bench gate` 之前强制运行,YAML 写错、依赖缺失这类问题会 abort 评测并给可操作错误,而不是让你拿到 garbage-in 的 verdict 数字。也可独立调用,适合本地迭代或 CI 单跑。
543
+
544
+ ```bash
545
+ omk doctor # 批量检查当前目录或 ./skills 下所有 skill
546
+ omk doctor skills/v1.md # 单个文件
547
+ omk doctor skills/ --json # JSON 输出供 CI 消费
548
+ omk doctor --gate; echo $? # 静默模式 — 任意 fatal 失败 exit 1
549
+ ```
550
+
551
+ doctor 检查项:
552
+
553
+ - **skill 文件可读** — 文件存在、内容非空、有最低长度
554
+ - **skill 元数据合法** — front-matter(若有)YAML 合法;directory-skill 有 `SKILL.md`
555
+ - **前置依赖完整** — 引用的 CLI 工具、文件、环境变量都可用(复用 `preflightDependencies`)
556
+ - **用例 ↔ skill 输入约定** — 传 samples 时校验非空且含 prompt 字段(warn 级)
557
+
558
+ executor / judge 连通性由独立的 evaluation preflight 阶段负责,不在 doctor 范围内 — 边界清晰:doctor 静态,eval 动态。`bench run` / `bench gate` 在 doctor 失败时 abort(exit 1,stderr 前缀 `doctor failed:`)。**doctor 是评测必经环节,无 skip flag**(静态检查零成本无理由跳过);LLM 连通性可用 `--skip-connectivity` 单独控制(`--resume` 时自动跳过)。
559
+
499
560
  ### `omk bench report`
500
561
 
501
562
  启动报告服务,浏览历史报告、提交反馈、删除报告。
@@ -540,7 +601,7 @@ gold-dir/
540
601
  ```bash
541
602
  omk bench debias-validate length <reportId> [选项]
542
603
  --variant <name> 只测一个 variant
543
- --judge-model <id> override report 的 judge model
604
+ --judge-models <executor:model> override report 的评委(仅支持单评委)
544
605
  --bootstrap-samples N bootstrap 迭代数 (默认 1000)
545
606
  --seed N 确定性种子
546
607
  ```
@@ -596,8 +657,7 @@ omk bench diagnose <reportId> [选项]
596
657
 
597
658
  ```bash
598
659
  omk bench failures <reportId> [选项]
599
- --judge-executor <name> 执行器 (默认 claude)
600
- --judge-model <id> 聚类用 model (默认沿用 report.meta.judgeModel)
660
+ --judge-models <executor:model> 聚类评委 (默认沿用 report.meta.judgeModels[0],仅支持单评委)
601
661
  --max-clusters <n> 最多多少 cluster (默认 5)
602
662
  --threshold <num> 算失败的分数阈值 (默认 3)
603
663
  --max-feed <n> 最多喂给 LLM 多少条 (默认 50,超出取最差)
@@ -670,7 +730,7 @@ omk analyze ~/.claude/projects/my-project --kb /path/to/project
670
730
 
671
731
  API 直调执行器支持通过环境变量自定义 Base URL:`ANTHROPIC_BASE_URL`、`OPENAI_BASE_URL`。
672
732
 
673
- Codex construct-validity 说明:(1) `codex` 使用 `PATH` 上找到的 `codex` binary;`codex-sdk` 使用 `@openai/codex-sdk` 解析到的自带 `@openai/codex` binary。报告会持久化 per-variant `meta.executorRuntimes` 以及 `meta.executorRuntime` / `meta.judgeRuntime` 指纹(binary 或 SDK 版本 + 能力快照),`bench diff` / `bench verdict` 会在 strict comparability 无法审计时提示。runtime 指纹不一致时,结果应解释为 executor runtime 对比,而不只是 prompt/template 行为对比。(2) 两个 executor 都隔离用户级 config:`codex` 传 `--ephemeral` + `--ignore-user-config`,`codex-sdk` 把 `$CODEX_HOME` 重定向到 per-process tmp 目录(auth.json 通过 symlink 透传)。用户的 `~/.codex/config.toml` 不会渗入任意一个 executor 的 eval。
733
+ Codex construct-validity 说明:(1) `codex` 使用 `PATH` 上找到的 `codex` binary;`codex-sdk` 使用 `@openai/codex-sdk` 解析到的自带 `@openai/codex` binary。报告会持久化 per-variant `meta.executorRuntimes`、`meta.executorRuntime`,以及每个评委的 `meta.judgeModels[].runtime` 指纹(binary 或 SDK 版本 + 能力快照),`bench diff` / `bench verdict` 会在 strict comparability 无法审计时提示。runtime 指纹不一致时,结果应解释为 executor runtime 对比,而不只是 prompt/template 行为对比。(2) 两个 executor 都隔离用户级 config:`codex` 传 `--ephemeral` + `--ignore-user-config`,`codex-sdk` 把 `$CODEX_HOME` 重定向到 per-process tmp 目录(auth.json 通过 symlink 透传)。用户的 `~/.codex/config.toml` 不会渗入任意一个 executor 的 eval。
674
734
 
675
735
  ### 自定义执行器
676
736
 
@@ -856,25 +916,25 @@ omk bench run \
856
916
  export OPENAI_API_KEY="你的智谱 API Key"
857
917
  export OPENAI_BASE_URL="https://open.bigmodel.cn/api/paas/v4"
858
918
  omk bench run --executor openai-api --model glm-4-plus \
859
- --judge-model glm-4-plus --no-cache
919
+ --judge-models openai-api:glm-4-plus --no-cache
860
920
 
861
921
  # 通义千问
862
922
  export OPENAI_API_KEY="你的通义 API Key"
863
923
  export OPENAI_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
864
924
  omk bench run --executor openai-api --model qwen-plus \
865
- --judge-model qwen-plus
925
+ --judge-models openai-api:qwen-plus
866
926
 
867
927
  # DeepSeek
868
928
  export OPENAI_API_KEY="你的 DeepSeek API Key"
869
929
  export OPENAI_BASE_URL="https://api.deepseek.com"
870
930
  omk bench run --executor openai-api --model deepseek-chat \
871
- --judge-model deepseek-chat
931
+ --judge-models openai-api:deepseek-chat
872
932
 
873
933
  # Moonshot(Kimi)
874
934
  export OPENAI_API_KEY="你的 Moonshot API Key"
875
935
  export OPENAI_BASE_URL="https://api.moonshot.cn/v1"
876
936
  omk bench run --executor openai-api --model moonshot-v1-8k \
877
- --judge-model moonshot-v1-8k
937
+ --judge-models openai-api:moonshot-v1-8k
878
938
  ```
879
939
 
880
940
  **Ollama 本地模型:**
@@ -884,12 +944,12 @@ omk bench run --executor "python examples/custom-executor/ollama-executor.py" \
884
944
  --model llama3 --no-judge
885
945
  ```
886
946
 
887
- **关于评委模型:**
947
+ **关于评委:**
888
948
 
889
- - `--judge-model` 指定 LLM 评委使用的模型,默认 `haiku`
890
- - `--judge-executor` 指定评委使用的执行器(默认与 `--executor` 相同)
891
- - 如果你没有 Claude,用 `--judge-executor` `--judge-model` 指向你可用的模型
892
- - 加 `--no-judge` 可跳过 LLM 评委,仅使用断言评分
949
+ - `--judge-models <list>` 指定评委,格式 `executor:model[,executor:model]`。默认 `${executor}:haiku`(没设 `--executor` 时为 claude:haiku)
950
+ - 1 = 单评委;≥ 2 条 = 多评委 ensemble + inter-judge agreement
951
+ - 没有 Claude 时把 `--judge-models` 指向你可用的模型,例如 `--judge-models openai-api:glm-4-plus`
952
+ - 加 `--no-judge` 可跳过 LLM 评委,仅使用断言评分
893
953
 
894
954
  ## 环境变量
895
955
 
@@ -921,4 +981,4 @@ omk bench run --executor "python examples/custom-executor/ollama-executor.py" \
921
981
 
922
982
  ---
923
983
 
924
- 版本变更记录见 [CHANGELOG](./CHANGELOG.md)。欢迎贡献 — 详见 [CONTRIBUTING](./CONTRIBUTING.md)。
984
+ 版本变更记录见 [GitHub Releases](https://github.com/lizhiyao/oh-my-knowledge/releases)。欢迎贡献 — 详见 [CONTRIBUTING](./CONTRIBUTING.md)。
@@ -7,7 +7,7 @@
7
7
  * is "is N=30 enough, or should I keep running?". Without a principled
8
8
  * answer, users either over-pay (running 200 when 50 was enough) or
9
9
  * under-pay (calling skill effects null at N=30 when N=80 would have
10
- * shown clearly significant — Bootstrap CI from Phase 1 just hasn't
10
+ * shown clearly significant — Bootstrap CI just hasn't
11
11
  * converged yet).
12
12
  *
13
13
  * Saturation analysis fits the right tool to the question: track a
@@ -19,7 +19,7 @@
19
19
  * checkpoints. Easy to explain. Fragile to outlier samples.
20
20
  * - **bootstrap-ci-width** (default): CI shrinks as O(1/√N); when its
21
21
  * decay rate flattens, more samples buy little. Statistically
22
- * grounded; pairs naturally with Phase 1.
22
+ * grounded; pairs naturally with the Bootstrap CI module.
23
23
  * - **plateau-height**: range of mean across the last K checkpoints.
24
24
  * Conservative — slow to declare saturation, hard to fool.
25
25
  *
@@ -7,7 +7,7 @@
7
7
  * is "is N=30 enough, or should I keep running?". Without a principled
8
8
  * answer, users either over-pay (running 200 when 50 was enough) or
9
9
  * under-pay (calling skill effects null at N=30 when N=80 would have
10
- * shown clearly significant — Bootstrap CI from Phase 1 just hasn't
10
+ * shown clearly significant — Bootstrap CI just hasn't
11
11
  * converged yet).
12
12
  *
13
13
  * Saturation analysis fits the right tool to the question: track a
@@ -19,7 +19,7 @@
19
19
  * checkpoints. Easy to explain. Fragile to outlier samples.
20
20
  * - **bootstrap-ci-width** (default): CI shrinks as O(1/√N); when its
21
21
  * decay rate flattens, more samples buy little. Statistically
22
- * grounded; pairs naturally with Phase 1.
22
+ * grounded; pairs naturally with the Bootstrap CI module.
23
23
  * - **plateau-height**: range of mean across the last K checkpoints.
24
24
  * Conservative — slow to declare saturation, hard to fool.
25
25
  *
@@ -1,4 +1,4 @@
1
- import type { ProgressCallback, Report, Sample } from '../types/index.js';
1
+ import type { JudgeConfig, ProgressCallback, Report, Sample } from '../types/index.js';
2
2
  interface WeakSample {
3
3
  sample_id: string;
4
4
  compositeScore: number;
@@ -29,12 +29,15 @@ interface EvolveOptions {
29
29
  rounds?: number;
30
30
  target?: number | null;
31
31
  model?: string;
32
- judgeModel?: string;
32
+ /** Single-judge config. evolve 不支持 ensemble — CLI 在 length>=2 时 exit 2,
33
+ * programmatic API 在 evolveSkill 入口同样 throw,二者一致。Default
34
+ * `[{ executor: <executorName>, model: 'haiku' }]`. */
35
+ judgeModels?: JudgeConfig[];
33
36
  improveModel?: string;
34
37
  executorName?: string;
35
38
  concurrency?: number;
36
39
  timeoutMs?: number;
37
- skipPreflight?: boolean;
40
+ skipConnectivity?: boolean;
38
41
  onProgress?: ProgressCallback | null;
39
42
  onRoundProgress?: ((progress: EvolveRoundProgressInfo) => void) | null;
40
43
  }
@@ -64,6 +67,6 @@ export interface RoundReport {
64
67
  report: Report;
65
68
  }
66
69
  export declare function mergeEvolveReports(roundReports: RoundReport[], skillName: string, totalCostUSD: number, samples?: Sample[]): Report;
67
- export declare function evolveSkill({ skillPath, samplesPath, rounds, target, model, judgeModel, improveModel, executorName, concurrency, timeoutMs, skipPreflight, onProgress, onRoundProgress, }: EvolveOptions): Promise<EvolveResult>;
70
+ export declare function evolveSkill({ skillPath, samplesPath, rounds, target, model, judgeModels, improveModel, executorName, concurrency, timeoutMs, skipConnectivity, onProgress, onRoundProgress, }: EvolveOptions): Promise<EvolveResult>;
68
71
  export {};
69
72
  //# sourceMappingURL=evolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"evolver.d.ts","sourceRoot":"","sources":["../../../src/authoring/evolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evolver.d.ts","sourceRoot":"","sources":["../../../src/authoring/evolver.ts"],"names":[],"mappings":"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"}
@@ -149,7 +149,15 @@ export function mergeEvolveReports(roundReports, skillName, totalCostUSD, sample
149
149
  report.analysis = analyzeResults(report, { samples });
150
150
  return report;
151
151
  }
152
- export async function evolveSkill({ skillPath, samplesPath, rounds = 5, target = null, model = DEFAULT_MODEL, judgeModel = JUDGE_MODEL, improveModel = DEFAULT_MODEL, executorName = 'claude', concurrency = 1, timeoutMs, skipPreflight = false, onProgress = null, onRoundProgress = null, }) {
152
+ export async function evolveSkill({ skillPath, samplesPath, rounds = 5, target = null, model = DEFAULT_MODEL, judgeModels, improveModel = DEFAULT_MODEL, executorName = 'claude', concurrency = 1, timeoutMs, skipConnectivity = false, onProgress = null, onRoundProgress = null, }) {
153
+ if (judgeModels && judgeModels.length > 1) {
154
+ throw new Error('evolveSkill does not support multi-judge ensemble (received '
155
+ + `${judgeModels.length} judges). Pass a single-judge array, e.g. `
156
+ + `[{ executor: 'claude', model: 'haiku' }]`);
157
+ }
158
+ const effectiveJudgeModels = judgeModels && judgeModels.length > 0
159
+ ? judgeModels
160
+ : [{ executor: executorName, model: JUDGE_MODEL }];
153
161
  const absSkillPath = resolve(skillPath);
154
162
  const absSamplesPath = resolve(samplesPath);
155
163
  const skillDir = dirname(absSkillPath);
@@ -177,7 +185,7 @@ export async function evolveSkill({ skillPath, samplesPath, rounds = 5, target =
177
185
  const reportHasUnreportedCost = (rep) => Object.values(rep.summary).some((v) => v.execCostReported === false || v.judgeCostReported === false);
178
186
  // Round 0: baseline evaluation
179
187
  const baselineReport = await evaluate(r0Path, {
180
- samplesPath: absSamplesPath, skillDir, model, judgeModel, executorName, concurrency, timeoutMs, skipPreflight, onProgress,
188
+ samplesPath: absSamplesPath, skillDir, model, judgeModels: effectiveJudgeModels, executorName, concurrency, timeoutMs, skipConnectivity, onProgress,
181
189
  });
182
190
  const baselineVariantKey = Object.keys(baselineReport.summary)[0];
183
191
  bestScore = baselineReport.summary[baselineVariantKey]?.avgCompositeScore ?? 0;
@@ -203,7 +211,7 @@ export async function evolveSkill({ skillPath, samplesPath, rounds = 5, target =
203
211
  }
204
212
  else {
205
213
  lastReport = await evaluate(allVersions[bestRound], {
206
- samplesPath: absSamplesPath, skillDir, model, judgeModel, executorName, concurrency, timeoutMs, skipPreflight, onProgress,
214
+ samplesPath: absSamplesPath, skillDir, model, judgeModels: effectiveJudgeModels, executorName, concurrency, timeoutMs, skipConnectivity, onProgress,
207
215
  });
208
216
  totalCostUSD += lastReport.meta.totalCostUSD;
209
217
  if (reportHasUnreportedCost(lastReport))
@@ -235,7 +243,7 @@ export async function evolveSkill({ skillPath, samplesPath, rounds = 5, target =
235
243
  allVersions.push(candidatePath);
236
244
  // Evaluate candidate
237
245
  const candidateReport = await evaluate(candidatePath, {
238
- samplesPath: absSamplesPath, skillDir, model, judgeModel, executorName, concurrency, timeoutMs, skipPreflight, onProgress,
246
+ samplesPath: absSamplesPath, skillDir, model, judgeModels: effectiveJudgeModels, executorName, concurrency, timeoutMs, skipConnectivity, onProgress,
239
247
  });
240
248
  const candidateVariantKey = Object.keys(candidateReport.summary)[0];
241
249
  const candidateScore = candidateReport.summary[candidateVariantKey]?.avgCompositeScore ?? 0;
@@ -289,19 +297,19 @@ export async function evolveSkill({ skillPath, samplesPath, rounds = 5, target =
289
297
  reportId,
290
298
  };
291
299
  }
292
- async function evaluate(skillFilePath, { samplesPath, skillDir, model, judgeModel, executorName, concurrency, timeoutMs, skipPreflight, onProgress }) {
300
+ async function evaluate(skillFilePath, { samplesPath, skillDir, model, judgeModels, executorName, concurrency, timeoutMs, skipConnectivity, onProgress }) {
293
301
  const { report } = await runEvaluation({
294
302
  samplesPath,
295
303
  skillDir,
296
304
  // evolve 评测每一轮只跑当前迭代的 skill,没有对照组;标为 treatment。
297
305
  variantSpecs: [{ name: skillFilePath, role: 'treatment', expr: skillFilePath }],
298
306
  model,
299
- judgeModel,
307
+ judgeModels,
300
308
  outputDir: null, // don't persist intermediate reports
301
309
  concurrency,
302
310
  timeoutMs,
303
311
  executorName,
304
- skipPreflight,
312
+ skipConnectivity,
305
313
  onProgress,
306
314
  });
307
315
  return report;