Continueの構文解析について(By DeepResearch)

序論 (Introduction)

ソフトウェア開発におけるAIコードアシスタントは、複数のプログラミング言語で開発者を支援するため、コードの構文構造を正確に理解・解析する能力が重要となる (Root path context: The secret ingredient in Continue's autocomplete prompt)。Continue (Introduction | Continue)はオープンソースのIDE拡張機能としてVS CodeやJetBrains IDE上で動作し、チャットや自動補完、コード編集提案など高度な機能を提供するAIコードアシスタントである。その中核技術の一つが**構文解析 (syntax parsing)**であり、コードベース全体を理解し文脈に応じた正確な支援を行う上で不可欠である。特にContinueでは、**抽象構文木 (AST: Abstract Syntax Tree)**を用いた高度なコンテキスト把握や、言語サーバプロトコル (LSP) の活用によるシンボル解決など、構文解析技術を巧みに組み合わせている (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。本稿では、Continueにおける構文解析の実装詳細に焦点を当て、どのように複数言語に対応しているか、各言語ごとにどのような手法(パーサー、AST解析、トークナイザなど)を用いているかを詳述する。さらに、Continue全体のアーキテクチャにおいて構文解析が果たす役割を、コード補完、シンボルジャンプ(定義への移動)、コード説明生成、リファクタリング支援といった機能別に整理し、利用されている構成要素や外部ライブラリについても明らかにする。最後に、これらの実装がシステムにもたらす効果や課題について評価・考察し、結論を述べる。

関連研究 (Related Work)

ソースコードの構文解析と多言語対応は、長年にわたり統合開発環境 (IDE) やプログラミング言語処理系で研究されてきた分野である。従来のIDEでは各言語ごとに構文解析器(パーサー)やAST構築ツールが組み込まれ、シンタックスハイライトやコード補完、リファクタリングなどを実現してきた (Mastering Code Refactoring with Abstract Syntax Trees | by ...) (AST-based refactoring with ts-morph - kimmo.blog)。しかし、AIを活用したコードアシスタントでは、より汎用的かつ軽量なパーサーが求められる。GitHub Copilotなど商用のコード補完システムでは、主に周辺のテキストを文脈として大規模言語モデルに供給する戦略が取られており (AI Code Assistant Internals. I am working on two serials of… | by Wei Lu | Medium)、明示的なAST解析を行っているかは公開されていない。一方、近年のオープンソースプロジェクト(たとえばSourcegraphのCodyやCursor、Aider等)では、汎用的な構文解析ライブラリであるTree-sitterの活用が注目されている。Tree-sitterはGitHub開発の高速なインクリメンタル構文解析ライブラリで、多数の言語の文法が既に用意されており、エディタ組み込みの構文解析に広く使われ始めている (Using Parsers - Tree-sitter) (Show HN: Continue.dev releases local, open-source tab-autocomplete)。実際、Aiderという別のオープンソースAIコーディングツールでは「Tree-sitter統合とLLMに優しいソースマップ」を特徴としており、ASTを用いたコード理解を強調している (Continue.dev: The Swiss Army Knife That Sometimes Fails to Cut)。Continueも同様にTree-sitterを基盤としており、さらに言語サーバプロトコル (LSP) を組み合わせることで、コード構造とシンボル情報を効率よく取得・活用している (Root path context: The secret ingredient in Continue's autocomplete prompt)。こうしたアプローチはRetrieval-Augmented Generation (RAG) (AI Code Assistant Internals. I am working on two serials of… | by Wei Lu | Medium)にも通じ、コード検索と生成を統合する最新のAI補助開発環境のトレンドと言える。本稿で取り ele上げるContinueの構文解析モジュールは、これら関連技術を組み合わせた具体例として位置づけられ、複数言語対応やAST活用の先進的手法を示すものである。

システム設計 (System Design)

Continueは、エディタ拡張(VS Code拡張およびJetBrainsプラグイン)とバックエンドサーバから構成されるハイブリッドアーキテクチャを採用している (ram - Why does the Continue VS Code extension continue to run in the background even after closing VS Code? - Stack Overflow)。エディタ拡張はユーザーからの入力(コードや自然言語での指示)を収集し、必要に応じてバックエンドのContinueサーバに処理を委譲する。バックエンドサーバはローカルで動作するPythonベースのサービスで、コードベースのインデックス作成、プロンプト(LLMへの入力文脈)の構築、ユーザー設定の保存などを担当する (ram - Why does the Continue VS Code extension continue to run in the background even after closing VS Code? - Stack Overflow)。このサーバは高速な起動と応答性を維持するために、IDEを閉じた後もバックグラウンドで稼働し続け、ユーザーの作業を継続的にサポートできるよう設計されている (ram - Why does the Continue VS Code extension continue to run in the background even after closing VS Code? - Stack Overflow)。さらに、検索インデックスにはMeiliSearch(後にはLanceDBなどのベクトルデータベース)を組み合わせ、コード検索や類似度検索による文脈取得を行っている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。

システム内で構文解析が果たす役割は大きく三つに分けられる:(1)コード自動補完 (Autocomplete)、(2)コード検索・文脈抽出 (Codebase Indexing & Context Retrieval)、(3)高度なコード編集・リファクタリング支援である。まず(1)自動補完において、Continueはユーザーのカーソル位置周辺のコードを解析し、AST上での位置情報を用いて適切な補完候補を生成する。特にContinue独自の「ルートパス・コンテキスト (root path context)」という手法では、カーソル位置の構文木上の親ノードを根 (root) まで辿ったパス上の情報をすべて収集することで、局所的だが関連性の高いコンテキストをLLMに与えている (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。このときASTから取得した型定義やクラス名、関数シグネチャなどの情報は、わずかなトークンでコード全体の構造を示すヒントとなり、モデルが正確な補完を生成する助けとなる (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。一方(2)のコードベース検索・文脈抽出では、プロジェクト中のファイルをあらかじめ解析・分割(チャンク化)してインデックス化する際に構文解析が活用される。Continueのチャンク生成はASTに基づくセクション分割により行われ、例えば「ファイル全体が長すぎる場合、各トップレベルの関数やクラス単位で分割し、それでも長ければメソッド内部をトランケートする」といった戦略が採られている (What are the accuracy limits of codebase retrieval?)。この手法により、意味的に完結したコード片(クラス定義や関数単位)を文脈として扱うことができ、LLMへの入力長を抑えつつ必要十分な情報を提供できる (What are the accuracy limits of codebase retrieval?)。最後に(3)のコード編集・リファクタリング支援では、ユーザーが「特定の変数名の一括変更」や「関数の抽出」といった指示を与えた場合に、Continueは構文解析によってコード構造を理解し、該当箇所の特定や変更内容の検証に利用すると考えられる。例えばRenameリファクタリングであれば、ASTを traversing することで変数の宣言と使用箇所を正確に把握できるし、関数抽出ではAST上のサブツリーを抜き出して新たな関数定義として再構築することが理論上可能である (Mastering Code Refactoring with Abstract Syntax Trees | by ...) (AST-based refactoring with ts-morph - kimmo.blog)。もっとも、現在のContinueは主にLLMを用いた対話的な変更提案とそれに対する**差分適用 (diff)**によってコード編集を行っており、ASTを直接書き換えてプログラム変換を行う機能は限定的かもしれない。しかし、後述する構文解析モジュールによりASTレベルでコードを理解できていることは、生成された編集内容(コード差分)が妥当かどうかを検証したり、LSPを用いてシンボルの整合性をチェックしたりする際に役立っていると推測される。以上のように、Continueのシステム設計ではバックエンドサーバ上で構文解析を駆使し、コード補完や検索、編集といった各機能に密接に統合することで、多言語・大規模コードベース上でも高精度かつ高速な支援を実現している。

構文解析モジュールの実装 (Implementation of the Syntax Parsing Module)

Continueの構文解析モジュールは、Tree-sitterを中心に据えて実装されている (Root path context: The secret ingredient in Continue's autocomplete prompt)。Tree-sitterは多言語対応の汎用パーサージェネレータ/ライブラリで、各言語の文法(grammar)定義から高速なインクリメンタル構文解析器を生成できる (Using Parsers - Tree-sitter)。Continueでは、このTree-sitterを組み込むことで統一的なAST構築を行っている。具体的には、Node.js環境で動作する**web-tree-sitterというnpmライブラリを用いてTree-sitterのWASM版パーサを初期化し、ファイルごとに適切な言語グラマーをロードしてパース処理を行っている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub) (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。言語ごとのパーサは、tree-sitter-wasmsというパッケージで事前ビルドされたWASMバイナリ群としてバンドルされており(例: tree-sitter-vue.wasmなど)、それらをLazy Load**して利用する実装になっている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。ContinueのコードベースにはgetParserForFileという関数があり、ファイルパス(拡張子等)から対応する言語のTree-sitterパーサを取得できるようになっている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。この関数は内部で該当言語のWASMパーサをロードし、Parser.Languageオブジェクトを生成してから、そのファイル内容のパースを行う。なお、もし対応する言語のパーサが未ロードの場合は初回にParser.init()で初期化を行い、WASMファイルをローカルディスク(.continueディレクトリ配下やnode_modules経由)からロードする (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。これにより、任意のプログラミング言語のソースコードに対してASTを構築する基盤が整えられている (What are the accuracy limits of codebase retrieval?)。

一度ASTが得られれば、Continueはその解析結果を様々な用途に活用する。特に重要なのは前述した「ルートパス・コンテキスト」機能の実現である (Root path context: The secret ingredient in Continue's autocomplete prompt)。その処理手順を整理すると以下のようになる (Root path context: The secret ingredient in Continue's autocomplete prompt):

  1. ASTの構築: 対象ファイルをTree-sitterでパースしASTを取得する(既にパース済みでキャッシュがあれば再利用)。 (Root path context: The secret ingredient in Continue's autocomplete prompt)

  2. カーソル位置のノード特定: ユーザーのカーソル位置(または補完を挿入したい位置)に対応するAST上の葉ノード(もしくは直近の下位ノード)を特定する。

  3. ルートパスの抽出: 上記ノードから親方向へ木を遡り、最上位のルートノード(通常ファイル単位)に至るまでの全てのノードを順次収集する (Root path context: The secret ingredient in Continue's autocomplete prompt)。この一連のノード列が「ルートパス」であり、現在位置がどのクラス内のどの関数内か、といった文脈の階層情報を表す(図1参照)。

  4. 重要ノードの付加情報取得: ルートパス上の各ノードに対して、その内部に含まれる重要要素を抽出する。具体的には、関数やクラス定義ノードであればパラメータの型注釈クラスのメンバ変数、ファイルルートであればインポート文型定義などが該当する (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。ContinueではTree-sitterのクエリ機能を用いて、言語ごとに「重要なサブノード」を探すパターンを定義し(例えばTypeScriptなら「関数定義内のパラメータの型」パターン)、それにマッチするコード片のAST位置を取得している (Root path context: The secret ingredient in Continue's autocomplete prompt)。

  5. シンボル定義の解決: 上記で見つけた型名やクラス名・変数名など、他の場所で定義されているシンボルについては、LSPを利用して定義箇所へジャンプし、その内容(定義文)を取得する (Root path context: The secret ingredient in Continue's autocomplete prompt)。例えば図1の例では、sayHappyBirthdayメソッドのパラメータcapitalizationTypeの型定義元をLSPで開き、AST経由で取得したCapitalizationTypeの定義文をコンテキストに含めている (Root path context: The secret ingredient in Continue's autocomplete prompt)。この処理により、現在編集中の箇所と密接に関係する型・関数・変数の実体情報がすべて揃い、モデルへの入力コンテキストが完成する。

(Root path context: The secret ingredient in Continue's autocomplete prompt)図1: AST上のカーソル位置からルートまでのパス(赤線部)に含まれる情報を収集する仕組み (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。この例では、ファイルPerson.ts内のPersonクラスのsayHappyBirthdayメソッド内部がカーソル位置である。赤線で示されたルートパス上の各ノード(ファイル、クラスPerson、メソッドsayHappyBirthday)およびそれらに関連する型CapitalizationTypeの定義を取得することで、補完に必要な文脈が得られる。

上記の実装におけるポイントは、Tree-sitterによる構文解析とLSPによるシンボル解決を組み合わせた点にある (Root path context: The secret ingredient in Continue's autocomplete prompt)。ASTから直接得られる情報(例えば親クラス名や関数シグネチャ)は、その場のコード片を超えて広範なコンテキストを示唆する。一方、ASTだけでは他ファイルに定義された型や関数の中身は不明なため、既存の言語サーバ(例: TypeScriptならtsserver、Pythonならpyright等)に問い合わせて定義場所を開き、その内容を取得している (Root path context: The secret ingredient in Continue's autocomplete prompt)。この「AST → LSP → 定義取得」という流れにより、AIモデルに与えるプロンプトには局所ASTコンテキスト + 関連シンボルの定義という構造化された情報が含まれることになる。これは従来の単純なテキスト近傍のコンテキストよりも高い関連性を持ち、結果として正確なコード自動生成・補完が可能となる (Root path context: The secret ingredient in Continue's autocomplete prompt)。

もっとも、言語サーバ(LSP)のレスポンス速度や質は各言語の実装に依存するため、Continueではパフォーマンス改善の工夫も行われている。一度取得した定義情報はキャッシュされ、同じASTノードに対する問い合わせを繰り返さないようにしている (Root path context: The secret ingredient in Continue's autocomplete prompt)。例えば、図1の場面で一度CapitalizationTypeの定義を取得したら、その後しばらくは再利用し、別の場所の編集で必要になるまでは改めて問い合わせない。これにより、入力毎にLSPに問い合わせるオーバーヘッドを削減しつつ、ユーザーがファイル内を移動しても大部分の文脈取得が高速に行えるようになっている (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。また、ASTパスに沿ったコンテキストは、プロンプト中で常に同じ順序(大域的な親→子の順)で並ぶため、LLM側でもキャッシュ(例えばトランスフォーマーのKVキャッシュやサーバ側のプロンプトキャッシュ)を活用しやすいという利点もある (Root path context: The secret ingredient in Continue's autocomplete prompt)。以上が、Continueの構文解析モジュールの内部実装とその工夫の概要である。

多言語対応 (Support for Multiple Programming Languages)

Continueは設計上「任意のプログラミング言語を扱える」ことを目指しており (Continue: AI-Powered Code Assistant for Development - Expify)、実際にAST解析基盤は言語非依存のTree-sitterで実装されている。しかし、現実には言語ごとの構文規則や利用シーンの違いがあるため、Continueではまず主要な5言語程度を優先サポートし、それ以外の言語にも徐々に対応を広げていく方針が取られている (Root path context: The secret ingredient in Continue's autocomplete prompt)。2024年9月時点の公式ブログによれば、「最も一般的な5つの言語から数十の言語へとサポートを拡大中」と述べられている (Root path context: The secret ingredient in Continue's autocomplete prompt)。具体的に「5つの言語」が指すものは明示されていないが、推測するにPython、JavaScript/TypeScript、Java、C#、そしてHTML/JSX/Vueなどのフロントエンド言語が含まれていたと考えられる。事実、ContinueのIssueにはVueファイル(.vue拡張子)に対するパーサ読み込みエラーの報告があり、開発者が「我々がTree-sitter用に使用しているVueパーサーに問題があるようだ」とコメントしている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。これはContinueが.vue用の文法(HTMLテンプレート+Scriptの複合言語)にも対応しようとしている証左である。また、他の報告ではC#コード(.csファイル)に対するパーサ読み込み失敗も言及されており (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub) (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)、C#用のASTパーサ(例えばtree-sitter-c-sharp)の組み込みに何らかの問題が生じていることが示唆されている。これらから、Continueは現時点で**Python、JavaScript、TypeScript、Vue(もしくは汎用のHTML/テンプレート言語)、C#**などをサポート対象として含めており、さらに順次サポート言語を拡大していると考えられる。Tree-sitterには既にGoやRuby、PHP、C/C++など多様な言語の文法定義が公開されているため、Continueがそれらを取り込むことも技術的には可能である。実装面では、新たな言語を追加する際に対応するWASMパーサをtree-sitter-wasmsパッケージ経由で入手し、getParserForFileに拡張子マッピングを加え、さらにASTクエリ(前述の重要サブノード抽出のパターン)を定義すればよい (Root path context: The secret ingredient in Continue's autocomplete prompt)。もっとも、各言語に適したASTクエリを書くにはその言語特有のAST構造への知識が必要となる。Continue開発チームも「Tree-sitterのクエリは各言語ごとに手作業で記述する必要があり、我々は現在それを5言語から数十言語へと拡大している」と述べており (Root path context: The secret ingredient in Continue's autocomplete prompt)、多言語対応には着実な拡張作業が伴うことがわかる。

複数言語への対応に際して課題となるのが、言語間で異なる構文要素や命名規則への対処である。例えば、静的型付け言語(JavaやC#)ではクラスやメソッドに明示的な型情報が多く含まれるが、動的言語(PythonやJavaScript)では型は文脈から推論するしかない。そのため、ASTクエリで「重要サブノード」を抽出する際も、TypeScriptでは関数パラメータの型注釈ノードを探すが、Pythonでは関数のdocstringやコメントに型ヒントが書かれていれば抽出するといった差別化が必要になるかもしれない。また、Go言語ではインポート文や構造体定義、Rubyではモジュールやシンボルテーブルの扱いなど、言語ごとに「コード理解の鍵」となる要素が異なる。Continueは現状、汎用的には「クラス・関数定義」「型定義(typeやinterface)」「インポート/using文」「変数宣言」などを中心にASTクエリで拾っていると推測される。Blog記事の例ではTypeScript/JavaScriptが中心に説明されているが (Root path context: The secret ingredient in Continue's autocomplete prompt)、Pythonの場合はクラスの属性や関数の引数名程度しか静的情報がないため、今後の課題として静的解析に頼らない別手法(例えば埋め込みベクトル検索との併用)が補完的に用いられる可能性もある。実際、Continueではコードベース全体に対するベクトル検索もサポートしており (Codebase - continue.dev docs)、ASTに基づく絞り込みとembeddingによる類似検索を組み合わせて包括的なコンテキスト取得を目指している (What are the accuracy limits of codebase retrieval? - Continue Blog)。

また、埋め込み言語 (embedded languages) への対応も重要な観点である。前述の.vueファイルはその典型例で、HTMLテンプレート内にJavaScript/TypeScriptが埋め込まれる形になる。Tree-sitterは文法のインジェクションに対応しており、一つのファイル内で異なる構文ルールを適用できる (Querying an embedded language with tree-sitter : r/neovim - Reddit)。ContinueでもVue用パーサを導入することで、テンプレート部分とスクリプト部分を適切に解析できるようにしている。しかしIssueから推察するに、その統合にはまだ不具合も残っている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub) (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。例えば、VueファイルのASTを処理する際に一部のノードが期待通り取得できずエラーとなるケースが報告されている (Unable to load language for file · Issue #1462 · continuedev/continue · GitHub)。こうした埋め込み言語の扱いは非常に難しい問題で、AST上で複数言語のノードが混在するためクエリ記述も複雑になる。Continueはこれに対し、Tree-sitterコミュニティ提供の既存文法を活用しつつ、場合によっては独自にフォーク・修正(例えばSourcegraphが独自ビルドしたtree-sitter-wasm集を利用)するなどして対応している (Prebuilt WASM binaries for tree-sitter's language parsers. - GitHub)。

以上より、Continueの多言語処理は基本方針として「できるだけ統一的に(Tree-sitterで)解析し、言語固有部分はASTクエリとLSPに委ねる」という戦略を取っていると言える。すなわち、言語ごとに全く異なるパーサーを実装するのではなく、Tree-sitterという共通基盤を使うことで解析処理の大部分を共通化しつつ、不足する部分だけを各言語のLSPや専用クエリで補完する設計である (Root path context: The secret ingredient in Continue's autocomplete prompt)。このアプローチにより、既存言語のサポート強化も新言語の追加も比較的容易になっており、実際「数十の言語」への拡大が現実的に見通せるようになっている (Root path context: The secret ingredient in Continue's autocomplete prompt)。多言語を扱うAIコード支援ツールとして、Continueは洗練された構文解析レイヤーによって柔軟性と拡張性を両立している。

評価 (Evaluation)

Continueにおける構文解析活用の効果は、ユーザーの体験や内部ベンチマークを通じて徐々に明らかになっている。まずコード補完の質に関して、AST駆動のコンテキスト取得(ルートパス・コンテキスト)の導入によって、モデルがより的確な補完提案を行えるケースが増えていると報告されている (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。定量評価としては、補完結果の正確性や編集の削減率などを測る必要があるが、Continue開発チームはまだ大規模なベンチマーク結果を公開していない。ただし定性的には、型情報や親クラス情報が与えられることで補完の一貫性が上がったこと、また関連のない巨大なコンテキストを切り捨てることで応答速度が高速(100ミリ秒台)に収まっていることが確認されている (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。特に「ファイル全体の内容ではなく、本当に必要な周辺構造だけを抜き出す」という戦略は、従来の埋め込みベクトル検索などより精度・速度の面で有利であったとされる (Root path context: The secret ingredient in Continue's autocomplete prompt)。

一方、コードベース検索(RAG文脈抽出)の精度向上にも構文解析は貢献している。Continueではコード検索精度を測るために$F_1$スコア(関連するファイルをいかに漏れなく含めつつ不要なものを除外できたか)を指標に内部テストを行っている (What are the accuracy limits of codebase retrieval?) (What are the accuracy limits of codebase retrieval?)。ファイル分割戦略として「ASTに基づくチャンク化」を採用したところ、単純な等長分割よりも適合率・再現率双方で優れる結果が得られたという (What are the accuracy limits of codebase retrieval?)。具体的には、大きすぎるファイルを関数・クラス単位に分割し、必要に応じて中身を省略する方法は、重要な定義を文脈から漏らしにくく、それでいてチャットモデルのコンテキスト長制限内に収めることができた (What are the accuracy limits of codebase retrieval?)。例えばPythonプロジェクトの検索では、クラス定義とメソッドシグネチャだけをチャンクに含め、メソッド内部は “...” で省略することで、クラスの全容を掴みやすくした上で詳細実装は除外する、といった調整が可能になる (What are the accuracy limits of codebase retrieval?)。これにより、ユーザーが「あるクラスの使い方を知りたい」と質問した場合などに、関連するチャンクのみが高精度に抽出され、余計なノイズが減る効果が出ている。

性能面では、Tree-sitter自体がインクリメンタルパーサーであるため、ユーザーが編集を進める間リアルタイムにASTを更新し続けても十分な高速性がある。上記ASTコンテキスト取得+LSP解決のパイプラインも、キャッシュ戦略 (Root path context: The secret ingredient in Continue's autocomplete prompt)や遅延ロード戦略によって、体感的には遅延を感じさせないよう工夫されている。実際、ContinueのTab補完は入力のたびに数百ms程度で返答を生成できており、その中で構文解析やシンボル解決に費やす時間はごく僅かである (Root path context: The secret ingredient in Continue's autocomplete prompt)。これらはバックエンドサーバを常駐させている恩恵も大きい。すなわち、一度プロジェクトを開いたら、AST解析結果やインデックスはメモリ上(あるいはローカルDB上)に保持しておき、次回以降すばやく利用できる。Stack Overflowでの開発者コメントにも「素早いスタートアップのためバックグラウンドでサーバを走らせている」とある通り (ram - Why does the Continue VS Code extension continue to run in the background even after closing VS Code? - Stack Overflow)、ユーザーが意識しない所で解析結果を使い回す設計となっている。

もっとも、いくつか課題も指摘されている。先述のVueやC#の例のように、言語追加時の不安定性が一部で報告されている。WASMパーサの読み込み失敗はユーザから見ると「特定ファイルだけ常に補完が働かない/エラーが出る」という現象につながるため、今後対応が必要だろう。また、LSPへの依存については、「言語によってパフォーマンス差が大きい」「大型プロジェクトでは応答が遅い」等の問題が考えられる (Root path context: The secret ingredient in Continue's autocomplete prompt)。Continueチーム自身、LSPの実装は言語ごとに開発元も異なり性能も様々で、一括で制御しづらい点を認識している (Root path context: The secret ingredient in Continue's autocomplete prompt)。このため「可能ならLSPに頼らず、すべてASTと自前の解析で完結したい」というジレンマもある。現状はタイプ定義などでどうしても必要な箇所だけLSPに任せ、それ以外はASTとテキストから取れる範囲でカバーするバランスを取っているものの、将来的なチューニング余地は残る。

考察 (Discussion)

Continueの構文解析戦略について、さらに広い視点で考察する。まず、Tree-sitterの採用メリットは極めて大きかったと言える。専用に各言語のパーサを書くことなく、既存の文法定義を利用して短期間で多言語のAST解析を実現できている (Root path context: The secret ingredient in Continue's autocomplete prompt)。加えて、Tree-sitterの持つクエリ言語により、AST上の特定パターン(例: 関数の引数の型ノード)を容易に検索できるため、Continue独自の「重要ノード抽出」ロジックもシンプルに書けている (Root path context: The secret ingredient in Continue's autocomplete prompt)。もっとも、クエリを書くには各言語の文法定義に登場するノード名を把握する必要があり、サポート言語が増えるほど保守コストも上がる。これは開発チームも認識している課題で、実際に「各言語ごとにクエリを手作業で増やしている」と述べている (Root path context: The secret ingredient in Continue's autocomplete prompt)。しかし裏を返せば、ASTクエリで抽出すべき情報の種類は限定的とも言える。つまり、「どの言語であれ、必要なのはクラス名・関数シグネチャ・型定義・インポート等であり、それ以外の細部(関数内部の実装細節など)はLLMによる補完には不要」と割り切っている点が重要だ。この設計ポリシーにより、多少言語が違っても共通して取得すべき要素が見極めやすく、結果として限定的なクエリセットですべての言語をカバーできる見込みが立っている。

次に、ASTとLLMの統合という観点では、Continueのアプローチは一つの模範となっている。ASTは従来コンパイラや静的解析ツールの領域で用いられてきたが、それを大規模言語モデル(LLM)へのコンテキスト圧縮手段として活用した点は新しい (Root path context: The secret ingredient in Continue's autocomplete prompt)。人間の開発者であれば、あるコード片を理解する際にまず「このコードはどのクラスのどの関数の中にあるか?」を確認し、必要に応じてそのクラスのプロパティ定義や関連する型定義を参照する。ContinueのASTルートパス手法 (Root path context: The secret ingredient in Continue's autocomplete prompt)は、まさにこの人間の思考プロセスを機械的に再現したものであり、AIにとって無駄な情報を省いて本質的な手がかりを与えていると言える (Root path context: The secret ingredient in Continue's autocomplete prompt)。さらにユニークなのは、そこで得た構造情報を**逐次的(階層順)**にプロンプトに並べることで、LLMの注意メカニズムに配慮している点である (Root path context: The secret ingredient in Continue's autocomplete prompt)。ASTの上位から下位へ情報を並べると、プロンプトの冒頭部分(AST上位)はユーザーがどの文脈にいるかを示し、後半部分(AST下位)は詳細な値や型を示す流れになる。これによりモデルは文章(コード)構造を自然に理解しやすくなり、不要な試行錯誤を減らせるだろう。これらの工夫は、単に「関連しそうなテキストをembeddingで検索して詰め込む」といった安易なRAG手法よりも、人間のプログラマの行動に近く、結果的にモデルの振る舞いも安定する可能性が高い。実際、Continueの補完結果について一部ユーザからは「Copilotに比べて文脈をよく理解している」との評価も見られる (Continue.dev: The Swiss Army Knife That Sometimes Fails to Cut)。無論、これがすべてASTのおかげとは断言できないが、構文的文脈を与える意義は十分示されたと考えられる。

考察すべき課題としては、ASTに現れない情報の扱いがある。ASTはプログラムの構文構造を表すが、コーディング支援にはそれ以外にも、たとえば変数や関数の意味論的関係、過去の編集履歴、実行時の動的挙動なども考慮できると有用である。Continueでは意味論的関係についてはLSP(型解決)でかなりカバーしているが、実行時情報や歴史的変更意図などは扱っていない。しかし、将来的にLLMがさらに高度化すれば、AST+静的解析の情報に加え、テスト結果や実行トレースを反映したコンテキストまで含める余地もあるだろう。もっとも、そこまで行くとAIアシスタントというより自動デバッガの領域となるため、本稿の範囲を超える。

最後に、Continueのようなシステムが示す方向性として、開発者ツールのオープン化と拡張性が挙げられる。Continueはオープンソースであり、誰でもその内部実装(AST解析部分も含め)を検証・改善できる (GitHub - continuedev/continue: ⏩ Create, share, and use custom AI code assistants with our open-source IDE extensions and hub of models, rules, prompts, docs, and other building blocks)。例えば、ある言語のサポートが不十分であればコミュニティがTree-sitter文法やASTクエリを拡張しプルリクエストを送ることも可能だ。このように、AIコードアシスタントの基盤部分を公開していることは、様々な言語やフレームワークへの対応を加速させる上で有効である。Copilotのようなクローズドな製品では得られない透明性と柔軟性が、Continueには備わっている。今後、より多くの開発者がContinueの構文解析基盤を活用し、自分たちのプロジェクト固有のルール(例えば社内コーディング規約をASTクエリに反映してコンテキスト抽出するといった応用)を組み込んでいくことで、AI開発支援ツールは一層パーソナライズされた強力なものとなっていくだろう。

(Root path context: The secret ingredient in Continue's autocomplete prompt)図2: ASTパスのキャッシュ利用イメージ。緑色が既に取得済みでキャッシュから再利用できる文脈、赤色が新たに取得する必要がある部分を示す (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。一度取得した上位ノード(例えばクラスPersonやファイルスコープの情報)は次の補完要求でもそのまま使えるため、新規に取得すべきは変更のあった下位ノード(例:celebrateBirthdayメソッド)周辺のみになる。これにより多数のノードにまたがる文脈でも効率よく再利用が可能である。

結論 (Conclusion)

本稿では、オープンソースAIコードアシスタントContinueにおける構文解析の実装と役割について、査読論文スタイルで詳述した。ContinueはTree-sitterによるAST解析とLSPによるシンボル解決を組み合わせ、複数のプログラミング言語に対応した統一的なコード理解基盤を構築している (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。この基盤により、コード補完ではカーソル位置からルートまでのASTパス上の情報を網羅的に収集し、型定義やクラス構造を含む高度な文脈をモデルに提供することが可能となった (Root path context: The secret ingredient in Continue's autocomplete prompt) (Root path context: The secret ingredient in Continue's autocomplete prompt)。また、コードベース全体のインデックス化においてもASTを用いたチャンク分割戦略を採用することで、関連部分のみを効率よく抜き出しLLMに与える工夫がなされている (What are the accuracy limits of codebase retrieval?)。複数言語対応については、共通の解析エンジン(Tree-sitter)上に言語固有のクエリを追加する形で拡張性を確保しており、当初サポートされた5言語からさらに多くの言語へと支援範囲が広がっている (Root path context: The secret ingredient in Continue's autocomplete prompt)。実装には一部課題も残るものの、ASTとAIを統合したContinueのアーキテクチャは、精度向上と応答性向上の両面で成果を上げつつある。

今後の展望として、Continueはさらなる言語サポートの充実と、AST解析結果の活用範囲拡大が考えられる。例えばより高度なリファクタリング操作を安全に自動化するには、ASTの差分比較や変更検証を行うモジュールを発展させる必要がある。また、解析結果のキャッシュ無効化(古い型定義の破棄など)や、巨大プロジェクトでのスケーラビリティ確保も引き続き重要な課題となる (Root path context: The secret ingredient in Continue's autocomplete prompt)。しかし、Continueが示した「構文解析を駆使したAIコード支援」のアプローチは、開発者の直観的なコード把握プロセスをモデルに活用する先進的な例であり、今後のAI搭載IDEの一つの標準形になる可能性を秘めている。オープンソースコミュニティの貢献も得ながら、Continueは多言語・多機能に対応するAI開発アシスタントとして進化を続けていくだろう。各種ライブラリ(Tree-sitter (Root path context: The secret ingredient in Continue's autocomplete prompt)、web-tree-sitter、言語ごとのLSPなど)に支えられたContinueの構文解析基盤は、コード理解と生成の橋渡し役としてますます重要となり、その知見は他のツールや将来の研究にも大いに参考になると考えられる。

参考文献(一部抜粋):

いいなと思ったら応援しよう!