Files
pp-qa-km/README.md
yellowadmin b90727fc11 feat: diag_refs 對帳診斷 + ingest 進度可見性/Ctrl-C 安全 (Closes #2) (#5)
## 摘要

本 PR 含兩個獨立關注點,各一 commit。

### 1. `diag_refs` — source_ref↔manifest 對帳診斷 (`04f4fd5`) — 回應 #4

lint 的「source_ref 不在 manifest」只報對不上、不辨成因。新增 `tools/diag_refs.py`,把每個對不上的 source_ref 分成五類(hash 不符/路徑字串岔開/檔名 hash 後綴岔開/檔在磁碟未登記/完全無對應),各附修法,讓「補帳本(§14.3)」與「修規則(§12)」的相反處置不再混為一談。純唯讀、結束碼 `0/1`,可當搬機或改 manifest 後的閘門。附 selfcheck 驗五型別分類、結束碼與零寫檔。README §3.3/§6/§7/§8 同步。

### 2. ingest 進度可見性 + Ctrl-C 安全回復 (`4add7fa`) — Closes #2

`--all-pending` 長時間本地 Ollama 攝入全程靜默,使用者不確定有沒有在跑、又不敢中斷:

- **進度可見**:每份來源 `[i/N]`、長文件逐段 `分段 k/n`、每個 item `↳ 新增/更新`、完成 `✓`,全 `flush=True` 即時顯示。
- **Ctrl-C 安全**:獨立攔 `KeyboardInterrupt`(它不是 `Exception` 子類,原本會略過善後)。因 commit 在迴圈之後,**main 必然未受影響**;中斷時印可照做的回復指令並以結束碼 130 收場。

## 測試

- `python tools/selfcheck_diag_refs.py` — ALL PASS
- `python tools/selfcheck_ingest.py` — ALL PASS(含進度標記、中斷後 main 未動、回復指令實測可回乾淨 main)
- README markdownlint 0 issues

Closes #2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: LittleYellow <crazytea@gmail.com>
Reviewed-on: #5
2026-07-24 05:42:35 +00:00

228 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# README — QA 知識庫使用手冊
金融電子支付 QA 部門知識庫,採 **Karpathy LLM Wiki 模式**:知識在文件**攝入時**由本地
LLM 編譯成 wiki 頁,查詢時只讀已編譯頁面(**非 RAG**,檢索用 BM25
> **本檔是操作手冊(怎麼裝、怎麼跑)。** 所有 schema、工作流細節、硬性約束與行為紀律的
> **唯一正本**是 [AGENTS.md](AGENTS.md)——動手前請先讀它。本檔只做操作說明,不複製其內容。
---
## 1. 環境需求
| 項目 | 需求 |
|------|------|
| Python | 3.11+ |
| 本地 Ollama | 執行於 `http://localhost:11434`(見 [config/models.yaml](config/models.yaml) |
| Ollama 模型 | 已 `ollama pull` 且與 `config/models.yaml` 的 tag 一致的**合規本地模型** |
| Git remote選用 | 攝入自動開 PR 用;無 remote 時分支保留於本地 |
**資料落地是硬性約束([AGENTS.md](AGENTS.md) §1.1**:所有文件內容的 LLM 處理一律走本地
Ollama**禁止**任何雲端 API、雲端轉換服務及任何 `:cloud` 後綴模型。供應鏈限制§1.3
禁用中國關聯模型bge / Qwen / GLM / MiniMax / Jina 等)。
---
## 2. 安裝
Windows PowerShell本專案主要環境
```powershell
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt
```
Linux / Gitea runner
```bash
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
```
接著確認 Ollama 已拉好 `config/models.yaml` 內指定的模型:
```powershell
ollama list # 對照 tasks.ingest.model / tasks.lint.model / tasks.fallback.model
```
**換模型只改 [config/models.yaml](config/models.yaml),不動任何程式碼**§1.2)。設定缺欄位時程式直接
報錯,不使用隱含預設值。唯一允許的覆寫來源是環境變數 `OLLAMA_BASE_URL`
> 下文指令以 Windows 的 `.venv\Scripts\python` 為例Linux 換成 `.venv/bin/python`。
---
## 3. 四大工作流
資料流:**原始檔 → `convert``raw/converted/` Markdown → `ingest``wiki/` 頁面 →
`search` / MCP 查詢**`lint` 定期健檢整庫。
### 3.1 轉換 `convert` — 原始檔轉 Markdown
把 docx / xlsx / pdf / pptx / html 或網頁 URL 轉成 Markdown並登記 SHA-256 至
`raw/manifest.json``raw/` 只讀不可變§1.4)。
```powershell
# 本機檔案(可多個)
.venv\Scripts\python tools\convert\convert.py 報告.docx 測項.xlsx 規格.pdf
# 網頁快照(保存完整 HTML因來源可能消失
.venv\Scripts\python tools\convert\convert.py https://example.com/guideline
# 只看計畫、不寫檔
.venv\Scripts\python tools\convert\convert.py 報告.docx --dry-run
```
- 支援:`.docx .xlsx .pdf .pptx .html/.htm``http(s)://` URL。
- hash 相同的檔會自動 `skip`(去重)。
- 掃描件PDF 無文字層)標記 `needs_ocr` 並跳過,**不擅自 OCR**,留待人工決定。
- 單檔失敗不中斷批次,最後彙總並以結束碼 1 回報。
### 3.2 攝入 `ingest` — 編譯成 wiki 頁
`raw/converted/` 的 Markdown呼叫本地 Ollama 產出 / 更新 wiki 頁,重建
`index.md`、追加 `log.md`,並**開新 git 分支 + PR**HITL 閘門§1.5——永不直接 commit 到 main
```powershell
# 攝入指定來源
.venv\Scripts\python tools\ingest.py raw\converted\xxx.md
# 攝入所有「尚無 summary 頁引用」的來源
.venv\Scripts\python tools\ingest.py --all-pending
# 只列計畫(分支名、模型、分段數),不呼叫 LLM、不寫檔
.venv\Scripts\python tools\ingest.py --all-pending --dry-run
# 已攝入過hash 相同)也強制重跑
.venv\Scripts\python tools\ingest.py raw\converted\xxx.md --force
```
**前置條件**:須在 `main` 分支、且工作區除 `raw/` 外無未提交變更,否則會報錯中止。
> **`convert` 的產出請保持未提交,不要另開分支 commit。** 除 `raw/` 外無未提交變更的條件
> 刻意把 `raw/` 排除在外——正確流程是在 `main` 上 `convert`、確認 `raw/converted/*.md` 內容
> 無誤後直接 `ingest`,由 ingest 把來源與編譯出的 wiki 頁**一起** commit 進同一個分支。這樣
> PR 的 diff 同時含來源與產出,審核者才能對照 LLM 有無編譯錯誤。若先開分支 commit 了轉換檔,
> 切回 `main` 時那些檔案會隨分支離開工作區;此時請先 `git merge` 該分支回 `main` 再攝入
> `raw/` 不受 §1.5 HITL 閘門管轄,該條只規範 wiki 層變更)。
執行後:變更落在 `ingest/<時間戳>-<slug>` 分支。有 remote 時自動 push 並印出 PR 建立網址;
無 remote / 離線時分支保留本地,請手動 push 後開 PR。**經人工審核合併後才進 main。**
### 3.3 健檢 `lint` — 全庫品質檢查
檢查 schema 完整性、過期主張、覆蓋缺口、孤兒頁,並用 LLM 偵測重複 / 矛盾頁。
**絕不修改或刪除任何檔案**一律產出報告列為「待人工核准」§1.5、§7
```powershell
# 完整健檢,報告寫入 reports/
.venv\Scripts\python tools\lint.py --output reports
# 跳過 LLM 重複/矛盾比對(較快,純 schema/結構檢查)
.venv\Scripts\python tools\lint.py --no-llm
```
- 報告路徑印在 stdout例如 `reports/lint-YYYYMMDD-HHMMSS.md`
- **結束碼**`0` = 無發現;`1` = 有待人工核准項目(供 CI 判斷 / 標紅通知)。
- 排程:[.gitea/workflows/lint.yaml](.gitea/workflows/lint.yaml)(每週一台北時間 05:00草稿部署 Gitea 時啟用)。
> **`source_ref 不在 manifest` 的成因分類**lint 只報「對不上」,不分辨成因。跑
> [tools/diag_refs.py](tools/diag_refs.py) 把每個對不上的 source_ref 分成五類hash 不符 /
> 路徑字串岔開 / 檔名 hash 後綴岔開 / 檔在磁碟未登記 / 完全無對應),各附修法——
> 「補帳本」§14.3與「修規則」§12的處置相反先分類再動手。純唯讀不改任何檔
> 結束碼同 lint`0` 全部解得開 / `1` 有對不上),可當搬機或改 manifest 後的閘門。
>
> ```powershell
> .venv\Scripts\python tools\diag_refs.py
> ```
### 3.4 查詢 `search` — BM25 檢索
```powershell
.venv\Scripts\python tools\search.py "AML 測試準則" -k 10
```
輸出 JSON 陣列(`path / title / description / tags / score`),供人工或 agent 定位候選頁。
`-k` 上限 10查詢工作流 §8先讀 `index.md` 定位、最多 10 頁、只讀命中頁、回答必附
`source_ref`、禁止全庫掃描)。
---
## 4. MCP server — 供內部 AI agent / 團隊查詢
[mcp/server.py](mcp/server.py) 是 FastMCP 薄殼,只暴露兩個唯讀 tool`search_wiki`BM25 檢索)與
`read_page`(讀單頁全文,依 `models.yaml` 的 token 上限截斷)。只讀已編譯 wiki 頁,不觸碰
`raw/` 層、不做全庫掃描。
```powershell
# stdio 啟動
.venv\Scripts\python mcp\server.py
```
測試時可用環境變數 `PP_QA_ROOT` 指定專案根目錄。`read_page` 有路徑跳脫防護,只接受
`wiki/` 下的 `.md`
---
## 5. Copilot Custom Agents雙棧
同一套 [AGENTS.md](AGENTS.md) 規範同時服務 Claude Code 與 GitHub Copilot§11 雙棧規則)。
[.github/agents/](.github/agents/) 提供三個 Copilot 編排 agent——它們**只編排、不處理文件內容**
(成本紀律 §1.6LLM 處理一律 shell out 給本地腳本agent 只讀精簡結果):
| Agent | 職責 |
|-------|------|
| [kb-ingest](.github/agents/kb-ingest.agent.md) | 轉換 → 攝入 → 開 PR |
| [kb-lint](.github/agents/kb-lint.agent.md) | 執行健檢並摘要報告重點 |
| [kb-query](.github/agents/kb-query.agent.md) | 檢索 → 只讀命中頁 → 附 source_ref 回答 |
---
## 6. 目錄速查
```text
config/models.yaml # Ollama 端點與模型 tag唯一設定來源
raw/originals/ # 原始檔,只讀
raw/converted/ # 轉換後 Markdown攝入的實際輸入只讀
raw/manifest.json # SHA-256 登記 + 原始檔↔轉換檔對應
wiki/summaries/ # 每份來源一頁摘要
wiki/entities/ # 實體頁(系統/模組/API/法規/專案)
wiki/concepts/ # 概念頁(跨來源綜合)
index.md # 目錄式導航(由 ingest 自動重建)
log.md # append-only 操作日誌
tools/ # convert/ ingest.py lint.py diag_refs.py search.py kb.py共用模組
mcp/server.py # MCP 薄殼
```
完整結構與各檔用途見 [AGENTS.md](AGENTS.md) §2。
---
## 7. 疑難排解
| 訊息 / 現象 | 原因與處置 |
|-------------|-----------|
| `config/models.yaml 缺欄位` | 設定不完整補齊欄位不要用預設值繞過§1.2)。 |
| `tasks.X.model 為 :cloud 模型` | 違反資料落地;改用本地模型 tag§1.1)。 |
| `須在 main 分支執行` | 攝入前先切回 `main`。 |
| `工作區有 raw/ 以外的未提交變更` | 先 commit / stash 非 `raw/` 的變更再攝入。 |
| `... 不在 manifest 的 converted 條目中` | 該來源尚未轉換;先跑 `convert.py`。 |
| lint 報 `source_ref 不在 manifest` | 跑 `tools/diag_refs.py` 分類成因:帳本掉條目→補登走 PR§14.3路徑字串岔開→修規則§12別逐頁改。 |
| `LLM 輸出驗證失敗(含 fallback` | 本地模型連主模型 + fallback 都無法產出合規 JSON檢查 Ollama 是否在線、模型是否拉好。 |
| `push 失敗(無 remote 或離線)` | 正常;分支已保留本地,手動 push 後開 PR。 |
| ingest 跑很久、看不到進度/想中斷 | 已逐來源 `[i/N]` 逐分段回報進度。Ctrl-C 安全main 不受影響,中斷時會印回復指令(`git checkout main && git stash -u && git branch -D <branch>`),續跑 `--all-pending` 自動接續。 |
---
## 8. 開發者自檢
各工具附 assert 式自檢腳本(免框架、免 fixtures§13.4
```powershell
.venv\Scripts\python tools\convert\selfcheck.py
.venv\Scripts\python tools\selfcheck_ingest.py
.venv\Scripts\python tools\selfcheck_lint.py
.venv\Scripts\python tools\selfcheck_diag_refs.py
.venv\Scripts\python tools\selfcheck_search.py
```