Agent-Selbstiteration
Lass einen Coding Agent selbst Partien spielen, Ergebnisse lesen, Code ändern und erneut spielen. Dafür braucht er einen Befehl, der unbeaufsichtigt läuft, einen strukturierten Spielbericht und ein klares Ziel.
In Einen Bot mit einem LLM schreiben übernimmst du den Schritt „Partie spielen → beobachten → dem Modell berichten“ selbst. Ein Coding Agent, der Befehle ausführen kann (Claude Code, Codex, der Agent-Modus von Cursor usw.), kann auch diesen Schritt übernehmen und so den Kreis schließen:
Code ändern ──► Partie spielen (unbeaufsichtigt) ──► Spielbericht lesen ──► wichtigstes Problem finden ──┐
▲ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────┘
Damit diese Schleife wirklich konvergiert, braucht der Agent drei Dinge.
1. Ein Befehl, der unbeaufsichtigt läuft
python tools/play.py --bot brains/my_bot.py --speed 200 --minutes 10 --fair
--minutessorgt dafür, dass die Partie garantiert endet (Minuten Echtzeit), damit der Agent nicht in einer Partie hängen bleibt;--speed 200spart mit doppelter Geschwindigkeit Zeit – aber im Bot nach der Spieluhr warten (g.clock()), nicht persleepnach Echtzeit;--fairsorgt dafür, dass er vom ersten Tag an nach Arena-Regeln schreibt und nur sieht, was in Sichtweite ist;- Am Ende gibt das Terminal den Grund für das Ende aus, z. B.
我方没有单位了(keine eigenen Einheiten mehr) oder到时间了(Zeit abgelaufen); was der Bot selbst perprintausgibt, steht ebenfalls im Terminal.
Ist das Fenster minimiert, steht die Spielsimulation still. Lass den Agent das Spiel im Standard-Fenstermodus starten und achte darauf, dass seine Instanznummer (--inst) nicht mit der Instanz kollidiert, die du gerade benutzt.
2. Ein strukturierter Spielbericht
Die Terminalausgabe ist für Menschen gedacht. Für den Agent sollte es ein JSON sein: was passiert ist, was nicht geklappt hat und warum. Das SDK liefert dir alle Rohdaten – Quittungen tragen Grundcodes, der Event-Stream liefert fertige Produktionen und Verluste. Du musst sie nur einsammeln:
import collections, json, time
from openwar3 import Bot
class Recorder(Bot):
"""Ergänzt einen Bot um einen Spielbericht. Davon erben und in eigenem on_start / on_event super() aufrufen."""
def on_start(self, g):
self.rejects = collections.Counter() # "train hfoo: rejected(人口不够)" -> Anzahl
self.timeline = [] # [Spielsekunde, Kategorie, Vier-Zeichen-Code]: Training / Forschung / Bau / Aufwertung fertig
self.lost = collections.Counter() # was bei uns gestorben ist
self.killed = collections.Counter() # was wir getötet haben
def check(self, r, what):
"""Umhüllt einen Befehl und zählt Ablehnungsgründe: self.check(g.train(b, "hfoo"), "train hfoo")"""
if r is not None and not r:
self.rejects[f"{what}: {r.reason}"] += 1
return r
def on_event(self, g, ev):
me = g.me()
if ev.kind == "production.done" and ev.owner == me:
self.timeline.append([round(ev.clock), ev.done_kind, ev.done_code])
elif ev.kind == "unit.died":
(self.lost if ev.owner == me else self.killed)[ev.type] += 1
def on_end(self, g, reason):
report = {"reason": reason, "timeline": self.timeline, "lost": self.lost,
"killed": self.killed, "rejects": self.rejects.most_common(10)}
try: # das Spiel ist evtl. schon beendet; nicht lesbar -> egal
report |= {"clock": g.clock(), "resources": g.resources(),
"army": len(g.my_army()), "workers": len(g.my_workers())}
except Exception:
pass
with open(f"run_{int(time.time())}.json", "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=1)
Fragen, die dieser Bericht beantwortet:
| Signal | Quelle | Was man daran erkennt |
|---|---|---|
| Häufigste Ablehnungsgründe | Quittung reason / verdict | Nahrung blockiert ständig (3), Befehle trotz Geldmangel (8 / 9), Angriffe auf Ziele im Kriegsnebel (1001), Helden werden trotz Tod neu trainiert (221) |
| Produktions-Timeline | production.done-Events (mit benötigten Spielsekunden) | In welcher Sekunde der erste Held kam, wann der Tier-up fertig war, ob die Kaserne durchgehend produziert hat; lässt sich mit den Eröffnungen von Profis vergleichen |
| Verluste beider Seiten | unit.died-Events | Ob ständig Einheiten verschenkt werden, wie oft der Held gestorben ist, ob sich das Creepen gelohnt hat |
| Grund für das Ende | on_end(g, reason) | 我方没有单位了 (keine eigenen Einheiten mehr) = verloren; 到时间了 (Zeit abgelaufen) = noch kein Sieger |
| Armee und Ressourcen am Ende | Einmal den Snapshot in on_end lesen | Gold gespart statt ausgegeben = Produktion kommt nicht hinterher; zu wenige Arbeiter = Wirtschaft kommt nicht in Gang |
Den Sieger programmatisch zu bestimmen ist eines der Grundlagenexperimente für die Arena und steht noch auf der Roadmap. Bis dahin kannst du „keine eigenen Einheiten mehr“ als Niederlage werten und „alle sichtbaren gegnerischen Gebäude zerstört“ näherungsweise als Sieg.
3. Ein klares Ziel und ein paar Regeln
Gib dem Agent den folgenden Text und passe ihn an dein Ziel an:
Ziel: brains/my_bot.py soll auf Echo Isles zuverlässig gegen den Computer auf Schwierigkeit "Leicht" gewinnen (Menschen gegen zufälliges Volk).
In jeder Runde:
1. python tools/play.py --bot brains/my_bot.py --speed 200 --minutes 10 --fair ausführen
2. Terminalausgabe und die neueste run_*.json lesen: Grund für das Ende, Produktions-Timeline, häufigste Ablehnungsgründe, Verluste beider Seiten
3. Das EINE Problem finden, das das Ergebnis am stärksten beeinflusst, und nur diese Stelle ändern; im Code-Kommentar Grund der Änderung und die zugrunde liegenden Daten festhalten
4. Zurück zu Schritt 1. Gibt es in 3 Partien hintereinander keinen Fortschritt, anhalten und mir Bericht und deine Einschätzung geben
Regeln:
- Nur Methoden aus docs/api.json verwenden, keine Schnittstellen erfinden
- Derselben Einheit nicht jeden Tick denselben Befehl erneut geben; nur untätigen Einheiten Befehle erteilen
- --fair beibehalten (nur Gegner verwenden, die in Sichtweite sind)
- Vor jeder Codeänderung python tools/run_tests.py ausführen und sicherstellen, dass die Beispiele nicht kaputt sind
Gewohnheiten, mit denen die Schleife schneller konvergiert
- Immer nur eine Stelle ändern. Änderst du drei Stellen gleichzeitig, weißt du bei einem Sieg nicht, welche geholfen hat, und bei einer Niederlage nicht, welche geschadet hat.
- Genug Partien vergleichen. Dieselbe Ausgangslage streut stark; zwei Partien zeigen nur große Unterschiede. Um zu beurteilen, ob es Fortschritt gibt, schau dir den Trend über mehrere Partien an.
- Erst Ablehnungen beheben, dann die Strategie tunen. Der häufigste Ablehnungsgrund in den Quittungen ist oft der größte Bug des Bots.
- Einschätzungen in Kommentare schreiben. Der Agent in der nächsten Runde (oder im nächsten Gespräch) sieht dann in den Kommentaren, warum etwas so geschrieben ist, und macht Korrekturen nicht wieder rückgängig.
- Offline-Tests als Absicherung. Schreib für die zentrale Logik Unit-Tests, die ohne laufendes Spiel auskommen (die Tests der Beispiel-Bots liegen in
brains/examples/tests/), und lass den Agent sie nach jeder Änderung zuerst ausführen.