背景
私は、ソフトウェアエンジニアリングの 設計書をほぼ Markdown で作成しています。
業務要件、ユースケース一覧、サービス記述書、API 仕様、ADR、ナレッジベース。気づけば、社内外で扱うドキュメントの大半が Markdown になっていました。
さらに、最近は GitHub Copilot や Claude Code の出力結果そのものも Markdown で返ってきます。つまり、インプットもアウトプットも Markdown という状況が、現場では当たり前になりつつあります。
そうなると、次に困るのが「この大量の Markdown を、どうやって AI エージェントに効率よく読ませるか」です。
Vibe Coding でエージェントに「この仕様に従って実装して」と頼むとき、関連 Markdown を全部 read_file させると、Context Window があっという間に埋まります。
正直、最初は「context window が大きくなったから大丈夫だろう」と思っていたのですが、実務で重めのセッションを回すと、思ったより早く窮屈になるんですよね。
この実感から、Markdown の効果的な検索と読み取りに特化したスキル markdown-query を作って公開しました。
この記事では、その背景にある Token 消費の話と、スキルの中身、セットアップ、GitHub Copilot からの使い方、ベンチマークの読み方までをまとめておきます。
注意点 / 前提
最初に断っておきます。
- これはあくまで 私個人の見解 であり、所属する組織の公式見解ではありません
- 数値(後述の Token 配分・削減率)は ツール・モデル・タスク・リポジトリの内容 によって大きくブレます
- プロダクション運用や、組織標準としてそのまま採用することは想定していません
- 紹介するスキルも「銀の弾丸」ではなく、特定の状況で効く道具として捉えてください
- ベンチマークの数値は、私のリポジトリ・私の環境で測ったものです。同じ結果は保証できません
万能ではありません。ここを踏まえた上で読んでいただけると助かります。
整理:そもそも Context Window は何で埋まるのか
「Token が足りない」と言うとき、私たちは何を消費しているのか。
ここで一度、整理してみます。
context window の中身は、ざっくり次の5つに分けられます。
- System / Tools / MCP / instructions
- 会話履歴
- ファイル読込
- コマンド出力・ログ
- 空き・buffer
つまり、AI に送っているのはユーザーの質問だけではなく、ツール定義・指示書・履歴・読み込んだファイル・実行ログまで全部含んだものです。
ここを誤解していると、「自分はそんなに長く話していないのに、なぜ context が圧迫されるのか」が分からなくなります。
問題は「会話量」ではなく、累積した周辺情報 だ、というのがポイントです。
本文:Vibe Coding における Token 消費のざっくり感
200k tokens の context window を前提にすると、重めの開発セッションは大体こんな配分になりがちです。
| 構成要素 | 軽い状態 | 重い状態 |
|---|---|---|
| System / Tools / MCP / instructions | 10〜20% | 25〜35% |
| 会話履歴 | 10〜25% | 40〜70% |
| ファイル読込 | 10〜30% | 40〜60% |
| コマンド出力・ログ | 5〜15% | 20〜40% |
| 空き・buffer | 20〜60% | 0〜20% |
正直、最初にこの内訳を見たとき「ファイル読込と会話履歴だけで大半が食われるのか」と少し驚きました。
ただ、考えてみれば当然で、AI エージェントはファイルを読むたびに、その内容をまるごと context に積んでいきます。grep や cat の出力も同じです。
GitHub Copilot CLI は約 80% 到達で background compaction を開始し、95% 近くまで埋まると compaction の完了待ちが発生する挙動が説明されています。実務上の目安は 80% を超える前に整理する こと、です。
- 参考: GitHub Copilot CLI の context management
- 参考: Claude の context window
- 参考: Claude Code session management と 1M context
実務での影響としては、
- セッション後半になるほど、修正提案がブレる
- 過去に決めた前提を AI が忘れて、同じ議論を繰り返す
- compaction 待ちで、体感のレスポンスが落ちる
このあたりが、地味にストレスとして効いてきます。
だからこそ、ファイル読込のところを賢くする のが、現場で一番効く節約ポイントだと感じています。
markdown-query スキルとは
markdown-query は、リポジトリ内の Markdown 群(仕様書、設計書、ナレッジ、README など)を ローカル完結で横断検索 し、ヒットした 見出し単位の小さなチャンク(snippet)だけ をエージェントに返すスキルです。
特徴
-
独自のインデックスを持つ —
.mdq/index.sqliteにチャンク・メタデータを保存し、増分更新可能 - 日本語の Tokenizer を使っている — 日本語の Markdown でも実用的にヒットする
- 完全にオフラインで動作する — 外部 API(埋め込み、ベクトル検索サービス等)を一切呼びません
- BM25 / grep / タグ・パス絞り込み に対応
- 見出し階層の俯瞰 や、チャンク ID 指定での本文取得 もできる
クラウド埋め込みやリモートベクトル DB を使わないので、社内のクローズドな設計書群でも安心して使えます。
逆に、Markdown の編集・生成はしません。読み取り専用 の道具です。
何が嬉しいのか(Why)
- 「全文を
read_fileさせる」 → 数万トークン消費、関係ない章まで読まれる -
markdown-query経由 → 該当チャンク数百〜千トークン程度に圧縮されて投入される
実測値は後述しますが、特定条件下で 97% 以上の Token 削減 が出ることもあります。もちろん、これは「特定条件下」の話です。
スキルパッケージに含まれるもの
スキル本体だけでなく、CLI とベンチマークツールが同梱されています。
| パス | 内容 |
|---|---|
skills/markdown-query/SKILL.md |
スキル本体。エージェントが読み込むトリガー定義と手順 |
skills/markdown-query/references/cli-reference.md |
mdq CLI の全サブコマンド・全オプション仕様 |
skills/markdown-query/references/query-patterns.md |
よくあるクエリ例 |
skills/markdown-query/references/indexing-internals.md |
索引のデータモデルとチャンク分割ルール |
skills/markdown-query/examples/prompt-snippets.md |
Copilot Chat / Custom Agent 向けプロンプト例 |
mdq/ |
スキルが内部で呼び出す Python 製 CLI 本体 |
setup/setup-markdown-query.{ps1,sh} |
mdq を .venv にインストールするスクリプト |
tools/markdown-query/ |
Context 削減効果を数値で確認するベンチマーク CLI |
セットアップ手順
前提条件
- Git CLI
- Python 3.11 以上(
mdqCLI の動作要件) - 利用するエージェント CLI(
copilot/claude/gemini/apmのいずれか)
1. スキルのインストール
GitHub Copilot CLI を例にすると、対話セッション内で次を実行します(初回のみマーケットプレイス追加)。
/plugin marketplace add dahatake/skills
/plugin install dahatake-skills@dahatake-skills
Claude Code、Gemini CLI、APM 経由のインストール手順は README を参照してください。
2. mdq CLI のインストール(必須)
スキルは内部で mdq CLI を呼び出します。プラグインを入れただけでは動きません。
リポジトリをクローンしたうえで、OS に応じてセットアップスクリプトを実行します。
Windows (PowerShell)
git clone https://github.com/dahatake/skills.git
cd skills
./setup/setup-markdown-query.ps1
macOS / Linux (bash)
git clone https://github.com/dahatake/skills.git
cd skills
chmod +x ./setup/setup-markdown-query.sh
./setup/setup-markdown-query.sh
スクリプトはリポジトリルートに .venv を作り、その中に mdq をインストールします。
-WithWatch / --with-watch を付けると、ファイル変更を監視する mdq watch 用の watchdog も入ります。
使い方 — GitHub Copilot から
ここからが本題です。
普段の Vibe Coding に組み込むときの流れを、順番に書いていきます。
1. インデックスの作成(初回・必須)
このスキルを使う前に、必ず 1 回実行してください。検索対象のリポジトリのルートで実行します。
mdq index
- 既定でカレントディレクトリを再帰走査し、
.md/.markdownを索引化 - 既定で
.git/node_modules/.venvなどは除外 -
.gitignoreは既定で尊重 -
.mdq/自体を.gitignoreに追加することを推奨
2. インデックスの更新
ファイルを追加・編集した後は、もう一度 mdq index を実行するだけです。SHA-1 + mtime で増分更新されるので、変わっていないファイルは再処理しません。
ファイル変更を逐次反映したい場合は、別ターミナルで watch モードを起動できます。
mdq watch
3. GitHub Copilot からの呼び出し例
インデックス作成後、Copilot Chat や Copilot CLI に、こんな感じで依頼します。
このリポジトリ配下の Markdown から「会員 同意管理」に関する設計を探して、要点だけ教えて。
docs/**配下の Markdown から "context window" を含む見出しを横断的に拾って。引用元のpath:linesも付けて。
業務要件とユースケース一覧を踏まえて、ロイヤルティポイント付与のサービス記述書の該当箇所だけを抜粋して。
スキルが起動すると、内部で mdq search が呼ばれ、ヒットした見出し単位のチャンクだけが Context に積まれます。
全文を読ませる場合と比べて、Context Window への影響が桁で変わります。
4. 手動で mdq を叩いてみる(動作確認)
エージェントに任せる前に、自分で叩いて感触を掴むのもおすすめです。
mdq search --q "会員 同意管理" --top-k 5 --max-tokens 800
主なオプション:
| オプション | 説明 |
|---|---|
--q |
検索クエリ(必須) |
--top-k |
返すヒット数(既定 5、推奨 3〜5) |
--max-tokens |
出力の最大トークン数(既定 800、推奨 400〜800) |
--paths |
検索対象パスを絞り込み(例: "docs/**") |
--tags |
frontmatter のタグで絞り込み |
--mode |
bm25(既定) / grep
|
--snippet-radius |
ヒット行前後の表示行数(既定 ±2) |
出力は JSONL(1 行 = 1 ヒット)です。気になるチャンクがあれば、chunk_id を指定して本文取得できます。
mdq get --chunk-id <ID>
ベンチマーク:本当に Token を節約できているか
「いい感じです」だけだと信用できないので、自分のリポジトリで数値確認するためのベンチマーク CLI を同梱しています。
何を測るのか
同一クエリ集合に対し、3 つのシナリオを比較します。
| シナリオ | Context に投入する内容 | 想定する使い方 |
|---|---|---|
baseline_full |
索引対象配下の 全 Markdown 本文 | スキルを使わない場合の上限値 |
mdq_bm25 |
mdq search --mode bm25 のヒットのみ |
既定の検索モード |
mdq_grep |
mdq search --mode grep のヒットのみ |
厳密一致モード |
各シナリオで 応答トークン数 / 検索 wall-clock / ベースライン比削減率 / coverage(任意) を計測します。
実行手順
-
インデックス作成(未作成なら
--ensure-indexで自動作成可)mdq index -
計測したいクエリを 1 行 1 件で書いたファイルを用意(サンプル:
tools/markdown-query/queries.sample.txt) -
ベンチマーク実行
python tools/markdown-query/benchmark.py \ --queries-file tools/markdown-query/queries.sample.txt \ --top-k 5 --max-tokens 800 --repeat 3 --ensure-index -
結果は
tools/markdown-query/results/bench-<UTCタイムスタンプ>.{json,md}に出力されます。
レポートの読み解き方
bench-*.md には、次のセクションが順に並びます。
- Environment — トークナイザ、Python・OS・コミットハッシュ。他環境と絶対比較するときは必ずここを確認
-
Parameters —
--top-k--max-tokens--repeatなどの実行条件 -
Index summary —
--ensure-index時の索引作成所要時間 -
baseline_full — 全文投入時の
files / chars / tokens。これが 削減率の分母 -
Skill なし vs Skill あり (プロンプトトークン比較) — シナリオごとに次を表示
-
avg_response_tokens— クエリ平均の応答トークン数(小さいほど節約) -
avg_vs_baseline_savings_pct— 削減率(例:98.5%なら全文比 1.5% に圧縮) -
latency_ms_all— 全クエリ ×--repeatのmean / p50 / p95 / min / max -
per_query[]— クエリごとの hits 数、トークン、削減率、coverage_proxy
-
実行例(参考値)
リポジトリ同梱の sample/ 配下(業務要件・ユースケース・サービス記述書 4 ファイル)に対して、5 クエリで実行した結果です。
あくまで「例」です。ユーザーの環境で同じ結果や精度を保証するものではありません。
測定環境: tiktoken/cl100k_base / Python 3.12.10 / Windows 11 / top_k=5, max_tokens=800, repeat=3
baseline_full: 4 files / 83,230 chars / 68,440 tokens
| シナリオ | avg tokens (with skill) | avg savings vs baseline | latency mean / p50 / p95 (ms) |
|---|---|---|---|
mdq_bm25 |
1,794.6 | 97.38% | 13.35 / 13.65 / 14.20 |
mdq_grep |
700.6 | 98.98% | 1.45 / 0.47 / 3.33 |
クエリ別(mdq_bm25、抜粋):
| query | hits | tokens | savings % |
|---|---|---|---|
| ロイヤルティプログラム | 5 | 2,484 | 96.37 |
| 生成AI パーソナライズ | 5 | 1,816 | 97.35 |
| ポイント付与 失効 | 5 | 1,250 | 98.17 |
| 会員 同意管理 | 5 | 1,402 | 97.95 |
| ユースケース | 5 | 2,021 | 97.05 |
この例では、全文投入の 約 1〜3% までプロンプトトークンが圧縮されました。
一方で mdq_grep は語の表記揺れに弱く、ヒットしないクエリも出ます(savings % = 100 は「ヒットなし」を意味するので、別途 coverage_proxy で精度を確認する必要があります)。
削減率だけで判断しない、というのが大事なところです。期待パスを紐付けた JSON で coverage まで見るのが、現実的な評価方法だと思います。
リポジトリ構成
README.md プロジェクトの README
LICENSE MIT ライセンス
plugin.json プラグイン定義(Copilot CLI / 共通)
apm.yml APM マーケットプレイス定義
.claude-plugin/marketplace.json Claude Code / Copilot CLI 用マーケットプレイス
.claude-plugin/plugin.json Claude Code 用プラグイン定義
gemini-extension.json Gemini CLI 拡張定義
setup/ スキル別の追加 CLI インストールスクリプト
setup-markdown-query.ps1
setup-markdown-query.sh
skills/ スキル本体
markdown-query/
SKILL.md
examples/prompt-snippets.md
references/
cli-reference.md
query-patterns.md
indexing-internals.md
mdq/ Python 製 CLI 本体
tools/markdown-query/ ベンチマーク CLI と結果
benchmark.py
queries.sample.txt
results/
sample/ デモ用の Markdown 群
plugin.json(ルート)と .claude-plugin/plugin.json は内容を重複させているため、片方を更新するときはもう片方も同期する必要があります。apm.yml と .claude-plugin/marketplace.json も同様です。
ここまでの整理
一度、箇条書きでまとめておきます。
良い点
- Markdown の設計書を AI エージェントに渡すときの Token 消費を、桁単位で減らせる可能性がある
- 完全オフライン動作なので、社内クローズドな設計書群でも使える
- 日本語 Tokenizer 対応で、日本語 Markdown でも実用的にヒットする
-
path:linesでの引用元明示ができる
注意点
- スキル本体だけでなく
mdqCLI のセットアップが必要(プラグインを入れただけでは動かない) - インデックスは事前作成・更新が必要(セッション間で共有されない前提)
-
grepモードは表記揺れに弱い
限界
- 読み取り専用(Markdown を編集・生成する用途には使えない)
- 埋め込みベースの意味検索は行わない
- ベンチマークの数値は環境依存。回答品質まで保証するものではない
まとめ
設計書もアウトプットも Markdown、という現場は今後ますます増えると思います。
そのとき、ファイル読込まわりの Token 消費 をどう設計するかは、Vibe Coding の体験を左右する地味だけど大事なポイントです。
markdown-query は万能ではありません。
ただ、
- 普段から Markdown で設計書を書いている
- 既に Markdown 化されたファイルが沢山ある
- Copilot の出力結果(Markdown)も含めて、エージェントに横断的に参照させたい
こういう状況であれば、効果が出やすい場面が多いと感じています。
まずは自分のリポジトリでインデックスを作って、benchmark.py を一度回してみる。
そこで出てきた数字を見て、自分の現場での落としどころを決める のが、現実的な向き合い方だと思います。
万能な解はありません。
ただ、Context Window を「有限のリソース」として扱う癖をつけるだけで、AI との付き合い方は確実に変わってきます。
まずはここまでで、現場で試してみる価値はあると思います。