con un clic
opt-improve
ボトルネックに合わせた改善策を設計・実行・検証する
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
ボトルネックに合わせた改善策を設計・実行・検証する
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
受け取ったデータから最適化問題の構造を把握し、仮説を立てる。最も重要なスキル。
実行可能性(feasibility)を確認する。問題の複雑度に応じて一発解きor段階的解法を選ぶ
最適化モデルの運用設計。自動化・監視・フォールバックを定義する
最適化結果を非技術者にも伝わる改善提案書にまとめる
追加データの依頼書を生成する。何がなぜ必要かを非技術者向けに説明
| name | opt-improve |
| description | ボトルネックに合わせた改善策を設計・実行・検証する |
| user_invocable | true |
/opt-improve [data_path] で実行。
ベースラインのエラー分析結果に基づき、改善策を設計して検証する。
run_in_background=true で同時投入。Before/After 表を一気に作る(探索の局所最適化を避ける)subagent_type=Plan で骨格設計してから実装詳細は reference/opus47_collaboration.md。
改善には3つのレイヤーがある。上のレイヤーほど効果が大きい。 下のレイヤーで頭打ちになったとき、同じレイヤーで粘るのではなく、一つ上に戻れ。
レイヤー1: 問題を変える(解の空間そのものを広げる/変える)
├── 暗黙の前提を疑う(「これは本当に動かせないのか?」)
├── 入力データの使い方を変える(同じデータから別の解釈を引き出す)
└── 運用ルールの変更を提案する(制約を緩和ではなく、現実を変える)
レイヤー2: モデルを変える(同じ問題を別の定式化で解く)
├── 制約のハード/ソフトの切り分けを見直す
├── 変数の粒度を変える(1人単位→チーム単位、1日単位→時間帯単位)
└── 分解の軸を変える(時間/空間/段階)
レイヤー3: パラメータを変える(同じモデルの中で調整する)
├── 目的関数の重みチューニング
├── ソルバーのパラメータ調整
└── ヒューリスティクスの設計改善
レイヤー1の思考法:
「ソルバーが OPTIMAL を返してこれが精一杯」は「このモデルの中での最適」でしかない。 ソルバーの外側に目を向けるために、以下を自問する:
Q1. 「固定」として扱っているものの中に、実は動かせるものはないか?
- リソースの割当状態(既にアサイン済みだが、入れ替えてよいかもしれない)
- リソースの利用可否(使えないとされているが、条件次第で使えるかもしれない)
- 需要の形(分割・統合・延期・委譲ができるかもしれない)
Q2. 制約として扱っているものの中に、実はコストで扱えるものはないか?
- 「できない」のか「やりたくない」のか
- 「不可能」なのか「高くつく」のか
Q3. モデルに含めていない資源や選択肢はないか?
- 使っていないがアクセス可能なリソース
- 現在の計画期間の外にあるが、前倒し/後ろ倒しで使える時間
- 問題のスコープ外だが、協力を依頼できる主体
判定フロー:
改善の余地があるか?
│
├── 解の品質が悪い → レイヤー3(パラメータ調整)から試す
│ └── 頭打ち → レイヤー2へ
│
├── 割当件数/カバレッジが頭打ち → まずレイヤー1を疑う
│ 「容量が足りない」「リソースがない」は結論ではなく出発点。
│ 容量を増やす打ち手、リソースを捻出する方法を3つ以上列挙してから
│ 「本当に不可能」と判断する。
│
└── 制約違反が解消しない → レイヤー2で定式化を見直す
└── それでも無理 → レイヤー1で制約の前提を疑う
レイヤー1の改善は、レイヤー3の10倍以上効くことがある。 目的関数の重みを延々チューニングする前に、5分で「問題の外側」を見渡せ。
エラー類型A: 特定の制約に違反が集中
まず違反の中身を深く分析する。「何が違反しているか」だけでなく「なぜ違反するか」を掘る。 分割の観点は最初から決め打ちできない。実験と分析を繰り返して見つけるもの。
分析の手順:
1. 違反の内訳を集計する
「31件の違反が全てHC6」→ HC6に集中
2. 「なぜその制約が破れるか」を調べる
「AM便の荷物がPMまで車内に滞留して2時間を超える」
→ 原因: AM便とPM便の混載
3. 原因から分割の観点が見える
「AMとPMを分ければ混載がなくなる」
→ 時間で分割すればよいとわかる
4. 試す → 結果を確認 → 効果があれば採用
AM/PM分割 → 違反31件→0件 → 採用
※ 最初から「時間で分割」が正解だとは限らない
※ 空間で分割、段階で分割も候補として試す
※ 間違った分割は逆効果になる(下記参照)
分割の候補と選び方:
○ 時間で分割(時間制約がきつい場合)
→ 違反の原因が「異なる時間帯の混在」なら有効
○ 空間で分割(地理的制約がきつい場合)
→ 違反の原因が「遠い場所の組合せ」なら有効
○ 段階で分割(複数の決定が絡んでいる場合)
→ まず大きな決定(割当)→ 次に小さな決定(順序)
× 分割してはいけない方向もある
→ 「いつ」と「何を」を分離 → スキル制約を破壊して69違反の大失敗例あり
判断基準: 「違反の原因を解消する方向で分割する」
対策2: ボトルネック制約に特化したムーブを設計する
例: 訓練ペアリングが壁 → 熟練者を先に配置する構築法
例: 時間枠制約が壁 → 時間帯ごとに分離してルート構築
エラー類型B: 何をやっても解けない(feasibility未達)
→ 手法の構造的限界を疑う
判定基準: ソルバーで解けるか?
├── ソルバーで解ける → 貪欲法/ヒューリスティクスの限界
│ → ソルバーを使うか、グローバル推論を持つ手法に切替え
│
└── ソルバーでも解けない → 問題そのものが不可能かもしれない
→ 思考回路⑦(不可能性の証明)へ
feasible達成に必要な条件(実験で確認済み):
○ ソルバー(CP-SAT, OR-Tools)→ 制約伝播+バックトラッキング
○ SWO + IFS → 反復フィードバック+バックトラック(ソルバー不要)
○ SWO + Ejection Chain → 反復フィードバック+連鎖交換(ソルバー不要)
× 単純な貪欲法 → 900回試して0回feasible(地平線効果)
× SA/GA単体 → 局所探索だけでは制約の相互作用を解消できない
× FunSearch/EoH → スコアは上がるがfeasibilityには不向き
「ソルバーなしで解きたい」場合:
SWO(問題箇所の反復修正)+ IFS(バックトラック)の組合せが有効。
ドメイン知識を組み込むとさらに効果的。
(例: 訓練ペアリング制約 → 熟練者を先に配置するルール)
エラー類型C: 解けるがスコアが低い
→ 目的関数と評価関数のズレを疑う
1. 評価関数のコードを精読
2. ソルバーの目的関数と評価関数の差分を特定
3. 目的関数を評価関数に精密一致させる
→ これだけで+15-27%改善した実績あり
エラー類型D: 解けるが一部が極端に悪い
→ 悪い部分を特定して局所的に再最適化
1. 解の品質分布を可視化(ルートごと/日ごと/人ごと)
2. 最悪の部分を特定
3. その部分だけ固定解除して再最適化
- 改善策をコードに落とす
- ベースラインと同じ評価器で測定
- Before/After比較テーブルを生成
ソルバーで解けてfeasibleだが、もっとスコアを上げたい場合に使う。
Step 1: 目的関数の精密一致(最優先、これだけで+15-27%)
評価関数のコードを精読 → ソルバーの目的関数との差分を特定
→ 目的関数を評価関数と完全に一致させる
→ これだけで大幅改善する。他の手法より先にやること。
Step 2: LLMにカスタムヒューリスティクスを進化させる
ソルバーの解をベースに、LLMがスコア関数やムーブを自動設計する。
RoCo方式: 4つの役割(探索者/改良者/批評者/統合者)で協調設計
→ 多様なアイデアが出やすい
EoH方式: 複数の戦略を同時に進化させ、最良を選択
→ 「どの順序で埋めるか」等の戦略レベルの改善に有効
ReEvo方式: 実行→失敗分析→改善を3ラウンド繰り返す
→ 「なぜダメだったか」の反省が的確な改善を生む
FunSearch方式: スコア関数の集団を生成→評価→選択→進化
→ スコア関数の微調整に向いている
使い分け:
├── スコア関数を改善したい → FunSearch / RoCo
├── 割当の戦略そのものを変えたい → EoH
└── 何が悪いか分析してから直したい → ReEvo
注意:
- ソフト制約のスコア改善には強い
- Hard制約のfeasibility達成には不向き(ソルバーを使うべき)
- 最も効果的な使い方: ソルバーの解をベースにLLMが微調整
ソフト制約の重み配分を変えた複数のバリエーションを生成し、数値スコアで比較する。 顧客に「どの方針で行くか」を選んでもらうための材料。
手順:
1. ソフト制約ごとに「重視するバリエーション」を作る
例: A=バランス型、B=公平性重視、C=夜勤制限重視、D=最低時間確保重視
2. 各バリエーションを同じソルバーで解く(HC は共通、SC の重みだけ変える)
3. 全ソフト制約を 0-100 のスコアで評価する
- 100 = 完全遵守
- スコアの計算方法は問題に応じて定義(遵守率、標準偏差ベース等)
4. 比較テーブルを出力する
| バリエーション | 充足率 | 公平性 | 夜勤制限 | 最低時間 | 総合 |
|--------------|--------|--------|---------|---------|------|
| A バランス型 | 95.8 | 69.6 | 100.0 | 100.0 | 92.7 |
| B 公平性重視 | 95.8 | 82.1 | 80.0 | 90.0 | 89.3 |
| C 夜勤制限重視 | 95.8 | 55.0 | 100.0 | 100.0 | 90.1 |
5. トレードオフを説明する
「公平性を上げると夜勤制限が犠牲になる」等
注意:
- 問題が小さい/制約がきつい場合、全バリエーションが同じ解になることがある
→ これ自体が発見:「トレードオフの余地がないほど余裕がない」
- バリエーションは 3-5 個が適切。多すぎると選べない
- 総合スコアの重みは顧客と合意して決める
出力ファイル: scripts/variants.py + results/variant_results.json
改善策を試した結果:
├── 解けた → /opt-report で報告書作成
├── 改善したがまだ不十分 → もう1周回す
└── 行き詰まった → 追加データが必要
│
何が足りないか:
├── 制約の詳細(「本当にこの制約は必須?緩和可能?」)
├── 実績データ(「実際にどれくらい時間かかってる?」)
├── 優先度(「どの指標が一番大事?」)
└── ドメイン知識(「現場の人はどうやってる?」)
→ 追加依頼の文面を生成
改善の過程で制約や仮定に変更があった場合、必ずバージョンフォルダ内の spec.md を更新すること。
spec.md を更新したら、必ずこのチェックを実行すること。 仕様変更がコードに反映されていないと、結果が仕様と矛盾する。
ソルバーの FEASIBLE フラグを信じてはいけない。
ソフト化した制約(penalty 化や 5→4 緩和など)を入れると、ソルバーは「緩和後のモデルで解を見つけた」を FEASIBLE と報告するが、元の spec.md の HC を満たしているとは限らない。
必ず以下の独立検証器を実装すること:
def verify_hard_constraints(solver, vars_d, data):
"""Re-check HC1..HCN independently from the raw assignment.
Does NOT rely on the model's internal satisfiability.
Reads solver.Value(x[...]) and checks each HC from scratch.
"""
violations = {f"HC{i}": [] for i in range(1, N+1)}
# ... HC1: demand met? HC2: max hours? ... HCn: pair constraints?
return {
"all_satisfied": all(len(v) == 0 for v in violations.values()),
"total_violations": sum(len(v) for v in violations.values()),
"by_constraint": {hc: len(lst) for hc, lst in violations.items()},
}
各シナリオの結果には必ず以下を記録する:
solver_status (ソルバーの内部ステータス)hc_all_satisfied (独立検証の結果)hc_total_violations (違反総数)hc_violations_by_constraint (HC別の違反内訳)レポートには hc_all_satisfied を主として表示し、「ソルバーが解を返した」と「元の HC を全て満たした」を区別すること。
ソフト化シナリオ(HC1 soft, HC8 soft など)は、原則として hc_all_satisfied = false になる(緩和した HC が違反する)。
■ チェック1: ハード制約の完全一致
spec.md の「ハード制約」テーブルの全項目が、ソルバーコードに制約として実装されているか?
手順:
1. spec.md から HC1, HC2, ... を列挙する
2. scripts/ 内の全 .py ファイルを検索し、各 HC が model.Add() で実装されているか確認
3. コードにあるが spec にない制約がないか(逆方向チェック)
よくあるミス:
- spec で HC→SC に変更したのに、コードがまだ model.Add() のまま(ペナルティになっていない)
- 新しい HC を spec に追加したのに、コードに未反映
■ チェック2: ソフト制約と目的関数の対応
spec.md の「ソフト制約」テーブルの全項目が、目的関数のペナルティ項に含まれているか?
手順:
1. spec.md から SC1, SC2, ... を列挙する
2. model.Minimize() の中身を確認し、各 SC に対応するペナルティ項があるか
3. 重みの大小関係が spec の「重み」列と矛盾していないか
よくあるミス:
- SC を追加したのに目的関数に項がない
- 「重み: 高」なのに実際の係数が小さい
■ チェック3: 仮定の値の一致
spec.md の「仮定」テーブルの値が、コード内の定数と一致しているか?
手順:
1. spec.md から仮定(A1, A2, ...)の値を列挙する
2. コード内の対応する定数・パラメータと突合する
よくあるミス:
- spec で移動速度を 30→22 km/h に更新したのに、コードが 30 のまま
- 作業時間の仮定を変えたのに評価関数の定数が古い
■ チェック4: 評価関数と目的関数の一致
evaluate() 関数が計算するスコアと、ソルバーの目的関数が最適化する対象が一致しているか?
手順:
1. evaluate() が使う項目を列挙
2. model.Minimize() が使う項目を列挙
3. 差分がないか確認
よくあるミス:
- evaluate() に新しい SC を追加したのに、ソルバー側に未反映(逆も同様)
- ペナルティの計算式が evaluate() と model で異なる
■ チェック5: 仕様書内の矛盾検出 spec.md 内で制約同士が矛盾していないか?情報源が古くなっていないか?
手順: 1. ハード制約同士の矛盾: HC-A と HC-B が同時に満たせない場合がないか 例: 「全員週40h以上」と「1日1シフトのみ」が10人×21シフトで矛盾 2. ハード制約とソフト制約の矛盾: HC が SC を無意味にしていないか 例: HC「夜勤禁止」と SC「夜勤週2回以下」が共存(SCが不要) 3. 仮定と制約の矛盾: 仮定の値が制約と整合しているか 例: 「作業時間10分」の仮定なのに「1件30分」の制約がある 4. 情報源の鮮度: Ref の取得日が古い項目はないか 例: 3ヶ月前のヒアリング結果を根拠にした制約が、その後変わっていないか
矛盾や古い情報が見つかった場合: → 確認型質問書(/opt-request 形式)を生成して依頼者に確認する → 「R3(2026-04-01 ヒアリング)で『夜勤2名必須』とありましたが、 R5(2026-04-03 メール)では『1名でも可』と読めます。 現在の正はどちらですか? A) 2名必須(R3 が正) B) 1名でも可(R5 が正) C) 条件による(___)」
**チェック結果は `reports/improve_report.md` の QA セクションに記録すること。**
**矛盾や確認が必要な項目があれば、確認型質問書を `reports/data_request.md` に追記すること。**
### 6. 出力
**以下のMarkdownをバージョンフォルダ内の `reports/improve_report.md` に保存すること。** 改善スクリプトは `scripts/` に、数値結果は `results/` に保存する。
```markdown
## 改善結果
| 手法 | Feasible | 違反数 | スコア | vs ベースライン |
|------|----------|--------|--------|----------------|
| ベースライン(ソルバー) | ... | ... | ... | 基準 |
| 改善策A | ... | ... | ... | +XX% |
| 改善策B | ... | ... | ... | +XX% |
## 何が効いたか
- [最も効果的だった改善と、なぜ効いたかの説明]
## ソフト制約バリエーション比較
| バリエーション | 充足率 | SC1 | SC2 | SC3 | SC4 | SC5 | 総合 |
|--------------|--------|-----|-----|-----|-----|-----|------|
| A バランス型 | ... | ... | ... | ... | ... | ... | ... |
| B ○○重視 | ... | ... | ... | ... | ... | ... | ... |
| C ○○重視 | ... | ... | ... | ... | ... | ... | ... |
(各スコアは 0-100。100 = 完全遵守)
### トレードオフの説明
- [「公平性を上げると夜勤制限が犠牲になる」等]
- [全バリエーションが同じ場合: 「トレードオフの余地がないほど制約がきつい」]
## まだ解決していない課題
- [残っている違反/スコア不足の原因]
## 追加で必要な情報
- [ ] [具体的に何が欲しいか]
## QA チェック結果
| チェック項目 | 結果 | 備考 |
|-------------|------|------|
| HC の spec↔コード一致 | ✓ / ✗ | [不一致があれば詳細] |
| SC の spec↔目的関数一致 | ✓ / ✗ | |
| 仮定値の spec↔コード一致 | ✓ / ✗ | |
| 評価関数↔目的関数一致 | ✓ / ✗ | |
| 仕様書内の矛盾 | ✓ / ✗ | [矛盾があれば詳細] |
| 情報源の鮮度 | ✓ / ✗ | [古い Ref があれば詳細] |
## 次のステップ
→ もう1周改善する or /opt-report で報告書
.opt_state.yaml の baseline セクションを読み込む.opt_state.yaml の improve セクションを書き込むreference/state_schema.md を参照原因と対策:
├── 目的関数と評価関数のズレ → パターン1(最優先で確認)
│ evaluator のコードを精読し、ソルバー目的関数との差分を特定
├── ボトルネックの特定が間違っている → /opt-baseline に戻って再分析
├── 問題の分解方向が間違っている
│ → 悪い分解の例: 「いつ」と「何を」を分離してスキル制約を破壊
│ → 違反の原因を分析して、原因を解消する方向で分解する
└── 下界に近い → 思考回路⑥で改善余地を確認。余地がなければこれが限界
原因と対策:
├── 目的関数にハード制約のペナルティが不足
│ → ハード制約違反のペナルティを10倍にする
├── ソフト制約の改善がハード制約を破壊している
│ → パターン6: まず feasibility だけ追求 → 次に品質改善
└── 制約間の相互作用が複雑
→ SWO+IFS(パターン4)やソルバー修復(パターン5)を検討
原因と対策:
├── 評価関数にノイズがある → 同じ入力で複数回評価して平均を取る
├── 探索空間が広すぎる → 1つのパラメータだけ変えて効果を確認
├── 進化の方向がランダム → ReEvo方式で「なぜダメだったか」の分析を挟む
└── そもそもLLM進化が向かないケース
→ feasibility問題にはソルバーを使う(LLM進化はソフト制約向き)
原因と対策:
├── 問題規模が大きい → 分解する(パターン3: Cluster+ソルバー)
├── 制約が多すぎる → 不要な制約を削減(本当に必要か再確認)
├── 対称性がある → 対称性除去制約を追加(ソルバーの探索を効率化)
└── 時間制限内に良い解が欲しい
→ add_hint() で初期解を与える(warm start)
→ まず短時間で feasible を見つけ、残り時間で改善