💨

GitHub Copilot Chat の Ask/Edit/Agent モードをコードレベルで理解して使い分ける

に公開

VS Code の GitHub Copilot Chat には、「Ask」「Edit」「Agent」という 3 つのモードがあります。これらの違いについては、以下のような理解をしている人が多いのではないでしょうか(自分もそうでした)。

  • Ask: 質問に答えてくれる (Read オンリー)
  • Edit: ファイルを編集してくれる (Read/Write)
  • Agent: 複雑なタスクを自律的にこなしてくれる

上記のような理解で実情困ることはあまりないのですが、動作を知らないが故に、「なんか Ask モードは回答が妙だな」とか「Edit と Agent の編集ってなにか違うの?」と思うことが結構あります。

このような(煩)悩に苛まれたままでは年を越せない、ということで、microsoft/vscode-copilot-chat のコードを実際に読みながら、実装レベルでこれらのモードの違いを探っていきます。

なお、この記事では、2025年12月26日時点のコードを参照しています(コミットハッシュ: 0544434)。GitHub Copilot Chat は頻繁に更新されるため、最新版では実装が異なる可能性がある点に注意してください。

何を調べるか

実装を追っていく前に、どんな違いがあるかの仮説を立てておきましょう。おそらく以下のような実装の違いから、差異が生まれているのではないかと考えられます。

  1. LLM に渡すプロンプトの違い: 各モードで「役割」が異なる指示を受けている?
  2. 使えるツールの違い: Edit と Agent はファイル操作ツールを持っているが、Ask は持っていない?
  3. 実行ループの違い: Agent だけ複数回 LLM を呼び出す仕組みになっている?

これから、実際のコードを読んでこれらの仮説を確かめていきます。

タスク処理の単位はインテント

実は、Ask/Edit/Agent などの「モード」はタスク実行の最小単位ではなく、インテント (intents) と呼ばれるより細かい概念で特定タスクを実行する仕組みになっています。後で見るように、モードはインテントを指定するための「ロジック」に近い役割を果たしています。

インテントとは何か?

インテントは、名前の通り、ユーザーの意図(実行したいタスク)を抽象化したものです。インテントごとに明確なタスク設定があり、目標のために Chat Completions API をどのように呼び出すかをクラスで管理します。src/extension/common/constants.ts を見ると、様々なインテントが定義されていることがわかります。

src/extension/common/constants.ts
export const enum Intent {
  Explain = "explain", // コードの説明
  Review = "review", // コードレビュー
  Tests = "tests", // テスト生成
  Fix = "fix", // バグ修正
  Search = "search", // 検索
  Edit = "edit", // Edit モード
  Agent = "editAgent", // Agent モード
  // ...他にも多数
}

GitHub Copilot Chat は、様々なコンポーネントから利用されます。例えば、パネルチャット(右側に出てくるアレ)で呼び出されることもあれば、 インライン補完の Modify で呼び出されることもあります。たくさんの呼び出しチャネルがある中で、インテントは「この呼び出しで何をしたいのか?」を明確にする役割を果たしています。

ユーザーから呼び出されると、「このユーザーは何をしたいのか?」を判断し、適切なインテントを選択します。インテントを決定する処理は、呼び出しの経路によってハードコードされていることもあれば、LLM による自動検出を使うこともあります。後者を、Intent Detection (intentDetection) と呼びます。

インテントが決まると、そのインテントに対応する処理ロジックを実行して、LLM から応答を得ます。具体的には、プロンプト構築とツール選択が主な作業です。得られた回答によって、ユーザーからの質問に答えたり、ツールを実行したり、ファイルを編集します。

たとえば、インライン補完の Modify を実行すると、まず複数の候補 (generate, edit, doc, fix, tests) から適切なインテントを選択するための Intent Detection が実行されます。仮に、追加コードを生成する必要があり、generate が選ばれたとすると、インライン補完で新しいコードを生成するための処理が呼び出され、最終的に LLM にリクエストが送信されます。

インテントと VS Code の拡張可能性

興味深いことに、インテントは VS Code の拡張機能システムと統合されています。src/extension/conversation/vscode-node/chatParticipants.ts を見ると、各インテントが チャット参加者 (Chat Participant) として登録されていることが分かります。この仕組みにより、拡張機能は新しいインテントを追加できます。

