に参加して、VS Code の AI 支援開発について学びましょう。

チュートリアル: 言語モデル API を使用して AI 搭載コード注釈を生成する

このチュートリアルでは、AI 搭載コードチューターを構築するための VS Code 拡張機能を作成する方法を学習します。言語モデル (LM) API を使用してコードを改善するための提案を生成し、VS Code 拡張機能 API を活用して、ユーザーが詳細情報を確認するためにホバーできるインライン注釈としてエディターにシームレスに統合します。このチュートリアルを完了すると、VS Code でカスタム AI 機能を実装する方法がわかります。

VS Code displaying custom annotations from GitHub Copilot as annotations

前提条件

このチュートリアルを完了するには、次のツールとアカウントが必要です

拡張機能を足場にする

まず、Yeoman と VS Code 拡張機能ジェネレーターを使用して、開発準備ができた TypeScript または JavaScript プロジェクトを足場にします。

npx --package yo --package generator-code -- yo code

新しい拡張機能ウィザードを完了するには、次のオプションを選択します...

# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? Code Tutor

### Press <Enter> to choose default for all options below ###

# ? What's the identifier of your extension? code-tutor
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm

# ? Do you want to open the new folder with Visual Studio Code? Open with `code`

package.json ファイルを修正して、正しいコマンドを含める

足場プロジェクトには、package.json ファイルに単一の "helloWorld" コマンドが含まれています。このコマンドは、拡張機能がインストールされたときにコマンドパレットに表示されるものです。

"contributes": {
  "commands": [
      {
      "command": "code-tutor.helloWorld",
      "title": "Hello World"
      }
  ]
}

行に注釈を追加するコードチューター拡張機能を構築しているため、ユーザーがこれらの注釈をオン/オフに切り替えることを許可するコマンドが必要です。command および title プロパティを更新します

"contributes": {
  "commands": [
      {
      "command": "code-tutor.annotate",
      "title": "Toggle Tutor Annotations"
      }
  ]
}

package.json は拡張機能のコマンドと UI 要素を定義しますが、src/extension.ts ファイルは、これらのコマンドで実行されるコードを配置する場所です。

src/extension.ts ファイルを開き、registerCommand メソッドを package.json ファイルの command プロパティと一致するように変更します。

