Skip to content

[BUG] --rerank がモデル未検出時にサイレントフォールバックし結果が変わらない #125

@Kewton

Description

@Kewton

再現手順

# llama3 が未インストールの環境で:
commandindexdev search "fullscreen" --format llm --limit 3 --rerank

期待される動作

rerankフォールバック時にユーザーが明確にスキップを認識できること:

  • 全フォーマット(json/llm/human/path)でフォールバック情報が出力される
  • stderrにアクション可能なヒント付き警告メッセージが表示される

実際の動作

[rerank] Reranking failed: Model not found: llama3
<!-- estimated tokens: ~3088 -->
## src/hooks/useFullscreen.ts
...
  • stderrに [rerank] Reranking failed が出力されるが、exitコードは0
  • 結果は --rerank なしと完全に同一(MD5ハッシュで確認済み)
  • ユーザーからは「rerankが成功した」ように見える

確認結果

# rerank あり
md5: ec2594d228425e0175c8c1b23e406f59

# rerank なし
md5: ec2594d228425e0175c8c1b23e406f59

根本原因

try_rerank() 関数(src/cli/search.rs)が Vec<SearchResult> を直接返す設計のため、呼び出し元でフォールバック発生を検知できない。エラー情報は eprintln!() でのみ出力され、出力フォーマットに反映されない。

さらに src/rerank/ollama.rs の provider 層にもタイムアウト時の eprintln! が存在し(L74-78)、部分結果を Ok() で返すため、try_rerank() 側でも検知できない。

実装方針

方針: Graceful degradation + 明示的フォールバック通知

デフォルトはgraceful degradation(フォールバックして検索結果を返す)を維持しつつ、フォールバック発生をユーザーに明確に通知する。

具体的な変更

  1. RerankStatus enum の導入:

    enum RerankStatus {
        Applied,
        AppliedPartially { warnings: Vec<String> },  // タイムアウト等で部分適用
        Skipped { reason: String },                    // 完全スキップ
        NotRequested,
    }
  2. try_rerank() のシグネチャ変更: Vec<SearchResult>(Vec<SearchResult>, RerankStatus) タプルを返す。フォールバック理由を構造化して伝搬する。

  3. provider 層の変更:

    • RerankProvider trait の rerank() 戻り値を Result<(Vec<RerankResult>, Vec<String>), RerankError> に変更(warnings を返す)
    • ollama.rs のタイムアウト時 eprintln!(L74-78)を削除し、部分適用情報を戻り値で伝搬
  4. 出力制御の一元化: try_rerank() 内および ollama.rs 内の全 eprintln! を削除し、run() 関数に一元化。

  5. フォーマット別フォールバック表現run() 関数内で制御):

    フォーマット フォールバック時の出力 stdout/stderr
    json JSONL先頭にメタデータ行 {"type": "metadata", "rerank_applied": false, "rerank_reason": "..."} stdout
    llm 出力冒頭に <!-- rerank skipped: {reason} --> コメント(estimated tokensより前) stdout
    human [rerank] Reranking skipped: {reason} + ヒント stderr
    path [rerank] Reranking skipped: {reason} + ヒント stderr

    JSON互換性: メタデータ行には "type": "metadata" を付与し、既存の結果行と判別可能にする。

  6. 全RerankError種別に対応したstderrヒント:

    RerankError ヒントメッセージ
    ModelNotFound Run 'ollama pull <model>' to install, or set rerank.model in config.
    NetworkError Is Ollama running? Try 'ollama serve'.
    Timeout Rerank timed out. Check Ollama server load.
    ApiError Ollama API returned an error. Check Ollama logs.
    InvalidResponse Unexpected response from Ollama. Check model compatibility.
    ConfigError Check rerank settings in commandindex.toml.

    タイムアウトの種類:

    • HTTPリクエストタイムアウト(REQUEST_TIMEOUT_SECS=10、固定)→ RerankError::Timeout
    • 全体デッドライン超過(config.rerank.timeout_secs)→ 部分結果 + AppliedPartially

影響範囲

対象 影響内容
src/rerank/mod.rs RerankProvider trait の戻り値変更、RerankStatus enum 追加
src/rerank/ollama.rs provider 実装の戻り値変更、eprintln! 削除
src/cli/search.rs try_rerank() シグネチャ変更、run() 内の出力制御追加
tests/e2e_semantic_hybrid.rs test_rerank_fallback_via_cli 拡充
tests/common/mod.rs JSONL パースユーティリティの metadata 行対応
workspace検索 影響なし(スコープ外)
impactコマンド 影響なし(rerankを使用していない)
パフォーマンス 軽微(メタデータ整形 + warning 収集のみ。rerank自体のコスト特性は据え置き)
外部依存 新規crate追加なし

スコープ外(別Issue)

  • デフォルトrerankモデルの変更(llama3 → 他モデル)
  • try_hybrid_search() の同様の修正(将来的に同じステータス/警告基盤を適用予定)
  • rerank実行前のモデル存在確認(preflight check)
  • --strict-rerank オプション(非ゼロexitコード返却)
  • workspace検索でのrerank対応
  • パフォーマンス改善(逐次リクエストの並列化等)

受け入れ基準

  • RerankStatus enum を定義(Applied / AppliedPartially / Skipped / NotRequested)
  • RerankProvider trait の rerank() 戻り値を Result<(Vec<RerankResult>, Vec<String>), RerankError> に変更
  • try_rerank()(Vec<SearchResult>, RerankStatus) を返すよう変更
  • provider 層含む全 eprintln! を削除し、出力制御を run() に一元化
  • RerankStatus::Skipped / AppliedPartially 時に各出力フォーマットでフォールバック情報を出力
    • json: JSONL先頭にメタデータ行("type": "metadata" 付き)
    • llm: <!-- rerank skipped: {reason} --> コメント(estimated tokensより前)
    • human: stderr警告メッセージ([rerank] プレフィックス維持)
    • path: stderr警告([rerank] プレフィックス維持)
  • 全RerankErrorバリアントに対応したアクション可能なヒントメッセージ
  • テスト拡充
    • フォールバック時のstderrにモデル名とスキップ理由が含まれること
    • json出力時にメタデータ行が存在し type: "metadata" を含むこと
    • llm出力時にrerankスキップコメントが含まれること
    • tests/common/mod.rs の JSONL パースがメタデータ行を正しく扱うこと
  • cargo clippy --all-targets -- -D warnings 警告0件
  • cargo test --all 全テストパス

環境

  • commandindex 0.1.0
  • Ollama(llama3未インストール、qwen3.5:35bはインストール済み)

深刻度

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions