项目文件夹

文件
wehub-resource-sync acf542cac6
Sync SKILL.md and rules / sync (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:07:10 +08:00

106 行
3.2 KiB
Python

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
"""
Run each prompt through Claude Code in three conditions and snapshot the
real LLM outputs:
1. baseline — no extra system prompt at all
2. terse — system prompt: "Answer concisely."
3. terse+skill — system prompt: "Answer concisely.\n\n{SKILL.md}"
The honest delta is (3) vs (2): how much does the SKILL itself add on top
of a plain "be terse" instruction? Comparing (3) vs (1) conflates the
skill with the generic terseness ask, which is what the previous version
of this harness did.
This is the source-of-truth generator. It calls a real LLM and produces
evals/snapshots/results.json. Run it locally when SKILL.md files change.
The CI-side `measure.py` only reads the snapshot and counts tokens.
Requires:
- `claude` CLI on PATH (Claude Code), authenticated
Run: uv run python evals/llm_run.py
Environment:
CAVEMAN_EVAL_MODEL optional --model flag value passed through to claude
"""
from __future__ import annotations
import datetime as dt
import json
import os
import subprocess
from pathlib import Path
EVALS = Path(__file__).parent
SKILLS = EVALS.parent / "skills"
PROMPTS = EVALS / "prompts" / "en.txt"
SNAPSHOT = EVALS / "snapshots" / "results.json"
TERSE_PREFIX = "Answer concisely."
def run_claude(prompt: str, system: str | None = None) -> str:
cmd = ["claude", "-p"]
if system:
cmd += ["--system-prompt", system]
if model := os.environ.get("CAVEMAN_EVAL_MODEL"):
cmd += ["--model", model]
cmd.append(prompt)
out = subprocess.run(cmd, capture_output=True, text=True, check=True)
return out.stdout.strip()
def claude_version() -> str:
try:
out = subprocess.run(
["claude", "--version"], capture_output=True, text=True, check=True
)
return out.stdout.strip()
except Exception:
return "unknown"
def main() -> None:
prompts = [p.strip() for p in PROMPTS.read_text().splitlines() if p.strip()]
skills = sorted(p.name for p in SKILLS.iterdir() if (p / "SKILL.md").exists())
print(
f"=== {len(prompts)} prompts × ({len(skills)} skills + 2 control arms) ===",
flush=True,
)
snapshot: dict = {
"metadata": {
"generated_at": dt.datetime.now(dt.timezone.utc).isoformat(),
"claude_cli_version": claude_version(),
"model": os.environ.get("CAVEMAN_EVAL_MODEL", "default"),
"n_prompts": len(prompts),
"terse_prefix": TERSE_PREFIX,
},
"prompts": prompts,
"arms": {},
}
print("baseline (no system prompt)", flush=True)
snapshot["arms"]["__baseline__"] = [run_claude(p) for p in prompts]
print("terse (control: terse instruction only, no skill)", flush=True)
snapshot["arms"]["__terse__"] = [
run_claude(p, system=TERSE_PREFIX) for p in prompts
]
for skill in skills:
skill_md = (SKILLS / skill / "SKILL.md").read_text()
system = f"{TERSE_PREFIX}\n\n{skill_md}"
print(f" {skill}", flush=True)
snapshot["arms"][skill] = [run_claude(p, system=system) for p in prompts]
SNAPSHOT.parent.mkdir(parents=True, exist_ok=True)
SNAPSHOT.write_text(json.dumps(snapshot, ensure_ascii=False, indent=2))
print(f"\nWrote {SNAPSHOT}")
if __name__ == "__main__":
main()