src/extension/conversation/vscode-node/chatParticipants.ts
// Workspace Agent を登録(Intent.Workspace)
private registerWorkspaceAgent(): IDisposable {
    const workspaceAgent = this.createAgent(workspaceAgentName, Intent.Workspace);
    workspaceAgent.iconPath = new vscode.ThemeIcon('code');
    return workspaceAgent;
}

// Editing Agent を登録(Intent.Edit)
private registerEditingAgent(): IDisposable {
    const editingAgent = this.createAgent(editingSessionAgentName, Intent.Edit);
    editingAgent.iconPath = new vscode.ThemeIcon('copilot');
    return editingAgent;
}

// Agent モードを登録(Intent.Agent)
private registerEditsAgent(): IDisposable {
    const editingAgent = this.createAgent(editsAgentName, Intent.Agent);
    editingAgent.iconPath = new vscode.ThemeIcon('tools');
    return editingAgent;
}

たとえば、GitHub Copilot for Azure (ms-azuretools.vscode-azure-github-copilot) 拡張機能をインストールすると @azure というチャット参加者が追加され、Azure 関連の質問に特化した応答が可能になります。内部的には、これと同時に @azure にまつわるインテントも追加されます。そして、@azure を指定してチャットすると、拡張機能で定義されたインテントに従って処理が実行されるという訳です。


azure チャット参加者が拡張機能によって追加されている例

話が少し脱線しましたが、GitHub Copilot Chat には様々なインテントがあり(拡張機能も独自のインテントを追加できる)、それらがタスク実行の最小単位になっているということを理解していただけたかと思います。

Ask/Edit/Agent とインテントの関係

それでは、Ask/Edit/Agent の 3 つのモードについて見ていきましょう。冒頭で述べたように、これらのモードは実際には特定のインテントを指定するための「ロジック」に近いものです。

  • Ask モード: 様々なインテントを自動検出して適切に処理する(ExplainIntent, ReviewIntent, SearchIntent, FixIntent, TestsIntent など)
  • Edit モード: EditCodeIntent というコード編集に特化したインテントのみを利用
  • Agent モード: AgentIntent という自律的なタスク実行に特化したインテントのみを利用

特に興味深い点は、Ask モードは「ユーザーの質問内容に応じて最適なインテントを選ぶ」のに対し、Edit/Agent モードは「最初から特定のインテントに固定」されていることです。

Ask モードで使えるインテント

src/extension/intents/node/allIntents.ts で登録されているインテントのうち、Panel(チャットパネル)で利用可能なものが Ask モードの既定の候補となります。

インテント 説明 実装クラス
explain コードの説明 ExplainIntent
review コードレビュー ReviewIntent
tests テスト生成 TestsIntent
fix バグ修正 FixIntent
search コードベース検索 SearchIntent
workspace ワークスペース全体の質問 WorkspaceIntent
その他 意図不明な質問 UnknownIntent

加えて、先程述べたように、拡張機能によって追加されたインテントも Ask モードで利用可能になります。

Edit モードで使えるインテント

Edit モードは EditCodeIntent のみを使用します。つまり、インテントの自動検出は行わず、最初から「コード編集」に特化した処理が実行されます。

Agent モードで使えるインテント

Agent モードは AgentIntent のみを使用します。これもインテントの自動検出は行わず、最初から「自律的なタスク実行」に特化した処理が実行されます。

このように、Ask だけが複数のインテントから選択し、Edit と Agent は固定のインテントを使うという設計になっています。

では、これらのインテントは実際にどう動作するのでしょうか?LLM の呼び出しプロンプトの違いからまずは紐解いていこうと思います。

プロンプトの違い

各インテントが使用するプロンプトは、src/extension/prompts/node/ ディレクトリに定義されています。Ask/Edit/Agent の各モードで使われるプロンプトを比較してみましょう。

Ask モードのプロンプト

Ask モードは複数のインテントを持つため、インテントごとに異なるプロンプトが使用されます。ただし、Panel での会話の基本となる共通プロンプトがあります。

panel/panelChatBasePrompt.tsx より。

You are an AI programming assistant.

