検索の入口が変わると、コードの探し方も変わります

「認証トークンを更新する処理はどこか」と探すとき、関数名や実装中の語が分からないことがあります。grep(ファイル内の文字列を検索するコマンド)では、検索語を先に推測する必要があります。意味検索なら、問い合わせとコードに共通の語がなくても候補を探せます。[1]

その仕組みの一つがRAG(検索拡張生成)です。検索で関連する箇所を取り出し、必要に応じて生成AIへ渡します。検索対象を分けた単位がチャンクで、埋め込みは、文章やコードを数値の並び(ベクトル)に変換する処理です。埋め込みモデルは、意味の近い内容が近いベクトルになるよう学習されています。[1]

検索システムは、検索に使うベクトルなどをまとめた索引を作り、問い合わせから候補を探します。相対パスは、ここではリポジトリ内のファイル位置を示す文字列です。[1]

構文に沿う分割は文脈を保ちますが、対応範囲に限りがあります

ファイル全体を一つのチャンクにする方式では、必要な箇所がファイルの一部でも、残りの内容も同じチャンクに含まれます。固定行数で切ると、関数の途中で分断したり、関係の薄いコードを同じチャンクへ入れたりします。

AST(抽象構文木)は、ソースコードを文法上の構造に沿って木の形で表したものです。JetBrainsの開発ブログは、構文ノードの種類や大きさ、子要素を見て分割範囲を決める方法を説明しています。[1]

分割方法検索単位の特徴主な制約
ファイル丸ごとファイルの情報を一括で含みます一部だけ必要な場合も、ファイル全体を含みます
固定行数行数で同じ大きさに区切ります関数を切ったり、無関係なコードを混ぜたりします
構文に沿う分割収まる大きな構文単位を使い、長い単位は再分割し、小さな隣接単位をまとめます構文解析に対応しない言語では行単位へ切り替わります

この分割方法は、説明用コメントや注釈を宣言と一緒に保ちます。可視性修飾子(publicやprivateなど、宣言の公開範囲を示す指定)やキーワードも対象です。JetBrainsの実装では、大きすぎて子要素のない構文単位を、より単純な方法で分けます。構文木は文法上の構造を示すもので、実行時の振る舞いまで保証するものではありません。[1]

開発ブログで示された実装では、構文解析と構造に沿った分割に9言語が対応しています。対象はKotlin、Java、Python、JavaScript、TypeScript、C#、PHP、Go、Rustです。JetBrainsの実装は、それ以外の言語や文書を行単位で分割します。[1]

独立した研究であるcASTも、収まる構文単位を保ち、長すぎる単位を分け、小さな隣接単位をまとめる方法を論じています。これは構文分割に関する研究例です。JetBrainsの実装がcASTを採用したことを示すものではありません。[2]

埋め込みと索引の作り方は、送信先と保存条件にも関わります

Air Contextの開発ブログにある構成

JetBrainsの開発ブログでは、索引作成と検索に同じ埋め込みモデルを使います。コードチャンクにはファイルの相対パスを添えて埋め込み、自然文の検索文には検索タスクを示す指示を加えます。[1]

開発ブログによると、Air ContextではJetBrainsが運用するGPU(並列計算用プロセッサ)上で埋め込みモデルを動かします。モデルの重み(学習で調整される数値)が公開されたopen-weightモデルを使います。

JetBrainsは、埋め込み要求を第三者のサービスへ送らず、コード本文のコピーをシステムに保存しないと説明しています。[1]

Context CLIのEAP規約が許諾・制限する範囲

JetBrains Context CLIは、コマンドを文字で入力して操作する製品です。CLIは、コマンドラインインタフェースの略称です。早期アクセスプログラム(EAP)の利用規約も確認する必要があります。本稿では、2026年7月15日発効のVersion 1.0を確認しました。発効日は、開発ブログの公開日とは別です。[3]

規約5.1では、入力や出力に加え、リポジトリ、設定情報、インフラ状態、運用メタデータ(運用状況に関する付帯情報)をEAP Dataと定義します。[3]

