
航空乗務員復旧でソルバーに勝つAIを作った。負けた。その負けが製品になった。
勝つために作ったベンチマークで、負けた
私はソルバーに勝つためにStormCrewの初版を作った。頭のなかのピッチはそれだけだった。航空会社の運用管制は何十年も続く最適化エンジンの上で動いている。だから、もっと賢いものを訓練できれば、語るに足る物語になるはずだ。何週間も費やした。それから自分の復旧エンジンを、次のものとベンチマークした — CBC。それは私がforループを書けるようになる前から戦場で鍛えられてきた、成熟したオープンソースの混合整数ソルバーだ。そしてCBCが勝った。四捨五入の誤差レベルではない。
二つの数字の列を見つめながら、自分の正しさを証明するために設計した実験が、かえって自分が間違っていることを証明したときに感じる、あの独特な空洞感を覚えた。ソルバーの方が速かった。計画はより安価だった。実行不可能なスケジュールを一度も返さなかった。私の賢い版は三つすべてで負けた。
だから、思いつく唯一の誠実なことをした。数字ではなく、主張を変えた。
ソルバーに勝つためにAIを作った。ソルバーが勝った。面白いのは、その戦いが隠していたすべての部分だった。
その逆転こそがStormCrewが実際になったものの背骨であり、当初語ろうとしていたものより有用な物語だと私は思う。全体は次の場所で自分で動かせる — veriprajna.com/ja/demos/airline-crew-scheduling-ai。だが、考えが変わった経緯を辿らせてほしい。ピボットこそが本題だからだ。
嵐がハブを足止めしたとき、本当に壊れるものは何か?
CBCに打ちのめされたあと、崩壊の事後検証を読み返した。失敗のほとんどは「数学が少し準最適だった」ではなかった。不規則運航、業界が呼ぶところのIROPSは、航空会社に年間およそ600億ドル(IATA)のコストをもたらす。典型的な災害である2022年12月のサウスウエストは、およそ12億ドル、約16,900便の欠航、足止めされた乗客はおよそ200万人に達した。そうした日々が実際にどう崩れていくかを辿ると、悪者はオプティマイザーではなかった。
壊れるのは別の三つだ。復旧は遅すぎる:嵐がハブを足止めしたとき、下流の連鎖への再乗務配置は依然として大半が4〜12時間の手作業の奔走である(出典のあるベンチマークであり、私が作った数字ではない)。そしてリスクが高すぎる:再乗務配置のたびにFAA Part 117の勤務・休息制限と、航空会社ごとの組合CBAを守らねばならず、一度の違反は注記ではなくコンプライアンス事象になる。そして不透明すぎる:乗務員を失ったばかりの下流便の連鎖は、それらの便がすでに欠航し始めるまで見えない。
最後の一点こそがレガシーツールが見落とすところであり、デモで最初に見せたものだ。最繁忙ハブに嵐を注入すると、アプリはブラスト半径を強調する:足止めされた便に加え、ローテーション経由で乗務員を失う一ホップ下流便だ。シード済みシナリオではネットワーク全体で53便がリスクにさらされる。

そのDOT自動払い戻し規則(2024年10月)以降、3時間超の連鎖遅延はすべて自動的な財務打撃にもなる。だから、遅い・違法・盲目であることのコストは、ツールが変わらないまま正確に上がった。これら三つの失敗のうち、どれもより良い目的関数では直らない。私はすでに問題なかった一点を最適化していたのだ。
なぜCBCに勝とうとするのをやめ、CBCに餌を与え始めたのか?
CBCに負けたことと折り合いをつけるために、別の仕事を与えた。ソルバーと競う代わりに、包み込んだ。パイプラインはすべて実在し、決定論的で、シード済みのコードだ:合成航空ネットワークと乗務員状態、ローテーション上のグラフ到達性でブラスト半径を計算する混乱注入器、勤務生成器、そしてエンジンとしてのCBCが計画を選び、何もしない場合とのシャドウ比較、そして署名付き証明書が続く。
シード済みの嵐で実行すると、生成器は1,762件の合法な復旧勤務を出す(うち52件は乗務員を必要な場所へ移すデッドヘッド再配置)、加えて53件の欠航フォールバックで、合計1,815本の候補列となる。CBCは結果の1,815変数・115制約の最小費用集合分割をOPTIMALまで解き、およそ0.11秒で計画を返す。そのシナリオの結果:53便中52便が再乗務配置(98パーセント)、欠航1便、使用乗務員34組(ライン25、予備9)。

