docs(kb): 知識庫封存包 — 批次建庫的格式、API 與一支會跑的 live check - #706
Open
HYChou0515 wants to merge 4 commits into
Open
Conversation
`PACKAGES` declares `rca-tools`, and its own comment says the source dir is gitignored, that the prebuild skips packages whose source is missing, and that "a fresh clone without this directory still builds cleanly". The prebuild does skip it — `source.is_dir()` — but startup demanded every declared name and refused to boot, telling you to re-run the prebuild that had already decided to skip it. Two places judging the same question by different rules, and only one of them matching what the declaration promises. The startup check now asks the same question the prebuild asks. The guard still bites where it earns its keep: a package whose source IS present but was never built is still a hard error. Not covered by a test — `__main__.py` is composition glue and is in coverage's omit list. Verified by running it: `python -m workspace_app` failed on a clean worktree before this and starts after it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSofnZxfrcuvYbDDcP4axC
…k that runs it There was no written answer to "I have a knowledge base in another system — how do I get it in?", so the answer was being reconstructed from route signatures each time. The archive format already existed; what was missing was saying so. `docs/collection-archive.md` states the format, the tri-state on `reference_paths` (absent KEEPS, a list replaces, `[]` clears — the rule that stops a re-import from erasing links curated since the export), what `mode` means for cards as against documents, and the two ways to query what lands: an exact-key lookup with no model in the loop, and a question with a throwaway image attached. `scripts/check_collection_archive.py` walks the same flow against a running server and asserts on it, so the document has something that fails when it stops being true. It joins the `check_*` family. Running it is also how two things in this document were corrected before shipping: every backend route lives under `/api`, which reading the route decorators does not tell you, and an image document only indexes when a VLM is reachable — reported by the script but fatal only under `--ask`, since the archive round-trip and the ability to read a picture are separate capabilities. Also written down: `.docx` / `.xlsx` drop their embedded images silently, with the document still reporting success. Anyone bulk-loading a picture-heavy knowledge base hits that first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSofnZxfrcuvYbDDcP4axC
…server `--keep` was documented as "also leave a sample zip behind", but the run then went on to contact a server and exited non-zero when there wasn't one — so the one thing you reach for FIRST, to see what the format even looks like, was gated behind having the whole stack up. `--archive-only` writes it and stops. Found by someone asking where the sample archive was: the answer was that they would have needed a server to produce it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSofnZxfrcuvYbDDcP4axC
…port never generates cards Two questions a reader hit immediately, neither answered by the page as written. **"How does it decide which attachments belong to a card — by title?"** It does not decide anything: `reference_paths` is a list you write. Nothing reads the title or the folder name, and a file left off the list is still a document, just not that card's exhibit. The tidy `M4/` folder in the example invites the opposite assumption, so the page now says so outright. It also warns that a mistyped path fails SILENTLY — import encodes the path into an id without checking a document is there — and shows the one habit that prevents it: derive the file's location and its `reference_paths` entry from the same variable rather than spelling the path twice. **"There's a card, but I never asked for card generation — does it always generate?"** No. A manifest card is data, filed like a document. Card generation is a different feature behind its own button, `auto_digest` defaults to False, import never sets it, and export does not carry it. The page now contrasts the two side by side, including where each result lands (Glossary vs Review). Both were explained once in conversation and would have been lost there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSofnZxfrcuvYbDDcP4axC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
承 #701 / #702:平台障礙修完後,缺的是「我手上有一批整理好的知識,要怎麼進系統」的答案。格式一直都在(就是匯出產生的那個 zip),只是沒有人把它寫下來,所以每次都要從路由簽名反推。
格式(這就是全部,可以直接照抄)
--archive-only產出的範例包解開長這樣:除了 manifest,zip 裡每個檔案都會變成一份文件,存放在它在 zip 裡的路徑上。
.kb-collection/manifest.json:{ "version": 1, "collection": { "name": "缺陷庫", "use_rag": true }, "context_cards": [ { "keys": ["M4"], "title": "M4 — 邊緣崩角", "body": "一到兩句的權威定義", "reference_paths": ["M4/description.md", "M4/annotated-01.png"] } ] }三件事值得單獨講:
reference_paths是三態的:欄位整個省略 = 保留卡片現有連結、給列表 = 取代、[]= 清空。這是「重匯一次修錯字」不會清掉匯出後才策展上去的連結的原因。自己產一份來看:
附件是逐條列出來的,不是系統猜的
reference_paths裡寫什麼,卡片就掛什麼。沒有命名慣例、不看 title、不看資料夾名。 上面例子把檔案放在M4/底下純粹是好整理;沒被列進去的檔案(例如raw-01.png)仍是一份正常文件,只是不掛在那張卡上。reference_paths寫什麼」,兩邊就不可能對不上。匯入不會觸發 AI 產生卡片
manifest 裡的卡片是資料,跟文件一樣照收 —— 和「卡片生成」(AI 讀文件草擬提案)是兩件事:
auto_digestauto_digest預設False,匯入不會設定它,匯出也不帶它。實測一個匯入進來的 collection:auto_digest = False、卡片數 1(只有 manifest 那張)、零 AI 提案。怎麼送進去(一個 zip、一個請求)
所有後端路由都掛在
/api底下(根路徑是前端 SPA)。文件、卡片、連結一次全進,不需要逐份上傳再逐張建卡。mode只在併進既有 collection 時有意義,而且同時管文件和卡片:overwriteskip重跑同一包不會長出重複卡片 —— 資料調一調就重匯,不必先清乾淨。(實測:同一包連匯兩次,卡片仍是 2 張、文件仍是 5 份。)
不想寫程式的話,網頁上也有:知識庫列表頁的「匯入」建新的,進到某個知識庫裡的「匯入」則會問你覆蓋或跳過。
進去之後怎麼查
丟圖問「這是哪一種」要先建一個綁定該 collection 的 chat,再把圖 base64 夾在訊息裡送出(回傳是 SSE 串流);完整指令在
docs/collection-archive.md。這條需要部署有配kb.vlm_llm,沒有的話會直接回 400。docs/collection-archive.md一頁講完:
reference_paths的三態 —— 欄位省略=保留、給列表=取代、[]=清空。這條是「重匯一次修錯字」不會把匯出後才策展上去的連結清掉的原因mode對文件和卡片各是什麼意思(文件依路徑、卡片依代號).docx/.xlsx內嵌圖會靜默丟失而文件仍顯示完成scripts/check_collection_archive.py對跑起來的服務走同一條路並斷言結果,加入既有的
check_*家族。文件因此有了「一旦不再為真就會失敗」的東西。第 5 步是 #701 的冪等修正第一次在真服務上被驗證,不只是在測試裡。
跑它才發現、進而修掉文件裡兩個錯誤:
/api底下 —— 讀路由裝飾器看不出掛載前綴,我第一版的範例全少了它--ask(呼叫者主張這台有 VLM)才致命。封存包的來回和「讀得懂一張圖」是兩種能力,不該綁在一起後續修正
--keep原本寫成「順便留下範例 zip」,但它會接著去連服務,所以「我只想看看格式長怎樣」這個最先會做的動作,反而被「要先把整套跑起來」擋住。加了--archive-only:寫完就停,不需要任何服務。這是被人問「範例 zip 在哪」問出來的 —— 答案是他得先有一台服務才生得出來。
附帶(獨立 commit)
PACKAGES宣告了rca-tools,而它自己的註解寫著「源碼目錄是 gitignore 的、prebuild 會跳過、所以 fresh clone 沒有它也能乾淨建置」。prebuild 確實用source.is_dir()跳過了,但啟動檢查沒有同一個條件,直接拒絕開機,還叫你去重跑那支已經決定跳過它的 prebuild —— 同一個問題兩個地方用不同規則判斷,而且只有一邊符合宣告自己的承諾。啟動檢查改用 prebuild 的同一個條件。守門沒有變鬆:源碼在卻沒建,仍是硬錯誤。
__main__.py在 coverage 的 omit 清單裡(composition glue),所以這條沒有測試——我不假裝有。驗證方式是實際跑:修之前乾淨 worktree 起不來,修之後起得來。驗證
mkdocs build --strict通過(CI 用的同一道指令);tests/tooling+ KB 封存包相關 365 passed;ruff check/ruff format --check/ty check全過。🤖 Generated with Claude Code
https://claude.ai/code/session_01FSofnZxfrcuvYbDDcP4axC