ハイパーパラメータ探索は長らく「数値の問題」として扱われてきた。TPEもガウス過程ベイズ最適化も、learning_rate という名前が何を意味するかは知らない。渡されるのは次元と範囲、そして過去の試行の数値だけだ。2026年7月7日に公開された Optim-Agent/optim-agent は、この前提を一箇所だけ入れ替える。Optuna風のStudy/Trial APIをほぼそのまま維持したまま、次の1点を決める「サンプラー」をClaude Code・Codex・OpenCodeといったコーディングエージェントのCLIに差し替えるという設計だ。パラメータの意味を自然言語で添えられるので、エージェントは数値の傾向と意味の両方を読んで次の候補を出す。
エージェント基盤全体の中でどのあたりに位置するツールなのかは、AIエージェントフレームワーク比較2026|LangGraph・CrewAI・Dify等9種をStar数・実コードで検証で整理している。本記事はそのうち「エージェントに数値最適化そのものを任せる」系統を、公式リポジトリ・CHANGELOG・PyPI・そして実際に手元へ入れて動かした結果から検証する。star 597・MIT・Python製で、記事執筆時点のPyPI最新は0.1.1、mainは0.2.0だ。
・何ができるか:Optuna風の
create_study / suggest_float のまま、次の候補点をLLMエージェントに提案させる。パラメータごとに context="決定しきい値。上げると再現率を精度と引き換える" のような意味を渡せる・何を解決するか:1回の評価が高価で試行が10〜20回しか取れない領域。この予算では古典的な代理モデルがまだデータ不足だという位置づけ
・何を代替できるか:Optunaのサンプラー層(TPE等)。Study/Trialの書き方はほぼ維持されるが、Optunaのドロップイン置換ではない
・要件:Python 3.9以降と、認証済みの
claude / codex / opencode のいずれか1つがPATH上にあること。配線確認用に backend="mock" がある・実測した注意点:
pip install で入る0.1.1にはREADMEが説明する summarize=True が無く、渡すとTypeErrorになる
optim-agentとは|Optuna風APIのサンプラーをLLMエージェントに差し替えるOSS
optim-agentは、探索空間の宣言と目的関数の評価はこれまでどおり自分のコードで行い、「次にどの値を試すか」だけをLLMに任せるライブラリだ。READMEの自己説明は「Agentic system optimization with coding agents.(コーディングエージェントによるエージェント的なシステム最適化)」で、副題として「アルゴリズムエンジニアが繰り返すパラメータ調整作業の自動化」を掲げている。
書き方はOptunaを使ったことがあれば見慣れたものだ。違いは sampler= に AgentSampler を渡すところと、suggest_* に context= で意味を添えられるところにある。
import optim_agent as oa
def objective(trial):
threshold = trial.suggest_float(
"threshold", 0.05, 0.95,
context="決定しきい値。上げると再現率を精度と引き換える",
)
budget = trial.suggest_int(
"budget", 10, 200, log=True,
context="計算・運用予算。大きいほど品質が上がる可能性がある",
)
return evaluate_system(threshold=threshold, budget=budget)
study = oa.create_study(
direction="maximize",
sampler=oa.AgentSampler(
backend="claude", # または "codex" / "opencode"
effort="high",
context="厳しい運用コスト上限のもとでシステム品質を最大化する",
history=5, # 直近5試行を毎回プロンプトへ載せる
),
storage="study.json", # 任意。中断・再開用
)
study.optimize(objective, n_trials=20)
print(study.best_value, study.best_params)
0.1.1 の公開APIを実際に読むと、Study が持つのは ask / tell / optimize / best_params / best_trial / best_value の6つで、Trial 側は suggest_float / suggest_int / suggest_categorical / report / should_prune だった。Optunaの広大なAPIのうち、探索に最低限必要な部分だけを写した構成になっている。READMEの謝辞も、Study/Trialインターフェースの普及とTPEベースラインの提供についてOptunaへ明示的に言及している。
読者が最初に確認すべき「何を解決するのか」は、READMEが自ら限定している。挙げられている利点は5つで、要点は評価が高価な領域に絞っていることだ。
・意味を踏まえた提案:各次元を無名の座標として扱わず、パラメータの意味・研究の文脈・観測結果を読んで提案する
・小予算での効き:評価が高価で、古典的な代理モデルがまだデータ不足の状況で有用
・CLI側の進歩に乗れる:最適化コードを変えずに、下敷きのエージェントが強くなれば提案品質も上がりうる(READMEはGPT-5.5からGPT-5.6への移行を例示)
・決定の追跡:JSON / SQLiteのstudyに構成・結果・状態・文脈・任意でエージェントの論拠が残る
・実行範囲の制限:エージェントは値を提案するだけで、検証はoptim-agent側が行う
最後の「実行範囲の制限」は重要な設計主張なので、後段で実際に壊してみる。適用領域としてREADMEはモデル学習・推論と配信・定量研究・強化学習と意思決定・科学計算ワークフロー・任意のブラックボックス系を挙げており、強化学習については「学習ループ自体は置き換えず、その周囲をチューニングする」と範囲を切っている。
pip installで入るのは0.1.1|READMEが説明する機能との差を実測する
ここが本記事で最初に伝えたい実測結果だ。公式README(日本語版を含む)が説明している機能の一部は、pip install optim-agent で入るバージョンには存在しない。
まず版の状況を整理する。PyPIには 0.1.0(wheel 2026-07-08)と 0.1.1(wheel 2026-07-13)の2つだけが上がっており、最新は0.1.1だ。GitHub側のリリースも 0.1.1 の1件(公開 2026-07-14)、タグも 0.1.1 のみ。一方でmainブランチの pyproject.toml は version = "0.2.0" を宣言しており、CHANGELOG.md には ## 0.2.0 - 2026-07-27 として2項目が記載されている。つまり0.2.0はCHANGELOG上は日付つきで確定しているが、PyPIにもタグにも出ていない状態だ。
CHANGELOGが0.2.0の追加として挙げるのは次の2つで、いずれもREADMEに使い方が書かれている。
・サマリーエージェント:create_study(..., summarize=True) で、optimize() 完了後に一度だけエージェントが結果を要約し、最良構成・探索空間の洞察・軌跡のハイライト・次の一手を構造化して出力・永続化する
・表形式ログ:Study.optimize(verbose="table") で探索空間の各パラメータを1列ずつ並べた表を描画し、非TTY出力では従来の1行形式へ自動フォールバックする
これを0.1.1で実際に呼ぶと次のようになった。
python -m venv venv && ./venv/bin/pip install optim-agent
./venv/bin/python -c "
import inspect, optim_agent as oa
print(oa.__version__)
print(inspect.signature(oa.create_study))
"
# 0.1.1
# (direction='minimize', sampler=None, pruner=None, storage=None, seed=None, max_concurrency=1) -> optim_agent.study.Study
summarize が引数一覧に無い。実際に渡すと TypeError: create_study() got an unexpected keyword argument 'summarize' になり、Study に summary 属性も存在しなかった。同じスクリプトを pip install "optim-agent @ git+https://github.com/Optim-Agent/optim-agent.git" で入れたmain(0.2.0)に対して走らせると、create_study の引数は10個に増え、summarize / summary_backend / summary_model / summary_effort が追加されていた。
モジュール構成の差も同じ線で説明できる。0.1.1に入っているのは agent / pruners / samplers / space / study の5つで、0.2.0はこれに reporting と summarizer が加わる。表描画を担う reporting.py は128行あり、0.1.1側の study.py を検索すると table / ljust / truncat はいずれも0箇所だった。
ここは正確に書き分けたい。verbose="table" を0.1.1に渡してもエラーにはならない。受け付けられ、1行形式のログが出る。筆者の検証は標準出力をパイプしていたため、READMEが明記している「非TTYでは1行形式へフォールバックする」挙動と区別がつかない条件だった。したがって「0.1.1で表が出ない」ことを実行結果だけから断定はできない。断定できるのは、0.1.1のパッケージ内に表を組み立てるコードが見当たらず、それは0.2.0で追加された reporting モジュールに入っているという事実のほうだ。
extras(追加依存グループ)も揃っていない。PyPI 0.1.1のメタデータが持つextrasは examples / dev / vision / ml で、examples の中身は numpy・matplotlib・optuna。mainの pyproject.toml は examples に scikit-optimize を追加し、さらに rl = ["gymnasium[box2d]>=1.0", "imageio>=2.31"] を定義している。READMEのベンチマーク再現手順にある pip install -e ".[rl,examples]" や、クレジットカードベンチマークのGP-BOベースラインが要求する scikit-optimize は、ソースから入れないと揃わないということになる。
・何ができるか:READMEどおりのサマリーエージェント・表形式ログ・RLベンチマーク再現を使いたいなら、PyPI版ではなく
git+https://github.com/Optim-Agent/optim-agent.git でソース導入する・何を解決するか:「ドキュメントのとおりに書いたのにTypeError」という初動の詰まりを回避できる
・何を代替できるか:ここは代替の話ではなく、導入経路の選択の話。安定性を取るなら0.1.1、機能を取るならmain
エージェントの返答が壊れたとき何が起こるか|実測した4つの経路
READMEは「エージェントは値を提案するだけで、optim-agentが宣言済みの空間に対して検証し、不正な出力は安全なサンプリングへ退避する」と説明している。この主張はLLMを最適化ループに入れるうえで一番効く安全弁なので、実際に壊して確かめた。
検証方法はLLMを呼ばない。claude という名前の偽の実行ファイルをPATHの先頭に置き、返答内容を自由に差し替えるだけだ。トークン消費はゼロで、誰でも再現できる。
# fakebin/claude — 常に「JSONでない」返答を返す偽バックエンド
#!/bin/sh
echo "call" >> "$FAKE_LOG"
echo "I am not JSON. Sorry."
これをPATHに置いてBranin-2D(x1 を -5〜10、x2 を 0〜15)で走らせると、4つの経路がはっきり分かれた。
取り出せるか"} B -->|"いいえ"| R["却下"] B -->|"はい"| C{"空間の全キーが
揃っているか"} C -->|"いいえ"| R C -->|"はい"| D{"各値が数値に
変換でき有限か"} D -->|"NaN / inf / 変換不可"| R D -->|"はい"| E["範囲内へクランプ
min(max(v, low), high)"] E --> F["そのまま目的関数へ"] R --> G{"2回目の試行か"} G -->|"1回目"| H["注意書きを足して再送"] H --> A G -->|"2回目"| I{"fail_closed"} I -->|"False(既定)"| J["警告してランダム点へ退避"] I -->|"True"| K["ValueError で停止"]
経路A:範囲内の正しいJSON。 そのまま採用され、CLI呼び出しは1試行あたり1回。
経路B:数値だが範囲外。 ここが一番の注意点だ。上限10の x1 に 999.0、下限0の x2 に -42.0 を返させると、目的関数が受け取ったのは x1=10.0000 x2=0.0000 だった。警告は出ず、再試行も起きない。 しかも同じ境界点が2試行連続で評価された。ソースを読むと理由は明快で、space.py の Float.validate は最後に min(max(v, self.low), self.high) を返す。Int も round してから同様にクランプする。
これは「READMEが嘘」という話ではない。クランプも宣言済み空間に対する検証の一形態で、却下して再サンプリングするか、範囲内へ丸めるかは実装上の選択だ。ただ運用上の意味は小さくない。エージェントが範囲を勘違いし続けると、探索は静かに境界へ張り付き、同一点の重複評価で貴重な試行が消える。しかも履歴には正常な試行として並ぶので、暫定最良値が動かないことが「収束」に見えてしまう。
経路C:数値として成立しない値。 Float(0.05, 0.95).validate() を直接叩いて挙動を並べると次のようになった。
| 返ってきた値 | 結果 |
|---|---|
0.5(範囲内) |
0.5 |
999.0(上限超え) |
0.95 にクランプ |
-42.0(下限未満) |
0.05 にクランプ |
"0.7"(数値の文字列) |
0.7(受理) |
float("nan") |
ValueError: non-finite value nan |
float("inf") |
ValueError: non-finite value inf |
"high" |
ValueError: could not convert string to float |
None |
TypeError |
True |
0.95(boolが1.0として扱われクランプ) |
Int(10, 200) は 5000 → 200、1 → 10、33.7 → 34 と、丸めてからクランプした。
経路D:JSONでない、またはキー欠落。 却下され、「前回の返答は解析できなかった。範囲内の値だけをJSONで返せ」という追記つきで1回だけ再送される。それでも駄目なら UserWarning: agent reply unparseable twice; falling back to random sampling が出てランダム点に退避し、studyは止まらずに完走した。
ここでREADMEに記載のないオプションが1つ見つかった。AgentSampler(fail_closed=True) を指定すると、同じ条件で退避せずに ValueError: agent reply unparseable twice; refusing Random fallback を投げて停止する。ランダム退避による静かな品質劣化を許容できない用途では、こちらが望ましいことが多いだろう。英語・日本語のREADMEどちらにも fail_closed の記述は無く、シグネチャを読んで初めて分かる引数だった。
Categorical(["adam","sgd"]) は大文字小文字を含む完全一致を要求し、"Adam" は ValueError: 'Adam' not in ('adam', 'sgd') になる。LLMは固有名詞を自然に大文字化するため、経路D(却下→再試行→ランダム退避)を踏みやすい。数値パラメータが静かにクランプされる一方で、カテゴリカルは明示的に却下される——という非対称を踏まえ、選択肢名は小文字などLLMが崩しにくい表記で宣言しておくのが無難だ。
再現性:create_study(seed=) だけでは固定されない
もう1つ実測で分かった落とし穴がある。mock バックエンド(LLMを呼ばずに最良点周辺を山登りする配線確認用)で5試行を3回繰り返し、最良値を比べた。
・create_study(seed=0) のみ → 11.352291 / 0.55858 / 8.852205(毎回変わる)
・create_study(seed=0) + AgentSampler(seed=0) → 0.134309 / 0.134309 / 0.134309(一致)
初期のランダム探索(既定 n_init=2)とサンプラー側の乱数が別系統で管理されているためだ。実験を再現可能にしたいなら両方に種を渡す必要がある。なおLLMバックエンドを使う場合は、種を揃えてもモデル側の非決定性が残るため、完全な再現は期待できない。
LLM CLIは何回呼ばれるか|試行数からコストを見積もる
エージェントを最適化ループに入れると、当然コストは試行回数に比例して増える。偽CLIの起動回数を実カウントして、その比例係数を確かめた。
n_init=2 ぶんはランダム初期化でエージェントを呼ばない(0.1.1で実測)n_trials=6・既定 n_init=2 の条件で、正しいJSONを返す偽CLIでは4回、常に解析不能な返答を返す偽CLIでは8回の起動だった。つまり基本の見積もりはこうなる。
・CLI呼び出し回数 = n_trials − n_init(既定 n_init=2。最初の2試行はランダム初期化でエージェントを呼ばない)
・返答が解析できないとその試行だけ2倍になる(再試行が1回入る)
・AgentPruner を併用すると枝刈り判定でも別途エージェントを呼ぶ
1回のプロンプトに何が載るかは history で決まる。既定は直近5試行で、history=None にすると完了・枝刈り済みの全試行が載る。長い探索で history=None にすると1回あたりの入力が試行数に応じて膨らむので、コストは呼び出し回数だけでなく履歴長にも効く。explicit_reasoning=False / qualitative_notes=False にすると返答側を短くできる。
偽CLIに渡された引数を記録すると、claude バックエンドの呼び出しは -p --effort high <プロンプト> の形だった。effort はそのままバックエンドCLIの推論努力フラグへ転送される設計で、プロンプト本体の制御(history / explicit_reasoning / qualitative_notes)とは別系統になっている。
なお max_concurrency > 1 の並行実行時には、1回の呼び出しで複数候補をまとめて出させる経路がソース上に存在した。返答の候補数が指定と一致しない場合や、既出の点と重複する候補が混じっていた場合は、その一括提案ごと却下して通常の単発提案へ落ちる実装になっている。この挙動もREADMEには記載が無い。
公開ベンチマークの読み方|10試行という予算で何が起きているか
READMEは4系統のベンチマークを数値と再現コマンドつきで公開している。優劣の断定は避け、条件と数値をそのまま読む。すべてリポジトリが公開している値だ。
数理関数(文脈なし・10試行・5シード)
エージェントにはタスクの文脈を一切渡さず、x1...x5 という無名のパラメータ名・数値の範囲・試行履歴だけを与える条件だ。
| 手法 | Branin 平均最良値 ↓ | Ackley-5D 平均最良値 ↓ |
|---|---|---|
| Random | 5.008 | 19.639 |
| TPE | 11.395 | 18.843 |
| GPT-5.5 | 1.326 | 3.960 |
| Opus-4.8 | 0.398 | 0.061 |
| Sonnet-5 | 3.850 | 0.143 |
| Kimi-K3 | 2.082 | 0.907 |
| Minimax-M3 | 0.970 | 0.574 |
| GLM-5.2 | 3.609 | 15.023 |
この表を読むうえで外せない条件が10試行だという点だ。表の中でTPE(11.395)はBraninでRandom(5.008)を下回っている。TPEは初期のランダム探索を終えて代理モデルが形になってから効く手法なので、10試行という予算では本来の性能が出る前の段階にある。したがってこの表は「TPEよりエージェントが優れている」ことの証明ではなく、評価が高価で試行が極端に少ない領域では古典的な代理モデルがデータ不足になるというREADME自身の位置づけを数値で示したもの、と読むのが妥当だ。参考として、Braninの真の最小値は約0.3979で、Opus-4.8の0.398はこれとほぼ一致する。
画像分類(MNIST / CIFAR-10)
主指標は「各試行時点での暫定最良テスト誤差を10試行ぶん足した累積値」で、低いほど早く改善したことを意味する。
| 手法 | MNIST 累積誤差 ↓ | MNIST 最終誤差 ↓ | CIFAR-10 累積誤差 ↓ | CIFAR-10 最終誤差 ↓ |
|---|---|---|---|---|
| Random | 9.174 | 0.648% | 278.920 | 25.072% |
| TPE | 7.166 | 0.580% | 279.936 | 25.596% |
| GPT-5.5 文脈あり | 5.668 | 0.506% | 220.994 | 21.322% |
| GPT-5.5 文脈なし | 8.910 | 0.632% | 281.466 | 25.960% |
ここで効いているのは文脈の有無だ。READMEは、文脈ありがMNISTでTPE比20.9%・CIFAR-10でRandom比20.8%の累積誤差削減だったとしつつ、文脈なしはMNISTでTPEより24.3%悪化・CIFAR-10でRandomより0.9%悪化したと書いている。同じモデル・同じ予算でも、自然言語で意味を渡したかどうかで結果が反転する。このOSSの価値の中心は「LLMを使うこと」ではなく「パラメータの意味を渡せること」にあると読める部分だ。
強化学習(Acrobot-v1 / LunarLander-v3)
CPUのみのGymnasium環境で、離散化したQ学習コントローラを20試行・5シードで調整した結果。目的は平均評価リターンなので高いほど良い。
| 手法 | Acrobot-v1 リターン ↑ | LunarLander-v3 リターン ↑ |
|---|---|---|
| Random | -200.000 | -62.139 |
| TPE | -199.900 | -72.088 |
| GPT-5.5 文脈あり | -199.700 | -50.825 |
| GPT-5.5 文脈なし | -199.100 | -59.751 |
Acrobot-v1は4手法すべてが -200 という床から0.9以内に収まっており、差はほぼ無い。READMEはこの表について「文脈ありが両環境で最も強い平均リターン」と述べ、根拠としてAcrobot-v1ではTPE比+0.2、LunarLander-v3ではRandom比+11.3という2つの差を挙げている。つまり比較対象として明示されているのはベースライン(TPE / Random)で、対照条件である文脈なしの数値には触れていない。同じ表を素直に読むと、Acrobot-v1では文脈なし(-199.100)のほうが文脈あり(-199.700)より高い。ベースラインに対しては確かに上回っているが、対照条件との比較まで含めると順序は逆になる、ということだ。もっともAcrobotの差は床から0.9以内であり、READMEもこのベンチマーク自体を「普遍的なランキングではなくCPUでのHPOストレステストとして扱え」と明記している。その注記どおり、手法の差を測れていない環境と見るのが素直だろう。LunarLander-v3側は数値の幅が大きく、こちらは文脈ありが文脈なし・両ベースラインのいずれも上回っている。
勾配ブースティング(UCIクレジットデフォルト)
HistGradientBoostingClassifier の8パラメータを、UCIの信用カードデフォルトデータセット(30,000行・23特徴)で20試行・5シード調整したもの。データはSHA-256で固定され、60/20/20で一度だけ分割されている。
| 手法 | 検証 log loss ↓ | ホールドアウト test log loss ↓ |
|---|---|---|
| Random | 0.433 | 0.425 |
| TPE | 0.430 | 0.422 |
| GP-BO | 0.430 | 0.423 |
| GPT-5.5 文脈あり | 0.428 | 0.422 |
| GPT-5.5 文脈なし | 0.433 | 0.427 |
差は小さい。READMEは文脈ありが対照(文脈なし)比で検証1.13%・test 1.23%の改善だとしつつ、残した構成が検証とtestの両方を見て選ばれているため、testの値は汎化性能の未汚染な推定ではなくベンチマーク比較として読むべきだと自ら注記している。この実験が方法論的なベンチマークであって本番の信用判断システムではないことも、リポジトリ側が明記している。
インストールと使い方|pip・プラグイン・スキルモードの3経路
導入経路は3つあり、それぞれ役割が違う。
# 1) Pythonライブラリとして(目的関数はブラックボックス扱い)
python -m pip install optim-agent
# READMEどおりの機能を使うならソースから
python -m pip install "optim-agent @ git+https://github.com/Optim-Agent/optim-agent.git"
# 2) Claude Code プラグインとして
claude plugin marketplace add Optim-Agent/optim-agent
claude plugin install optim-agent@optim-agent
# 3) Codex プラグイン / スキルとして
codex plugin marketplace add Optim-Agent/optim-agent
codex plugin add optim-agent@optim-agent
前提はPython 3.9以降と、認証済みの claude / codex / opencode のいずれか1つがPATH上にあることだ。実装の BACKENDS は ('claude', 'codex', 'opencode') の3つで、これに加えて配線確認用の mock が使える。導入直後の疎通確認は、LLMを呼ばないこの mock で済ませるのが早い。
python -c "
import optim_agent as oa
def objective(trial):
x = trial.suggest_float('x', -5, 10)
return (x - 3) ** 2
study = oa.create_study(sampler=oa.AgentSampler(backend='mock', seed=0), seed=0)
study.optimize(objective, n_trials=5)
print('best:', study.best_value, study.best_params)
"
スキルモードはpipパッケージと役割が異なる。pip版は目的関数をブラックボックスとして扱うが、スキル/プラグインとしてコーディングエージェントのセッションに読み込むと、エージェントがまずプロジェクトのコードを読んで各パラメータの役割を把握し、その上で study.ask(params) / study.tell(trial, value) を自分で回す。studyのJSONが履歴を保持するのでセッションを越えて継続できる。「パラメータの意味を渡せることが効く」というベンチマークの示唆を踏まえると、意味を人間が context= に書き起こす手間を省く方向の設計と読める。なおこうしたスキル形式で配られるOSSが増えると、どのスキルをどの版で入れているかの管理自体が課題になる。その観点はAgent Skill Harbor徹底解説|AIエージェントのスキル資産をGitで一元管理するOSS基盤で扱っている。
枝刈りは AgentPruner が担い、level を loose / medium / tight から選ぶ。エージェントが現在の学習曲線を完了済み試行と比べて続行か中断かを答える仕組みで、READMEは「エージェント側のエラーで試行が枝刈りされることはない」と明記している。並行・分散実行では max_concurrency でプロセス内の同時評価数を決め、.db / .sqlite のストレージを共有すればプロセス・マシンをまたげる。ただしエージェントへの問い合わせ自体は直列化され、並行するのは目的関数の評価側だ。READMEはOpenCodeバックエンドが分散実行に未対応であることと、スレッドはGILを共有するためCPU律速の目的関数は別プロセス化が望ましいことも書いている。
トラブルシューティングで実用的なのは、エージェントセッションの内側で claude を呼ぶと ANTHROPIC_API_KEY を継承して401になるケースだ。READMEは env -u ANTHROPIC_API_KEY で外すか、クリーンなシェルから実行するよう案内している。
類似ツールとの比較|optim-agentとOptuna・GP-BOの設計上の違い
optim-agentはOptunaの置き換えを狙うツールではない。READMEの謝辞がOptunaをStudy/Trialインターフェースの源流かつTPEベースラインの提供元として挙げているとおり、同じ器の上でサンプラー層だけを差し替える関係にある。設計上の違いを、優劣ではなく前提の違いとして並べる。
| 観点 | optim-agent(AgentSampler) | Optuna TPE | ガウス過程ベイズ最適化(GP-BO) |
|---|---|---|---|
| 次の点の決め方 | LLMがパラメータの意味・文脈・履歴を読んで提案 | 過去試行の分布を密度比で推定 | 代理モデルの事後分布と獲得関数 |
| パラメータの意味 | context= で自然言語を渡せる |
扱わない(次元と範囲のみ) | 扱わない(次元と範囲のみ) |
| 外部依存 | 認証済みエージェントCLIが必須 | ライブラリのみ | ライブラリのみ |
| 1試行あたりのコスト | LLM呼び出し1回(失敗時2回) | ほぼ無視できる | 試行増加につれモデル更新コスト増 |
| 再現性 | モデル側の非決定性が残る | 種で固定可能 | 種で固定可能 |
| 想定予算 | 評価が高価な小予算(10〜20試行)を明示 | 数十〜数百試行で本領 | 数十試行程度 |
| 不正提案時 | クランプ、または再試行→ランダム退避 | 構造上発生しない | 構造上発生しない |
| 成熟度 | pyproject上 Alpha、公開3週間ほど | 広く実運用 | 実装により差 |
実務上の判断軸は素直に「1回の評価にどれだけかかるか」だ。1試行が数秒で終わる目的関数なら、LLM呼び出しの待ち時間とコストのほうが支配的になり、TPEを数百回回したほうが速い。逆に1試行がGPU数時間・実機実験・高価なAPI呼び出しといった領域では、試行数そのものが取れないので、1点あたりの選び方に計算を投じる価値が出る。optim-agentが「小予算での効き」を前面に置いているのは、この線引きに沿っている。
もう1つの軸は、パラメータに人間の知識があるかどうかだ。ベンチマークで文脈の有無が結果を反転させていたことを踏まえると、context= に書けることが何も無い純粋なブラックボックスでは、このツールの持ち味は出にくい。「このしきい値を上げると再現率と精度がトレードオフになる」「この予算は運用費に直結する」といった説明が書けるなら、それが効く入力になる。
エージェントに機械学習の改善そのものを任せる方向のOSSと比べると、線引きの違いがはっきりする。autoresearch:KarpathyのAIエージェントが一晩でLLMを自律改善する最小構成フレームワーク入門で扱ったツールは、エージェントが学習コードそのものを書き換えて改善を回す。対してoptim-agentは、探索空間の宣言と目的関数の評価を人間のコードに残したまま、エージェントの権限を「宣言済みの範囲から次の1点を選ぶ」ことだけに限定する。前者は自由度が高く、後者は本記事で見たように提案が壊れても検証層で受け止められる。どちらが良いかではなく、エージェントにどこまで権限を渡すかの設計判断が違う。
成熟度は率直に見ておきたい。star 597・fork 29に対し、bot以外のコミッターは1アカウント、コミットは77件、公開は2026-07-07で3週間ほど。pyproject.toml の分類子は Development Status :: 3 - Alpha だ。加えて本記事で実測したとおり、既定設定ではエージェントの返答が壊れてもランダム退避で走り続ける。長時間の学習ジョブに組み込むなら、fail_closed=True を検討し、storage にJSON/SQLiteを指定して各試行の構成・結果・論拠を残しておくのが現実的だろう。
まとめると、optim-agentは「LLMで最適化」という漠然とした売り方をせず、サンプラー層という交換可能な一点に絞ってLLMを差し込んだOSSだ。Optuna風のAPIを保つので既存の書き方から離れずに試せて、backend="mock" があるためLLMを呼ばずに配線確認もできる。ベンチマークが示す肝は「LLMだから強い」ではなく「パラメータの意味を渡せると変わる」ことで、文脈なし条件が軒並み振るわない点がむしろそれを裏づけている。
一方で、手元で動かして初めて見える段差もあった。pip install で入る0.1.1はREADMEが説明する summarize=True を受け付けずTypeErrorになる。範囲外の値は却下されず境界へ丸められ、警告なしで同じ境界点が連続評価されうる。再現性を確保するには create_study と AgentSampler の両方に種が必要で、返答の破損時に例外で止めたいなら未記載の fail_closed=True を使う。導入を検討するなら、まず mock で配線を確認し、ソース導入かPyPI版かを機能要件から選び、storage を有効にして履歴を残すところから始めるのが安全だ。
参照ソース
・Optim-Agent/optim-agent — GitHubリポジトリ(README・ソースコード):本記事の機能説明・ベンチマーク数値・トラブルシューティングの一次ソース。日本語READMEは docs/i18n/README_JA.md
・optim-agent CHANGELOG.md:0.1.0 / 0.1.1 / 0.2.0 の変更内容と日付
・optim-agent — PyPI:公開バージョン・wheelのアップロード日時・extrasのメタデータ
・Optuna — GitHubリポジトリ:Study/Trialインターフェースと、ベンチマークのTPEベースラインの出所(optim-agent側の謝辞で言及)
検証環境: macOS 14(Darwin 23.5.0) / Python 3.14(venv) / optim-agent 0.1.1(PyPI)および 0.2.0(mainからのソース導入) / 検証日 2026-07-30。GitHubの実体値(star 597・fork 29・MIT・Python・コミット77件)は同日にGitHub REST API v3で取得した。