
既然可以上傳 PDF、EPUB、電子書等素材,乾脆把這些素材,整理成一個圖書館。它不取代素材庫,它是素材庫的目錄與書架。
圖書館頁:左邊分類與批次上傳,右邊書籍列表,可搜尋、可依分類篩

第一個決定:圖書館的閱讀器不自己開發。存書、書目、瀏覽器裡翻書這三件事全部交給 Calibre,它本來就是做這個的,有自己的伺服器與帳密。我們只做一件事:書進門的時候判斷它是什麼、該放哪一格、有沒有重複,然後把它交給 Calibre,再把切好的段送進素材庫。兩邊用命令列串起來,書名作者分類存在 Calibre 那邊。
這個決定順手解決另一個空間問題。這台機器的系統碟只有 34G,可用 29G。掃描書如果要自己做翻頁器,每一頁都得匯出成圖永久留著,一本估 1.2GB。交給 Calibre 之後,它可以直接讀原始 PDF,頁圖辨識完就刪,單本永久佔用空間降到接近零。
分類分兩層。大分類是受控詞彙,一份清單,語言模型只能從清單裡挑一個,真的都不符才提一個新的。種子清單是我自己先用桌面上的 AI 對整個書庫粗分過一次得來的,一開始 10 個:靈性修行、心理學、歷史、投資、程式、寫作、健康、商管、飲食、小說。
系列是自由的,但要盡量沿用既有系列名,存在 Calibre 原生的系列欄位裡,因為它天生支援「歷史的轉換期 01 到 11」這種編號。現在大分類長到 19 個,系列 28 個。一層受控一層自由的理由:受控的那層是給檢索範圍用的,自由的那層是給人翻書架用的,如果把兩層混在一起,最後會得到一份既不能篩、也不好翻的清單。
依分類篩:十三經 28 本,系列與注疏是第二層標籤

依分類篩:靈性修行 73 本

重複的書是我自己開口要求的:「幾本書會重複,要先檢查」。擋兩次。第一次在上傳當下算整個檔案的 SHA256,跟圖書館裡現有的比,完全相同的檔案直接判重複略過,不跑。
第二次在書名判別出來正規化之後,跟現有圖書館內的書名比對,疑似同一本的不自動入庫,該入庫工作停在待覆核,畫面上會有「略過」或「仍然新增」。為什麼同書名不直接跳掉?因為同一本書可能有不同掃描、不同版本,檔案完全不同,只有第二層看得出來。而第二層一定要停下來等人,因為系統分不出是同一本書的新版本,或真的重複了。
ssh 連到 writer,切換到 /opt/writing-studio,執行 claude code:
把素材庫往上長一層:圖書館。書要有名字、作者、分類,可以整本翻,重複的在門口擋下來。
一、⛔ 閱讀器不要自己寫。存書、書目、瀏覽器翻書全部交給 Calibre,用 calibredb 與
calibre-server;我們只做「入庫判斷」:這是哪本書、放哪一格、有沒有重複,
然後交給 Calibre,再把切好的段送進素材庫。
⚠️ 書名/作者/分類的唯一真相在 Calibre 的資料庫,素材庫那邊只留一張薄映射表。
⚠️ 系統碟只有 34G。掃描書辨識完的頁圖一律刪,⛔ 不要為了翻頁器把每一頁永久留著。
二、書名與作者分三層:先讀檔案內嵌 metadata → 讀不到或讀到垃圾才把內文開頭丟給本地那台
語言模型猜 → 每一個欄位事後都可以手改。
⛔ 不可以信檔名。⛔ 上傳檔不可以存成通用檔名(raw.pdf 這種),
沒有內嵌書名的 PDF 會把檔名當書名回傳。
三、分類兩層。大分類是受控詞彙,放一份清單檔;模型只能從清單挑一個,真的都不符才提新的,
新的要登記回清單。系列走 Calibre 原生的 series/series_index,盡量沿用既有系列名。
種子清單用我給的 10 個。
四、🔴 查重擋兩次。①上傳當下算 SHA256 比對館內,完全相同直接判重複略過,
⛔ 不跑辨識、不猜書名、不算向量。②書名判出來之後正規化比對既有書名,
疑似同一本的 ⛔ 不可以自動入庫,停在待覆核,畫面上讓我選「略過」或「仍然新增」。
⚠️ 第二層一定要停下來等人:程式分不出「新版本」與「真重複」。
五、⚠️ 素材問答與生產頁的檢索範圍預設只納入「靈性修行」「心理學」兩個大分類,
其他分類要我手動勾選才進來。書庫太廣,不收斂會汙染生成素材。
規則:入庫工作要可續跑,狀態存在工作目錄的 meta 檔,服務重啟後能接著跑。
網站電子書閱讀
點書開新分頁,直接進 Calibre 的閱讀器:書目頁看得到格式、分類、系列與冊序,按下去就是全文,掃描書讀的是原始 PDF,不是辨識出來的文字。但一本書能在這裡被翻、同時能在素材庫裡被搜,中間要過的關比想像多,下面是真的撞到的那幾關。
Calibre 書目頁:格式、標籤、系列、作者,Read 按下去就是全文

