大規模コードベースの安全なインデックス化
チームメイトの既存インデックスを安全に再利用することで、最大規模のリポジトリでも初回クエリ時間を数時間から数秒に短縮。
キーポイント
セマンティック検索がAIエージェントのコード生成精度を平均12.5%向上させ、コード変更の定着率とユーザー満足度を高める
大規模コードベースのインデックス作成を高速化するため、チーム内で類似度92%のコードベース間でMerkle木を用いた安全なインデックス再利用を実現
ファイル変更時は構文チャンク単位で埋め込みをキャッシュし、未変更部分の再計算を回避することで、インデックスの更新・維持コストを大幅に削減
影響分析・編集コメントを表示
影響分析
この技術は、大規模コードベースでのAI支援開発の実用性を劇的に高め、チーム全体の開発効率を向上させる可能性がある。セマンティック検索の精度向上とインデックス作成の高速化は、AIコードエージェントの採用障壁を下げ、組織レベルでの導入を促進する重要な進展と言える。
編集コメント
Cursorが大規模リポジトリのインデックス作成を「数時間から数秒」に短縮した点は、実務でのAIツール導入における最大の課題の一つを解決する画期的な進歩。チーム開発環境での実用性が一気に高まる。
大規模コードベースの安全なインデックス化
セマンティック検索は、AIエージェントの性能を大きく左右する要素である。最近の評価では、応答精度が平均12.5%向上し、コード変更がコードベースに残りやすくなり、全体的なリクエスト満足度も上昇したことが確認されている。
Cursorはプロジェクトを開く際、セマンティック検索を可能にするためにコードベースの検索可能なインデックスを構築する。小規模プロジェクトではこれは瞬時に行われるが、数万ファイルを抱える大規模リポジトリでは、単純な方法ではインデックス作成に数時間を要し、作業の80%が完了するまで検索機能は利用できない。
この課題に対し、開発チームは「ほとんどのチームはほぼ同一のコードベースのコピーで作業している」という観察に基づき、インデックス化の高速化を図った。実際、同一組織内のユーザー間では、同じコードベースのクローンは平均92%の類似性を示す。
つまり、新たなメンバーが参加したりマシンを切り替えたりする際に毎回一からインデックスを再構築するのではなく、チームメイトの既存のインデックスを安全に再利用できる。これにより、最大規模のリポジトリでも、初回検索までの待機時間が数時間から数秒に短縮される。
Cursorはコードベースの最初の状態をマークルツリーを用いて把握する。このツリーには各ファイルの暗号学的ハッシュに加え、子要素のハッシュに基づいて計算された各フォルダのハッシュが含まれる。これにより、変更されたファイルやディレクトリを全体を再処理することなく正確に検出できる。
クライアント側での小さな編集が行われた場合、変更されたファイル自体と、ルートに至るまでの親ディレクトリのハッシュのみが更新される。Cursorはこれらのハッシュをサーバー側のバージョンと比較し、両方のマークルツリーがどこで分岐したかを正確に把握する。ハッシュが異なるエントリのみが同期され、一致するものはスキップされる。この同期プロセスでは、クライアント側のファイルが変更されることはない。
マークルツリーのアプローチにより、各同期で転送する必要のあるデータ量が大幅に削減される。5万ファイルのワークスペースでは、ファイル名とSHA-256ハッシュのみで約3.2MBとなるが、ツリー構造を用いることで、ハッシュが異なるブランチのみを走査すれば済む。
ファイルが変更されると、Cursorはそれを構文上のチャンク(塊)に分割する。これらのチャンクはセマンティック検索を可能にする埋め込み表現(エンベディング) に変換される。この埋め込みの作成が計算コストの高いステップであるため、Cursorはこれを非同期でバックグラウンド実行する。
ほとんどの編集では、チャンクの大半は変更されない。Cursorはチャンク内容ごとに埋め込み表現をキャッシュする。変更のないチャンクはキャッシュがヒットするため、推論時に再計算するコストをかけずに、エージェントの応答を高速に保つことができる。結果として
原文を表示
Blog / researchSemantic search is one of the biggest drivers of agent performance. In our recent evaluation, it improved response accuracy by 12.5% on average, produced code changes that were more likely to be retained in codebases, and raised overall request satisfaction.
To power semantic search, Cursor builds a searchable index of your codebase when you open a project. For small projects, this happens almost instantly. But large repositories with tens of thousands of files can take hours to process if indexed naively, and semantic search isn't available until at least 80% of that work is finished.
We looked for ways to speed up indexing based on the simple observation that most teams work from near-identical copies of the same codebase. In fact, clones of the same codebase average 92% similarity across users within an organization.
This means that rather than rebuilding every index from scratch when someone joins or switches machines, we can securely reuse a teammate's existing index. This cuts time-to-first-query from hours to seconds on the largest repos.
Cursor builds its first view of a codebase using a Merkle tree, which lets it detect exactly which files and directories have changed without reprocessing everything. The Merkle tree features a cryptographic hash of every file, along with hashes of each folder that are based on the hashes of its children.
Small client-side edits change only the hashes of the edited file itself and the hashes of the parent directories up to the root of the codebase. Cursor compares those hashes to the server's version to see exactly where the two Merkle trees diverge. Entries whose hashes differ get synced. Entries that match are skipped. Any entry missing on the client is deleted from the server, and any entry missing on the server is added. The sync process never modifies files on the client side.
The Merkle tree approach significantly reduces the amount of data that needs to be transferred on each sync. In a workspace with fifty thousand files, just the filenames and SHA-256 hashes add up to roughly 3.2 MB. Without the tree, you would move that data on every update. With the tree, Cursor walks only the branches where hashes differ.
When a file changes, Cursor splits it into syntactic chunks. These chunks are converted into the embeddings that enable semantic search. Creating embeddings is the expensive step, which is why Cursor does it asynchronously in the background.
Most edits leave most chunks unchanged. Cursor caches embeddings by chunk content. Unchanged chunks hit the cache, and agent responses stay fast without paying that cost again at inference time. The resulting index is fast to update and light to maintain.
#Finding the best index to reuse
The indexing pipeline above uploads every file when a codebase is new to Cursor. New users inside an organization don't need to go through that entire process though.
When a new user joins, the client computes the Merkle tree for a new codebase and derives a value called a similarity hash (simhash) from that tree. This is a single value that acts as a summary of the file content hashes in the codebase.
The client uploads the simhash to the server. The server then uses it as a vector to search in a vector database composed of all the other current simhashes for all other indexes in Cursor in the same team (or from the same user) as the client. For each result returned by the vector database, we check whether it matches the client similarity hash above a threshold value. If it does, we use that index as the initial index for the new codebase.
This copy happens in the background. In the meantime, the client is allowed to make new semantic searches against the original index being copied, resulting in a very quick time-to-first-query for the client.
But this only works if two constraints hold. Results need to reflect the user's local codebase, even when it differs from the copied index. And the client can never see results for code it doesn't already have.
To guarantee that files won't leak across copies of the codebase, we reuse the cryptographic properties of the Merkle tree.
Each node in the tree is a cryptographic hash of the content beneath it. You can only compute that hash if you have the file. When a workspace starts from a copied index, the client uploads its full Merkle tree along with the similarity hash. This associates a hash with each encrypted path in the codebase.
The server stores this tree as a set of content proofs. During search, the server filters results by checking those hashes against the client's tree. If the client can't prove it has a file, the result is dropped.
This allows the client to query immediately and see results only for code it shares with the copied index. The background sync reconciles the remaining differences. Once the client and server Merkle tree roots match, the server deletes the content proofs and future queries r
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み