航空会社の問題は、ソルバーが弱すぎることではなかった。遅すぎ、リスクが高すぎ、手遅れになるまで見えなかった復旧こそが問題だった。
あのスクリーンショットの正直さに注目してほしい。復旧エンジンはCBCであり、パネルに名前が書いてある。耐久する主張は、自分のコードがソルバーを凌駕する最適化をしたことではない。出典のある手作業プロセスが4〜12時間かかるところを、計画が1秒未満で届くことであり、アプリはその差を公に測る。スコープを正確にしたい。これはデモであり、実態以上に粉飾するのは拒否する:その正確な数字は一つのシード済み合成ネットワークの結果であり、実世界への保証ではない。通用するのは速度対手作業という主張だ。
合法性の保証は、モデルの判断ではなくコードに置く
これを作って初めて得た強い意見があるので、はっきり言う。合法性の保証はモデルの判断には置けない。決定論的なコードの中に、構成として置かねばならない。違法な乗務勤務が一度も推奨されないようにする方法は、それを避けるようモデルを訓練することでも、目的関数にペナルティ項を足してオプティマイザーが迂回することを期待することでもない。そもそも違法な勤務を生成不可能にすることだ。
だから制約は生成時に強制され、事後に採点されない。Part 117は勤務期間を780分、飛行時間を480分に上限し、最小地上待機を30分とする。サンプルのCBAは勤務を4セグメントに上限する。それらすべてを満たす勤務だけが候補列になる。これがアクションマスキングだ。違法な割当は罰せられるのではなく、表現不可能になる。CBCが渡された列で何をしようと、任意のコパイロットが後から計画について何を言おうと、違法な勤務を生き返らせることはできない。最初から集合に入っていなかったからだ。
これでスコアではなく不変条件が得られる:違法割当は常に0、ユニットテスト済み(テストスイートは3/3合格。ブラスト半径が空でないこと、合法列のみが生成されること、復旧計画が合法な分割であることを検査)。スコアは後退しうる。不変条件は約束できる。

だからこそ、安全の物語が「モデルがやらないと学習した」であるとき、「自律型AI運用」の売り込みはもう説得力がない。この構築の初期に、硬い規則を守るようモデルを信頼したのは一度だけだ。問題ない入力では大丈夫だったが、そうでない一つの入力で破綻した。一度の違反が規制事象になる領域では、「だいたい合法」は「合法ではない」と同じだ。監督するより、可能性そのものを消したい。
一年で最悪の日には何が起きるのか?
何でも自動承認する版をほぼ出荷しかけた。シナリオが止めてくれてよかった。デモをsevereに切り替えると、予備が尽きるほど事態が悪く、およそ乗務員の30パーセントしか残らない。CBCはそれでも完全に合法な計画を、およそ0.05秒で見つけ、依然違法0だ。だがその計画は53便中20便を欠航させ、それは半径の38パーセントに相当し、OCCの15パーセント自動承認しきい値を大きく超える。
そこで正しい動きは、影響ネットワークの三分の一超を欠航させる計画に黙って印を押すことではない。だから状態はESCALATE、人の承認が必要に切り替わり、理由が表示される。計画は依然として計算され、合法で、管制官に提示される(33便が復旧、半径の62パーセント)。ただ自動承認されないだけだ。

