目次
「ALE-Bench」と「ALE-Agent」
最近話題のSakanaAIが発表した「ALE-Bench」と「ALE-Agent」。
これは、AtCoderで実際に出題された最適化コンテストの問題群をベンチマークとして利用し、AIに解かせることでその改善能力を測るという、かなり面白い試みです。
しかもこのALE-Agent。普通のLLM(大規模言語モデル)をベースにしながらも、試行錯誤とフィードバックを通じて少しずつ“賢く”なっていく設計になっています。
そこで、実際にこの仕組みをGoogle Colabで再現できないかと思い、簡易バージョンのALE-Agent風を作ってみました。
ALE-Agentってなに?
ざっくり言うと、ALE-Agentとは
最初は適当な答えを出すけど、スコア(点数)を見て反省しながら、少しずつ解を改善していくAIエージェントです。
まるで将棋のAIが何千回も対局して強くなるように、最適化問題に対して試行錯誤を繰り返し、より良い解を探していくのがこのエージェントの特徴です。
SakanaAIのALE-Benchでは、過去のAtCoder Heuristic Contest(AHC)の問題がベンチマークとして活用されており、AIの改善能力が公平に比較できるようになっています。
Google Colabで簡易版を実行してみる
もちろん本家のALE-Agentのような高度な設計をそのまま再現するのは大変ですが、まずは以下の3ステップで簡易版を作りました。
1 シンプルな最適化問題を定義
今回は、「1〜10の数字を並び替えて、隣り合う数字の差の合計を最大にする」という簡単な問題に設定。
この問題は「最適解が1つに定まらず、試行錯誤でスコアが改善していく構造」があり、ALEの仕組みと似ています。
2 初期解とスコア評価関数
最初はランダムに数字を並べて、スコアを評価。
その後、OpenAIのGPT-4 APIに「今の答えよりも良くなるような並びを提案して」と依頼し、改善案を取得します。
3 スコアが上がったら更新、下がれば無視
提案された解が今より良ければ採用、ダメなら却下という単純なフィードバックループを作成。
これを数多く繰り返すことで、最初の適当な並びから、スコアが高い「より良い解」へと少しずつ進化していきます。
2つのバージョンを用意する
今回はLLMを使わない高速バージョンとLLMを使うハイブリッドバージョンの2つのコードを実行してみました。
1番最後にコードを貼っておきますので、興味のある方は、google colabにて実行してみてください。
(LLMを使うバージョンはopenAIのAPIを使うので課金されます。無料でやりたい方は高速バージョンを使ってください)
実行してみた感想
高速バージョン
最初のスコアは30台後半。そこから少しずつ改善され、最終的には40台後半、場合によっては50台までスコアが伸びることもありました。
実際の出力は以下のようなイメージ:


ハイブリッドバージョン
同じような動きですが、LLMをつかわないでスコアが停滞すると、LLMへGOのスイッチが入り、よりよい解が得られるように、進化していきます。


