9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHub Copilot SDK のランタイムとエージェントループについて

9
Posted at

これは、『Let's Learn GitHub Copilot SDK (English)』(2026/09/25) の配信アーカイブを見ながら、
GitHub Copilot SDK (自分のアプリに Copilot の機能を組み込める SDK) について学ぶ記事です。

image.png

スピーカーは、
Microsoft Cloud Advocate の Matt さんと
GitHub Copilot SDK のプロダクトマネージャーの Patrick さんです。

以前は CLI SDK と呼ばれていたこのツールの進化や、今後導入される機能、そして SDK の背後にあるランタイムの仕組みについて詳しく解説しています。

内容がとても良かったので、
GitHub の公式ドキュメントと照らし合わせ、たびたび補足も交えながら、
内容を記事にまとめていきます。

注意!

この記事は GitHub Copilot の「使い方」の記事ではありません。
GitHub Copilot の「中身や仕組み」についての記事です

[宣伝] 日本語での配信をします

今日のお昼に GitHub Copilot SDK の初心者向け配信します。ぜひ見てください!

GitHub Copilot SDK 1.0 と 2.0

image.png

GitHub Copilot SDK は今年の 6 月に GA (正式リリース) されました。

そして「まもなくリリース予定」のバージョン 2.0 では、
ランタイムと開発者ツールを含め、
SDK 全体が根本的に再構築されました。

ランタイムが TypeScript から Rust に書き直された

Rust を使用した書き直し (マイグレーション) が行われており、
これにより SDK の柔軟性やパフォーマンス、多様なプラットフォームでの動作能力が大幅に向上しています。

この技術的な刷新については、GitHub の公式ブログ記事『Migrating the GitHub Copilot runtime to Rust, using Copilot』で詳しく解説されています。

(マイクロソフトの超優秀なエンジニアにより、技術的な内容がめちゃくちゃ詳細に膨大な量が書かれていて めっちゃ長い (本当に長い) ので、Matt さんが「ブラウザがクラッシュするかと思った」と冗談を言っていましたw)

内容についての技術的な要約は先日ツイートにまとめたのでぜひご覧ください👀
(↓ ちょっと長いので折り畳まれています)

要するに

「Node.js で動く CLI を SDK 経由で呼び出す構造」
から、
Rust 製のネイティブな共通ランタイムへ移行し、各アプリのプロセス内に組み込んで実行する方式も選べるようになった(オプトイン)
ということです👀

image.png
(↑この図は配信で使われたものではなく、私が記事を読みながら手元で勝手に (AI で) 作成した図です)

観点 TypeScript版の実装 なぜ問題になったか Rust版での対応
SDKとランタイムの接続 SDKがヘッドレスCLIを子プロセスとして起動 ランタイムを使うだけでも、別プロセスの起動・管理が必要 C ABIを公開し、FFI経由でアプリのプロセス内に組み込めるようにした
起動時間 Node.js/V8を起動してJavaScriptを読み込む 解析・バイトコード生成など、最初の処理までに準備が必要 コンパイル済みのネイティブコードで、ランタイム部分のNode.js/V8起動コストを除去
メモリ C#やPythonなどから使う場合も、追加でNode.js/V8を抱える SDKクライアントごとに追加の言語ランタイムが必要になり、サーバーの収容密度を制限 ネイティブランタイムによってメモリ負担を削減
通信 呼び出し・イベント・コールバックがプロセス境界を越える パイプやソケット経由の通信コストが発生 プロセス内実行ではFFIの関数呼び出しでデータを渡す。ただしJSON-RPCの処理は維持
CPU処理の並行性 Node.jsの標準的なモデルではCPU処理がメインスレッドに集中しやすい 多数のセッションを処理する際、CPU処理が直列化されやすい Tokioなどの複数スレッドで処理できる構造へ移行
UIとランタイムの関係 TUIとランタイムが絡み合い、SDKがCLIの上に載っていた UIを必要としないアプリもCLIの実装に依存 ランタイムを独立したライブラリとして分離。CLIをSDKの公開APIだけに載せる作業は継続中

「SDK の裏側で毎回 Node + V8 を起動するのではなく、直接ネイティブコードを呼びたい」
などが可能になりました。(爆速!軽量!)

Rust へのマイグレーションを行ったエンジニア、すごい人

今回この GitHub Copilot Runtime の Rust 移行を行なったのは、
Microsoft の Distinguished Engineer (卓越したエンジニア) である、Stephen Toub(スティーブン・トゥーブ)さんです。

