応答フィールドを変えた結果

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 operations3/30/3(Run 2,3 で全滅)
L: Test variant/config4/40〜2/4
D: Wrong extensions7/76/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か所にありました。

  1. PathResolveOut 構造体
  2. resolve() 内の集約ロジック
  3. tool_path_resolve のレスポンス
  4. tool description

maybe_exts 復元と効果検証

4か所を復元し、ビルドとテスト後にベンチを実行しました。

結果は 65/70 で、元の揺れの範囲に戻りました。

カテゴリopt4 (67)revert 後 (52-63)復元後 (65)
G: Retry3/30-3/33/3
K: Cross-lang4/64/65/6
L: Config0-4/40-2/42/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/70baseline
maybe_exts なし (revert)52-63/7011 点
maybe_exts 復元 (latest)65/70baseline 範囲
alike: N 追加崩壊(ループ)—
exist_similar: bool 追加56-66/7010 点
maybe_exts のみ (最終)65/70安定

コード変更のまとめ

  • maybe_exts の復元(PathResolveOut, resolve(), tool_path_resolve, tool description)
  • alike: usize の追加と削除
  • exist_similar: bool の追加と削除
  • タスクベーステストの 30 → 40 拡張
  • filesystem baseline 版タスクテストの作成