pathfinderのMCP応答を変えて精度を比較
pathfinderのmaybe_exts・件数・boolを比較し、70問と40タスクで測定。LLM導入とMCPツール開発で使う応答設計の記録です。
応答フィールドを変えた結果
pathfinderのMCPレスポンスを変えたところ、70問のベンチで15点以上の差が出ました。
同じstemの候補拡張子を返す maybe_exts を削除すると、67/70から52〜63/70へ下がり、復元後は65/70になりました。件数の alike: N はループを起こし、常時返す exist_similar: bool は揺れ幅が10点になりました。
このモデル向けには、次のレスポンスが合いました。
- 必要な場合だけ返す:曖昧な場合だけ出し、ない場合は一意と伝えます。
- 少ない候補:2〜3要素に絞ります。273という大きな件数は探索を増やしました。
- 次の行動が分かる:試す拡張子などを直接返します。
- 短いレスポンス:繰り返す情報を減らします。
背景
pathfinderはColBERT MaxSimとレキシカルスコアでパスを解決する自作MCPです。qwen3.5-35b-a3b(Q5_K_M)で70問を測っていました。LLM導入時のツール応答を、小規模モデルに合わせるための検証です。
lexiopt4の最高67/70から、revert後に52〜63/70へ下がったことが調査のきっかけです。
revert 後のスコア劣化の調査
lexiopt4-1、4-2、4-3を比較しました。変更前はlexiopt4 67/70、lexiopt5 61/70、変更後は63、52、57でした。
主に下がった項目です。
| カテゴリ | revert 前 | revert 後 |
|---|---|---|
| G: Retry operations | 3/3 | 0/3(Run 2,3 で全滅) |
| L: Test variant/config | 4/4 | 0〜2/4 |
| D: Wrong extensions | 7/7 | 6/7(Test 31 が安定して失敗) |
初めはrevertで segment_overlap、dir_ext_counts、warmup改善、tool_retry_with_resolve のtool_name追加が失われたと考えました。
revert されていなかった
コードを確認すると、4機能とも残っていました。
lexiopt4時点の9192d6bとHEAD d6c9dc8をgit diffで比べました。
maybe_exts の発見
差分は maybe_exts の削除でした。
maybe_exts はbest candidateと同じstem(拡張子を除く名前)の拡張子一覧です。config.go に対して config.rs もあれば、stem config の maybe_exts: ["go", "rs"] を返します。
定義は4か所にありました。
PathResolveOut構造体resolve()内の集約ロジックtool_path_resolveのレスポンス- tool description
maybe_exts 復元と効果検証
4か所を復元し、ビルドとテスト後にベンチを実行しました。
結果は 65/70 で、元の揺れの範囲に戻りました。
| カテゴリ | opt4 (67) | revert 後 (52-63) | 復元後 (65) |
|---|---|---|---|
| G: Retry | 3/3 | 0-3/3 | 3/3 |
| K: Cross-lang | 4/6 | 4/6 | 5/6 |
| L: Config | 0-4/4 | 0-2/4 | 2/2 |
maybe_exts: ["rs","go"] の数tokenを戻すと、10点以上回復しました。拡張子の判断を助けたと考えています。
レスポンス語彙のさらなる実験
他のヒントも試しました。
alike: N(同一 stem ファイル数)の追加
maybe_exts は似た拡張子、alike は同じstemの件数を返します。
config は273件で、alike: 273 を返しました。モデルは探索を増やし、list_dir に失敗した後、件数確認を繰り返しました。「59 PASS, 1 FAIL」を何十回も計算し、Test 61-70を飛ばしました。
exist_similar: bool への切り替え
件数をやめ、exist_similar: true/false を毎回返しました。
3回は66、60、56で10点差でした。lexiopt6-1はK=6/6、L=4/4でしたが、lexiopt6-3はG=0/3でした。maybe_exts だけの65/70より揺れています。
false も確定情報になるという仮説でしたが、安定しませんでした。
maybe_exts のみに回帰
exist_similar と alike を削除し、maybe_exts へ戻しました。
結果の解釈
結果を次の3点で解釈しました。
毎回返す情報の蓄積
candidates はtop-Kのpath / score / why / rootを返し、1件50-80 tokenです。top-5 × 70問では数千tokenになります。exist_similar: false も70回続くため、余分な情報の蓄積が影響したと考えています。
maybe_exts は一意解では出ず、曖昧な場合だけ出ます。追加contextが少ないことが安定に寄与したという解釈です。
Primacy-Recency カスケード
中盤のG(Test 46-48)と終盤のLが一緒に下がりました。最初と最後へ注意が偏り、蓄積したフィールドが中盤以降の判断を難しくしたという仮説です。
情報を増やしても改善しなかった
alike: 273 と exist_similar: false を足しても精度は上がりませんでした。今回の最良は、必要なときだけ少数の拡張子を返す maybe_exts です。
タスクベースベンチの拡張
F: intent、K: cross-lang、L: config disambiguationの失敗を含む10タスクを追加し、test_prompt_tasks.mdを30から40へ増やしました。
追加した31-40です。
- Go vs Rust client 判別(K カテゴリ対応)
- Hand-written vs generated 判別(K カテゴリ対応)
- Dev vs prod Kubernetes overlay(L カテゴリ対応)
- VPC vs ECS Terraform module(L カテゴリ対応)
- Go config vs Rust config(D カテゴリ対応)
- Deep OAuth callback, Postgres vs PostgREST, vendor 除外, GraphQL schema vs generated, reranker entry point
結果は 40/40、42 tool calls でした。タスクには目的があるため、pathfinderのintent_textが効きやすいと考えています。
filesystem MCPだけで同じ問題を解くtest_prompt_tasks_baseline.mdも作りました。
ベンチスコア推移
| 構成 | スコア | 揺れ幅 |
|---|---|---|
| maybe_exts あり (lexiopt4) | 67/70 | baseline |
| maybe_exts なし (revert) | 52-63/70 | 11 点 |
| maybe_exts 復元 (latest) | 65/70 | baseline 範囲 |
| alike: N 追加 | 崩壊(ループ) | — |
| exist_similar: bool 追加 | 56-66/70 | 10 点 |
| maybe_exts のみ (最終) | 65/70 | 安定 |
コード変更のまとめ
maybe_extsの復元(PathResolveOut, resolve(), tool_path_resolve, tool description)alike: usizeの追加と削除exist_similar: boolの追加と削除- タスクベーステストの 30 → 40 拡張
- filesystem baseline 版タスクテストの作成
