-
Notifications
You must be signed in to change notification settings - Fork 0
複数コマンド併用時の合計トークン量制御 #117
Description
概要
search + related + impact + context の結果を併用する際の合計トークン量を制御する機能を追加する。
背景・課題
anvil 0.0.6 + commandindex 0.1.0 での8パターン性能検証で、複数コマンドの結果を結合した際のトークン量が成功率に直接影響することが判明した。
問題
P6パターンでは search + related + impact + context の結果をJSON結合してプロンプトに渡した結果、合計20KBに到達。これがanvildevのコンテキストウィンドウを圧迫し:
- コンテキストリセット(完全重複サイクル)が発生
- 73回のfile.readのうち61回が無駄な重複
- 最終的に変更0件で463秒を浪費
最適範囲の推定
| パターン | プロンプトサイズ | 結果 |
|---|---|---|
| P2 (context のみ) | 3.5KB | 成功 (240秒/2ファイル) |
| P3 (related のみ) | 2.5KB | 部分的 (75秒/1ファイル) |
| P6 (全コマンド) | 20KB | 失敗 (463秒/0ファイル) |
| P7 (全コマンド+tag) | 20KB | 成功 (416秒/3ファイル) |
5〜10KB程度が最適範囲と推定される。
補足: P6とP7は同じ20KBだがP7はtag付きで情報の構造化・質が異なるため成功した可能性がある。トークン量だけでなく情報の質(冗長度・構造化度)も成功率に影響する。
提案(スコープ: Phase 1のみ)
本Issueでは以下のPhase 1のみを対象とする。自動調整モードは別Issue化を検討する。
Phase 1: 各コマンドへの --max-tokens オプション追加
設計方針: 各サブコマンドに個別に --max-tokens を追加し、呼び出し側(anvil等)がコマンドごとのトークン配分を制御する方式(方針A)を採用する。
理由: commandindexは各サブコマンドが独立したCLIコマンドとして実行される設計であり、コマンド横断の合計制御は呼び出し側の責務とするのが最も自然。
対象コマンド:
| コマンド | 現状 | 追加内容 |
|---|---|---|
search |
--limit(件数制御のみ) |
--max-tokens 追加(全モード対応) |
search --related |
--limit(件数制御のみ) |
--max-tokens 追加 |
search --related-stdin |
--limit(件数制御のみ) |
--max-tokens 追加(related と同様) |
search --changed-since |
impact に委譲 | --max-tokens を impact に伝達 |
search --workspace |
複数リポジトリ集約 | 集約後の最終結果に --max-tokens 適用 |
impact |
--limit(件数制御のみ) |
--max-tokens 追加 |
context |
--max-tokens 実装済み(#105) |
変更なし |
注:
suggestコマンドは出力が通常小さく、途中切断でLLMが不完全な戦略を受け取るリスクがあるため、Phase 1のスコープから除外する。
--limit との併用ルール: まず --limit で件数を絞り、その結果に --max-tokens でトークン制限をかける(--limit が先に適用される)。
--rerank との併用ルール: limit → rerank → limit trim → max_tokens trim の順で適用する。
--with-snippet との併用ルール: スニペット付与後に --max-tokens トークン打ち切りを適用する。
--max-tokens パラメータ仕様:
- 型:
u64 - 範囲:
1..=1_000_000(context と統一) - 未指定時: 制限なし(後方互換性)
トークン制限の実装方式
共通モジュール化: context.rs の打ち切りロジック(estimate_entry_tokens, tokens_to_char_budget, truncate_snippet_for_char_budget 等)を共通モジュール(output/token_budget.rs)に抽出し、各コマンドから呼び出す。
トークン推定方式(コンテンツベース推定): 出力フォーマットのオーバーヘッド(JSON構造、Markdownヘッダー等)は無視し、コンテンツベースの推定で --max-tokens を適用する。フォーマット差によるずれはドキュメントに注記する。
各出力型のトークン推定対象フィールド:
| 出力型 | トークン推定対象フィールド |
|---|---|
SearchResult |
body(検索結果本文) |
SymbolSearchResult |
name + kind + file_path + children のテキスト表現 |
RelatedSearchResult |
file_path + relation_types + snippet |
SemanticSearchResult |
body(検索結果本文) |
ImpactResult |
file_path + snippet |
早期打ち切りパターン: context の build_context_pack() と同一のパターンを使用。各結果アイテムの推定トークン数を累積し、max_tokens を超えた時点で残りをスキップ。最初のエントリは例外として必ず含める(context と同じ設計)。
help_llm 対応
- help_llm.rs の CommandInfo 定義に search/impact の
--max-tokensオプション情報を追加
トークン推定に関する注意
現在の推定式: text.chars().count() / 4(1トークン≒4文字)
日本語テキストの注意: 日本語では1文字≒1トークンに近いため、この推定式は過小評価になる可能性がある。将来的にtiktoken等の正確なトークナイザー導入を検討する余地がある。
フォーマットオーバーヘッド:
--max-tokensはコンテンツベースのトークン推定に基づく制限であり、各フォーマット(human/json/path/llm)の装飾・構造オーバーヘッドは含まない。実際の出力トークン数はフォーマットにより上回る場合がある。
受け入れ基準
searchコマンド(全モード: 通常/symbol/related/related-stdin/semantic/changed_since/workspace)に--max-tokensオプションが追加され、出力のトークン量を制限できることimpactコマンドに--max-tokensオプションが追加され、出力のトークン量を制限できることsearch --changed-since経由で--max-tokensが impact に正しく伝達されることsearch --workspaceで集約後の結果に--max-tokensが適用されること--max-tokens未指定時は従来どおり制限なしで動作すること(後方互換性)--limitと--max-tokensの両方が指定された場合、--limit→--max-tokensの順で適用されること--rerankと--max-tokensの両方が指定された場合、limit → rerank → limit trim → max_tokens trimの順で適用されること- トークン推定には既存の
estimate_tokens関数を使用すること - トークン打ち切りロジックは共通モジュール(
output/token_budget.rs)に実装し、各コマンドから呼び出すこと - help_llm 出力に新オプション情報が含まれること
--max-tokens指定時に出力トークン数が上限を超えないことを検証するテストが存在することcargo test,cargo clippy,cargo fmtが全てパスすること
優先度
中
関連
- context コマンドのトークン数制御の実効化 #105 (context トークン数制御) — 本Issueは単一コマンドではなく複数コマンド併用時の制御
- 自動調整モード(関連度順ランク付けによる上限内最適化)は別Issue化を検討
将来の拡張(別Issue)
- 自動調整モード: 各コマンドの出力を関連度順にランク付けし、上限内で最も重要な情報を残す
- tiktoken等の正確なトークナイザー導入
- config デフォルト値: commandindex.toml に default_max_tokens 設定を追加
- suggest への --max-tokens 追加: 出力構造の安全な切り詰め方式を設計してから追加
- suggest 戦略への --max-tokens 自動配分: suggest が提案するコマンドにトークン予算を自動配分