feat(miracle): add replay-driven LLM harness loop - #19
Open
gaoxiaobei wants to merge 28 commits into
Open
Conversation
- official_logic/: 24_miracle 官方对战逻辑原样移植(子进程运行,零改动) - protocol.py/logic_runner.py: 官方线协议(4 字节长度头 + json)与子进程运行器 - host.py: 评测机——逐帧驱动官方逻辑、agent 决策桥接、全量 trace 记录、 决策超时与防卡死(相同 obs 连续 3 次 → 官方超时帧判负) - agent_bridge.py: MiracleAgent 接口 + EndRoundAgent/SampleAgent(自写规则策略, 含召唤容量感知、被拒感知、立方坐标移动) - match.py: run_match 高层对局运行器(replay/trace 落盘、seed 注入) - tests/miracle/test_smoke.py: 协议往返、双 endround 100 回合平局、 sample 对局正常终局、可复现性(5 passed)
- decision_space.py: Obs schema(UNIT/PLAYER 字段索引)、macro-action 枚举与编码、 action mask(召唤点/容量/mana/移动/攻击,含官方障碍与边界 MAPBORDER/ABYSS、 飞行地面同格)、终止条件、信息增益用动作支持集 - 官方 Parser 仲裁一致性测试: mask 全量候选被官方接受、非法动作被拒且不在 mask - 单位属性(UNIT_STATS)与官方 Data.json 核对,决策空间自包含不依赖官方目录
- ig.py: 统一口径 KL(new‖old) 逐决策点→episode→iteration 聚合落盘 - 缺失原因显式记录不冒充: support_expansion(严格 KL 发散)/state_mismatch/degenerate - 数据契约对接 AgentBenchResults: agentbench_data/ig/24_miracle/<iter>/<ep>.json + ig_index.json(iteration 汇总) - 单测 8 项:手算 KL 精确值、外扩缺失、全缺失、归一化、落盘往返
- .reasonix/skills/miracle-replay-reader/SKILL.md: 游戏规则、trace 帧格式、 obs 字段数字含义、关键事件、10 条常见误读、解析工作流 - tests/miracle/test_replay_read.py: 用真实 trace 验证 skill 格式定义 (长度前缀/字段索引/操作对齐/终局分类),7 项全过
- replay.py: 按官方 get_media_info 编码解码(7-int 块、round 单调守卫、 ActivateArtifact 变长参数),GameStart/GameEnd/操作事件全量还原 - 与真实对局交叉核对 100% 一致:Summon 12/Move 128/Attack 26/TurnEnd 44 vs trace 操作分布;GameEnd winner=0 round=44 与 MatchResult 一致 - test_replay.py 6 项:事件表、操作对齐、终局、单调性、无 UNSYNC、JSON 往返
- iterate.py: 评测→决策点收集(ε-soft 分布)→IG→导出→曲线 全管线 - SampleV2Agent: 一次受控策略更新(召唤优先级反转),AGENTS 注册即保存新版本 - AgentBenchResults 数据契约: runs/24_miracle/<族>/<iterN_ver_seedN>/ run.toml + summary.json + ig.json(aggregate.py 可直接扫描) - 演示(如实保留失败): iter0 sample 胜(30000/44轮)、iter1 sample_v2 负(0/99轮) IG=1.9474(172 决策点全可比);score/IG 曲线版本对齐 - test_iterate.py 8 项:决策点提取、ε-soft、导出契约、曲线
- versions.py: 策略源码+git commit+评测摘要+时间戳的版本快照归档 - loop.py: 改策略→存版本→再评测编排,全程 events.jsonl 可追溯 - cli.py/__main__.py: match/evaluate/iterate/replay/versions/curves 子命令 - 端到端验证: iterate sample,sample_v2 → events 5 条 + 版本快照 2 份 + IG 1.947356(172 决策点全可比) - test_loop_versions.py 6 项
- curves.py: build_curves/curves_to_svg(无依赖 SVG)/save_curves/curves_ascii
- 从 runs/ 契约目录汇总 score/IG per iteration;无数据时 no_data=true 如实标注
- 真实产物: agentbench_data/curves/24_miracle/sample_curves.{json,svg}
- test_curves.py 5 项:版本对齐、无数据报告、SVG 渲染、落盘往返
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a runnable, replay-driven LLM harness for the 24th Miracle game:
Quick start
Run all commands from the
AgentBenchFrameworkrepository root. The only Miracle entry point is:Show help with:
1. Strategy interface
A Miracle strategy implements
MiracleAgent:choose_cards(camp)selects one artifact and three creatures.act(obs)returns one official operation:summon:{type, level, position};move:{mover, position};attack:{attacker, target};endround:{};surrender:{};For manual
match/igcommands, register a named strategy once inAGENTSat the bottom ofsrc/agentbench_frame/miracle/agent_bridge.py:The LLM
loopdoes not registerv0/v1/v2globally. It loads the configured initial strategy and every generatedCandidateAgentfrom immutable per-iteration source files.2. Run a battle and save replay
agent0is first player/camp 0;agent1is second player/camp 1.seedfixes official-logic randomness such as map type and day/night values.winner,scores,rounds,terminated_by,errors,replay, andtrace.terminated_by="normal"anderrors=[].Each battle saves:
*.mrc: official binary replay;*.mrc.trace.jsonl: readable host/logic traffic, including observations and actions.The same interface is callable from Python without registration:
3. Read a replay
Parse the official
.mrcinto an event timeline:The command prints the winner, final round, and event counts.
--jsonlis optional.Use the paired
.mrc.trace.jsonlto inspect the exact observations sent to an agent and the operations returned by it. Important replay semantics:.mrcis binary, not JSON;payload.content[0]has a six-character length prefix before its JSON body;stateis not the game round; use the decoded observation'sround;30000is an official win/loss marker, not 30,000 ordinary points;units[i]is an 18-field array documented inskills/miracle-replay-reader/SKILL.md;CAN_MOVE/CAN_ATK = 0means unavailable this turn, often because the unit was just summoned or already acted;target=campmeans attack that camp's Miracle;obs; official logic remains the final legality arbiter.The full event-code, unit-field, creature/artifact-code, damage-type, and buff-type tables are in
skills/miracle-replay-reader/SKILL.md.4. Compare old and new deterministic policies (strict KL status)
First generate a real trace with
match, then replay the same observation sequence through two registered strategies:Run again with
--camp 1to compare decisions for the other seat. Outputs include per-decision records and an aggregatedig_curve.json.Strict deterministic KL reporting is intentionally not replaced by a proxy metric:
unchanged_ratio: old/new legal actions match, so strict KL is0;infinite_ratio: deterministic actions differ, so strict KL diverges;missing_ratio: an action is invalid, unparsable, or outside the finite action support;finite_kl_mean: mean of genuinely finite KL values only; otherwisenull.The finite support is generated from each observation and includes end-round, surrender, legal summons, moves, attacks, and artifact uses. Official logic still performs final adjudication.
5. Run the OpenAI-compatible LLM harness loop
Copy and edit
examples/miracle-loop.toml:initial_strategyis resolved relative to the TOML file. It must contain a completeCandidateAgentimplementation.Set the key only through the configured environment variable and start the Run:
The API contract is OpenAI-compatible
POST /v1/chat/completions. SSE streaming is enabled by default to survive long generations and gateway idle timeouts. Setstream=falseonly for a provider that does not support streaming.max_tokensis omitted by default and is sent only when explicitly configured.max_context_tokensdefaults to 1,000,000 and is checked against authoritative prompt + completion usage returned by the provider; the harness does not pretend that character counts are token counts.What the LLM sees
Every update request contains:
miracle-harnessSkill;miracle-replay-readerSkill;The LLM must return:
{ "analysis": "problem found and reason for this update", "strategy_code": "complete Python source defining CandidateAgent" }Patches, shell commands, or partial methods are rejected. The harness validates, saves, loads, battles, and compares the returned source itself.
Budget semantics
All limits are cumulative across one Run:
max_iterations: LLM update attempts, excluding baseline iteration 0;max_rollouts: battles actually started;max_episode_reads: replay episodes exposed to the LLM;max_decision_reads: individual structured observations exposed to the LLM;max_total_tokens: provider-reported total tokens;max_context_tokens: provider-reported tokens in any single request;max_wall_seconds: total Run wall-clock time.A Run is one complete benchmark execution; an iteration is one strategy-update attempt; an episode is one battle; a round is one in-game round.
Invalid model output, invalid strategies, API errors, battle timeouts, incomplete evaluations, and missing IG are retained with explicit status/reason. They are never silently removed from curves.
6. Output layout and interpretation
--data-dir ../AgentBenchResultsproduces:iteration-0000is the raw baseline.strategy.pyis the immutable accepted strategy for that iteration.candidate.pypreserves generated source before/while validation.episodes/contains result JSON, official.mrc, and readable.trace.jsonl.events.jsonlis the ordered audit log for API calls, battles, failures, and iteration transitions.summary.jsoncontains raw/evolved score, gain, best iteration, AUC, failure counts, and cumulative budgets.score_curve.jsonkeeps version-alignedraw,evo,gain, win/completion rates, rollouts, token, episode-read, and time axes.ig_curve.jsonkeeps version-aligned strict-KL status ratios. Missing/incomplete points remain visible.API keys are read from the configured environment variable and are not saved in Run files.
Validate exported Results with:
7. Verification
6 valid, 0 invalidacross retained Runs.Artifact policy
Generated Runs,
.mrcreplays, traces, temporary API configuration, caches, credentials, andAgentBenchResultsare intentionally excluded from this PR. They are reproducible runtime artifacts, not source files.Canonical detailed references:
skills/miracle-harness/SKILL.mdskills/miracle-replay-reader/SKILL.mdexamples/miracle-loop.tomlexamples/miracle-initial-strategy.py