Use Markdown formatting in your answers.
The user works in an IDE called Visual Studio Code...
You can only give one reply for each conversation turn.

特徴:

  • 「AI programming assistant」というシンプルな定義
  • 「1 ターンに 1 回だけ返信できる」と制限
  • フォーマットや IDE の説明が中心

この基本プロンプトの上に、選択されたインテント(ExplainIntent, ReviewIntent など)に応じた追加の指示が加わります。

Edit モードのプロンプト

Edit モード (EditCodeIntent) のプロンプトは panel/editCodePrompt.tsx にあります。システムメッセージは「You are an AI programming assistant」のみで、後はファイル編集に特化したユーザーメッセージが記載されます。

The user has a request for modifying one or more files.

1. Please come up with a solution that you first describe step-by-step.
2. Group your changes by file. Use the file path as the header.
3. For each file, give a short summary of what needs to be changed followed by a code block that contains the code changes.
4. The code block should start with four backticks followed by the language.
5. On the first line of the code block add a comment containing the filepath.
6. Use a single code block per file that needs to be modified, even if there are multiple changes for a file.
7. The user is very smart and can understand how to merge your code blocks into their files, you just need to provide minimal hints.
8. Avoid repeating existing code, instead use comments to represent regions of unchanged code. For example:

```languageId
// path/to/file
// ...existing code...
{ changed code }
// ...existing code...
{ changed code }
// ...existing code...
```

指示をざっくりまとめると。

  • 編集内容をファイルごとにグループ化
  • コードブロックで変更内容を返す
  • 既存コードは // ...existing code... コメントで省略
  • コードブロックの最初にファイルパスをコメントで記載

ということを指示しています。特に、コードブロックで編集内容を返すという点が重要です。下記はそのために追加で含めている few-shot prompts です。

Here is an example of how you should format a code block belonging to the file example.ts:

### example.ts

Add a new property 'age' and a new method 'getAge' to the class Person.

```typescript
// example.ts
class Person {
  // ...existing code...
  age: number;
  // ...existing code...
  getAge() {
    return this.age;
  }
}
```

勘の鋭い読者の方ならすでにお気づきかもしれないのですが、実は Edit モード (EditCodeIntent) は、tool use (function calling) を使わずに LLM の応答をパースして編集内容を抽出する仕組みになっています。この点は Agent モードのファイル編集とかなり違っていて興味深いです(後ほど詳しく説明します)。

Agent モードのプロンプト

agent/defaultAgentInstructions.tsx を見ると、Agent モード (AgentIntent) のプロンプトが確認できます。

You are a highly sophisticated automated coding agent with expert-level knowledge
across many different programming languages and frameworks.

The user will ask a question, or ask you to perform a task, and it may require lots
of research to answer correctly. There is a selection of tools that let you perform
actions or retrieve helpful context to answer the user's question.

You can call tools repeatedly to take actions or gather as much context as needed
until you have completed the task fully. Don't give up unless you are sure the
request cannot be fulfilled with the tools you have.

特徴:

  • 「sophisticated automated coding agent」と自己紹介
  • 「ツールを繰り返し呼び出せる」と明示
  • 「タスクを完全に完了するまで諦めるな」という強い指示

自律的なタスク実行のためのインテントらしく、ツールへの言及が中心になっています。Edit モードとは対照的に、Agent モード (AgentIntent) は tool use を通じてアクションを行う設計になっています。

ツール使用 (tool use) の違い

プロンプトの違いで明らかになったように、「同じ編集という作業でもモードによって実現方法が違う」ということは、LLM に渡すツール定義も違うということを意味します。では、実際にどのようなツールが各モードで利用可能なのでしょうか?具体的に見ていきましょう。

Ask モードのツール

Ask モードでは、インテントが決まった時点で利用可能なツールが自動的に決定されます。 ユーザーが直接ツールを選択する UI は提供されていません。

ツール提供の仕組み

各インテントは IToolsService.getEnabledTools() を使ってツールをフィルタリングします。askAgentIntent.ts の実装を見ると、以下の条件でツールが有効化されます。

src/extension/intents/node/askAgentIntent.ts
return toolsService.getEnabledTools(
  request,
  model,
  (tool) =>
    tool.tags.some((tag) => lookForTags.has(tag)) ||
    request.toolReferences.some((ref) => ref.name === tool.name)
);

