はじめに
コーディングエージェント(Claude Code / Codex / GitHub Copilot CLI / Cursor など)を使っていて、こんな体感はないでしょうか。
「まだ1行もコードを直していないのに、もうコンテキストウィンドウが半分埋まっている」
その犯人の多くは リポジトリ探索(repository exploration) です。grep して、glob して、10ファイル読んで……という一連の“下調べ”が、そのままメインエージェントの会話履歴に残り続ける。トークンを食い、しかも無関係なスニペットが後段の推論を汚染します。
本記事で扱う FastContext は、Microsoft と上海交通大学(SJTU)の共同研究チームが提案した、この問題への直球の回答です。ひとことで言うと:
探索(Explore)と解決(Solve)を、別のモデルに分離する。
論文タイトルは FastContext: Training Efficient Repository Explorer for Coding Agents(arXiv:2606.14066、2026年6月公開)。Mini-SWE-Agent に組み込んだ実験では、エンドツーエンドの解決率が最大 +5.5、メインエージェントのトークン消費が最大 60% 削減という結果が報告されています1。
⚠️ 最初に重要な注意
本家のgithub.com/microsoft/fastcontextリポジトリと公式モデルの掲載は、2026-06-30 に予告なく削除されました。現在アクセスできるのは MIT ライセンス下で保全されたミラーやフォーク、およびコミュニティが再アップロードしたモデル重みです。本記事のコード例はミラーの README に基づいています。将来的に URL が変わる可能性がある点はご承知おきください。
1. なぜ「探索」がボトルネックなのか
FastContext の論文が説得力を持つのは、まず現状を計測しているからです。
著者らは SWE-bench Multilingual の全 300 インスタンスについて、GPT-5.4-high + Mini-SWE-Agent の軌跡(trajectory)を丸ごと分析しました。ツール呼び出しを「読み取り/検索/編集/テスト/その他」に分類した結果がこちらです。
| 指標 | 数値 |
|---|---|
| 1インスタンスあたりの平均ツール使用ターン | 17.72 ターン |
| うち「読み取り+検索」 | 9.96 ターン(全体の 56.2%) |
| 「読み取り+検索」が占めるメインエージェント総トークン | 46.5% |
| 最初のコード編集が始まるまでの平均ターン | 8.47 ターン目 |
| 最初の編集前の探索ツール呼び出し(中央値) | 15.5 回 / 6 連続ターン |
さらに示唆的なのが、解決できなかったケースほど編集前の探索ターンが長いという点です(未解決 8.34 ターン vs 解決 6.67 ターン)。
もちろんこれは「難しい問題ほど探索が必要」という当たり前の相関でもあり、論文自身も「探索が失敗の原因だと証明するものではない」と慎重に書いています。ただし、難しい問題ほど探索コストが膨らむ=そこを外出しする価値が大きいという設計上の示唆にはなります。
「コンテキスト汚染」という2つ目の問題
トークン量だけの話ではありません。探索の過程で読んだ無関係なコードが、解決フェーズの推論に残り続けることが問題です。
一度立てた誤った仮説(「たぶんこのファイルが原因だ」)が履歴に残ると、エージェントはその後のターンを真の原因の調査ではなく、誤った仮説の修復に費やしてしまいます。
[従来型:単一モデル]
メインエージェントの履歴
├─ grep結果(500行) ← 残り続ける
├─ ファイルA全文(800行) ← 実は無関係
├─ ファイルB全文(1200行) ← 実は無関係
├─ grep結果(300行)
├─ ファイルC(当たり)
└─ ここでようやく編集開始 ... しかも上のノイズを引きずったまま
2. FastContext のアーキテクチャ
2.1 委譲コントラクト(delegation contract)
FastContext は「探索専用サブエージェント」です。メインエージェントとの契約はきわめてシンプル。
FastContext は関連コードを見つける。メインエージェントはその根拠を使って編集・テスト・回答する。
[FastContext 型:探索と解決の分離]
メインエージェント (GPT-5.4 / GLM-5.1 / Kimi-K2.6 など)
│
│ 自然言語のコンテキストクエリ
│ "認証を実装しているファイルを見つけて"
▼
┌─────────────────────────────┐
│ FastContext (4B〜30B の専用モデル) │
│ ├─ Read : 行番号付きファイル読み取り │ ← すべて read-only
│ ├─ Glob : パスパターン探索 │
│ └─ Grep : 正規表現検索(ripgrep) │
│ ※ 独立した呼び出しは並列実行 │
└─────────────────────────────┘
│
│ <final_answer> ブロック(数十トークン)
▼
メインエージェント:ノイズゼロの根拠だけを受け取る
2.2 3つのツールしか持たない
FastContext が公開するツールは、言語非依存の3つだけです。
| ツール | 役割 |
|---|---|
Read |
行番号付きでファイル内容を返す |
Glob |
パスパターンからファイルを発見する |
Grep |
リポジトリ全文に対する正規表現検索(内部で ripgrep を使用) |
書き込み系ツールは一切ありません。 FastContext は設計上、ファイルを変更できません。これは安全性の担保であると同時に、「探索器は探索に徹する」という責務分離の表明でもあります。
2.3 並列ツール呼び出し
1ターン内で複数のツール呼び出しを発行でき、それらは並列実行されます。
これが効くのは、探索が本質的に仮説の同時検証だからです。「パス名に auth が含まれるファイル」「authenticate というシンボル」「エントリポイントらしき main.py」——これらは互いに独立した手がかりなので、直列に試す必要がありません。
2.4 出力コントラクト:<final_answer>
FastContext の最終出力は、ファイルパスと行範囲だけの極小ブロックです。
<final_answer>
/path/to/repo/src/router.py:42-58 (Router definition)
/path/to/repo/tests/test_router.py:101-119
</final_answer>
数千トークンの探索履歴が、数十トークンの座標情報に圧縮される。これが「最大60%削減」の正体です。メインエージェントは、この座標を頼りに自分で必要な箇所だけを読めばよい。
3. どう訓練したか — SFT → RL の2段構え
FastContext の「Training」の部分が、この研究のもう一つの核心です。汎用の小型モデルにプロンプトを与えるだけでは、質の高い探索器にはなりません。
3.1 Stage 1: SFT(教師あり微調整)でふるまいを初期化
Sonnet 4.6 の探索トレースから 2,954 件のフィルタ済みサンプルを構築。特徴的なのは、「最終的な答え」だけを学習させるのではなく、ランタイムで必要な3つの振る舞いに分解して教師データを作っている点です。
| データソース | 学習させる振る舞い | 構築方法 |
|---|---|---|
parallel_toolcalls |
初手の広い探索 | クエリ+トップレベルのディレクトリ一覧を与え、パスパターン・シンボル・エントリポイントなど冗長でない相補的な並列ツール呼び出しを生成させる |
multiturn_traj |
複数ターンでの証拠収集 | system/user メッセージ、assistant のツール呼び出し引数、生のツール観測結果を含む軌跡をそのまま保持 |
linerange |
精密な引用生成 | 取得済みファイル内容を与え、狭い <final_answer> ブロックだけを出力させる |
損失は assistant トークンのみを対象とし(マスク $m_t$ で非 assistant トークンを除外)、通常のテキストと構造化されたツール呼び出し引数の両方を損失に含めます。
$$\mathcal{L}{\mathrm{SFT}}=-\frac{1}{|\mathcal{D}{\mathrm{sft}}|}\sum_{(x,y)\in\mathcal{D}{\mathrm{sft}}}\sum{t=1}^{|y|}m_{t}\log p_{\theta}(y_{t}\mid x,y_{<t})$$
3.2 Stage 2: RL(強化学習)で「本当に役に立つ引用」に寄せる
SFT は模倣にすぎず、「その引用が実際に issue を解くのに必要な箇所を覆っているか」を直接最適化しません。そこで論文はタスク接地型(task-grounded)の RL を行います。
データ構築のアイデアが秀逸です。
正解パッチ(reference patch)をパースして、変更されたファイルと行範囲を取り出し、それを探索の正解ラベルとして使う。
つまり「人間が実際に直した場所」=「探索器が指し示すべき場所」とみなすわけです。400 プロンプトの RL セットが構築されました。
報酬関数はこう定義されます。
$$R = \underbrace{F_{1}(P_f, G_f) + F_{1}(P_l, G_l)}{\text{タスク成果}} + \underbrace{r{\mathrm{parallel}}}{\text{並列呼び出しボーナス}} - \underbrace{r{\mathrm{format}}}_{\text{フォーマット違反ペナルティ}}$$
| 項 | 意味 |
|---|---|
| $F_1(P_f, G_f)$ | ファイルレベルの F1(パス正規化後)。予測 $P_f$ vs 正解 $G_f$ |
| $F_1(P_l, G_l)$ | 行レベルの F1。より厳しい粒度 |
| $r_{\mathrm{parallel}}$ | 適度な並列ツール呼び出しへの小さなボーナス |
| $r_{\mathrm{format}}$ | 空・長すぎ・不正形式・ファンアウト過多の出力へのペナルティ |
空集合を返した場合はスコア 0 です(「何も答えない」で逃げられない)。
最適化は SFT チェックポイントから初期化し、GRPO(Group Relative Policy Optimization)で 1 プロンプトあたり複数軌跡をサンプリング。
なぜこの報酬設計が賢いのか
- 完全に決定論的:LLM-as-judge を使わないので、報酬ハッキングもコストも抑えられる
- ファイル F1 と行 F1 の二段構え:ファイルは当たったが行範囲が広すぎる(=結局大量に読ませる)出力を、行 F1 が罰する
- フォーマットペナルティ:「とりあえず 50 ファイル列挙しておけば再現率は上がる」という抜け道を塞ぐ
4. 実験結果
4.1 評価セットアップ
| ベンチマーク | 内容 |
|---|---|
| SWE-bench Multilingual | 複数プログラミング言語にまたがる 300 件の issue 解決タスク |
| SWE-bench Pro | より難易度の高い SE タスク。ランダムサンプルした 200 件の固定サブセットで評価 |
| SWE-QA | リポジトリレベルの QA。パッチ生成ではなく「コードを探して推論する」能力を測る。評価は GPT-5.4 を LLM-as-judge として使用 |
メインエージェントには GPT-5.4 / GLM-5.1 / Kimi-K2.6 の3種、サブエージェントには FC-30B-SFT / FC-4B-SFT / FC-4B-RL を組み合わせ、w/o Explore(FastContext なし)をベースラインとしています。エージェントフレームワークは Mini-SWE-Agent。
4.2 主要な結果
| 観点 | 結果 |
|---|---|
| エンドツーエンド成功率 | 委譲探索により最大 +5.5 の改善 |
| メインエージェントのトークン消費 | 最大 60.3% 削減 |
| RL の効果 | FC-4B-RL は、報告されたすべてのエンドツーエンド設定で FC-4B-SFT を上回るか同等 |
| 単体の探索性能 | 訓練済み FastContext モデルは、非 FastContext の小型モデルベースラインより、パッチ関連ファイル・シンボルを高精度に回収 |
| オーバーヘッド | FastContext 呼び出し自体のコストは「marginal(わずか)」 |
具体例として、Kimi-K2.6 + FC-4B-RL の組み合わせでは、SWE-bench Multilingual で 78.3(↑2.0)/トークン 1384k(↓10.9%)、SWE-QA で 72.6(↑1.0)/378k(↓25.9%)が報告されています。
4.3 ここが本質:スコア–トークンのトレードオフ曲線が動く
論文の Figure 1 が示すのは「スコアが上がった」でも「安くなった」でもなく、両方が同時に起きたということです。
通常、エージェントの性能向上は「もっと読ませる=もっと払う」と引き換えです。FastContext はトレードオフ曲線そのものを外側にシフトさせています。安く済むうえに当たる。
そして削減の内訳を見ると、減っているのは主に file reading と code search のトークン。つまり狙い通りの部分が、狙い通りに減っています。
4.4 4B が 30B に肉薄する意味
FC-4B-RL が FC-30B-SFT と同等以上の場面がある、というのは実務的に大きな意味を持ちます。
4B モデルはローカルの Mac で動きます。 つまり「フロンティアモデルには API 課金し、探索はローカルの小型モデルに無料で任せる」という運用が現実的になる。これは単なる論文の数字ではなく、個人開発者のコスト構造を変える話です。
5. 実践:動かしてみる
以下はミラーリポジトリの README に基づく手順です。
5.1 インストール
Python 3.12 以上、パッケージ管理は uv を使用します。
# リポジトリのルートで
uv tool install .
# 開発用
uv sync --all-groups
# wheel をビルド
uv build # → dist/fastcontext-0.1.0-py3-none-any.whl
5.2 モデルエンドポイントの設定
FastContext は OpenAI 互換の chat completions エンドポイントを期待します。
export BASE_URL="https://your-endpoint.example/v1"
export MODEL="your-model-name"
export API_KEY="your-api-key"
5.3 モデル重みの選び方
| フォーマット | サイズ | 備考 |
|---|---|---|
| BF16 safetensors | 約 8 GB | オリジナル重み。mlx-lm / vLLM / SGLang で配信 |
| MLX 8-bit | 約 4 GB | 推奨ローカル量子化。Apple Silicon の LM Studio / mlx-lm で精度確認済み |
| MLX 4-bit | 約 2.1 GB | パス接地が劣化(引用のハルシネーション)。メモリが厳しい場合のみ |
| GGUF Q8 | 約 4.3 GB | Ollama / llama.cpp 向け |
💡 ハマりどころ:Ollama で GGUF を直接使うと空応答になる
Ollama が自動導出するチャットテンプレートが<think>ブロックを強制的に開いてしまいます。ところが FastContext のベースモデル Qwen3-4B-Instruct-2507 は non-thinking バリアントのため、モデルは即座に stop トークンを吐き、毎回レスポンスが空になります。対処は、テンプレートから
thinkを含む行を削除したラッパーモデルを作ること(重みの再ダウンロードは不要):{ echo 'FROM hf.co/mitkox/FastContext-1.0-4B-RL-Q8_0-GGUF' echo 'TEMPLATE """' ollama show --template hf.co/mitkox/FastContext-1.0-4B-RL-Q8_0-GGUF | sed '/<think>/d' echo '"""' } > Modelfile ollama create fastcontext-ollama -f Modelfileその後
BASE_URL=http://localhost:11434/v1、MODEL=fastcontext-ollamaを設定します。M4 で約 11 秒/クエリ、引用精度は MLX 8-bit 量子化と同等と報告されています。
量子化モデルを使う場合は、サンプリング設定を必ず下げてください。
export TEMPERATURE=0.6 # デフォルト 1.0
export TOP_P=0.95 # デフォルト 0.95
export MAX_TOKENS=4000 # デフォルト 32000
# ← stop トークンを取りこぼすと何分も生成し続けるため必須級
5.4 Apple Silicon でのローカル配信(mlx-lm)
BF16 safetensors は GGUF 変換なしに Apple Silicon で直接動きます(4B で RAM 約 8GB)。
# Glob/Grep ツールには ripgrep が必須
brew install ripgrep
hf download ShaunGves/FastContext-1.0-4B-SFT --local-dir ./models/FastContext-1.0-4B-SFT
# 新しい transformers/mlx はこの mlx-lm を壊すので、ピン留めが重要
uv tool install "mlx-lm==0.29.1" --with "transformers<5" --with "mlx<0.31"
mlx_lm.server --model ./models/FastContext-1.0-4B-SFT --port 8080
export BASE_URL="http://127.0.0.1:8080/v1"
# mlx-lm サーバはリクエストの model フィールドが指すものをロードするため、
# MODEL にはローカル重みの絶対パスを指定する
export MODEL="/absolute/path/to/models/FastContext-1.0-4B-SFT"
export API_KEY="local"
5.5 CLI で使う
探索したいリポジトリのルートで実行します。
fastcontext \
--query "認証を実装しているファイルを見つけ、どこを変更すべきか説明して" \
--max-turns 6 \
--traj .fastcontext/trajectory.jsonl
機械可読な引用ブロックだけが欲しい場合:
fastcontext \
--query "リクエストバリデーションのロジックを特定して" \
--citation
| オプション | 説明 |
|---|---|
--query, -q
|
自然言語の探索リクエスト |
--traj, -t
|
JSONL 軌跡の出力パス |
--max-turns |
最終回答を強制するまでの最大探索ターン数 |
--verbose |
中間メッセージと実行時情報を表示 |
--citation |
<final_answer> ブロックのみを返す |
5.6 Python API
import asyncio
from fastcontext.agent.agent_factory import make_fastcontext_agent
async def main() -> None:
agent = make_fastcontext_agent(
trajectory_file=".fastcontext/trajectory.jsonl",
work_dir="/path/to/repo",
)
answer = await agent.run(
prompt="Find where database migrations are defined",
max_turns=6,
citation=True,
)
print(answer)
asyncio.run(main())
citation=True にすれば <final_answer> ブロックだけが返るので、自作のエージェントループに組み込むのが容易です。この関数呼び出しをそのままメインエージェントの「ツール」として登録すればいい。
5.7 リポジトリ構成
src/fastcontext/
cli.py コマンドライン エントリポイント
agent/
agent.py エージェントループ
agent_factory.py デフォルトの FastContext エージェント構築
context.py 会話・軌跡ストレージ
llm.py OpenAI 互換 LLM ラッパー
system.md 探索器のシステムプロンプト ← 一読の価値あり
tool/
read.py / glob.py / grep.py
tool.py ツール基底クラスと ToolSet
benchmark/ Docker 環境ヘルパ、評価ランナー、スコアリング
prompts/ FastContext 統合済み Mini-SWE-Agent プロンプト設定
training/ SFT / RL 訓練スクリプト
serving/ サービング マニフェスト例と API チェック
📌 読むならここ:
src/fastcontext/agent/system.md(探索器のシステムプロンプト)とprompts/(メインエージェント側の統合プロンプト)。「どうメインエージェントにサブエージェントを呼ばせるか」の実例として、自作エージェントにそのまま応用できます。
5.8 再現実験
git submodule update --init --recursive
uv build
cp benchmark/evaluation/configs/example.env .env
# .env にメインエージェントと FastContext のエンドポイント資格情報を記入
uv run --group benchmark python benchmark/evaluation/bench_mini_swe_agent.py \
--bench swebench-multilingual \
--agent-config prompts/gpt-multi-fc.yaml \
--config .env \
--output preds.json \
--logs-dir logs \
--workers 1
SWE-bench Pro は --bench ScaleAI/SWE-bench_Pro --agent-config prompts/gpt-pro-fc.yaml に差し替えます。
6. 使いこなしのコツと注意点
6.1 クエリの書き方が精度を決める
README が明示的に推奨しているのは、探索対象の振る舞い・サブシステム・エラー・ファイルを名指しする具体的なクエリを書くことです。
| ❌ 曖昧 | ✅ 具体的 |
|---|---|
| 「バグを見つけて」 | 「タイムゾーンが UTC でないときに日付パースが 1 日ずれる箇所を特定して」 |
| 「認証について教えて」 | 「JWT のリフレッシュトークン検証を実装しているファイルと、その失効チェックのロジック」 |
| 「テストを探して」 | 「Router クラスのルーティング解決を検証している統合テスト」 |
FastContext は 4B〜30B の小型モデルです。フロンティアモデルのような「行間を読む」能力は期待できません。 その代わり、明確な検索意図に対しては極めて速く正確に動きます。
6.2 制約を理解しておく
- 編集はできない:設計上、コード修正用ではありません
- ツール出力には上限がある:応答性を保つためのキャップがあります
-
軌跡は既定で
.fastcontext/に記録:--trajを指定しない場合。対象リポジトリを汚したくない場合は明示的に指定してください -
ripgrepは必須:これがないと Grep が黙って失敗し、探索器が答えを強要されて引用をハルシネーションします(ミラーの修正点の一つがまさにこれ)
6.3 MLX 4-bit を安易に選ばない
ミラーの検証では、MLX 4-bit 量子化でパス接地が劣化し、存在しない引用を生成したと報告されています。FastContext の価値は「正確な座標」にあるので、ここが崩れると使う意味がなくなります。8-bit を推奨。
7. 設計思想としての FastContext — 何を持ち帰るべきか
FastContext を「便利なツール」としてだけ見ると、本質を取り逃がします。この研究が提示している一般原則は以下の3つです。
原則1:役割ごとにモデルサイズを変える
すべてのサブタスクにフロンティアモデルは要りません。探索は 4B で足りる、というのが実証されました。エージェント設計とは、能力とコストのポートフォリオ設計です。
原則2:サブエージェントの価値は「コンテキストの隔離」にある
サブエージェントの本当の効用は「並列化」でも「専門化」でもなく、汚れ仕事の履歴をメインの会話から締め出せることです。返ってくるのは結論だけ。プロセスは呼び出し元に持ち込まない。
これは自作のエージェントループにそのまま適用できる設計原則です。「このサブタスクの中間生成物は捨ててよいか?」と自問し、Yes ならサブエージェントに切り出す候補です。
原則3:出力コントラクトを狭く固定する
<final_answer> にファイルパスと行範囲だけ、という極端に狭い出力契約が、圧縮率・検証可能性・RL 報酬の設計しやすさをすべて同時に実現しています。
自由形式の要約を返すサブエージェントは、結局ノイズを持ち込みます。構造化された座標を返させる方が、ほぼ常に優れています。
8. まとめ
| 論点 | 要点 |
|---|---|
| 問題 | コーディングエージェントのツール使用ターンの 56.2%、総トークンの 46.5% がリポジトリの読み取り・検索に費やされている |
| 解法 | 探索を専用の read-only サブエージェントに委譲。Read / Glob / Grep のみ、並列呼び出し、<final_answer> で座標だけを返す |
| 訓練 | Sonnet 4.6 トレース 2,954 件で SFT →正解パッチ由来のファイル/行 F1 を報酬に GRPO で RL(400 プロンプト) |
| 効果 | エンドツーエンド解決率 最大 +5.5、メインエージェントのトークン 最大 60.3% 削減 |
| 実用性 | 4B モデルが Apple Silicon でローカル動作。MIT ライセンス |
| 注意 | 本家リポジトリは 2026-06-30 に削除済み。ミラー/フォーク経由での利用となる |
「賢い一つのモデル」から「役割の分かれた複数のモデル」へ。FastContext は、その移行を再現可能なレシピと具体的な数字で示した点に価値があります。
自分のエージェントループに探索フェーズがあるなら、まずは --citation で 4B をローカルに立てて、実際にどれだけコンテキストが節約できるか計測してみることをおすすめします。
参考リンク
- 論文:FastContext: Training Efficient Repository Explorer for Coding Agents (arXiv:2606.14066)
- HTML 版論文:https://arxiv.org/html/2606.14066v1
- Hugging Face Papers ページ:https://huggingface.co/papers/2606.14066
- 保全ミラー(README の実践手順の出典):https://github.com/manjunathshiva/fastcontext
- DeepWiki による解説:https://deepwiki.com/microsoft/fastcontext
-
FastContext: Training Efficient Repository Explorer for Coding Agents, arXiv:2606.14066 — https://arxiv.org/abs/2606.14066 ↩