このように、全体のパフォーマンスが自動で向上していく様がリアルに見えて、なかなか楽しいです。
Darwin Gödel Machineとの違いってなに?
SakanaAIの技術といえば、ALE-Agentと並んで注目されているのが「Darwin Gödel Machine(DGM)」というもう一つの概念。
このDGMは、ALE-Agentとは全く違うレイヤーの自己改善型AIです。
たとえば、今回のALE-Agent風システムは「ちょっとずつ調整して、より良い答えを目指す」タイプ。
一方、DGMは「そもそも自分の考え方が間違ってるかもしれないから、自分の仕組み自体を論理的に修正する」というレベルの話です。
つまり、ALEは「戦術を変える」、DGMは「自分という存在を進化させる」といった違いがあります。
実装難度や動作速度の観点では、現時点ではALE型の方がずっと扱いやすいです。
将来的にはDGM型のAIが真の「汎用人工知能(AGI)」の入口になる可能性もあるかと思います。
(なんと言っても、自分自身のコードを書き換える訳ですから、これはすごい技術です)
まとめ
今回、SakanaAIが提唱するALE-Agentのエッセンスを自分なりにColabで再現してみました。
AIが「自分の出力を反省して少しずつ良くする」というプロセス。
DGMとはまた違ったアプローチを知りました。
もちろん、本家のように高度なツール統合していませんが、
「初期解 → スコア → 改善 → 再評価 → 進化」というループは、通常のシステムにはない面白さがあります。
「とりあえず自分でもやってみたい」という方には、下記にコードを2種類貼っておきますので、google colabにて実行してみてください。
・高速バージョン
LLMを使わないので、API料金はかかりません。
その分、コードもシンプルでLLMを使うからこその面白さには欠けます。
メリットは高速なこと。
import random
import math
import matplotlib.pyplot as plt
# ===== 問題:1〜10の数字を並べて隣接差の合計を最大化 =====
def evaluate(solution):
return sum(abs(solution[i] - solution[i+1]) for i in range(len(solution)-1))
# ===== 初期解を生成 =====
def generate_initial_solution():
sol = list(range(1, 11))
random.shuffle(sol)
return sol
# ===== 近傍解を生成(2つの数字をランダムに入れ替える) =====
def generate_neighbor_solution(solution):
neighbor = solution.copy()
i, j = random.sample(range(len(solution)), 2)
neighbor[i], neighbor[j] = neighbor[j], neighbor[i]
return neighbor
# ===== 焼きなまし法の受容判定 =====
def should_accept(current_score, new_score, temperature):
if new_score > current_score:
return True
delta = new_score - current_score
probability = math.exp(delta / temperature)
return random.random() < probability
# ===== パラメータ =====
MAX_ITER = 100
INITIAL_TEMP = 10.0
COOLING_RATE = 0.95
# ===== メインループ =====
solution = generate_initial_solution()
score = evaluate(solution)
temperature = INITIAL_TEMP
scores = [score]
print("===== 焼きなまし法による最適化開始 =====")
for i in range(1, MAX_ITER + 1):
neighbor = generate_neighbor_solution(solution)
new_score = evaluate(neighbor)
if should_accept(score, new_score, temperature):
solution = neighbor
score = new_score
print(f"✅ Iter {i:2d} | New Score: {new_score} | Temp: {temperature:.4f} | 採用")
else:
print(f"❌ Iter {i:2d} | New Score: {new_score} | Temp: {temperature:.4f} | 却下")
scores.append(score)
temperature *= COOLING_RATE
# ===== 結果表示 =====
print("\n===== 最適化終了 =====")
print("最終解:", solution)
print("最終スコア:", score)
# ===== スコア推移のグラフ =====
plt.figure(figsize=(8, 5))
plt.plot(range(len(scores)), scores, marker='o')
plt.title("Score Transition (Simulated Annealing)")
plt.xlabel("Iteration")
plt.ylabel("Score")
plt.grid(True)
plt.show()
・ハイブリットバージョン 上記に加えて、スコアが停滞すると、LLMよGO!のサインが入ります。 結果、スコアが改善される確率が上がります。 注意点はコードを実行するとopenAIのAPI料金がかかります。
!pip -q install --upgrade openai matplotlib
import random, math, re, matplotlib.pyplot as plt
from openai import OpenAI
# ---------- OpenAI クライアント ----------
client = OpenAI(api_key="ここにAPIキーを入れる") # ← APIキーを入力 実際は環境変数に入れたほうが良いが簡易版なので
# ---------- 評価関数(隣接差の合計) ----------
def evaluate(sol):
return sum(abs(sol[i] - sol[i + 1]) for i in range(len(sol) - 1))
# ---------- 初期解 ----------
def random_solution():
s = list(range(1, 11))
random.shuffle(s)
return s
# ---------- ローカル近傍(2点スワップ) ----------
def local_neighbor(sol):
nb = sol.copy()
i, j = random.sample(range(len(sol)), 2)
nb[i], nb[j] = nb[j], nb[i]
return nb
# ---------- LLM から改善案を取得 ----------
def llm_propose(sol, score):
prompt = f"""
目的:1〜10 の数字を並び替え、隣接差の合計を最大化してください。
現在の解: {sol}
現在のスコア: {score}
制約: 1〜10 を重複なく使用し、Python list 形式で 1 行だけ回答してください。
"""
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0.7,
)
text = resp.choices[0].message.content
nums = list(map(int, re.findall(r"\d+", text)))
return nums if len(nums) == 10 and len(set(nums)) == 10 else sol
# ---------- 焼きなまし受容判定 ----------
def accept(cur, new, temp):
return new > cur or random.random() < math.exp((new - cur) / temp)
# ---------- パラメータ ----------
MAX_ITER = 30 # 総イテレーション
INITIAL_TEMP = 10.0
COOLING_RATE = 0.9
STAGNATE_LIMIT = 4 # 改善なしが連続何回で LLM 発動か
sol = random_solution()
score = evaluate(sol)
best = score
temp = INITIAL_TEMP
no_improve = 0
history = [score]
print("=== 停滞時 LLM 発動ハイブリッド焼きなまし ===")
for it in range(1, MAX_ITER + 1):
# ---- 改善案生成 ----
if no_improve >= STAGNATE_LIMIT:
print(f"\n🧠 Iter {it}: 改善停滞 ({no_improve}) → LLM 発動")
cand = llm_propose(sol, score)
no_improve = 0
else:
cand = local_neighbor(sol)
cand_score = evaluate(cand)
if accept(score, cand_score, temp):
sol, score = cand, cand_score
accepted = "✅ 受容"
no_improve = 0 if score > best else no_improve + 1
best = max(best, score)
else:
accepted = "❌ 却下"
no_improve += 1
print(f"{accepted} | Iter {it:2d} | Score {score:2d} | Temp {temp:.3f}")
history.append(score)
temp *= COOLING_RATE # 冷却
# ---------- 結果 ----------
print("\n=== 最終結果 ===")
print("最終解 :", sol)
print("最終スコア:", score)
# ---------- スコア推移グラフ ----------
plt.figure(figsize=(8, 4))
plt.plot(history, marker='o')
plt.title("Score Transition (Stagnation-Triggered LLM Hybrid SA)")
plt.xlabel("Iteration")
plt.ylabel("Score")
plt.grid(True)
plt.show()
いろいろ試してみてください。
sakanaAIさんのブログ記事
https://sakana.ai/ale-bench-jp/
同じく論文
https://arxiv.org/abs/2506.09050
****************
最近のデジタルアート作品を掲載!
X 旧ツイッターもやってます。
https://x.com/ison1232
インスタグラムはこちら
https://www.instagram.com/nanahati555/
****************