たとえば、Web Searchfor Copilot 拡張機能 (ms-vscode.vscode-websearchforcopilot) をインストールすると、web_question というインテントが追加されます。これには以下のような説明がついています。

The user is asking a question that requires current knowledge from a web search engine. Such questions often reference time periods that exceed your knowledge cutoff.

そして、Ask モードで「https://github.com/... を調べて」と質問をすると、例のごとく担当インテントを自動判断するための Intent Detection が走ります。LLM が web_question インテントを選択すると、拡張機能で実装された処理が走ることになります。そして、ここからが興味深いのですが、web_question インテントの実体は、Language Model API (copilotLanguageModelWrapper) 経由で websearch ツールを tool use することです。


Ask モードで web_question インテントが選ばれた例。websearch ツールが有効化されている。

このように、Ask モードのインテントとして呼ばれた場合でも、LLM tool use によって検索できるような仕組みを実現しています(当然 tool use 用のツールを登録するという機能も持っているので、Agent モード時は単純なツール提供者になる)。

つまるところ、Ask モードのツールは質問内容/インテントに応じて自動的に決定される設計で、ユーザーが直接制御する余地はありません。

Edit モードのツール

Edit モードは tool use を使わないため、編集用のツールを持っていません。代わりに、LLM が生成した Markdown コードブロックをパースして編集を実現します。これが前セクションで見た「設計図アプローチ」の実体です。

tool use をサポートしないことは、editCodeIntent.ts#L335-L337getAvailableTools() が必ず undefined を返すことから分かります。

export class EditCodeIntentInvocation implements IIntentInvocation {
  // コードブロックが編集を表すことを明示
  public readonly codeblocksRepresentEdits: boolean = true;

  // ツールを一切提供しない
  getAvailableTools():
    | vscode.LanguageModelToolInformation[]
    | Promise<vscode.LanguageModelToolInformation[]>
    | undefined {
    return undefined;
  }
}

Agent モードのツール

Agent モードでは、豊富なツールが利用可能です。toolNames.tsToolName enum に利用可能なツールが定義されています。これらのツールが実際に LLM に渡される流れは以下の通りです。

  1. Agent インテントがツールを取得 - agentIntent.ts の getAgentTools 関数で、toolsService.getEnabledTools() を呼び出してツールリストを取得
src/extension/intents/node/agentIntent.ts
const tools = toolsService.getEnabledTools(request, model, (tool) => {
  if (typeof allowTools[tool.name] === "boolean") {
    return allowTools[tool.name];
  }
  return undefined;
});
  1. LLM API に渡す - extChatEndpoint.ts で、取得したツールを vscode.LanguageModelChatRequestOptionstools パラメータに変換
src/platform/endpoint/vscode-node/extChatEndpoint.ts
const vscodeOptions: vscode.LanguageModelChatRequestOptions = {
  tools: ((requestOptions?.tools ?? []) as OpenAiFunctionTool[]).map(
    (tool) => ({
      name: tool.function.name,
      description: tool.function.description,
      inputSchema: tool.function.parameters,
    })
  ),
};

const response = await this.languageModel.sendRequest(
  vscodeMessages,
  vscodeOptions,
  token
);
拡張機能と MCP によるツール追加

拡張機能や MCP (Model Context Protocol) によってツールを追加できます。VS Code の Language Model API の一つである vscode.lm.registerTool を介して、任意の拡張機能がツールを登録できます。

実は、tools.ts を見ると、内蔵ツールも同じ API で登録されています。

src/extension/tools/vscode-node/tools.ts
for (const [name, tool] of toolsService.copilotTools) {
  if (isVscodeLanguageModelTool(tool)) {
    // 各ツールを vscode.lm に登録
    this._register(vscode.lm.registerTool(getContributedToolName(name), tool));
  }
}

そして、ツールをまとめて提供するサービスである toolsService.ts では、vscode.lm.tools から全ての登録済みツールを取得します。

