"""Harness² 融合演示:不花模型钱,跑通一轮完整改进。 用法(在项目根目录): python3 examples/harness2_demo.py --mode parallel --k 1 python3 examples/harness2_demo.py --mode sequential --k 1 --output /tmp/h2demo 任务是对账本求和。base harness 的脚本只加正数(账本含一笔负数 credit, base 会漏掉它);确定性编辑器去掉正数过滤;选择器按产物挑带符号和; 反思器把“正负都要算”写进经验库。跑完打印:被采纳的产物、回落情况、 经验库条目位置。真实接线时,这里的三个确定性类换成 codex 任务 (见 docs/harness2.md),执行器换成 Worker 的任务执行,循环本身不变。 """ import argparse import subprocess import sys import tempfile from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from cloud.harness2 import ( # noqa: E402 EditResult, Library, Rollout, improve_task, read_tree, write_tree, ) BASE_SCRIPT = """import csv import sys from decimal import Decimal with open(sys.argv[1]) as f: amounts = [Decimal(r['amount']) for r in csv.DictReader(f)] print(f"Total: {sum((a for a in amounts if a > 0), Decimal(0)):.2f}") """ BASE_TREE = { "AGENTS.md": "Use scripts/summarize.py to total the ledger.\n", "scripts/summarize.py": BASE_SCRIPT, } class LedgerAdapter: task_id = "ledger-1" domain = "accounting" prompt = "Sum every signed amount in ledger.csv. Return Total: with two decimals." def __init__(self, root): self.root = Path(root) self.root.mkdir(parents=True, exist_ok=True) self.ledger = self.root / "ledger.csv" self.ledger.write_text("amount\n100.25\n-20.10\n5.00\n", encoding="utf-8") self.executions = 0 def base_harness(self): return dict(BASE_TREE) def execute(self, label, harness): self.executions += 1 work = self.root / "runs" / label work.mkdir(parents=True, exist_ok=True) write_tree(harness, work / "harness") proc = subprocess.run( [sys.executable, str(work / "harness" / "scripts" / "summarize.py"), str(self.ledger)], capture_output=True, text=True, timeout=10) out = proc.stdout.strip() return Rollout(label=label, ok=proc.returncode == 0, delivered=out.startswith("Total:"), deliverable_text=out, trajectory="[ACTION] Run scripts/summarize.py\n[OBSERVATION]\n" + out, cost_usd=0.01) def validate_tree(self, harness): if "scripts/summarize.py" not in harness: raise ValueError("The local executor requires scripts/summarize.py") class FixEditor: def edit(self, mission, context_dir, label): harness_dir = Path(context_dir) / "harness" script = harness_dir / "scripts" / "summarize.py" script.write_text(script.read_text().replace(" if a > 0", ""), encoding="utf-8") return EditResult(tree=read_tree(harness_dir), notes="Keep signed amounts: the base total omitted credits.") class PickSignedSelector: def select(self, mission, context_dir): for path in sorted((Path(context_dir) / "candidates").glob("*.md")): if "Total: 85.15" in path.read_text(): return path.stem, "The signed total matches the source ledger.", 0.0 raise ValueError("no candidate with the signed total") class LedgerReflector: def reflect(self, mission, context_dir): root = Path(context_dir) changed = (root / "harness" / "scripts" / "summarize.py").read_text() != ( root / "base_harness" / "scripts" / "summarize.py").read_text() if not changed: return {} return { "cue": "When a ledger includes credits and debits", "lesson": "Include both signs when summing in scripts/summarize.py.", "evidence": "Removing the positive-only filter changed the probe total to " "include the credits omitted by the base trajectory.", "confidence": "high for this observed arithmetic contrast", } def main(): ap = argparse.ArgumentParser() ap.add_argument("--mode", default="parallel", choices=["parallel", "sequential"]) ap.add_argument("--k", type=int, default=1) ap.add_argument("--output", default="") args = ap.parse_args() tmp = None root = Path(args.output) if args.output else Path(tempfile.mkdtemp(prefix="h2demo-")) if not args.output: tmp = root adapter = LedgerAdapter(root) library = Library(root / "library", "accounting") result = improve_task(adapter, FixEditor(), selector=PickSignedSelector(), reflector=LedgerReflector(), work_dir=root / "work", k=args.k, mode=args.mode, library=library) chosen = result.mode_result.rollouts[result.selection.chosen_label] print(f"mode={result.mode} k={args.k} ok={result.ok}") print(f"executions={adapter.executions} (base + candidates + finals)") print(f"chosen={result.selection.chosen_label} deliverable={chosen.deliverable_text}") print(f"fell_back={result.mode_result.fell_back or 'none'}") print(f"library_entry={result.library_entry}") print(f"experience={result.experience.get('lesson', '(none)')}") print(f"work_dir={root}") assert chosen.deliverable_text == "Total: 85.15", "demo must end at the signed total" assert result.library_entry is not None, "demo must enter the library" print("demo OK: signed total adopted and stored in the library") _ = tmp if __name__ == "__main__": main()