- 大規模コードベースでLLMを効果的に活用するには、「ガイド(guide)」と「監督(oversight)」への投資が中核である
- ガイドは文脈と環境を提供してLLMがより良い選択をできるよう支援し、監督は結果を検証して方向性を示す役割を果たす
- プロンプトライブラリを構築し、コードベースの規則、文書、ベストプラクティスをLLMが理解できるようにすることが重要
- 技術的負債の管理とコード構造の単純さ、モジュール化、一貫性は、LLMのコード理解力と生産性向上に直結する
- 自動化された監督と検証の仕組みによって、LLMが安全で一貫したコードを生成できるよう支援することが、長期的な拡張性の鍵である
LLM拡張のための中核概念
- LLMを大規模コードベースに適用する方法はまだ確立されていないが、ガイドと監督への投資が最も効果的なアプローチとして示されている
- ガイド(Guidance) は、LLMが正しい選択を行うのを助ける文脈と環境を意味し、監督(Oversight) は生成された結果を検証し、方向を調整する役割を担う
ガイドへの投資
- LLMが一度の試行で高品質なコードを生成する**「ワンショット(one-shotting)」**を達成するには、明確なガイドが必要
- 逆に、結果が不適切で手動修正が必要な場合は**リワーク(rework)**となり、非効率である
- LLMはコード内のあらゆる選択(変数名、関数構造、技術スタックなど)を生成するため、プロンプトにはビジネス要件だけを含め、それ以外は推論可能またはエンコード済みの状態が理想的
プロンプトライブラリの構築
- プロンプトライブラリは、コードベースの文書、ベストプラクティス、構造マップなどを含むLLM向けの文脈集合である
- LLMの出力が外れるたびに、「何を明確にすべきだったか」を見直し、それをライブラリに追加する
- 網羅性と簡潔さのバランスが重要
- 例では、
@prompts/How_To_Write_Views.md、@prompts/The_API_File.md などの文書をLLMに提供して機能開発を導いている
- プロンプトは十分に具体的であるべきだが、生成されたコードのすべての行をレビューする必要がある
環境とコード品質
- **技術的負債(technical debt)**が多いコードベースは、LLM活用の効率を低下させる
- Metaの事例では、技術的負債のために自動化目標の達成が難しかったと述べられている
- クリーンなコード、モジュール化、明確な命名、単純な構造が、LLMの理解度と正確性を高める
- Djangoの例では、各アプリのエントリーポイントを
_api.py ファイルに置くことで、LLMが必要な機能を素早く見つけられるよう構造化している
- 例:
visit_api.handoff_to_doctor(user) の形で外部アクセスを単一化
_api パターンをプロンプトライブラリに明記し、LLMが正しい場所を参照するよう誘導する
監督への投資
- LLMの自動化は、エンジニアを置き換えるのではなく、チームを強化する方向で捉えるべき
- 監督は、チーム、アラインメント(alignment)、ワークフローへの投資へとつながる
- チームの観点では、設計能力の向上が重要であり、それがアーキテクチャ品質につながる
- 設計能力を高める方法としては、本・ブログ・コードを読むこと、優れた作品の再現、直接実装の練習などが挙げられている
- 例: TLDraw、SerenityOS Jakt などのコード分析を通じて設計感覚を広げる
自動化された監督
- 一部の設計検証はプログラムによって自動化できる
- 例: 型エラーやルール違反を環境内で即座にフィードバックする
- **「安全性(safety)」**とは、抽象化を保護することを意味する
- Pierceの定義によれば、安全な言語は、プログラマーが意図せず抽象化を壊してしまわないよう保証する
- 例: Djangoアプリ間で内部ファイルへ直接アクセスすることを禁じるルールを、ASTベースの検査スクリプトで自動化する
from visit import logic.internal_file 形式の不正アクセスを検出
検証(Verification)
- 設計と実装に加えて、**検証段階(コードレビュー、QA)**も品質確保に不可欠
- 作業量が増えるほどレビュー速度がボトルネックになるため、次のような改善策が示されている
- 開発環境がなくてもQAを実施できるよう、参入障壁を下げる
- テストデータ生成など、テスト作成が容易な環境を構築する
- 繰り返されるPRフィードバックを文書化し、LLMが一部レビューを自動実行できるよう支援する
- セキュリティルールをフレームワークのデフォルトとして組み込む
結論および追加の観察
- LLMは新規(greenfield)プロジェクトで特にうまく機能する
- プロジェクトが大きくなるほど、一貫性とモジュール化が生産性を左右する
- 検証済みコンポーネントを再利用するモジュール型構造が、効率的な開発の中核である
1件のコメント
Hacker Newsの意見
モデルがどんどん改善され、複雑なコードベースや長いファイルも扱えるようになってきた
そこで私は、繰り返し使うシンプルなフレームワークループを作った
このループを20〜30分回すと、かなり使える結果が出る。結局のところ重要なのは、コンテキスト管理とテストのフィードバックループを作ることだ
「explore」というキーワードで探索を始めると、別途計画を書いたりコンテキストを初期化したりしなくてもResearchが可能だ
ただしコード言語をCやPythonだと想定しがちで、状態をオブジェクトにカプセル化せず関数5つに分けるような非構造的なコードを生成しがちだ
またclaudeはしばしばCLAUDE.mdを無視するので、先にそのファイルを読ませてから「explore」させると安定する
最新モデルは不要なコンテキストをうまく捨てるが、古いモデルでは依然として計画文書ベースのアプローチの方が良い場合がある
計画やガイドラインを真逆に実行したり、同じ文を読み直しても反対の結論を出したりすることが多かった
しばらくはLLM中心のプロセスを作れると信じていたが、今は確信が薄れている
モデルが「良い状態」のときは問題ないが、その状態にすること自体がいまだに運任せだ
/research_codebase、/create_plan、/implement_planのようなカスタムコマンドをClaude Codeに追加した丁寧にレビューして修正すれば非常によく動くが、チーム全体には広がらなかった
完全に新しい機能を作るときだけコンテキストを初期化する。Codespacesでは問題ないが、Tasks機能はほとんど役に立たない
大きな作業を任せるとおかしな方向へ行ってしまうこともあるので、常に監視する必要がある
コンテキストの再プライミングにも有用で、よく活用している
プロンプトライブラリを有用にするには反復的な改善が必要だ
LLMが少し外すたびに、「何をもっと明確にすべきだったか?」と自分に問い、その答えをプロンプトに追加する
ただEnterを押したり自動承認したりするだけではトークンを無駄にする。代わりにLLMがどこで詰まるのか観察し、CLAUDE.mdに短く記録する
コンテキストファイルが大きくなったら、作業タイプごとに分ける
私の主なユースケースは、コードベース探索、実行経路の追跡、必要なファイルの要約提供だ。質問タイプごとに結果の伝え方を明示しておくと、はるかに効率的になる
私はこれを「Student Pattern (Fresh Eyes)」と呼んでいる。サブエージェントが初心者の視点で文書やコードを読み、混乱点・矛盾・欠落情報を見つける方式だ
開発者が見落としがちな暗黙知を拾い上げるのに非常に優れている。新しい文書レビューやプロンプト評価の前段階として有用だ
CLAUDE.mdを読めと何度も指示しても無視することが多く、セッション開始直後でもランダムに抜ける
文書と命令をすべて用意しても、なお「忘れる」ことが多い
大きなコードベースをエージェントフレンドリーに構造化する実験をしている
プロジェクトをnix flakesベースの有向グラフに分解し、各ノードが独立した開発環境を持つようにした
Claude Codeをflake devshellで実行すると、その範囲だけを認識してコンテキスト過負荷を防げる
flakes間の入出力で協調させ、互いに機能要求やテストをやり取りさせる
このコンテキスト分割がトークン爆増問題を減らす鍵だと考えている
既存ワークフローを改善するだけでなく、LLMが容易にスケールできる構造を新たに設計すべきだ
「テスト容易性・拡張性・安全性」といった属性とコード構造の関係を探っている
私もDockerベースのプロジェクトで似た実験をしたことがあるが、これを自動化してくれるツールがあるとよい
LLMは私があまり知らないテーマは見事に説明するが、専門分野では自信満々に間違える
私は別の見方をしている。LLMの性能を高める最良の方法は、コードベース自体に意味を埋め込むことだ
つまり、DDD(Domain-Driven Design)のように構造化されたコードはLLMにも理解しやすい
複雑なコードをツールで無理やり扱おうとするのは金の無駄だ
結局LLMが証明したのは、「言語と意味」を重視するDDDの哲学が正しかったということだ
関連記事: DDD & the Simplicity Gospel
「LLMはなぜグリーンフィールドプロジェクトでうまく動くのか?」という問いに対して、私は逆の経験をしている
コードベース内でパターンが2〜3回繰り返されると、LLMはそれを学習して一貫して複製する
しかし「一貫性」がそのまま「品質」を意味するわけではない。基準なしに一貫性だけを追えば、保守不能なコードになる
「エンジニアが理解できないコードはLLMも理解できない」というのは正しいが、その逆は成り立たない
人間には理解できてもエージェントには理解できないケースが多い
コードベースを人間よりエージェントに理解しやすくする方が難しい
「フィードバックをコンピュータに移せば一発成功率が上がる」という主張もあるが、これはP=NPを主張するのに近い
検証が容易だからといって、解を見つけるのが容易になるわけではない
ATSやIdrisのような言語では、正しさの証明をコードと一緒に書ける
もしその主張が正しいなら、こうした言語でLLMが最高の性能を示すはずだ
しかし現実はそうではない。結局、今はモデルの改善を待つ方がましだという考えだ
こうした問題のため、私は意見の強いフレームワークがAIコーディングの生産性を高めると見ている
フレームワークのルールをLLMがすでに知っているので、別途ガイドラインが不要だからだ
一方でGo、Rust、Elixir、C#は、はるかに多くの依存関係と指示を必要とした
Rustは結果自体は良かったが、200を超えるパッケージを引っ張ってきて負担が大きかった
「Garbage in, garbage out」の原則は正しいが、LLMには完全には当てはまらない
インターネット全体のノイズだらけのデータで学習していても、かなりうまく動く
ハルシネーション(hallucination) は、単なるノイズよりも不正確なコンテキストでより頻繁に起きる
構造がひどいコードベースでも、情報量が多ければ依然として有用なコンテキストを提供する
結局のところ、人々は基本原則を学び直している
ドキュメント化(=プロンプトライブラリ)と整ったコード構造が開発速度を高めるという事実を、あらためて実感しているのだ