const disposable = vscode.commands.registerCommand('code-tutor.annotate', () => {

F5 キーを押して拡張機能を実行します。これにより、拡張機能がインストールされた新しい VS Code インスタンスが開きます。⇧⌘P (Windows、Linux Ctrl+Shift+P) を押してコマンドパレットを開き、「tutor」を検索します。「Tutor Annotations」コマンドが表示されるはずです。

The "Toggle Tutor Annotations" command in the VS Code Command Palette

「Tutor Annotations」コマンドを選択すると、「Hello World」通知メッセージが表示されます。

The message 'Hello World from Code Tutor' displayed in a notification

「annotate」コマンドを実装する

コードチューターの注釈を機能させるには、コードを送信し、注釈を提供するように依頼する必要があります。これを3つのステップで行います

  1. ユーザーが開いている現在のタブから行番号付きのコードを取得します。
  2. そのコードを言語モデル API に送信し、モデルに注釈を提供する方法を指示するカスタムプロンプトも送信します。
  3. 注釈を解析し、エディターに表示します。

ステップ 1: 行番号付きのコードを取得する

現在のタブからコードを取得するには、ユーザーが開いているタブへの参照が必要です。これは、registerCommand メソッドを registerTextEditorCommand に変更することで取得できます。これら2つのコマンドの違いは、後者がユーザーが開いているタブへの参照 (TextEditor と呼ばれる) を提供することです。

const disposable = vscode.commands.registerTextEditorCommand('code-tutor.annotate', async (textEditor: vscode.TextEditor) => {

これで、textEditor 参照を使用して、「表示可能なエディター空間」内のすべてのコードを取得できます。これは画面に表示できるコードであり、表示可能なエディター空間の上または下にあるコードは含まれません。

extension.ts ファイルの末尾にある export function deactivate() { } の行の直上に次のメソッドを追加します。

function getVisibleCodeWithLineNumbers(textEditor: vscode.TextEditor) {
  // get the position of the first and last visible lines
  let currentLine = textEditor.visibleRanges[0].start.line;
  const endLine = textEditor.visibleRanges[0].end.line;

  let code = '';

  // get the text from the line at the current position.
  // The line number is 0-based, so we add 1 to it to make it 1-based.
  while (currentLine < endLine) {
    code += `${currentLine + 1}: ${textEditor.document.lineAt(currentLine).text} \n`;
    // move to the next line position
    currentLine++;
  }
  return code;
}

このコードは、TextEditor の visibleRanges プロパティを使用して、エディターに現在表示されている行の位置を取得します。次に、最初の行の位置から最後の行の位置に移動し、各行のコードを行番号とともに文字列に追加します。最後に、すべての表示可能なコードを行番号とともに含む文字列を返します。

これで、このメソッドを code-tutor.annotate コマンドから呼び出すことができます。コマンドの実装を次のように変更します

const disposable = vscode.commands.registerTextEditorCommand(
  'code-tutor.annotate',
  async (textEditor: vscode.TextEditor) => {
    // Get the code with line numbers from the current editor
    const codeWithLineNumbers = getVisibleCodeWithLineNumbers(textEditor);
  }
);

ステップ 2: コードとプロンプトを言語モデル API に送信する

次のステップは、GitHub Copilot 言語モデルを呼び出し、ユーザーのコードと注釈を作成するための指示を送信することです。

これを行うには、まず使用するチャットモデルを指定する必要があります。構築している種類のインタラクションにとって高速で有能なモデルであるため、ここでは 4o を選択します。

const disposable = vscode.commands.registerTextEditorCommand(
  'code-tutor.annotate',
  async (textEditor: vscode.TextEditor) => {
    // Get the code with line numbers from the current editor
    const codeWithLineNumbers = getVisibleCodeWithLineNumbers(textEditor);

    // select the 4o chat model
    let [model] = await vscode.lm.selectChatModels({
      vendor: 'copilot',
      family: 'gpt-4o'
    });
  }
);

モデルに注釈を作成するように指示する命令、つまり「プロンプト」と、応答の形式が必要です。インポートのすぐ下のファイルの先頭に次のコードを追加します。

const ANNOTATION_PROMPT = `You are a code tutor who helps students learn how to write better code. Your job is to evaluate a block of code that the user gives you and then annotate any lines that could be improved with a brief suggestion and the reason why you are making that suggestion. Only make suggestions when you feel the severity is enough that it will impact the readability and maintainability of the code. Be friendly with your suggestions and remember that these are students so they need gentle guidance. Format each suggestion as a single JSON object. It is not necessary to wrap your response in triple backticks. Here is an example of what your response should look like:

{ "line": 1, "suggestion": "I think you should use a for loop instead of a while loop. A for loop is more concise and easier to read." }{ "line": 12, "suggestion": "I think you should use a for loop instead of a while loop. A for loop is more concise and easier to read." }
`;

これは、言語モデルに注釈を生成する方法を指示する特別なプロンプトです。モデルが応答をフォーマットする方法の例も含まれています。これらの例 (「マルチショット」とも呼ばれます) は、応答の形式を定義し、それを解析して注釈として表示できるようにするものです。

メッセージは配列でモデルに渡します。この配列には、好きなだけメッセージを含めることができます。この場合、プロンプトの後にユーザーのコードが行番号付きで含まれます。

const disposable = vscode.commands.registerTextEditorCommand(
  'code-tutor.annotate',
  async (textEditor: vscode.TextEditor) => {
    // Get the code with line numbers from the current editor
    const codeWithLineNumbers = getVisibleCodeWithLineNumbers(textEditor);

    // select the 4o chat model
    let [model] = await vscode.lm.selectChatModels({
      vendor: 'copilot',
      family: 'gpt-4o'
    });

    // init the chat message
    const messages = [
      vscode.LanguageModelChatMessage.User(ANNOTATION_PROMPT),
      vscode.LanguageModelChatMessage.User(codeWithLineNumbers)
    ];
  }
);

メッセージをモデルに送信するには、まず選択したモデルが利用可能であることを確認する必要があります。これにより、拡張機能が準備できていない場合や、ユーザーが GitHub Copilot にサインインしていない場合が処理されます。次に、メッセージをモデルに送信します。

const disposable = vscode.commands.registerTextEditorCommand(
  'code-tutor.annotate',
  async (textEditor: vscode.TextEditor) => {
    // Get the code with line numbers from the current editor
    const codeWithLineNumbers = getVisibleCodeWithLineNumbers(textEditor);

    // select the 4o chat model
    let [model] = await vscode.lm.selectChatModels({
      vendor: 'copilot',
      family: 'gpt-4o'
    });

    // init the chat message
    const messages = [
      vscode.LanguageModelChatMessage.User(ANNOTATION_PROMPT),
      vscode.LanguageModelChatMessage.User(codeWithLineNumbers)
    ];

    // make sure the model is available
    if (model) {
      // send the messages array to the model and get the response
      let chatResponse = await model.sendRequest(
        messages,
        {},
        new vscode.CancellationTokenSource().token
      );

      // handle chat response
      await parseChatResponse(chatResponse, textEditor);
    }
  }
);

チャット応答はフラグメントとして届きます。これらのフラグメントには通常単語が含まれますが、句読点のみが含まれる場合もあります。応答がストリームとして表示されるときに注釈を表示するには、完全な注釈が揃うまで待つ必要があります。モデルに応答を返すように指示した方法により、閉じ括弧 } を見たときに完全な注釈があることがわかります。次に、注釈を解析してエディターに表示できます。

extension.ts ファイルの getVisibleCodeWithLineNumbers メソッドの上に、不足している parseChatResponse 関数を追加します。

async function parseChatResponse(
  chatResponse: vscode.LanguageModelChatResponse,
  textEditor: vscode.TextEditor
) {
  let accumulatedResponse = '';

  for await (const fragment of chatResponse.text) {
    accumulatedResponse += fragment;

    // if the fragment is a }, we can try to parse the whole line
    if (fragment.includes('}')) {
      try {
        const annotation = JSON.parse(accumulatedResponse);
        applyDecoration(textEditor, annotation.line, annotation.suggestion);
        // reset the accumulator for the next line
        accumulatedResponse = '';
      } catch (e) {
        // do nothing
      }
    }
  }
}

実際に注釈を表示するには、もう1つのメソッドが必要です。VS Code はこれを「デコレーション」と呼びます。extension.ts ファイルの parseChatResponse メソッドの上に次のメソッドを追加します。

function applyDecoration(editor: vscode.TextEditor, line: number, suggestion: string) {
  const decorationType = vscode.window.createTextEditorDecorationType({
    after: {
      contentText: ` ${suggestion.substring(0, 25) + '...'}`,
      color: 'grey'
    }
  });

  // get the end of the line with the specified line number
  const lineLength = editor.document.lineAt(line - 1).text.length;
  const range = new vscode.Range(
    new vscode.Position(line - 1, lineLength),
    new vscode.Position(line - 1, lineLength)
  );

  const decoration = { range: range, hoverMessage: suggestion };

  vscode.window.activeTextEditor?.setDecorations(decorationType, [decoration]);
}

このメソッドは、モデルから解析された注釈を受け取り、それを使用してデコレーションを作成します。これは、まずデコレーションの外観を指定する TextEditorDecorationType を作成することによって行われます。この場合、単に灰色の注釈を追加し、25文字に切り詰めています。ユーザーがメッセージにホバーしたときに完全なメッセージを表示します。

次に、デコレーションが表示される場所を設定します。注釈で指定された行番号の行末に表示する必要があります。

最後に、アクティブなテキストエディターにデコレーションを設定します。これにより、注釈がエディターに表示されます。

拡張機能がまだ実行中の場合は、デバッグバーから緑色の矢印を選択して再起動します。デバッグセッションを閉じた場合は、F5 キーを押して拡張機能を実行します。開いた新しい VS Code ウィンドウインスタンスでコードファイルを開きます。コマンドパレットから「Toggle Tutor Annotations」を選択すると、エディターにコード注釈が表示されるはずです。

A code file with annotations from GitHub Copilot

エディターのタイトルバーにボタンを追加する

コマンドパレット以外の場所からコマンドを呼び出すことができます。この場合、現在のタブの上部にボタンを追加して、ユーザーが注釈を簡単に切り替えられるようにすることができます。

これを行うには、package.json の「contributes」部分を次のように変更します

"contributes": {
  "commands": [
    {
      "command": "code-tutor.annotate",
      "title": "Toggle Tutor Annotations",
      "icon": "$(comment)"
    }
  ],
  "menus": {
    "editor/title": [
      {
        "command": "code-tutor.annotate",
        "group": "navigation"
      }
    ]
  }
}

これにより、エディターのタイトルバーのナビゲーション領域 (右側) にボタンが表示されます。「アイコン」は 製品アイコンリファレンス から取得されます。

拡張機能がまだ実行されていない場合は、緑色の矢印で再起動するか、F5 キーを押します。コメントアイコンが表示され、「Toggle Tutor Annotations」コマンドがトリガーされるはずです。

A comment icon appears in the title bar of the active tab in VS Code

次のステップ

このチュートリアルでは、言語モデル API を使用して AI をエディターに統合する VS Code 拡張機能を作成する方法を学びました。VS Code 拡張機能 API を使用して現在のタブからコードを取得し、カスタムプロンプトでモデルに送信し、モデルの結果を解析してデコレーターを使用してエディターに直接表示しました。

次に、Code Tutor 拡張機能を拡張して、チャット参加者を含めることもできます。これにより、ユーザーは GitHub Copilot チャットインターフェイスを介して拡張機能と直接やり取りできます。また、VS Code のすべての API を探索して、エディターでカスタム AI エクスペリエンスを構築する新しい方法を探索することもできます。

このチュートリアルの完全なソースコードは、vscode-extensions-sample リポジトリで見つけることができます。

© . This site is unofficial and not affiliated with Microsoft.