src/extension/tools/vscode-node/toolsService.ts
get tools(): ReadonlyArray<vscode.LanguageModelToolInformation> {
  // vscode.lm.tools から全ツールを取得(内蔵 + 拡張機能提供)
  const input = [...vscode.lm.tools];
  const contributedTools = [...input]
    .sort((a, b) => {
      // 内蔵ツール(vscode_*, copilot_*)を優先
      const aIsBuiltin = a.name.startsWith('vscode_') || a.name.startsWith('copilot_');
      const bIsBuiltin = b.name.startsWith('vscode_') || b.name.startsWith('copilot_');
      // ...
    });
  // ...
}

LLM へのリクエストの違い

プロンプトやツール以外にも、LLM API への実際のリクエストにも違いがあります。

Thinking Budget (思考予算)

src/platform/endpoint/node/chatEndpoint.ts を見ると、Agent モードの時だけ特別な設定があります。

src/platform/endpoint/node/chatEndpoint.ts
const isConversationAgent = options.location === ChatLocation.Agent;
if (
  isAnthropicFamily(this) &&
  !options.disableThinking &&
  isConversationAgent
) {
  const configuredBudget = this._configurationService.getExperimentBasedConfig(
    ConfigKey.AnthropicThinkingBudget,
    this._expService
  );
  if (configuredBudget && configuredBudget > 0) {
    const normalizedBudget = configuredBudget < 1024 ? 1024 : configuredBudget;
    body.thinking_budget = Math.min(
      32000,
      this._maxOutputTokens - 1,
      normalizedBudget
    );
  }
}

Agent モードでは、Anthropic (Claude) モデルを使用する場合、thinking_budget というパラメータが設定されます。これは Claude が内部的に「思考」するためのトークン数の予算です。

その他の違い

モードによって、以下のようなパラメータも変わる可能性があります。

  • temperature - 創造性のレベル(Agent は計画的、Ask はより柔軟)
  • max_tokens - 最大出力トークン数(Agent は長い応答が必要)
  • tool_choice - ツール使用の強制度

これらの調整により、各モードの特性に合った LLM の振る舞いが実現されています。

まとめ

実装レベルで見てきた違いを整理すると、以下のようになります。

観点 Ask Edit Agent
インテントの選択 複数から自動検出 EditCodeIntent 固定 AgentIntent 固定
プロンプトの焦点 質問に答える 指定ファイルを編集 タスク完遂
実行ループ 1 ターンで回答 繰り返し 繰り返し
ファイル編集の方式 編集不可 コードブロックパース tool use
ツール コール インテントに応じて自動決定 なし 内蔵ツール + 拡張ツール
拡張機能によるツール ✅ (インテントとして追加可) ✅ (ツールとして追加可)

おわりに

この記事では、vscode-copilot-chat のコードを実際に読みながら、Ask/Edit/Agent モードの違いを探りました。表面的な機能の違いだけでなく、プロンプト、ツール、実行ループという 3 つの軸で、それぞれのモードがどう設計されているかが見えてきました。

これらの違いを理解することで、状況に応じて適切なモードを選び、GitHub Copilot Chat をより効果的に活用できるようになると感じました。たとえば、個人的には以下のような使い分け基準が出来ました。

  • インテントを使う場合は Ask モード: たとえば拡張機能が有益なインテントを追加する場合、Ask モードで積極的にそのインテントを使ってあげるのが良さそうです。ただし、どんなインテントが拡張機能によって追加されるのか分かりづらいのと、その実装が公開されない場合もあるのでそこが難しいポイントですね。
  • Edit モードは基本使わなくてよさそう: Edit モードはコードブロックのパースに依存しているため、複雑な編集には向かない印象。単純な修正なら良いが、Agent モードでツールを使った方が柔軟性が高い。
  • 基本 Agent モード一択: VS Code 上の設定と、裏側の仕組みのメンタルモデルを最も簡単に一致させられるのが Agent モードです(Chat Completion API を素直に実行して tool use でアクションを行うだけ)。もし、Read-only なモードが欲しければ、ツールの選択で簡単に実現できます。唯一と言っても良いデメリットは、Intent Detection を実行出来ないことですが、あまりインテントに頼るシーンも想像できないです。

今後も、(必要に応じてたまにコードを追いながら)GitHub Copilot の最新情報をキャッチアップしていきたいと思います。

Microsoft (有志)

Discussion