Plan: LLM sanity checks + replay diagnostics (#51)¶
起因(2026-06-06 實戰):insight extraction 對 qwen3:14b 無聲失敗了一整輪 — 所有 fake-LLM 測試全綠,真模型在任務上接龍/schema 漂移,沒有任何一層告訴 使用者或開發者「這顆 LLM 撐不起這個功能」。#51 要求:(1) 現有功能要有檢查 機制 (2) 架構要能手動新增檢查 (3) FE 要有 indicator (4) 內部 agent 也要涵蓋。 經
/grill-me走完決策樹定案如下。
0 · 進度總覽¶
| 階段 | 內容 | 狀態 |
|---|---|---|
| P1 | Check 框架 — ISanityCheck ABC + CheckResult + registry + factories 組裝 |
✅ ccc6043 |
| P2 | 七個 bundled canned checks | ✅ b87745f |
| P3 | Check API — GET /health/checks(cached)+ POST /health/checks/run;startup sync/async 兩段 |
✅ b82050c |
| P4 | Replay API — context-snapshot rebuild + pure-LLM probe(doc / turn / tool-call) | ✅ 85b5e0c |
| P5 | FE — 全域診斷頁 + 健康 indicator | ✅ 42dbd3d |
| P6 | FE — doc 級 / turn 級 / tool-call 級 replay 入口 | ✅ adfe93e |
每階段完成定義:ruff check && ruff format --check && ty check 清、pytest 綠、commit、本表打勾。
1 · 鎖定的決策(grilling)¶
- Q1 — 範圍:七項全部。
- RCA workspace agent(tool-calling probe)
- KB chat agent(
kb_searchtool-calling probe) infer_modulessub-agent(分類 probe)- Retrieval 增強(multi-query expand probe;HyDE/rerank 同 LLM 同形狀,v1 以 expand 代表)
- Insight extraction(迷你對話 → ≥1 個合法 kind 的 insight)
- VLM describer(已知內容的測試圖 → 描述含關鍵詞)
- Embedders(default + code:embed 一句 → dim 正確)
- Q2 — 時機:啟動時 sync 跑 <1 分鐘的項目(connectivity 類:Ollama/endpoint 可達、 模型存在、embedder dim probe),接著 async 跑全項 capability probes;結果 cache + 時間戳。FE 可手動重跑(整輪或單項)。無定時重跑(中途掛靠使用現場 error + 手動重驗)。
- Q3 — Replay 入口:四個全要 — 全域診斷頁、doc 級(KB 文件)、turn 級(agent 對話)、tool-call 級(單次 tool 使用)。
- Q4 — Replay 本質:只測 LLM,不執行 tool、零副作用。Replay =
(context snapshot, target LLM) → raw output。要看 LLM 對 tool output 的反應, 用 history 裡既有的 tool output 組 context 餵它 — 永遠不真的 call tool、不寫 任何狀態。原始輸出(含 reasoning)原樣呈現給人眼比對。 - Q6 — Gating:check fail 只顯示警告不鎖功能(check 可能過時/誤判)。
- UI/UX:授權照業界慣例自定(系統健康 indicator:header 狀態點 + 診斷頁;
warning 不擋操作;文案不露內部技術細節 — per memory
ui-copy-no-internals)。
2 · 推定項(照 codebase 慣例,未另行確認)¶
ISanityCheckABC(I<Name>、介面/實作分檔,per memoryabc-over-protocol),kb/之外開新health/模組(七項橫跨 RCA/KB/VLM,不屬於 kb 子系統)。CheckResult = {check_id, status: pass|fail|skip|error, detail, latency_ms, checked_at};skip= 功能未配置(vlm_llm: null→ VLM check skip 不是 fail)。- Bundled 七項在 factory 寫死;custom 走 config dotted path(
health.checks: [...], 同kb.parsers模式)+health.checks_disabled。 - 結果存 specstar resource(
CheckRun— 歷史可查,per memoryspecstar-CRUD-routes-fine),最新一輪另有 in-memory cache 給 GET 用。 - API 回 pydantic models(per memory
pydantic-response-models)。 - Canned probe 的斷言是功能級不是連線級(qwen3:14b 事件的核心教訓:HTTP 200 不代表能用)。
3 · Replay 的 context snapshot 形狀¶
| 入口 | context 來源 | 重建方式 |
|---|---|---|
| Doc 級(extraction / parser) | SourceDoc blob + extraction prompt | 與 Ingestor 同碼路,dry-run |
| Turn 級 | Conversation.messages[:n] | 與 runner 同 prompt 組裝,只取第一個 LLM 輸出(text 或 tool-call intent),不進 tool loop |
| Tool-call 級 | messages 截至該 tool call 前 | 同上;呈現「當時 call 了 X(args)/ 現在想 call …」對照 |
| VLM | SourceDoc 原圖 + describe prompt | VlmDescriber 同碼路,回 raw markdown |
素材皆在現有資料(Conversation、Message.tool_args、SourceDoc blob)— 不需新記錄層。
4 · 不在範圍(v1)¶
- 定時背景重跑(Q2 明確排除)
- check fail 自動 gate 功能(Q6 排除)
- 隔離 sandbox 重放 exec(replay 不執行 tool,本項不存在)
- 自動回歸比對(replay 結果與歷史 output 的 diff 評分)— v1 人眼比對
4.5 · 首輪實戰戰果(2026-06-06,vlm-describe)¶
上線第一輪 vlm-describe 即 fail。replay/分層診斷結論:
- transport 正常(wire payload 帶
images;Ollama 原生 API + 短 prompt 能認出紅色) - qwen2.5vl:7b(經 Ollama)對無特徵合成圖不可靠:配長模板會幻覺(把紅色方塊
說成折線圖)、把 context 行抄進 transcription;256px 合成圖甚至觸發 llama.cpp
GGML_ASSERT把 runner 弄崩(upstream bug)。對有文字的圖(production 真正 的輸入:截圖/slides/掃描)則穩定可讀。 - 處置:probe 改為讀回渲染文字("REFLOW ZONE 3" → 斷言 "reflow")— 量 ingestion
真正依賴的能力;
vlm_describe.md模板改為描述先行 + 空節出口 ((no visible text)/(none)),live 驗證 7B 不再離軌。色彩 probe 會對 「實務上沒問題」的模型過度警報,棄用。
5 · 教訓落地(開發流程)¶
Fake-LLM 測試驗「我們的程式」,canned check 驗「這顆模型」,replay 驗「這次失敗」。 三層缺一不可 — 新增任何 LLM-backed 功能時,bundled canned check 是 DoD 的一部分 (寫功能必附 check,如同必附測試)。