「Cloud LLMはFPSには遅すぎる」を、モデルの賢さではなく時計とaction ageに分解して確かめる。
Latency Killsは、Cloud LLMと小型専用modelを、35 Hzで止まらず動くoffline ViZDoomへ接続する リアルタイム制御実験です。出発点は「LLMのthinkingをそのまま筋肉にしたら面白いのでは?」でしたが、 現在の主題はactionが何tick古いとFPS agentは壊れるのかです。
旧名はThought Leak Range。raw thinkingを射撃へ漏らしたV0の技術名と、互換用Python distribution / CLI
thought-leak-range、module thought_leak_rangeにその痕跡を残しています。
オンラインゲームbotではありません。OSのキーボードやマウス、commercial game、anti-cheatには 接続せず、ViZDoomのローカル練習scenarioだけをAPI経由で操作します。
このrepositoryが追試する出発点は、VAGO Solutionsらの2026年のarXiv preprint Playing DOOM with 1.3M Parameters: Specialized Small Models vs Large Language Models for Real-Time Game Control です。著者はDavid Golchinfar、Daryoush Vaziri、Alexander Marquardt。 公開modelはSauerkrautLM-Doom-MultiVec-1.3M、 実装はGitHubにあります。
この研究は、ViZDoomのdefend_the_centerを次の方法で解きます。
- 画面を40×25のASCIIへ変換し、16段階のdepth情報を加える
- 31,645 frameのhuman demonstrationで、4 actionを選ぶ専用classifierを学習する
- 5-layer ModernBERT-Hash+attention poolingで、総parameter数を約1.3Mに抑える
shoot/move_forward/turn_left/turn_rightをmulti-labelで選ぶ
原論文の主結果は次の通りです。これは本repositoryの測定値ではなく、VAGO論文Table 2の報告値です。
| VAGO論文のagent | parameters | episodes | latency / decision | total frags |
|---|---|---|---|---|
| SauerkrautLM-Doom-MultiVec | 1.3M | 10 | 31 ms | 178 |
| GPT-4o-mini | proprietary | 10 | 646 ms | 0 |
| Gemini Flash Lite | proprietary | 10 | 920 ms | 8 |
| Nemotron-120B | 120B | 5 | 8.9 s | 3 |
| Qwen3.5-27B | 27B | 3 | 13.3 s | 2 |
表1 — VAGO原論文Table 2の報告値。episode数がmodelごとに異なるため、total fragsだけを横並びにして 「同条件の平均score」とは扱わない。
| 言葉 | ここでの意味 |
|---|---|
| episode | ゲーム開始から死亡または制限時間までの1試行 |
| frag / kill | score上で敵1体分を倒したこと。monster同士の攻撃が加算される場合もあるため、実験ではhitやammoも併記 |
| game tic | ViZDoom内部時間の1刻み。35 Hz設定では約28.6 ms |
| action age | 画面を観測してから、その観測に基づく操作が実行されるまでの古さ |
| stopped / V4-S | Cloud返答待ちの間、ViZDoom内部時間も敵も停止する診断条件 |
| unpaused / 非同期 | modelの推論中もViZDoomが35 Hzで進み続ける条件 |
| formal run | score集計用の正式測定。録画負荷などで時計を乱さない |
| visual-only run | 挙動を目で確認するGIF用run。正式scoreには混ぜない |
つまり原論文の結論は明快です。リアルタイム制御では、巨大な汎用LLMより、速くて小さい専用modelが 圧倒的に強い。 本repositoryもこの勝敗自体には反論しません。実際、1.3M modelを止まらない世界へ 載せ直して、論文の17.8 frags/episodeに対して17.7を再現しました。
VAGOの公開benchmark loopは、観測後にmodel/APIの返答を待ち、その後make_action()でViZDoomを
進める同期構造です。Cloud APIを待っているwall-clock時間中、game tickは進みません。これは実装を読んだ
だけでなく、同じpolicyへ0 ms / 650 msの待ち時間を入れ、RGB・depth・step・kill・HP trajectoryが
bit-identicalになることでも確認しました。詳細はVAGO timing probeにあります。
これはVAGOの1.3M modelが弱いという話ではありません。31 msなら世界を止めなくても十分に速いはずです。 一方、Cloud LLMの646 ms〜13.3 sというlatencyを「real-time game controlの失敗原因」として読むなら、 API待機中も世界が進む条件と、古いactionが身体へ届く条件を分けて測る必要があります。
そこで本repositoryでは、次の三つを作りました。
- ViZDoomをmodel推論と独立した35 Hz threadで動かす、止まらないVAGO adapter
- 一つのCloud LLMが一文字でWAIT / LEFT / RIGHT / FIREを直接選ぶCloud V4
- 同じVAGO 1.3Mのaction到着だけを200 msへ遅らせるlatency ablation
調べたいのは「どちらのmodelが賢いか」ではなく、同じ判断が何native tic古くなった時に使い物に ならなくなるかです。
同じseed 7〜16で、時計とaction latencyを明示して比較しました。
| 条件 | 推論中のworld | 観測からactionまで | kill合計 / 平均 |
|---|---|---|---|
| Cloud V4-S / Llama 3.1 8B | 停止 | 214.2 msのwall time | 263 / 26.3 |
| Cloud V4 / 同じLLM | 35 Hz継続 | 232.8 ms、約8 tic | 40 / 4.0 |
| VAGO MultiVec 1.3M / T4 | 35 Hz継続 | 28.1 ms、1.049 tic | 177 / 17.7 |
| 同じVAGO 1.3M + 200 ms floor | 35 Hz継続 | 7.038 tic | 42 / 4.2 |
表2 — seed 7〜16の10 episode比較。停止Cloudの26.3は診断上限、残り3条件はworldが進み続ける。 Cloud V4とVAGOは入力・学習・action空間が違うため、4.0対17.7をmodel知能の直接対決とは扱わない。
最初の行はworldを止めるdiagnostic上限であり、リアルタイムscoreではありません。1.3M modelは、 止まらない世界でもVAGO公開値17.8に対して17.7を再現しました。ところがmodel、weights、入力、 action policyを変えず、action到着だけを最低200 msへ遅らせると17.7から4.2へ76.3%低下。 別設計のCloud V4が出した4.0とほぼ同じscore帯へ着地しました。
1.3Mの専用脳から賢さを奪わず、反射神経だけCloud並みにしたら、戦績までCloud並みになった。
これは「両modelの知能が同じ」、あるいは「Cloud V4がVAGOに勝った」という意味ではありません。 むしろVAGOの勝利を再現した上で、勝敗を説明する主要因の一つとしてaction stalenessを切り出した結果です。 現在の仮説は、リアルタイムAgentの能力をparameter数や平均推論msだけでなく、 何native tic前の観測を操作しているかでも測るべき、というものです。
V4では、一つの汎用Cloud LLMがWAIT / LEFT / RIGHT / FIREとpulse長を一文字で直接選びます。 以下は、Marine認識修正後に取得した、worldを止めないFlat-4版のseed 08です。7 killしましたが、 GIF録画負荷がgame clockへ影響したvisual-only runなので、上表のformal scoreには使っていません。
GIF 1 — Cloud V4 / seed 08 / 7 kill / worldは停止しない。録画負荷でclockが乱れたvisual-only映像であり、 formal平均4.0の計算には含めていない。画面上の操作字幕はCloud LLMが返した一文字を固定変換したもの。
以前ここに掲載していたV4 / V4-SのGIFは、現在版の代表映像として不適切でした。Freedoomの
チェーンソー兵はMarineChainsawVzdというactorですが、古い観測filterがその名前をmonsterとして
認識せず、座標をLLMへ渡していませんでした。LLMは見えている敵を無視したのではなく、prompt上では
その敵が存在していなかった、というsensor bugです。
修正ではMarineChainsawVzdの互換名とViZDoomのMonster categoryを認識し、同時に一体だけを見る
target lockを追加しました。修正直後のV4-Sをseed 7〜24で18 episode走らせると、215 kill、平均11.94。
ログ上でもMarineを観測し、少なくとも146 killをMarineへのFIREへ帰属できました。
次は修正済みV4-S seed 10の14-kill replayです。これはCloud待機中にworldを止めるcorrectness診断で、 リアルタイム性能ではありません。
GIF 2 — Marine認識修正後のV4-S / seed 10 / 14 kill・14 hit / 525 tic完走。Cloud待機中は敵も時計も 停止するため、これはLLM+Systemの対応を調べる映像であり、リアルタイム性能の証拠ではない。
ただし、修正後も「LLM+Systemが完全に正しい」とは判定できませんでした。Marineが照準より少し右に いる段階でFIREを繰り返し、敵が横移動または接近して当たり判定へ入った時に倒す場面が多く、 Marineへの実弾命中率は39.7%でした。つまり認識漏れは直った一方、早すぎるFIREと照準誤差は別問題として 残っています。詳細と18本すべてのGIFは Marine recognition repair baselineにあります。
全replayとformal / visual-onlyの区別も公開しています。GIFはrepository本体を 肥大化させないよう、実験別GitHub Releasesへ置いています。
ViZDoom labels: 最接近敵の v / x / ammo
│ 0.1秒ごと、3 laneを時間差で重ねる
▼
Llama 3.1 8B via OpenRouter / Groq
│ streamed first valid token
▼
0 WAIT / 1,2 LEFT / 3,4 RIGHT / 5 FIRE
│
文法・観測番号・TTLだけ検査
▼
35 Hzで止まらないViZDoomへ直接入力
local側は敵位置から操作を選び直しません。LLMの誤答も、期限と文法を満たせばそのまま実行します。 3 laneは三人格の会議ではなく、同じpolicyを重ねてnetwork待ちを隠す非同期pipelineです。
screen + depth ──> upstream ASCII/depth converter ──> 1.3M policy on T4
▲ │
│ latest-only observation ▼
35 Hz PLAYER thread <── 4-tic composite action <── process boundary
ViZDoomを専用threadが35 Hzで進め、model processが遅れてもworldを止めません。古い未処理frameは latest-onlyで置換し、前actionは4 ticで必ず失効します。200 ms実験ではmodel計算後に 「観測時刻+200 ms」まで待ち、遅い推論のlatencyとthroughputを模擬します。
| mode | LLMが決めること | local側 |
|---|---|---|
| fire-gate | 数秒のFIRE許可 | 探索、追尾、中央確認、実射 |
| direct-bit | 一発ごとのFIRE / WAIT | 左右追尾 |
| four-agent / V3 | 4 AgentがWAIT / LEFT / RIGHT / FIREへ投票 | 期限付きarbitration |
| direct-motor / V4 | 全操作とpulse長 | 一文字の固定変換と安全検査 |
| VAGO adapter | upstream 1.3M policyのcomposite action | clock、queue、action expiry |
「Cloud LLMがFPSを全部操作した」と呼ぶ主対象はV4です。fire-gateはLLM+local spineの 階層制御実験であり、LLM自身が照準を合わせた結果とは数えません。
Python 3.12とuvを使います。
git clone https://github.com/RPG-478/latency-kills.git
cd latency-kills
uv sync --extra dev --locked --python 3.12
uv run python -m thought_leak_range mock --duration 6OpenRouter keyはprocess環境またはignored .envから読みます。repository、引数、ログには書かないでください。
$env:OPENROUTER_API_KEY = Read-Host "OpenRouter API key"
uv run python -m thought_leak_range live --model meta-llama/llama-3.1-8b-instruct --provider Groq --no-provider-fallback --tap-mode direct-motor --lanes 3 --scenario defend_the_center --duration 15 --observation-interval 0.10 --motor-token-max-age-ms 400 --world-clock clock-thread --motor-body clock-thread --max-tokens 16 --max-requests 180 --max-usd 0.025
Remove-Item Env:OPENROUTER_API_KEYmodel/providerの提供状況と価格は変わり得ます。必ず小さい--max-usdと--max-requestsから始めてください。
VAGO repositoryとcheckpointは外部入力です。このrepositoryにはweightsもupstream policyも同梱しません。
uv run python tests/manual_vago_multivec_async_batch.py --upstream C:\path\to\SauerkrautLM-Doom-MultiVec --scenario-path C:\ascii-path\defend_the_center.cfg --device cuda --seeds 7 8 9 10 11 12 13 14 15 16 --output runs\vago-1.3m-async.json200 ms floorを再現するには--minimum-action-latency-ms 200を追加します。episodeごとのOS process隔離と watchdogは、ColabでViZDoomが三episode目に停止した再現性事故を黙って平均から外さないためのものです。
| 項目 | 値 |
|---|---|
| OS | Windows 11 Home 64-bit、10.0.26200 build 26200 |
| CPU | 12th Gen Intel Core i5-1235U、10 cores / 12 logical processors |
| GPU | Intel Iris Xe Graphics、driver 32.0.101.5542、shared integrated memory |
| RAM | 7.7 GiB usable |
| experiment Python | CPython 3.12.10 via uv |
| system Python | CPython 3.14.2(project対象外) |
| uv / Git / PowerShell | uv 0.11.31 / Git 2.52.0.windows.1 / PowerShell 7.6.4 |
| project runtime | httpx 0.28.1 / Pillow 12.3.0 / ViZDoom 1.3.0 |
このPCでVAGO公式同期runnerをCPU再現した時は、Torch CPU推論が平均216.2 msでもworldが停止するため 平均15.6 killでした。GPUを持たないこのPCで独立35 Hz clockとCPU推論を同時に走らせると、model processが game threadまで飢えさせ14〜20 Hzへ落ちました。したがって正式な止まらない1.3M値はColab T4で取得しています。
| 用途 | 環境 | 主な実測 |
|---|---|---|
| Cloud V4 | OpenRouter、Groq、Llama 3.1 8B Instruct | mean 232.8 ms、平均4.0 kill |
| 1.3M async | Google Colab、Tesla T4、Python 3.12 | compute 28.1 ms、35.019 Hz、平均17.7 kill |
| 1.3M + 200 ms | 同じColab T4 | action age 7.038 tic、35.045 Hz、平均4.2 kill |
公開する環境情報からは、account、メール、端末名、ユーザー名、serial、IP、API key、Colab認証情報を除外しています。
- Cloud V4はViZDoom labelsから最接近敵一体の構造化位置を読む
- VAGOはscreenを40×25 ASCIIへ変換し、16段階depthも読む
- Cloud V4は一文字につき一種類、VAGOは前進・旋回・射撃を同時押しできる
- VAGOは31K human-play framesで学習したDoom専用model、V4は汎用Cloud LLM
- V4-Sの26.3は推論中にworldを止めた診断値で、リアルタイム勝利とは呼ばない
- GIF captureはnative clockを遅くし得るため、formal数値runとvisual-only runを分ける
- KILLCOUNTにはmonster infightingが入り得るため、hit、ammo、damageも併記する
- seed 7〜16の10本は強い予備結果だが、一般化にはseed増量と複数scenarioが必要
このprojectは世界初を主張しません。Cloud LLMをViZDoomへ接続した先行例はあります。差分と、 どこまで反例になるかはprior artと公平性へ明記しています。
| 世代 | 発明と失敗 | 主な結果 |
|---|---|---|
| V0 | raw reasoning中の自然言語を直接motorへ漏らす | 固定標的へ実射 |
| V2 | LLMは引き金、35 Hz local spineが追尾 | 10 run平均5.4 |
| V3 | WAIT / LEFT / RIGHT / FIREの4 Cloud Agent | 平均1.5、会議が身体を止めた |
| V4 | 一つのLLMが一文字で全操作 | 旧15秒run平均3.5 |
| V4-S | 同じV4で推論中のworldを停止 | flat-4平均26.3 |
| V4 Async | worldとmotorを独立35 Hz clockへ修理 | flat-4平均4.0 |
| VAGO Async | 1.3M専用modelを同じ止まらない世界へ | 平均17.7 |
| VAGO 200 ms | 1.3Mのaction鮮度だけCloud級へ落とす | 平均4.2 |
途中の黒板干渉、敵label取りこぼし、LONG=20 tic、overshoot、CPU starvation、Doom lifecycle hangも 失敗ごと公開しています。documentation mapから全記録へ進めます。
- 30 / 60 / 100 / 150 / 200 / 233 / 300 msのlatency cliffを描く
- 固定delayと同じ平均を持つCloud型jitterを比較する
- stale actionを実行 / 破棄 / 予測補正する条件を比べる
- seed数とscenarioを増やし、bootstrap confidence intervalを出す
- action ageを第一級metricとして、robotics / VLA / networked controlの先行研究を再監査する
詳しくはpaper plan。再現、反証、もっと良い身体、面白い失敗のIssueを歓迎します。
runは既定でruns//へevent、summary、任意のGIF / raw thoughtを保存します。runs/、 .env、virtualenv、build output、GIFはGitから無視されます。
- output tokenはrequest、観測番号、TTLへ束縛し、期限切れ・逆順・重複を拒否
- actionはWAIT / LEFT / RIGHT / FIREのallow-list
- leaseが切れたtickは全ボタンを離す
- model出力をshell、Python、任意codeとして実行しない
- API keyはartifactへ保存せず、HTTP errorでもredact
- live modeはrequest数とUSD budgetを起動前から制限
- native keyboard / mouse inputを実装しない
脆弱性はpublic Issueへ秘密情報を貼らず、Security policyに従ってprivate advisoryへ報告してください。
uv sync --extra dev --locked --python 3.12
uv run python -m pytest -qCIはUbuntu / Windows、Python 3.12で実行します。
Latency Kills自身はMIT Licenseです。
VAGOのHugging Face model cardは
Apache-2.0を表示しています。一方、2026-08-21確認時点で
GitHub source repository自体にはLICENSE fileがなく、
GitHub API上のlicenseも未判定です。本repositoryはupstreamのweights、source、action policyを再配布せず、
ユーザーが別途用意したcheckoutを動的に読み込むadapterだけを提供します。sourceを利用する場合は
upstreamの最新表記を確認してください。
くだらないことを、ちゃんと作る。

