【Go言語をLLMで読むVSCode拡張を作りました】K8sのソースコードをLLMで爆速で読もう!ハンズオン
tldr;
1: LLMにGo言語のコードを読ませるVS Code 拡張機能 Repilot を作りました
2: CNCFのGo言語プロジェクト(Kubernetes, argo-cdなど)で、関数を見つけ出すことで挫折をする事は無くなった。ので、今回k8sのコード(kubectl)を読むハンズオンを書いた。
3: LLMに重要な関数候補を出してもらい、関数の中身をLLMに渡す、という流れを再帰的に続ける仕組み
⏩ とりあえず10分ハンズオンだけ見たい方はこちら
導入
エンジニアになったからには、絶対挑戦したい事はありますか?
- 自作OS
- 自作DB
- 大規模OSS貢献
- ITビジネス立ち上げ
- AIエージェント開発 ...
様々なことがあると思います。
その多くの挑戦で必要になってくる力が「コード読解力」です。
ただ有名なOSSのようにコードが大規模になればなるほど、コードを読むのはしんどくなります...
- 単純にコードが多すぎてつまらない
- どの関数が重要か分からない
- 深くまで探索した関数が間違っていたが、元の関数に戻るのがしんどい
そんな悩みを自分も抱えていて、せっかくたくさんあるOSSを一部しか読めないことを残念に思っていたので、「自然言語で大規模コードを理解できる」プログラミングの読解を簡単にするVSCode拡張を作ってみました(一旦Go言語限定)。
関連記事↓
この記事は、私が作った「LLMを使ったプログラミングの読解に特化したVSCode拡張」を使って、k8sのコードを読んでみようというハンズオン形式の記事になります。
「大規模コードを読むのは、自分には無理...」
そう思ったあなたでも大丈夫です。
このVSCode拡張を使えば、LLMがコードを読んでくれます。なのであなたがコードを読む必要はありません。あなたがすべきなのは、LLMが読む経路が間違った方向に行かないように制御するだけです。
興味があったら、一読ください。
⏩ とりあえず10分ハンズオンだけ見たい方はこちら
対象読者
- 大規模OSSのへの貢献に興味があるが、憧れのままだった人
- CNCFの新旧プロジェクトであるk8sなどのOSS貢献したいが、難しくて挫折した人
- AIエージェントの実装に興味がある人
なぜ作ったか?
ちょうど半年くらい前の2024年9~10月に、個人的に Kubernetes 周りの技術に凝っていた時期があって、Kuberenetes のオープンソースの Go言語のコードを読んでいた頃がありました。
ただ読めば読むほど、kubectlやetcdとの接続に留まらない、Kubenetesの奥深さに絶望するだけでした。具体的には、kube-scheduler, kubelet, kube-proxy, kube-aggregator から Kubeneretesの周辺機能である様々な CNCF のプロジェクト...と、自分一人の個人の力ではとても全て追うのは不可能だと思っていました。
時は経って、2025年。
LLMについて研究をしていたときに、vulnhuntr というLLMを使ったセキュリティスキャンツールを見つけました。
vulnhuntr のコアの実装は
- LLMに関数を見てもらい、その関数の中からセキュリティ的に不審な箇所候補をいくつか挙げてもらう
- LSPで関数ジャンプして関数の中身を取得
- 1〜2を繰り返す
のようになっているのですが、これを、大規模コードリーディングにも使えるのではないかと考えたのが今回のようなツールを作ったきっかけです。
つまり、vulnhuntr を少し改善して、
- LLMに読んでもらうエントリポイントの関数とコードリーディングの目的を入力
- 1の情報を元に、LLMにエントリーポイントの関数から関数の全体を取得し、入力された目的とあう関数の候補を取得
- ユーザーにジャンプした関数を選んでもらい、LSPで候補関数にジャンプし再度関数の中身を取得
- 2〜3を繰り返す
のように実装できると思ったのです。そうすれば「自然言語で大規模コードを理解できる」が実現できると思いました。
そこで、CLIツールを開発したり(もう追加開発はしない予定です)、
これの VSCode拡張版を作ったりしました。
実際に このツールを使って、今までは Kubenetes の読解が難しくしんどかった、scheduler や kubelet の機能の大枠の重要な関数をざっくり理解できるようになり、argo-cd や prometheus でもコードの理解の役に立つ情報をコスパよく見れていると思います。
まぁ、自己語りはここまでにして、どのようにしてこのVSCode拡張 Repilot を使って k8s を読んでいくかを説明していきます。
k8sを読んでみよう!Repilotを使った「自然言語で大規模コードを理解できる」コードリーディングハンズオン
では早速、k8sをLLMを使って読んでみましょう!(※:kubeletのコードリーディングですが、Youtube動画もあります、音声注意)
インストールさえできればそこからは10分くらいでできるので、よかったらお付き合い下さい。
[急いでいる人向け]コードリーディングの結果をLLMに要約させたレポート
まずは準備からです。
0:まずは以下を用意する必要があるので、用意していただきます。
-
vs code の更新
1.99.3 以上にして下さい
-
k8sのコードベース
git clone https://github.com/kubernetes/kubernetes.git
- ClaudeのAPI Key
申し訳ないですが、現時点では OpenAI, Gemini などには対応していません。
自分で Claude のAPI Keyを取得してみてください(ちなみにAPIが不安定なので、3.5 sonnetを使っています)。
- gopls
brew install gopls # macユーザーの場合
go install golang.org/x/tools/gopls@latest # windowsユーザーの場合はこれっぽいです
which gopls # Macユーザーの場合は /opt/homebrew/bin/gopls
- repilot
VSCode拡張検索で、repilotと調べれば出てきます。
使う時はインストールをした後で、「Command + Shift + p」でコマンドパレットを開き、そこで「repilot」を検索し、「Open repilot at new tab」をクリックします。
1:k8sのエントリーポイントを探す
いきなりですが、これが一番難しいですよね。
一応アーキテクチャは、以下のようになっているそうです。
左の方がコントロールプレーンという「状態保存(etcd)やNodeなどへの操作を指示するAPI(api-server)やNodeなどの割り当ての優先順位付け(kube-scheduler)などの操作を担当」、右の方が「実際のコンテナを実行(kubeletがcriを実行)を担当」する構成になっています。
ここら辺のエントリーポイントは、以下にまとめたのでよかったらみてみて下さい。
エントリーポイントまとめ(主要なもののみ)
ここでは、一番フロント寄りの kubectl を今回のrepilotで見てみましょう!
kubectl とは、kube-apiserver に HTTP リクエストを送る CLI クライアントで、普段開発者が目にすることが多い機能です。つまり入口です。
上の展開部分の中にも書きましたが、kubectl のエントリーポイントは staging/src/k8s.io/kubectl/pkg/cmd/cmd.go の NewDefaultKubectlCommand にあります。
これを見つけ出すのは比較的簡単で、kubernetes レポジトリの cmd フォルダがCLIで使うコマンドを登録している(kubeletやkubectlなど)ので、cmd/kubectl/kubectl.go から1つ目の関数を辿っただけです。
次からは、ようやく repilot を使用していきます。
2:repilot を初期化する
今回のVSCode拡張機能のrepilot を開きます。
開く時は、「Command + Shift + p」でコマンドパレットを開き、そこで「repilot」を検索し、「Open repilot at new tab」をクリックします。
初期画面を開いても、APIの設定がされていないので、まずはそこら辺の設定をします。
上の青の「Here」ボタンを押しますと、
このような設定画面が出てくるので、ここに情報を入力します。
- Claude API KEY は APIキーの情報
- Gopls Path は
which gopls
の結果 - Path to Save Report はコードリーディングのサマリを保存したい場所
- Language は
日本語
をそれぞれ入力し、また Back to ChatView
をクリックします
これで、Repilotを動かせるようになります!
(ちなみにここら辺の設定は、VSCodeのsecretとglobalStateに保存しているので、次回以降は入力不要です)
3:Repilotを開始する
ここまで来れば、ようやく Repilotを動かせます!
まず「Please input rootPath you want to search.」と出てきているので、ここは前に出てきた
/path_to_k8s/kubernetes/staging/src/k8s.io/kubectl/pkg/cmd/cmd.go
※:/path_to_k8s/ は kubernetes までのパスを入力
を入力します。
次に「Please input rootFunctionName you want to search.」と出てくるので、ここは検索するエントリーポイントの関数名を入力します(もし関数名だけを入力して上手く行かない場合は、関数名を含んだ1文を入力して下さい)。
NewDefaultKubectlCommand
もしくは
*func NewDefaultKubectlCommand() cobra.Command {
次に「Please input purpose of your search.」と出てくるので、ここではコードリーディングの目的を入力します。
kubectlがAPI-serverを叩くに行っている場所を知りたい
ここまで入力して青のボタンを押したら、青のボタンが「Start Task」になるので、ここでもう一度「Start Task」をクリックします。
すると以下のように「Create API Request...」と表示されます。
これで無事最初のタスクは開始されました!
4:Repilotを制御する
少しするとAPIリクエストの結果が返ってきます。
ここでは最初のエントリーポイントの関数から重要そうな部分を5箇所までLLMにかえさせています。Kuberenetesくらい有名なら、LLMがアーキテクチャを理解しているので、意外と良い結果が返ってくることの方が多いです。
Claudeの調子による部分はありますが、自分の場合は以下のような結果が返ってきました。
0 : NewDefaultKubectlCommandWithArgs
Details : kubectlのメインコマンドを生成する関数で、API-serverとの通信に必要な設定フラグやオプションを初期化します。ConfigFlagsを通じてAPI-serverへの接続情報が設定されます。
Whole CodeLine : return NewDefaultKubectlCommandWithArgs(KubectlOptions{
Original Code : return NewDefaultKubectlCommandWithArgs(KubectlOptions{
Confidence: 80
-----------------
1 : defaultConfigFlags
Details : API-serverとの通信に必要な設定(認証情報、エンドポイント、コンテキストなど)を初期化する関数です。この設定を基にAPI-serverとの通信が確立されます。
Whole CodeLine : ConfigFlags: defaultConfigFlags().WithWarningPrinter(ioStreams),
Original Code : ConfigFlags: defaultConfigFlags().WithWarningPrinter(ioStreams),
Confidence: 75
-----------------
2 : NewDefaultPluginHandler
Details : kubectlプラグインのハンドラーを初期化する関数で、プラグインを通じてAPI-serverとの追加的な通信機能を提供する可能性があります。
Whole CodeLine : PluginHandler: NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes),
Original Code : PluginHandler: NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes),
Confidence: 40
-----------------
この中から、探索したい関数を0から最大4を入力し、さらにその関数について調べてもらえます。
ただ API の調子が悪いと思ったら、5を入力すれば再度同じ関数を検索できます。
これを、自分が満足するまで続けるのがこのツールの使い方です。
※:ちなみに6を入力すればここまでの検索経路表示・7を入力すればここまでの検索サマリ出力(LLM使用)・8を入力すればLLMが見ている関数を見れます(ファイルが開いてそこで選択されるので、選択する部分を見つけにいく手目が必要ですが...)
上の例で、こちらで続けるならまずは 0 でしょう。
すると、再度 gopls の関数検索状態 → LLMの検索状態へと遷移し、関数の中身から重要そうな関数を抽出してくれます。
0 : NewKubectlCommand
Details : kubectlコマンドの基本的な構造を初期化する関数です。この中でAPI-serverとの通信に必要なクライアント設定やコマンドの構造が設定されている可能性が高く、API-serverとの通信の起点となる重要な関数です。
Whole CodeLine : cmd := NewKubectlCommand(o)
Original Code : cmd := NewKubectlCommand(o)
Confidence: 85
-----------------
1 : Find
Details : 指定されたコマンドパスに基づいて適切なサブコマンドを検索する関数です。これはAPI-serverへのリクエストを実行する具体的なコマンドハンドラーを特定するための重要なステップとなります。
Whole CodeLine : if foundCmd, foundArgs, err := cmd.Find(cmdPathPieces); err != nil {
Original Code : foundCmd, foundArgs, err := cmd.Find(cmdPathPieces)
Confidence: 70
-----------------
2 : HandlePluginCommand
Details : プラグインコマンドを処理する関数で、カスタムのAPI-server通信ロジックを含むプラグインを実行する可能性があります。標準のコマンドが見つからない場合のフォールバックとして機能します。
Whole CodeLine : if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, 1); err != nil {
Original Code : if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, 1)
Confidence: 60
-----------------
そんなこんなで、自分で進めた感じだと、以下の経路で進めました。
- NewDefaultKubectlCommand(エントリーポイント)
- NewDefaultKubectlCommandWithArgs
- NewKubectlCommand
- NewFactory
この NewFactory が
0 : NewFactory
Details : API-serverとの通信を含むKubernetesクライアント操作の主要な機能を提供するファクトリーを作成します。このファクトリーは、認証情報の管理やAPIリクエストの構築など、API-serverとの対話に必要な全ての機能を初期化します。
Whole CodeLine : f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
Original Code : f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
Confidence: 95
と核になっていそうですね。興味があったら、さらに深堀してみてはどうでしょうか?(自分的には、その先の Factory > RestClient らへんが真相に近いのかなとは思いました)
ここまでに使った時間は、自分は10分程度だったのですが、いちいち長いコードを読むよりは早く目的の関数に辿り着けたのではないでしょうか?
5:過去の経路に戻る
ただ探索をしてどうしてもミスったということは可能性としてあります。
そのような時は、6を入力します。すると、以下のような結果が返ってきます。
rootPath: /Users/coffeecup/Documents/open_source/kubernetes/kubernetes/staging/src/k8s.io/kubectl/pkg/cmd/cmd.go
|NewDefaultKubectlCommand
|0e03522
|NewDefaultKubectlCommandWithArgs
|3fc467b
|NewKubectlCommand
|77951c2
|NewFactory
|638e22f
|ConfigFlags
|5e180fd
|NewMatchVersionFlags
|e378127
|addCmdHeaderHooks
|7d66c92
|Find
|7be32c2
|HandlePluginCommand
|f2f782f
|defaultConfigFlags
|f8ed89c
|NewDefaultPluginHandler
|b41d4fd
この関数群の中から再度戻って調べたい関数の下にある「hash値」を入力すると、そこから再度探索を進めてくれます。
6:おまけ サマリーを取得する
過去の経路に戻るだけではなく、サマリーも取得できます。
取得には、7を入力して、だいたい以下のような結果が返ってきました。
ここまでの結果で出力したサマリレポート
そんなわけで、ここでは簡単に kubectl の中身について簡単に見てみました!
ただ今回のツールが完璧なものとは自分も思っていません。それに今回のハンズオンだけでkubectlの全ての詳細を理解できるとも思っていません(k8s上級者からすればkubectlくらいの内容なら簡単すぎでしょうきっと...)。
あくまでもこのツールは、特定の目的に沿った関数の経路を教えてくれるからで、関数の中身までは教えてくれないからです。
なので、関数の経路が分かったら、関数を自分で調べる必要はあると思っています(もしくは関数の中身のマーメイド図を出力する機能もつけようとは思っています)。
ただ、kuberetes くらい大規模なコードを読んでいると迷子になって困ることはしょっちゅうだと思います。それをある程度防げる点では使う意味はあると思います。
使う時の注意点
- Cline みたいに Auto Approve した方がいいのでは?
コードリーディングは頭に印象を残すことだと思っているのとLLMの選択を自分は完全に信用していない(だから再実施の5がある)ので、あえて選択式にしています。ただ、Auto Approveで最終的にレポートだけ出すのも面白そうですよね。 - 入力したのと同じ関数を候補として提示されることがあるが、バグっているのではないか?
そのような事例は承知しています。ただ 構造体のレシーバー変数の関数一覧を取得したい場合などに、再度同じ関数を検索して便利な時もあるのであえて残しています - なぜか止まってしまう・・・
CLIツール・ウェブアプリも合わせて、ゴールデンウィーク中に急いで作ったので、バグはあるはずです。その場合は以下のレポジトリにissueを切るか、zennで聞いてくださると嬉しいです。ついでに VSCodeで検証も使える(help>toggle developer toolをクリック)のでそれのログを残してくれると尚嬉しいです。
- 随時追加
今後追加したい機能
- 関数のマーメイド図(Mermaid.js)出力機能
上にも書きましたが、「9を入力したらLLMが見ている関数のマーメイド図を出力」する機能を作りたいですね。 - OpenAIやGeminiなど他LLMへの対応
会社の企画大会みたいなので今のVSCode拡張Repilotを作っているのですが、そこで必要になりそうな予感がします。 - C, Java, TypeScript 対応
これも会社関係で必要そうになりそう - 数字を入力するのではなく、ボタンをクリックするUIにする
難しそうですが、やってみたいですね。流石に0とか6とか入力するのはスマートではなさすぎる。
Repilot の限界
ChatGPT に聞いたら手厳しい意見もありました。
-
自然言語の曖昧さ
「APIを叩く処理」など抽象的な目的を与えると、LLMが意図と違う経路を選ぶこともあります。 -
関数内部の深い理解はユーザー任せ
関数候補をLLMが提示してくれますが、その詳細な動作やデータフローはまだ人間の理解に頼っています。 -
LLM応答の安定性
Claude APIの応答時間やエラーによって、操作性に波があることも実感しています。
→ Clineを参考に2回まで失敗後にリトライするようにしています。
おわりに
この記事では、LLMを活用したVSCode拡張「Repilot」を使って、Kubernetesのような大規模OSSのコード読解をどう効率化できるかを紹介しました。
OSS貢献へのハードルを下げたい方、AIエージェントによるコード解析に興味がある方には、ぜひ一度試してみてほしいです。
「コードを読むのが遅いから貢献できない」
↓
「AIと一緒なら、コードリーディングも怖くない」
このような体験を、より多くの人に広げられたらと思っています。
また時間があったら、Go言語以外の別の言語のAgentを作ってみると良い経験になりますよ!
ここまで読んでくださり、ありがとうございます!
🚀 Repilot を試してみる
- 👉 VS Code 拡張機能をインストールする
- 📦 GitHub でコードを見る
- 🐦 感想・バグ報告は @coffeecupjp まで!
Discussion