json_repair:把 LLM 吐出的壞 JSON 修回可用的 Python 物件
Repair malformed JSON from LLMs, APIs, logs, and user input in Python.
秒懂
- 它是什麼?
- 這是一個 MIT 授權的 Python 套件,用來修補缺引號、缺逗號、夾雜說明文字或被截斷的 JSON。它的定位是 json.loads() 的備援層,而不是通用解析器;理解它的修補順序與 skip_json_loads 的取捨,才知道該不該放進正式流程。
- 適合誰用?
- 如果你在 Python 服務裡接收 LLM 或第三方 API 的 JSON,且錯誤型態以缺引號、缺逗號、尾隨逗號、夾雜說明文字為主,json_repair 可以放在嚴格解析失敗之後當備援層,用預設的 loads() 呼叫即可,讓它自己先跑一次標準函式庫檢查。若你的輸入是使用者上傳的設定檔、金融或法規資料,或錯誤型態其實是編碼與傳輸損毀,這個套件會把損壞內容悄悄補成看似合法的物件,此時應該讓 json.loads() 直接拋錯。
- 可以商用嗎?
- 可以。MIT 是寬鬆授權:你可以使用、修改並販售以它為基礎的軟體,只需保留著作權與授權聲明。
- 還在維護嗎?
- 有在維護。儲存庫最近一次提交在 5 天前。
- 用什麼語言寫的?
- 主要是 Python(依據 GitHub 的語言統計)。
以上回答依據專案的 GitHub 資料(最近同步於 2026年9月15日)與我們的分析,不構成法律意見。
開源專案深度解析
它要修的是哪一種壞 JSON
README 的動機段落寫得很直白:有些 LLM 在回傳結構化資料時會漏括號,或是在 JSON 裡面多塞幾個字,因為那正是語言模型的行為。作者說他找過輕量的 Python 套件來處理這件事,沒找到合適的,於是自己寫了一個。
這個問題的邊界值得說清楚。它處理的不是任意文字轉 JSON,而是「本來就打算是 JSON、只是壞掉」的輸入。README 列出的支援情境包括缺少引號、逗號放錯位置、未轉義字元、不完整的鍵值對,以及 true、false、null 這類字面值格式錯誤。它也能處理夾雜註解或位置不對的字元,清掉之後維持結構。
還有一種情況是值整個不見,套件會用預設值補上,README 提到的是空字串或 null。這代表修補結果不一定等於原始意圖,只是等於一份合法文件。誰適合用:把 LLM 輸出接進後續流程、又不想在每次回應上做嚴格重試的團隊。誰不適合:需要可追溯、可稽核地證明資料未被改寫的場景。
修補流程的順序:先嚴格解析,再進修補器
預設行為是這個套件最容易被誤解的地方。README 說明,json_repair 會先嘗試標準函式庫的 JSON 載入器,只有在嚴格解析失敗時才進入修補解析器。也就是說,呼叫 json_repair.loads() 並不等於放棄驗證,而是把驗證與修補串成兩段。
README 特別點名一種反模式:自己寫 try 包住 json.loads(),在 JSONDecodeError 時才呼叫 json_repair.loads()。文件說這很浪費,因為套件預設已經幫你做了那次嚴格檢查。正常流程就是直接呼叫 json_repair.loads(json_string)。
如果你已經知道輸入無效,可以傳 skip_json_loads=True 跳過第一段驗證,直接進修補解析器。README 把這描述成一個明確的取捨,而不是效能技巧:預設是先驗證、需要時才修補;開啟這個參數則是跳過快速路徑。文件同時警告,這個參數只適用於你已經確定無效的輸入。這一點在實務上很關鍵,因為它把「保護」拿掉了。
安裝與實際呼叫方式
安裝指令是 pip install json-repair,套件在 PyPI 上的名稱用連字號,匯入時用底線。README 給的第一個例子是 repair_json():
from json_repair import repair_json good_json_string = repair_json(bad_json_string)
文件提醒,如果字串壞得太嚴重,這個函式會回傳空字串。要拿回 Python 物件而不是字串,可以改用 json_repair.loads(),或呼叫 repair_json(json_string, return_objects=True)。
讀檔案有兩個入口。json_repair.load(file_descriptor) 是 json.load() 的對應版本,範例是先用 open(fname, 'rb') 取得檔案描述器再交給它。另一個是 json_repair.from_file(json_file)。README 明確指出,套件不會攔截 IO 相關例外,OSError 與 IOError 要由呼叫端自己處理,這一點在寫入檔案處理流程時容易漏掉。
關於輸出格式,repair_json 會接受 json.dumps 支援的參數並直接傳遞,文件舉的例子是 indent。這表示輸出的排版控制沿用標準函式庫的語意,不需要另外學一套。
非拉丁字元與 ensure_ascii 的陷阱
對繁體中文使用者來說,這一段比安裝指令更重要。README 說明,處理中文、日文、韓文這類非拉丁字元時,必須傳 ensure_ascii=False 才能保留原字元。
文件給的例子很具體。呼叫 repair_json("{'test_chinese_ascii':'統一碼'}") 會回傳 {"test_chinese_ascii": "\u7edf\u4e00\u7801"},也就是被轉成 ASCII 逃逸序列。加上 ensure_ascii=False 之後,輸出才是 {"test_chinese_ascii": "統一碼"}。
這個預設值沿用標準函式庫的行為,語意上沒有問題,但對中文日誌、中文欄位名稱或需要人工檢視的輸出,預設值會讓結果難以肉眼比對。如果你的流程後面還要拿這份字串去做字串比對或寫進面向中文使用者的介面,記得在呼叫時就把參數帶上,而不是等到發現輸出變成 \u 開頭的序列才回頭改。
它會安靜地幫你補內容,這正是風險
README 的支援情境裡有一條是自動補完缺失的值,用空字串或 null 之類的預設值填進去,讓文件合法。同一份文件也提到,不完整或破損的陣列與物件會透過補上逗號、括號或預設值來修好。
把這兩條放在一起看,就是這個套件最需要被理解的行為:它傾向產出一份合法文件,而不是告訴你哪裡壞了。對 LLM 輸出這是優點,因為模型本來就常常漏掉一兩個符號,補回來不影響語意。對其他來源就不是了。
想像一份使用者上傳的設定檔少了右括號,或是一筆交易記錄在傳輸中被截斷。修補器會把它補成合法 JSON,你的驗證層看到的是合法物件,錯誤因此往下游擴散,而且沒有任何訊號指出內容被改寫過。這是它作為「錯誤工具」的典型案例:當輸入的來源不可信、或資料完整性本身就是需求時,應該讓 json.loads() 直接拋錯,把問題擋在進入點。
另外要注意,README 開頭提到「如果字串壞得太嚴重會回傳空字串」。這句話沒有定義什麼叫太嚴重,文件也沒有給出判準。如果你的流程會把空字串當成合法結果往下送,這裡就是一個需要自己加檢查的接縫。
與標準函式庫的差別,以及它不打算取代什麼
最直接的替代方案就是 Python 內建的 json 模組。差別在於對錯誤的態度:json.loads() 遇到尾隨逗號或缺引號就丟出 JSONDecodeError,呼叫端必須自己決定重試、丟棄或修字串;json_repair 則是把這些錯誤當成可推測的缺漏,直接補完並回傳物件。
README 甚至把這個套件描述成可以完全取代 json.loads(),因為它預設就會先跑一次嚴格解析。這個說法在功能上成立,但在診斷能力上交換掉了東西:你不再從例外裡得知原始輸入哪裡壞。
另一條路線是要求上游產出合法 JSON,例如在呼叫 LLM 時使用結構化輸出或 schema 約束。這條路線的成本在上游,好處是下游不需要修補邏輯。json_repair 的 repo topics 裡同時出現 json-schema 與 pydantic,README 也把自己定位成 schema 導引的修補步驟之一,但文件沒有展開這部分的用法細節,所以無法從現有材料判斷它與 pydantic 整合的實際行為。如果你的主要需求是欄位型別與結構驗證,而不是語法修補,那應該優先看驗證工具,而不是修補工具。
維護節奏、授權與升級成本
授權是 MIT,這對商業使用與再散布相對寬鬆,但仍應由你自己的法務確認條款適用性。
維護面可以從版本節奏看出一些線索。近期發布包含 v0.63.4、v0.63.3、v0.63.2,時間集中在 2026 年 8 月,最後一次推送是 2026 年 9 月 3 日,儲存庫未封存。三個版本號都在 0.63.x,屬於 0.x 階段,這通常意味著介面仍可能調整。README 也提到這個套件是作者以 side project 形式維護,並設有贊助連結。
對採用者的實際含義是:升級前應該看 release notes,而不是假設 0.63.x 之間沒有行為變動。修補器的行為變動往往不會以 API 破壞的形式出現,而是某些輸入的修補結果改變,這在測試裡不容易被既有案例抓到。如果你的流程對修補結果有依賴,值得把實際會遇到的壞 JSON 樣本存成固定測試資料,在升版時重跑比對。這不是通用建議,而是針對一個會安靜改寫輸入內容的套件所必須付的成本。
編輯結論
如果你在 Python 服務裡接收 LLM 或第三方 API 的 JSON,且錯誤型態以缺引號、缺逗號、尾隨逗號、夾雜說明文字為主,json_repair 可以放在嚴格解析失敗之後當備援層,用預設的 loads() 呼叫即可,讓它自己先跑一次標準函式庫檢查。若你的輸入是使用者上傳的設定檔、金融或法規資料,或錯誤型態其實是編碼與傳輸損毀,這個套件會把損壞內容悄悄補成看似合法的物件,此時應該讓 json.loads() 直接拋錯。採用前先確認三件事:你的 Python 版本是否符合 README 標示的 3.10 以上、輸出是否需要保留中日韓文字(需要就傳 ensure_ascii=False)、以及你是否打算用 skip_json_loads=True 跳過驗證。最後一點尤其要留意,README 明確指出它只適用於你已經確定無效的輸入。
社群筆記