なぜ「退屈な言語」がAIエージェントに選ばれるのか

2026年5月、Jacob Young(Sancho Studio創業者)が発表した “Use Boring Languages with LLMs” がHacker Newsで話題を集めている。その主張はシンプルだ。「LLMは訓練コーパスの分散が低い言語で圧倒的に良いコードを生成する。逆に分散が大きいエコシステムは、エージェントの出力品質を著しく低下させる。」

この論文はHNで203ポイント・293コメントの議論を巻き起こし、Goコミュニティを中心に「AIエージェント時代の最適言語」を巡る活発な論争を引き起こした。本稿では、この論文の核心的な主張をコード例を交えて解説し、日本におけるAIエージェント言語選定の一助とする。

低分散エコシステムとは何か

Youngの主張を一言で言えばこうだ。

LLMは一貫性のある技術スタックを増幅し、断片化した技術スタックを静かに劣化させる。

「低分散エコシステム」とは以下の特徴を持つ言語・ツールチェーンのことを指す。

  1. 訓練コーパスの分散が小さい — 言語の書き方が一貫しており、LLMの学習データにおける表現のばらつきが少ない
  2. 「唯一の正しい書き方」が存在する — Convention over Configurationの原則が浸透している
  3. ツールチェーンが強固 — フォーマッター、リンター、静的解析が標準装備
  4. 依存関係の選択肢が限定的 — フレームワークやライブラリの「迷い」が少ない
  5. 後方互換性が長期にわたって維持される — 言語自体が頻繁に破壊的変更を行わない

この条件を最もよく満たす言語として、YoungはGoを第一候補に挙げる。次いでRailsに代表されるRuby、そしてある程度はRustも該当する。逆に最もスコアが低いのはJavaScript/TypeScriptエコシステムとPythonだ。

GoがAIエージェントに最適な5つの理由

1. シンプルな並行処理モデル

GoのgoroutineはチャネルベースのCSP(Communicating Sequential Processes)モデルを採用している。これは訓練コーパスにおいて極めて一貫性のある表現を持つ。

results := make(chan string, len(urls))
for _, u := range urls {
    go func(u string) {
        resp, err := http.Get(u)
        if err != nil {
            results <- err.Error()
            return
        }
        defer resp.Body.Close()
        results <- resp.Status
    }(u)
}
for range urls {
    fmt.Println(<-results)
}

このコードは「これがGoでの標準的な並行処理の書き方」として確立されており、LLMが何度も見てきたパターンだ。対照的にJavaScriptのasync/awaitやPromise.all、Pythonのasyncioやconcurrent.futuresは複数の書き方が混在しており、LLMがどのパターンを選ぶべきかを推論するコストが増加する。

2. 包括的な標準ライブラリ

Goの標準ライブラリはHTTPサーバー、暗号化、JSON/XML処理、テンプレートエンジン、SQLデータベース等、商用アプリケーションに必要な大部分をカバーする。これによりサードパーティへの依存判断が最小限で済む。

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "ok")
    })
    http.ListenAndServe(":8080", nil)
}

このHTTPサーバーのコードはGoの訓練コーパスに無数に存在する。エージェントは「どのフレームワークを使うか」を判断する必要がなく、標準ライブラリの範囲内でコードを生成する。

3. 強制力のあるツールチェーン

gofmtgo vetgolangci-lint はコードのスタイルを一貫させるだけでなく、LLMが生成したコードの品質を機械的に検証する。Go 1.26ではASTレベルの自動リファクタリングを行う go fix が大幅に強化され、エージェントによるリファクタリングの信頼性が向上している。

$ go vet ./...
./user.go:22:2: result of fmt.Errorf call not used
./user.go:38:9: declaration of "err" shadows declaration at line 34

$ golangci-lint run
user.go:51:6: exported func LoadUser should have comment (revive)
user.go:63:3: if block ends with return, drop this else (golint)

重要なのは、これらのツールがプロンプトを必要とせずに自動実行でき、かつ結果が常に明確であることだ。JavaScriptのESLint設定ファイル(.eslintrcの形式、ルールの選び方、プラグイン構成)と比較すると、その差は歴然としている。

4. GCによるメモリ安全性と抽象化の天井

Goはガベージコレクションによりメモリ管理の煩わしさから開発者を解放する。これはエージェントにとっても同様の恩恵をもたらす。

Rustは所有権・ライフタイム・借用の概念が強力である一方で、エージェントがこれらの概念を正しく扱うには多くの推論トークンを消費する。HNの議論でも「ライフタイムはグローバルな性質を持ち、LLMはグローバルな推論が苦手」という指摘がなされている。実際のデータでも、RustはAutoCodeBenchで中位に留まっている。