Calibre 閱讀器:瀏覽器裡直接翻,這本是自己譯的《文殊三十六卦》

一開始所有書排同一條隊,同時最多 3 個工作在跑。掃描書要逐頁送去OCR那台辨識,一本要跑幾十分鐘到幾小時;純文字,ePub 幾秒就完。結果是兩本圖片型的 EPUB 把隊伍佔死,後面 150 本文字書乾等。於是改成兩個工作列:PDF 與圖片型 EPUB 走一個工作流程,文字書走另一個工作流程,各自 2 個名額,這樣,文字版本可以迅速處理完,要 OCR 的就慢慢排隊。
辨識的觸發條件第一版寫的是完全抽不到文字才辨識。七月中做全庫體檢,抓到 4 本空殼:兩本圖解經濟學、一本手作品牌、一本解憂起笑店,每本只抽到 188 到 1055 字,其餘全是圖。它們文字非零,舊條件攔不住,書名分類都正常,只是素材庫裡那本書幾乎沒有內容,問它任何問題都撈不到。條件改成兩件事同時成立才辨識:抽到的文字低於 2000 字,而且內嵌圖片至少 10 張。一本真的書抽出來的字數不可能低於 2000,這個數字是看著 4 本空殼定的,不是猜的。規則是:判斷這本書進來了沒不能只看它有沒有進 Calibre,要看素材庫裡它有幾段。
七月最大的一批是中華書局的廿五史,22 部史書、205 冊,全部是掃描 PDF。這一批逼出三件事。
第一,書名與作者不給語言模型猜。檔名本身已經精確寫著哪一史第幾冊,作者查表就有,所以這一批入庫零語言模型呼叫,書名加上 01 到 25 的順序前綴,冊序寫進系列編號。批次期間本地那台語言模型的 GPU 故障了兩次,這一批不靠它猜書名,照樣往前跑。
第二,毒頁。個別文字特別密的頁,OCR辨識模型的輸出會打壞伺服器端的解析器,同一張圖重試 3 次、換三種溫度全部固定失敗,整本書卡在錯誤。處理不是修模型,是給頁面一個自動階梯,一級一級降規格,最後才留給人讀圖,批次期間人工或半自動救援 10 次以上。
第三,續跑。每一頁辨識完就寫成一個檔,重跑只補沒有的頁。批次收尾:0 失敗,館藏 726 本。編號完整,沒有一冊需要事後改名。
七月下旬上傳一批蘇東坡的書,全是簡體。之前 EPUB 多半是繁體版,這批簡體 PDF 的書名、作者、全文原封不動進了館,跟整館繁體格格不入,簡繁混雜還會拉低檢索。
所以做兩件事:
- 先把那 8 本重新轉換成繁體字,Calibre 書目、素材庫全文、來源名稱三處一起改,4,689 段重新算向量。
- 在書本入庫時:抽完文字之後、分類之前,偵測內文是不是簡體,是,就將全文、書名、作者,全部轉成繁體中文。偵測的方法是看某個字經過轉換會不會變形,變形的比例超過 5% 才判為簡體。
一本掃描書能在閱讀器裡被翻、在素材庫裡被搜,中間這條入庫管線是這幾段 prompt 一次一次修出來的,合起來是這樣:
圖書館入庫管線:掃描書、大批次、簡繁、失敗處理。
一、⚠️ 掃描 PDF 與圖片型 EPUB 一本要辨識幾十分鐘到幾小時,文字書幾秒。⛔ 不可以排同一條隊。
PDF/圖片型 EPUB 走重池,文字書走輕池,各 2 個名額,互不搶。
「圖片型 EPUB」快篩看壓縮檔裡的檔名清單;圖超過 10 張而快篩沒攔到的,真的抽一次文字確認。
二、🔴 辨識的觸發條件不是「完全沒有文字」:抽到的文字低於 2000 字、而且內嵌圖片至少 10 張就要辨識。
⚠️ 「這本書進來了沒」的判準是素材庫裡它有幾段,⛔ 不是它有沒有出現在 Calibre。
三、🔴 廿五史這種檔名已精確寫著哪一史第幾冊的批次,書名與作者 ⛔ 不給語言模型猜:作者查表、
分類固定、書名加 01–25 順序前綴、冊序寫進 series_index。
續跑要到「頁」這一級:每一頁辨識完就寫一個檔,重跑只補沒有的頁,⛔ 不可以整本重來。
毒頁(辨識輸出打壞解析器、重試固定失敗)給一個自動階梯,一級一級降規格,最後才留給人讀圖。
跳針(同一行重複幾十次)的頁棄用留佔位標記,判斷式要吃去重前的原始文字。
四、🔴 簡繁:抽完文字之後、分類之前偵測內文是不是簡體,是就轉全文+書名+作者,三處一起。
偵測看某個漢字經轉換會不會變形,比例超過 5% 才判簡體;⛔ 低於門檻一律不轉(古籍的正字也會變形)。
⚠️ 抽樣要全篇均勻,⛔ 不可以只看開頭 —— 掃描書前段是書名頁、目錄,漢字少又多簡繁同形。
轉完做全量稽核,列出「合法繁體字但在這本書裡是錯的」(卷→捲、云→雲、干→幹、后→後);
稽核腳本帶保護詞清單,真的該轉的不可以被改回去。
五、⚠️ 檔案內嵌 metadata 是輸入不是事實:書名含控制字元要清掉,含替換字元(U+FFFD)視為爛書名重猜,
作者同樣處理,⛔ 不可以只認「unknown」這個字。
六、🔴 重啟服務前一律先查三條佇列:圖書館入庫、辨識、翻譯,有東西在排就不重啟。
「背景工作不隨主行程被殺」只保行程,不保執行環境 —— 私有暫存目錄重啟時整個銷毀。
七、🔴 入庫是「寫兩個地方」:先寫 Calibre,再寫素材庫。第二個地方失敗,第一個地方要撤回來。
⛔ 不可以留「Calibre 有、素材庫無」的半殘。「仍然新增」遇到素材庫查無此書名時,先清 Calibre 裡的孤兒再入庫。
失敗的工作要能用原檔重試,原始上傳檔只有成功入庫之後才刪。
進度卡上「重試」跟「移除」⛔ 不可以長得一樣、不可以挨在一起;移除會刪原始檔,先跳確認。
八、⚠️ 大批入庫之後排一次全庫分類健檢:排除帶編號的正史,其餘逐本看分類對不對,該開的類別開出來。
重複書判準:EPUB 優先於 PDF、內容多的優先、標題乾淨的優先;⛔ 刪之前先列出兩本的段數與字數。
素材查詢
查詢是整座圖書館的驗收。勾定範圍、問一題、看它的回答,就知道書切得對不對、分類對不對。
素材問答:先勾分類,再勾來源;這次只勾《文殊三十六卦》一本