大半の「自律」売り込みが飛ばすのは、正しい行動が「動かないこと」であり、その日を人間に渡すことだと知ることだ。
そのゲートを作ったことで、このカテゴリ全体への感じ方が変わった。エスカレーションはシステムの失敗ではない。悪い日についてシステムが誠実であることだ。常に自信ある答えを返すアドバイザーはデモしやすく、信頼するには危険だ。ときどき「これはあなたの線を超えている、決めてくれ」と言うものこそ、午前3時の管制官の隣に本当に置きたいものだ。
管制官だったら欲しいアーティファクト
翌朝に運用管制官が必要とするものは何か、と自分に問い続けた。答えはダッシュボードではなく記録だった。だからすべての復旧は署名付きのrecovery_plan.jsonに封印される:混乱、乗務員と便ごとの選ばれた計画アクション、アクションごとに上限と照合した具体的なPart 117とCBA条項、復旧のウォールクロック、節約額。これはOCCの監査記録であり、なぜこの復旧が推奨されたかをワンクリックでエクスポートできる。

任意の計画コパイロットもある。どこに位置するかはっきりさせたい。LLMへの薄いアダプタ(既定はClaude、プロバイダ差替可能、またはキー不要のローカルブリッジ)で、計画を平易な英語で説明する。キーがなければ完全に棄権する。それ以外はすべてオフライン・キーレスで動き、決定コアの外にいる。決定するのは決定論的マスク、CBC、エスカレーションゲートだ。モデルは事後に語るだけだ。意図的にそこに置いた。言語モデルが勤務の合法性に影響した瞬間、構築全体で稼いだ保証を失うからだ。
節約についても同じ規律が当てはまる。通常シナリオのシャドウ比較は、何もしない場合に対して52件の欠航回避とおよそ237万ドルのDOT払い戻しエクスポージャ回避(乗客一人あたり300ドルのモデル)を示す。これは最も愛想の良い枠組みだ。ベースラインがブラスト半径全体を足止めすることであり、その一シナリオの例示だとラベルされている。見出しではなく、自分のコードが何かを凌駕して最適化した証明でもない。初日にCBCにその議論で負けた。マーケティング数字で静かに勝ち返すつもりはない。
では「置き換えず、増強する」とは実際に何を意味するのか?
かつての私は、増強は臆病な選択で、大胆なものが作れないときに言うことだと思っていた。今は逆だと思う。ここでの買い手はすでに良いソルバースタック(JeppesenやIBS)を持ち、リップアンドリプレース、ロックイン、一年で最悪の日の説明できない推奨を耐えられない。その買い手に「捨てて私の賢いモデルにしろ」と言うのは大胆ではなく、ベンチマークで自分にすでに反証した主張だ。
正直に提供できるのは、すでに信頼しているソルバーの周りの運用レイヤだ。噛みつく前に連鎖を可視化する。違法な手を、単に抑止するのではなく生成不可能にする。何時間を何秒に圧縮する。そしてその日が十分悪く、正しい答えが自動承認ではなくエスカレーションだと知る。デモのすべては合成・シード済みだ。ネットワーク、乗務員、混乱、ドル数字。実在の航空会社データはどこにもない。本物なのは仕組みであり、エンドツーエンドで動く様子は次で見られる — veriprajna.com/ja/demos/airline-crew-scheduling-ai。
説明を読むより見る方がよければ、全体がエンドツーエンドで動く様子がここにある。
CBCに負けて以来、問い続けていることがある。競っているソルバーがすでに良く、買い手がすでにそれを持っているとき、残るのはより良い答えを作ることではない。答えとのより良い関係だ:より速く、証明可能に合法で、可視化され、エスカレートできるほど謙虚であること。では今年売られているAIのうち、どれだけが本当に難しい部分を解いていて、どれだけが壊れていなかった部分を解き直しているのか?