5.2では、端末上で解析したEAP DataをJetBrainsのクラウドへ送信することを、ユーザが許諾します。生成したベクトル索引をクラウドデータベースに継続して保持することも許諾します。[3]

規約5.3は、ローカル解析と索引生成後、元のソースコードのテキストを永続的なクラウド保存から除外すると定めています。5.4では、JetBrains Contextで処理したEAP Data、索引、関連する意味検索クエリを生成AIモデルの学習などに使わないとしています。[3]

非保存は、送信しないことを意味しません。この条項から、別接続先のLLM(大規模言語モデル)の取り扱いや、完全なオフライン利用を推測することもできません。[3]

1bit化は容量を抑えますが、関連度判定には限界があります

量子化は、数値をより少ないbitで表す処理です。JetBrainsは、ベクトルの成分数を示す次元数を保ったまま、全成分を1bitにすると説明しています。数値の表し方である32bit浮動小数点形式のベクトルと比べ、記憶量は32分の1になります。1bit化では正負の符号だけを残し、値の大きさを捨てます。このように正負の2つの状態で表す方式を、二値量子化と呼びます。[1]

次の表は、一般的な容量計算例です。float32は32bit浮動小数点形式、1 byteは8bitです。ベクトル本体だけを数えており、索引全体の容量や製品の設定値を示すものではありません。

ベクトルの例本体の容量計算
4096成分・float3216,384 byte4096 × 32bit ÷ 8
4096成分・1bit512 byte4096 × 1bit ÷ 8
128成分・float32512 byte128 × 32bit ÷ 8

表の例では、次元数を減らすことと、成分あたりのbit数を減らすことは別の選択です。1bit化による32倍は同じ次元数のベクトル本体についての比率です。索引全体、処理時間、運用費が32分の1になることや、精度が変わらないことは保証しません。JetBrainsは関連度の絶対判定にfloat16(16bit浮動小数点形式)のベクトルを保持すると説明しています。[1]

符号だけを残したベクトル同士は、異なるbit位置の個数であるHamming距離で比較します。JetBrainsは、二値量子化で再現率、つまり関連する結果を検索で拾える割合が下がり得るとしています。候補の相対順位を付ける用途と、スコアの閾値(判定の境目となる値)で絶対的な関連度を判定する用途は分けて考える必要があります。[1]

Qdrantの公式文書は、二値量子化が高次元ベクトルに向き、値の分布が中心化されていること(0付近を中心に広がること)を条件として挙げています。次元数が小さい場合や分布が異なる場合は、適切な設定の検討が必要です。これはQdrantによる一般的な説明で、JetBrainsの採用方式を示すものではありません。[4]

Qdrantでは、量子化した索引から最終表示数より多く候補を取り、元ベクトルで再スコアする方法も説明されています。元ベクトルを保持し、候補の再評価に使います。Qdrantは、元ベクトルがディスク上にある場合、再スコアで検索速度が下がることがあると説明しています。[4]

実務では、検索候補から元コードとテストへ進みます

既知の識別子(変数や関数などの名前)を探すなら、まず文字列検索で候補を絞れます。名前が分からず目的から探したい場合は、意味検索を試し、返された候補から識別子や参照先を調べる使い方が考えられます。これは検索の性質に基づく使い分けの提案で、速度や精度の改善を測定した結果ではありません。

LSP(Language Server Protocol)は、エディタとコード解析機能をつなぐ通信規約です。検索道具の選び方については、GrepとLSPの使い分けを扱った記事も参照してください。

検索結果は、問い合わせに関連する候補を見つける手掛かりです。開発者は、候補の順位や関連度だけでは、変更したコードが正しいとは判断できません。実務では、候補から元コードを読み、参照先やテストも確認してください。

導入時は、自分のリポジトリで問いを用意し、必要なコードが候補に入るか確かめることが判断材料になります。対象言語の分割方式、圧縮後の順位や閾値判定の制約、クラウドへの送信・保存条件も併せて確認してください。