エージェントを指揮し、約 14.5 週間・128 本のPRで、本番コード約 83 万行の Rust へ移行しました。
他チームの機能開発も並行して継続しています

彼は長年 Microsoft の .NET (C# とかが動く環境) チームに所属し、特にパフォーマンス最適化やライブラリ開発において非常に著名な存在の方です。

彼が毎年出す .NET ランタイムのパフォーマンス向上についての記事は毎回めちゃくちゃ詳細だし専門外の人には難解すぎて理解が難しい上にめちゃくちゃ長いので、私は昔からずっとファンです。

たとえば直近の記事はこれです。ぜひご覧ください。

「Performance Improvements in .NET 11」

(毎回スクロールバーの短さにビビるから本当に見て欲しい。ちなみに AI 無い時代からずっとこの長さ。この熱量、C# オタクとして見習わないといけない)

そして、今回彼は、GitHub Copilot のランタイムを TypeScript から Rust へ移行する大規模プロジェクトを主導しました。

GitHub Copilot SDK は 6 言語に対応

image.png

TypeScript, Python, .NET, Go, Java, Rust 向けに SDK を提供

CLIを中心とした構造から、組み込み可能な共通ランタイムへ

image.png

GitHub Copilot SDK は、アプリから Copilot のエージェントランタイムを利用するための窓口です。

当初は、SDK が Copilot CLI を別プロセスで起動し、JSON-RPC で通信する構造でした。
その後、ランタイムを CLI の画面処理から分離する取り組みと、TypeScript から Rust への移行によって、アプリに組み込みやすい共通エンジンとして再構成されました。

ランタイムの分離と組み込み

Rust 製ランタイムは、対応するアプリのプロセス内に読み込んで利用する方式と、別プロセスのサーバーとして利用する方式の両方をサポートします。

同一プロセス内で利用する場合は、C ABI と各言語の FFI(Foreign Function Interface)を通じて、ネイティブライブラリを呼び出します。
これにより、IDE やデスクトップアプリ、Web アプリのバックエンドなどから、共通のエージェントランタイムを利用できます。

(GitHub の Rust 移行記事 では、この同一プロセス方式は明示的に選択する方式として紹介されています。従来の別プロセス方式を置き換えて廃止するものではありません。)

ランタイムループの主な仕組みと構成要素

GitHub Copilot SDK の核となる「ループ」の仕組みについて詳細に解説しています。

image.png
↑ パトリックさんの自作ツール「ハーネス ビジュアライザー」(スクショは私が手元で和訳したもの)

GitHub Copilot SDK のような「ランタイム」は、実体が見えにくいライブラリ形式であるため、
開発者が構成を理解しやすくするためパトリックさんが可視化ツールを作ってくれました。

GitHub Copilot SDK における「ランタイムループ(Runtime Loop)」は、
エージェントがユーザーの要求を理解し、ツールを駆使して回答を導き出すまでのエンジン部分を指します。

公式ドキュメント:「The agent loop (GitHub Docs)」

ランタイムの詳細な動きのトレース

image.png

まず、10 個のボックスがランタイムに接続されています。

6 つのフェーズ

GitHub Copilot SDK を使うと、モデルの判断とツールの実行を組み合わせたエージェントの仕組みを、自分のアプリに取り込めます。その動作は、次の6つの段階で整理できます。

  1. Configure(構成):役割・ツール・権限・使用するモデルなどを設定する。
  2. Assemble(組み立て):指示や会話履歴、取得済みの情報から、モデルへの入力を組み立てる。
  3. Infer(推論):モデルが回答やツール呼び出し要求を生成する。
  4. Authorize(認可):要求された操作を、設定したルールに基づいて許可・拒否する。
  5. Execute(実行):許可されたツール操作を実行し、その結果を回収する。
  6. Continue(継続):実行結果を次の判断につなげ、必要に応じてループを続ける。

Configure が主に初期準備を担い、その後はツールの結果を取り込みながら、入力の組み立て・推論・認可・実行を繰り返します。

この仕組みの核心は、モデルが次の行動を判断し、ランタイムがツールの実行と結果の受け渡しを進めるという役割分担です。
開発者は、アプリ固有の指示やツール、権限制御を用意することで、共通のエージェントループを業務に合わせて利用できます。

ただし、ループの終了は、タスクの達成や結果の正しさを保証するものではありません。権限制御や結果の検証を組み合わせることで、複数のステップにわたる作業を任せられるアプリを設計できます。

1. Configure(設定):エージェントが動く条件を整える

image.png

エージェントが処理を始める前に、開発者がSDKを通じて、役割・ツール・権限・使用するモデルなどを設定します。

アプリ固有の設定をランタイムに結び付ける

独自ツールや拡張機能、権限のルール、処理の途中に介入するフックなどを登録します。
これにより、共通のエージェントランタイムを、自分のアプリの業務に合わせて利用できます。

役割と指示を設定する

「配送案内の担当」「社内文書を調べるアシスタント」といった役割や、守るべき業務ルールをシステムプロンプトなどで設定します。
モデルに渡す具体的な入力は、次の Assemble 段階で会話履歴などと組み合わせて構成します。

利用可能なツールを準備する

アプリ独自の関数や、MCP サーバーが提供するツールを利用できるように設定します。
モデルが必要なツールを選べるよう、ツールの説明や引数の定義を用意します。実際の呼び出しは、設定された権限の範囲で行われます。

使用するモデルと接続先を設定する

GitHub Copilot 経由のモデルに加え、対応する外部プロバイダーや、Ollama などで提供するローカルモデルへの接続を設定できます。ランタイムは接続方式の違いを吸収し、共通のエージェントループを提供します。ただし、利用できる機能や判断の精度は、選択したモデルによって異なります。

2. Assemble (組み立て)

image.png

ランタイムループにおける「② Assemble(組み立て)」は、
指示や会話履歴、取得済みの情報などをまとめ、次の LLM 呼び出しに渡す入力を構成する段階です。

Configure で設定した役割やツールに加え、ユーザーの依頼や、それまでの処理で得られた結果を組み合わせます。
これにより、モデルは現在の文脈を踏まえて、次の行動を判断できるようになります。

コンテキストの集約

ランタイムが、
システムプロンプト、ユーザーの依頼、会話履歴、利用可能なツールの説明や引数の定義、これまでのツール呼び出しとその結果など
を組み合わせます。

プロジェクト内のファイルについても、
添付やアプリ側の処理、過去のツール実行などで取得された情報を、モデルへの入力に含めることができます。
(ただし、この段階で関連ファイルがすべて自動的に読み込まれるわけではありません。追加の調査が必要な場合は、モデルが後続のステップで検索や読み取りのツールを要求します。)

実行環境に応じた情報の追加

モデルへの入力には、作業ディレクトリなどの実行環境に関する情報や、アプリ側で用意した業務・プロジェクト情報も組み込めます。

SDK が追加する環境情報に加え、
開発者はフックなどを使って、アプリ固有の情報を補うことができます。
これにより、同じエージェント設定でも、実行環境や対象業務に応じた情報をモデルの判断材料として提供できます。

次の推論への受け渡し

組み立てた入力は、次の Infer(推論)段階でモデルに渡されます。
モデルは、与えられた役割や指示、ユーザーの依頼、取得済みの情報に基づいて、回答するか、追加のツールを呼び出すかを判断します。

情報が不足していれば、ツールによる調査を続け、その結果を次回の入力に組み込みます。
このように Assemble は、ループの進行に伴って増える情報を、次の判断につなげる役割を担います。

なお、操作上の制約をモデルに伝えることと、実際に操作を許可することは別です。ツールの実行可否は、権限ハンドラーなどの仕組みで制御します。

3. Infer(推論)

image.png

ランタイムループにおける「③ Infer(推論)」は、Assemble で組み立てた入力を大規模言語モデル(LLM)に渡し、次の行動を判断させる段階です。

モデルは、ユーザーへの回答を生成したり、追加の情報取得や操作に必要なツール呼び出しを要求したりします。

エージェントの「思考エンジン」に相当するのが LLM であり、
ランタイムはその呼び出しと、返された応答の処理を担当します。

モデルによる判断

モデルは、システムプロンプト、ユーザーの依頼、会話履歴、利用可能なツールの定義、過去のツール実行結果などを基に、次に何をするかを判断します。

たとえば、回答に必要な情報がそろっていれば回答を生成し、不足していれば検索やファイル読み取りなどのツール呼び出しを要求します。その際には、使用するツールと、それに渡す引数を指定します。

この段階で生成されるのは、あくまでツールの「呼び出し要求」です。
実際の実行は、後続の Authorize(権限確認)とExecute(実行)の段階で行われます。

モデルプロバイダーの違いを吸収する仕組み

Configure で設定したモデルと接続先を使って、ランタイムがモデルを呼び出します。

GitHub Copilot 経由のモデルに加え、Microsoft Foundry/Azure OpenAI、OpenAI、Anthropic など、対応する外部プロバイダーも利用できます。
SDK とランタイムが提供する仕組みにより、開発者はプロバイダーごとにエージェントループ全体を作り直す必要がありません。

ただし、利用できる機能や制約、判断の精度はモデルやプロバイダーによって異なります。
共通の仕組みで利用できることは、すべてのモデルが同じように振る舞うことを意味しません。

ローカルモデルの利用

Ollama などが提供する OpenAI 互換 API を通じて、ローカル環境で実行するモデルを接続することもできます。
利用するモデルや API には、エージェントの動作に必要なツール呼び出しなどの機能への対応が求められます。

ローカルモデルを使えば、モデルへの入力を外部の推論サービスに送らずに処理する構成を選べます。
ただし、ツールや MCP サーバーが外部サービスにアクセスする場合もあるため、アプリ全体のオフライン動作やデータの機密性は、モデル接続だけでなくシステム全体の構成によって決まります。

4. Authorize(認可)

image.png

ランタイムループにおける「④ Authorize(認可)」は、モデルが要求したツール操作について、設定された権限やルールに基づいて実行を許可するか判断する段階です。

モデルが「このツールを使いたい」と要求することと、実際にその操作が許可されることは別です。
Authorize は、この二つの間に置く「関所」に相当します。

操作の実行可否を制御する

開発者は、権限ハンドラーや実行前フックを通じて、ツール操作の実行可否を制御できます。

たとえば、指定したディレクトリ内のファイルだけ操作を許可したり、特定のツールの使用を拒否したりするルールを実装できます。
環境を書き換える操作に加え、情報の読み取りや外部サービスへのアクセスについても、アプリの要件に応じた制御を設計します。

必要に応じてユーザーの承認を求める

権限ハンドラーをアプリ側のUIと連携させ、ユーザーに「この操作を許可しますか?」と確認するフローを実装できます。

すべての操作について確認を求める必要はありません。
あらかじめ許可した操作は自動的に承認し、重要な変更などについてはユーザーの判断を求める、といった設計が可能です。

業務や組織のルールを反映する

アプリ側で業務や組織のポリシーを評価し、その結果を操作の許可・拒否に反映させることもできます。

たとえば、特定のツールの使用や、許可範囲外のファイルへのアクセスを制限できます。こうした仕組みは、データの持ち出しを制限するルールなどを実装するための接点になります。
ただし、Authorize 自体が DLP(Data Loss Prevention:データ損失防止)の機能一式を提供するわけではありません。

モデルの判断と権限制御を分離する

「この操作は禁止」とモデルに指示することに加えて、実行側でも操作の可否を制御することが重要です。

Authorize では、モデルの出力をそのまま実行せず、アプリ側が定めた条件に照らして判断します。
許可された要求は Execute(実行)へ進み、拒否された要求は実行されません。

この段階は、エージェントを許可した範囲で動作させるための保護層です。
ただし、操作を許可したことが、その結果の正しさや安全性まで保証するわけではありません。
必要に応じて、ツール側の入力検証や外部システムのアクセス制御などと組み合わせて設計します。

5. Execute(実行)

image.png

ランタイムループにおける「⑤ Execute(実行)」は、
モデルが要求し、設定された権限制御によって許可されたツール操作を、実際に実行する段階です。

Infer で生成されたツール呼び出し要求を受けて、対応するツールの実装が動作します。
ここで、情報の取得やファイルの編集、コマンドの実行など、具体的な処理が行われます。

ツールによる具体的な処理

実行する内容は、要求されたツールによって異なります。

たとえば、ファイルの読み取りや編集、シェルコマンドの実行、外部 API からの情報取得、アプリ独自の業務処理などが含まれます。
情報を取得するだけのツールもあれば、ファイルや接続先システムの状態を変更するツールもあります。

実行場所もツールの構成によって異なり、ランタイムの実行環境、アプリ側の関数、MCPサーバーや接続先サービスなどで処理されます。
実際の処理を行うのはツールのコードであり、LLM自身がファイルや外部システムを直接操作するわけではありません。

実行結果の回収

ランタイムは、ツールが返したデータや出力、成功・失敗に関する情報を回収します。結果の形式や内容は、ツールの定義によって異なります。

必要に応じて、開発者は実行後のフックを使い、結果の加工や監査ログの記録などを行うこともできます。

ただし、ツールの実行が成功したことは、ユーザーの目的を達成したことや、変更内容が正しいことを保証しません。たとえば、ファイルの編集に成功しても、そのコードが期待どおりに動くかは別途確認が必要です。

結果を次の判断につなげる

実行結果は後続の処理を通じて会話の文脈に組み込まれ、次のモデル呼び出しの判断材料になります。

モデルはその結果を基に、追加の調査、テスト、修正などを要求したり、ユーザーへの回答を生成したりします。失敗が返された場合も、その情報を基に別の方法を選ぶことがあります。

このように Execute は、モデルの要求を具体的な処理に変え、その結果を次の判断につなげる段階です。一度の実行で完了する場合もあれば、実行と判断を繰り返してタスクを進める場合もあります。

6. Continue(継続)

image.png

ランタイムループにおける「⑥ Continue(継続)」は、ツールの実行結果を次の判断につなげ、必要に応じて推論と実行を繰り返す段階です。

一度のモデル呼び出しだけで処理を終えるのではなく、実際に得られた情報や操作結果を基に、追加の調査や修正、検証などを進められるようにします。

実行結果を次の推論へ渡す

ランタイムは、モデルが要求したツールの実行結果を会話の文脈に追加し、再びモデルを呼び出します。6段階の流れで捉えると、Assemble へ戻り、更新された情報から次の入力を組み立てることになります。

モデルは、その結果を基に追加のツールを要求するか、ユーザーへの回答を生成するかを判断します。次の行動を選ぶのはモデルであり、ランタイムはツールの実行と結果の受け渡しを進行します。

会話と作業の文脈を引き継ぐ

次のモデル呼び出しでは、ユーザーの依頼や、それまでの会話、ツール呼び出しとその結果などが判断材料になります。

たとえば、検索で見つけたファイルを読み、その内容を基に編集し、さらにテスト結果を確認する、といった連続した作業が可能になります。

ただし、モデルが把握できる範囲は、入力として提供された情報に依存します。また、長いセッションではコンテキストの圧縮が行われることがあり、過去の情報がすべて元の形で保持されるとは限りません。

進捗をイベントとしてアプリに伝える

処理の進行に伴う応答やツール実行、処理終了などは、SDKを通じてイベントとしてアプリに通知されます。アプリはこれらを利用して、進捗や結果を画面に表示できます。

イベント通知は、アプリが処理の状況を把握するための仕組みです。アプリ側がイベントを受け取るたびに、次のモデル呼び出しを指示する必要はありません。

継続と終了を区別する

通常のツール利用ループでは、モデルが追加のツールを要求すると、ランタイムが実行し、その結果を渡して再びモデルを呼び出します。モデルが追加のツール要求を出さずに回答すると、ループは終了します。

アプリは、session.idle イベントで処理が終了し、次のメッセージを受け付けられる状態になったことを検知できます。ただし、これはユーザーの目的が達成されたことや、結果が正しいことを保証する信号ではありません。

Continue は、ツールの結果を次の判断へつなぐことで、複数のステップにわたるタスクを進める仕組みです。
エージェントループ全体を通じて、調査・実行・検証を繰り返せることが、GitHub Copilot SDK による自動化の重要な特徴です。

[デモ] GitHub Copilot SDK を既存のアプリケーションへ導入する

(SDK を入れ込む実装についても、Copilot に頼んだら良い感じに実装してくれますというデモ)

デモシナリオ:簡単なテキストエディタに Copilot の機能を入れ込む

600 以上の小さなオープンソースアプリのコレクションの載っている「Tiny Tool Town」から、
軽量なテキストエディタ「FancyGist」を紹介しました。

ライブのページ

この軽量テキストエディタ web アプリに、
GitHub Copilot SDK を使い、編集支援の機能を入れてみるデモを行いました。

GitHub Copilot App に以下の指示をしました:

image.png

Install the Copilot SDK. I want to be able to highlight text and call an agent into action to support editing or providing suggestions.
Let's add a side pane with the agent chats so I can see what's going on and steer them.

(Copilot SDK をインストールしてください。テキストを選択して、編集の支援や改善提案を行うエージェントを呼び出せるようにしたいです。
また、エージェントとのやり取りが見えるようにサイドペインを追加し、そこでエージェントの動作状況を確認したり、必要に応じて指示や方向修正ができるようにしましょう。)

↓

image.png

画面下側に「Copilot chats」欄が現れました。

テキストエディタに「Hi there」と入れて
チャット画面で「Made the greeting more formal」(挨拶をもっとフォーマルにして) と指示文を入れると
「Hello」を候補を出してくれました。

というわけで、
アプリに GitHub Copilot SDK を使い、Copilot の機能を載せることができました。

まとめ

本当は動画はもっと続くのですが、長くなったのでいったんここで切ります。

9
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?