提問,取材 6 段,生成走本地那台語言模型

查詢中:檢索素材再生成

回答逐點帶出處,下面 6 段原文可以展開對照

館藏過了幾百本之後,素材問答與生產頁的檢索出現一個問題:書越多,答案越差。問一個心理學的問題,回答會混著史書與食譜。所以檢索範圍預設只納入兩個大分類:靈性修行與心理學,這是我寫東西最常用的兩類。其他歷史、投資、科技、飲食、小說,要手動勾選才進來。
另一個數字:不帶任何篩選的檢索,在素材庫 18 萬列的時候一次要 90 秒以上。所以:知識庫做大之後,預設範圍要收斂。
圖書館做起來之後,它開始收書以外的東西。素材頁上傳的檔案與網址一律改走圖書館流程:查重、定名、分類、存 Calibre、進素材庫,一條龍。自己寫的文件可以編成一本 EPUB 併入圖書館,分類叫「我的作品」。八月下旬我從控制中心丟了一份市場摘要進去,沒有給任何分類,系統自己推出書名、推出作者是那份摘要的來源機構、分類「商業管理」,切成 5 段。這件事的意義是:圖書館不只是放書的地方,它是所有以後想找回來的東西的統一入口。
現在的數字。館藏 1015 本,12.8 GB,EPUB 614 本、PDF 401 本。作者 701 位,系列 28 個。七月進了 885 本,八月 130 本。大分類 19 個,最大的一格是廿五史 287 冊,其次歷史 156、心理學 99、商業管理 95、靈性修行 72。素材庫那邊 1066 筆來源、433,833 段。走過文字辨識的書 85 本:掃描 PDF 70 本,圖片型 EPUB 15 本。這些數字全部是掃描產生的,不是手寫的表格。手寫的表一定會過期,而且過期得很安靜。
查詢這一頁的規則,跟圖書館一起長出來:
素材問答與生產頁的查詢範圍。
一、查詢範圍兩層:先勾大分類,再勾來源;不勾就是全部,⛔ 不要預設幫我縮小範圍。
⚠️ 但預設勾選只有「靈性修行」「心理學」兩類 —— 書庫太廣,其他類要我自己勾進來。
類別下拉要列出每一類有幾本,非書的素材歸「一般素材」。
二、🔴 答案只能根據檢索到的段落來寫。每一則答案下面逐條列出:哪一本書、第幾段、原文全文,可以展開。
⛔ 檢索不到就說檢索不到,不要用常識補一段看起來合理的答案。
三、取幾段要可以調,預設 6。⚠️ 取太少會漏,取太多會把不相干的段落一起餵進去。
四、🔴 不帶篩選的檢索在素材庫 18 萬列的時候一次要 90 秒以上,逼近無法使用。
向量從 JSON 文字改存二進位 BLOB(一列 22,785 bytes → 4,096 bytes,省掉逐列解析)。
一次性遷移腳本要冪等、已轉的列跳過;⚠️ 先停服務、確認三條佇列都空再跑,跑完回收空間。
五、⚠️ 每一段要能回答「這是哪一本、第幾段」。改書名的時候,段、來源、書目三張表一起改名,
⛔ 不可以只改其中一張。
規則:問答的紀錄留檔,那些問題本身就是下一篇的題目。
回頭看,圖書館真正的工作不是收書,是收書之後那些沒完沒了的維護:查重、健檢、簡繁、回滾、孤兒。每一條規則後面都是一本真的壞掉的書。它現在是整套系統的地基:素材問答從它撈段落,生產頁從它勾來源,自己寫的東西也回到它裡面。圖書館建好了。
接下來要處理的是每天的事情:待辦、行事曆、提醒。明天來弄個小秘。
本文為 iThome 2026 鐵人賽「一個人的機房」系列第 18 篇,同步發表於 iT 邦幫忙。