Goの「抽象化の天井(ceiling on abstraction)」は、LLMにとっては欠点ではなく利点だ。Goにジェネリクスが追加されるまで10年以上かかったことは人間の開発者にとっては不満だったかもしれないが、LLMにとっては表現力の抑制が予測可能性に直結する。

5. 有限で既知の落とし穴

どの言語にもfootgun(自爆装置)は存在するが、Goのそれは有限かつ検出可能だ。代表的なnilポインタは静的解析で捉えられる。

data, err := os.ReadFile(path)
if err != nil {
    return fmt.Errorf("read config %q: %w", path, err)
}

対照的に、Pythonでは動的型による実行時エラーや、パッケージマネージャの乱立(pip vs poetry vs uv)、非同期処理の選択肢の多様性(asyncio vs trio vs anyio)など、検出が困難な問題が多数存在する。

Rails(Ruby)もまた「退屈な」言語

YoungはGoだけでなくRuby on Railsも低分散エコシステムの好例として挙げている。Railsには本質的に「唯一のRails」しか存在せず、規約(convention)がコードの構造を強制する。

実際、2026年5月に公開されたIvan Turkovicの分析(「Rails + RubyLLM vs LangChain」)では、RailsとRubyLLMの組み合わせがLangChainベースのPython実装を上回る生産性を示したと報告されている。RailsのCoC(Convention over Configuration)は20年前に人間の開発者の生産性を向上させたが、今度はLLMの出力品質を向上させているという点で注目に値する。

# Railsの典型的なコントローラ
class PostsController < ApplicationController
  def index
    @posts = Post.published.recent
  end

  def show
    @post = Post.find(params[:id])
  end
end

このコードが「唯一の正しい書き方」であることが、LLMによる生成を極めて信頼性の高いものにしている。

HNコミュニティの反応:代替案と反論

当然ながら、「Goが最適」という主張には多くの反論が寄せられている。

Rust支持派の主張

  • Rustの所有権システムは、コンパイルエラーという形で即座にフィードバックを返す。Goでは実行時にしか発覚しない問題も、Rustではコンパイル時に捕捉できる
  • cargo test が単体テストを同じファイルに記述する規約により、エージェントが自動的にテストを更新する
  • Rustの「コンパイルするまで動かない」特性は、安全なコードを保証するための投資として価値がある

Java支持派の主張

  • Javaの訓練コーパスはGoよりも桁違いに大きい
  • スタティックな型システムはGoと同等以上に堅牢
  • LLM推論の観点では、より多くのトレーニングデータを参照できることが有利に働く

これらに対するYoungの反論は「Goの抽象化の天井がLLMにとっては予測可能性を担保する」という一点に集約される。Rustのライフタイム推論やMaven/Gradleの設定迷路は、エージェントが消費するトークンを増加させるだけで本質的な価値を生まない、というのがその立場だ。

実践的推奨:どの言語を選ぶべきか

AIエージェントを活用した開発において、言語選定の基準は従来とは異なる視点が必要だ。

ユースケース 推奨言語 理由
APIサーバー・マイクロサービス Go 標準ライブラリが充実、デプロイが単純、エージェントが一貫したコードを生成
AI SaaSのプロトタイプ Ruby on Rails CoCがエージェントの出力を構造化
パフォーマンス重視のシステムツール Rust コンパイル時検証によりエージェントの出力を検証できる。ただしトークン消費は多い
CLIツール・エージェントオーケストレーター Go 静的バイナリ、高速起動、シンプルな依存管理
データサイエンス・機械学習パイプライン Python(やむを得ない) エコシステムの支配力。ただしLSPと型ヒントでエージェントの精度を補完する必要がある

Youngの最終的なアドバイスはこうだ。「Goとエージェントを使って、次のCLI、バックエンドサーバー、エージェントオーケストレーターを構築することを検討しよう。この言語とツールチェーンは、働くエンジニアが欲しいと思う非ビジュアルソフトウェアの大部分を書くことができる。」

まとめ

Jacob Youngの「Use boring languages with LLMs」は、AIエージェント時代の言語選定に新たな視点を提供する。鍵となる概念は訓練コーパスの分散の低さであり、Go、Rails、そしてある程度のRustがこの条件を満たす。逆にJavaScript/TypeScriptやPythonはエコシステムの断片化がエージェントの出力品質を低下させる。

このフレームワークは、AIエージェントがコードを書く時代における「なぜGoなのか」という問いに、従来のパフォーマンスや生産性とは異なる次元からの回答を与えている。あなたの次のプロジェクトでAIエージェントを最大限に活用したいなら、一度「退屈な言語」を検討してみてほしい。


この記事はAIによって生成され、人間の編集を経て公開されています。 Appwright AI は AI によるコンテンツ制作の可能性を探求する実験的プロジェクトです。