分類: Productivity

  • 如何快速修復格式錯誤的 JSON 檔案:開發者實戰手冊

    如何快速修復格式錯誤的 JSON 檔案:開發者實戰手冊

    你的 API 呼叫因 JSONDecodeError: Expecting property name enclosed in double quotes 而失敗。時鐘在滴答作響。資料來自 LLM,而在那個 2000 token 的回應裡,某一個多餘的尾隨逗號毀掉了你整條流水線。

    截至 2026 年 5 月,修復格式錯誤的 JSON 檔案最快的方法是使用自動化函式庫,例如 json_repair(Python)或 jsonrepair(npm)。這些工具專為瞬間修復 LLM 產生的語法錯誤而生。至於手動修復,常見的「元兇」是尾隨逗號單引號未加引號的鍵——這是違反 RFC 8259 標準的三種最常見情形。

    最快的修復方式:針對 LLM 輸出的 json_repair

    像 Python 的 json.loads() 這類標準解析器,在設計上就是嚴格的。一個錯位的字元就會觸發 JSONDecodeError,一切都隨之停止。這在 2026 年是家常便飯,因為 LLM 經常把 JSON 包裹在對話文字裡,把回應截斷在句中,或者撒進一些破壞規範的註解。

    json_repair 函式庫是首選方案。據 GitHub 顯示,截至 2026 年該專案已獲得超過 4700 顆星。它的工作原理是「猜測」字串的意圖——補上缺失的括號、加上引號,並剝除 JSON 區塊周圍多餘的文字。

    json_repair 簡單的三步流程:輸入(損壞)-> 猜測意圖 -> 輸出(有效)

    Python:改造前後

    安裝:pip install json-repair

    損壞的輸入:

    import json_repair
    
    bad_json = '{"user": "Alice", "status": tru'
    decoded_object = json_repair.loads(bad_json)
    

    幕後發生了什麼:json_repair 判斷出 tru 很可能是 true,補上了缺失的右大括號,並回傳了一個合法的 Python 字典。全程零人工介入。

    Salvage 模式:資料實在慘不忍睹時

    對於更棘手的情況,json_repair(v0.59.5+)提供了 Salvage 模式。正如專案文件所述,這個模式專為被截斷的 AI 回應或損壞的日誌而構建。它可以把陣列強制轉換為物件,或者丟棄那些實在救不回來的項目,從而保證輸出符合你的資料結構。

    import json_repair
    
    # Salvage mode for severely truncated data
    result = json_repair.loads(
        '{"items": [{"id": 1, "name": "Widget"}, {"id": 2, "na',
        salvage_mode=True
    )
    # Result: {'items': [{'id': 1, 'name': 'Widget'}, {'id': 2}]}
    # Dropped the incomplete 'na' but saved everything else
    

    npm 替代方案

    對於 Node.js 專案,jsonrepair CLI 能完成同樣的工作:

    # Fix a file in place
    npx jsonrepair broken.json > fixed.json
    
    # Fix a string in a script
    const { jsonrepair } = require('jsonrepair');
    const fixed = jsonrepair('{"name": "test",}');
    

    手動除錯:找出破壞規範的元兇

    當自動化工具也搞不定時,你需要精確定位檔案在何處違反了 RFC 8259。JSON 遠不如 YAML 或 JavaScript 那樣寬容。正如 JSONParser 診斷團隊所解釋的:「解析器在遇到第一個它無法理解的字元時就會失敗,而這往往是幾行之前某個問題的下游症狀。」

    三大 JSON 殺手

    殺手 1:尾隨逗號

    DEV Community 的說法,尾隨逗號是解析失敗的頭號原因。在 JavaScript 裡它們沒問題,但在 JSON 陣列或物件的最後一項之後卻是非法的。

    // BROKEN - trailing comma after "active"
    {
      "name": "Alice",
      "status": "active",
    }
    
    // FIXED - no comma before closing brace
    {
      "name": "Alice",
      "status": "active"
    }
    

    殺手 2:單引號

    JSON 要求鍵和字串值都使用雙引號(")。很多 Python 和 JavaScript 開發者會不小心用上單引號(')。正如 TidyCode 所指出的,這是必須修正的。

    // BROKEN - single quotes
    {'name': 'Alice'}
    
    // FIXED - double quotes
    {"name": "Alice"}
    

    殺手 3:未加引號的鍵

    在 JavaScript 中你可以寫 { name: "Alice" }。但在 JSON 裡,每個鍵都需要雙引號。

    // BROKEN - unquoted key
    {name: "Alice"}
    
    // FIXED - quoted key
    {"name": "Alice"}
    

    非法 JSON 與合法 JSON 語法的並排比較

    「Unexpected Token」錯誤

    當驗證器報出「Unexpected Token」時,意思是解析器遇到了 NaNInfinityundefined——這些都是 JSON 不支援的 JavaScript 常數。JSON 只允許 nulltruefalse 和數字。

    // BROKEN - NaN is not valid JSON
    {"score": NaN, "result": Infinity}
    
    // FIXED - replace with null or valid values
    {"score": null, "result": null}
    

    嚴格解析 vs. 修復解析:何時用哪個

    正確的方法取決於你的資料來自哪裡。人工編輯的設定檔應當使用嚴格解析,以迫使作者修正錯誤;而來自 LLM 或 API 日誌的機器生成資料,則需要基於修復的解析。

    特性 嚴格(json.loads 修復(json_repair
    尾隨逗號 拋出 JSONDecodeError 自動移除
    單引號 失敗 轉換為雙引號
    被截斷的資料 失敗 補全未閉合的括號/引號
    註解 失敗 自動剝除
    最佳用例 人工編輯的設定檔 LLM 輸出、API 日誌

    用 Pydantic 做結構引導的修復

    你可以使用 Pydantic v2JSON Schema 來引導修復過程。給 json_repair 提供一個 schema,工具不僅能修復語法——還能糾正型別(把字串 "1" 轉成數字 1)並用預設值填補缺失的必填欄位。

    from pydantic import BaseModel
    import json_repair
    
    class User(BaseModel):
        id: int
        name: str
        active: bool = True
    
    # Broken JSON with wrong types
    raw = '{"id": "42", "name": "Alice"}'
    repaired = json_repair.loads(raw)
    
    # Validate against schema
    user = User(**repaired)
    # user.id is now int(42), user.active defaults to True
    

    正如 Stefano Baccianella 在其 2025 年的專案說明中所提到的,這種方式針對的是語言模型常產出的那種「大體正確但技術上非法」的 JSON 而做了最佳化。

    處理多 GB 檔案而不崩潰

    修復一個 10KB 的片段很容易。修復一個 2GB 的檔案則需要一套不會吃光你記憶體的策略。把整個檔案載入記憶體會導致記憶體耗盡(OOM)錯誤。

    策略 1:用 ijson 串流處理

    對於海量資料集,使用 ijson 逐塊處理資料。正如 Scrapfly 所述,ijson 會增量地處理資料。把它與一個在解析前逐行修復問題的清理腳本搭配使用。

    import ijson
    
    # Stream through a large JSON file
    with open('huge_broken.json', 'r') as f:
        for item in ijson.items(f, 'records.item'):
            # Process each item individually
            process(item)
    

    策略 2:用 CLI 管道實現最高效率

    處理大檔案時最省記憶體的方法是使用 jsonrepair CLI,並把輸出直接管道到一個新檔案:

    # Streams repair, never loads full file into memory
    jsonrepair large_broken.json > fixed.json
    

    這比把檔案載入 Python 或瀏覽器要省記憶體得多。

    結語

    得益於 json_repair 這類對 AI 友好的函式庫,修復格式錯誤的 JSON 已不再是體力活。你仍然需要了解 RFC 8259 的基本規則——不能有尾隨逗號、不能有單引號、鍵必須加引號——但在 2026 年面對大規模資料時,自動化才是唯一現實的做法。

    工作流程很簡單:先嘗試修復函式庫。如果失敗,再用驗證器精確定位語法錯誤。這樣即使輸入的資料不那麼完美,你的應用也能持續運行。

    常見問題

    JSON 官方是否支援註解或單引號?

    不支援。RFC 8259 標準嚴格禁止註解。單引號同樣非法——鍵和字串只允許使用雙引號。不過,json_repair 這類工具可以自動剝除註解並轉換引號,使檔案能被標準函式庫解析。

    如何處理超大且格式錯誤的 JSON 檔案而不崩潰?

    使用 ijson 這類串流解析器分塊處理資料。避免把整個格式錯誤的字串載入單一變數。為了最快速度,可使用 CLI 修復工具,把輸出直接管道到磁碟上的新檔案,無需把所有內容都留在記憶體中。

    格式錯誤的 JSON 和無效的 JSON 有什麼區別?

    格式錯誤(malformed)的 JSON 違反語法規則——缺失括號、鍵未加引號、尾隨逗號——使其無法解析。無效(invalid)的 JSON 遵守所有語法規則,但不符合某個具體的 JSON Schema(例如某個欄位在 schema 裡應為整數,實際卻是字串)。修復格式錯誤的 JSON 屬於結構性修復;修復無效的 JSON 則關乎資料完整性。

    我能把 json_repair 和 Pydantic 驗證一起用嗎?

    可以。先用 json_repair.loads() 修復語法錯誤,再把修復後的字典傳給你的 Pydantic 模型進行型別驗證和 schema 校驗。這種兩步走的方法同時解決了結構性和語意性問題。

    帶有 JavaScript 風格註解的 JSON 怎麼辦?

    標準 JSON 不支援註解,但 json_repair 可以自動剝除 ///* */ 註解。如果你需要在設定檔裡保留註解,可以考慮使用 JSONC(帶註解的 JSON)格式,並搭配 json5(Python)這類相容的解析器。

  • 如何用格式化器編寫 AI 提示詞:面向開發者的結構化工程

    如何用格式化器編寫 AI 提示詞:面向開發者的結構化工程

    當 AI 的輸出與你要求的大相逕庭時,你一定有過那種挫敗感:JSON 格式錯誤、語氣不對,一半的指令被直接忽略。問題不在模型,而在於你如何格式化提示詞。

    要掌握如何用格式化器編寫 AI 提示詞,就要使用 RTCCO 框架(Role 角色、Task 任務、Context 背景資料、Constraints 約束、Output 輸出),搭配 XML 或 JSON 這類結構化分隔符。這樣可以把提示詞當作可重用的軟體資產來對待,截至 2026 年 5 月,這種做法能將模型幻覺降低多達 60%,並把人工處理時間縮短 75%。

    為什麼段落式提示詞總是失敗

    到了 2026 年,專業的 AI 工作已經從「聊天」轉向了提示詞即程式碼(Prompt-as-Code,PaC)。段落式提示詞——那些冗長、無結構的文字區塊——的問題在於,模型很難把你真正的指令,與混雜在其中的背景資料或輸出要求區分開來。

    來自 PromptOT 的資料顯示,轉向結構化工程可以把錯誤率降低 60%,並讓人工處理速度提升 75%。Alex Ostrovskyy 把硬編碼的提示詞比作「原始碼中魔法數字的現代翻版」——脆弱的系統,幾乎無法在不破壞現有功能的前提下更新。

    改造前後:格式化的差異

    改造前(無結構):

    You are a helpful coding assistant. Please write a Python function that validates
    email addresses. Make sure it handles edge cases like plus signs and subdomains.
    The output should be in JSON format with a valid boolean and the cleaned email.
    Also make sure you add proper error handling and don't forget logging.
    

    改造後(RTCCO + XML 分隔符):

    <system_instructions>
      <role>Senior Python engineer specializing in input validation</role>
      <primary_objective>Write a production-grade email validator</primary_objective>
    </system_instructions>
    
    <context>
      Must handle: plus addressing ([email protected]), subdomains,
      internationalized domains. Target: Python 3.11+.
    </context>
    
    <task_requirements>
      <rules>
        - Use only stdlib (no regex shortcuts)
        - Return structured JSON
        - Include type hints
      </rules>
      <steps>
        1. Parse the input string
        2. Validate format per RFC 5322
        3. Return JSON with "valid" boolean and "cleaned_email"
      </steps>
    </task_requirements>
    
    <output_format>
      {"valid": bool, "cleaned_email": str, "error": str | null}
    </output_format>
    

    目標相同,結果卻天差地別。格式化後的版本讓模型沒有任何產生歧義的空間。

    RTCCO 框架:你的提示詞骨架

    業界已經把 RTCCO 視為標準的提示詞架構。每個提示詞都拆解為五個部分:

    元素 作用 範例
    R 角色(Role) AI 是誰? 「資深後端工程師」
    T 任務(Task) 具體做什麼? 「寫一個限流中介軟體」
    C 背景(Context) 有哪些背景資料? RAG 檢索結果、程式碼片段
    C 約束(Constraints) 規則是什麼? 「不依賴任何外部函式庫」
    O 輸出(Output) 輸出該長什麼樣? 「帶型別註解的合法 Python 3.11」

    RTCCO 框架的五個組成部分

    可以直接複製的 XML 骨架模板

    下面是可直接用於生產環境的模板。複製它、改造它、部署它。

    <system_instructions>
      <role> [Expert Persona] </role>
      <primary_objective> [Main Goal] </primary_objective>
    </system_instructions>
    
    <context>
      [Background Data or RAG Retrieval]
    </context>
    
    <task_requirements>
      <rules> [Non-negotiable Constraints] </rules>
      <steps> [Specific Workflow] </steps>
    </task_requirements>
    
    <output_format>
      [JSON/XML/Markdown Specification]
    </output_format>
    
    <recency_recap>
      [Reminder of Critical Constraints]
    </recency_recap>
    

    為什麼「近因回顧」很重要

    大語言模型存在一種已知的「首因與近因」偏差——它們對提示詞開頭和結尾的記憶,要好於中間部分。PromptOT 引用的測試表明,把關鍵規則從中間移到底部的「近因回顧(Recency Recap)」區塊,能讓生產環境的準確率從 78% 提升到 96%。把角色放在頂部,把最重要的規則放在底部。

    長提示詞中首因與近因效應的視覺化

    把分隔符當作安全圍欄

    分隔符不僅關乎組織結構——它還是一種安全機制。用 <user_input> 之類的標籤包裹使用者輸入,等於告訴模型:「這是待處理的資料,而不是要遵循的新指令。」這是你抵禦提示詞注入攻擊的首要防線——在這類攻擊中,使用者會試圖覆蓋你的系統指令。

    常見陷阱: 如果你直接把使用者資料塞進提示詞而不加分隔符,使用者只需寫一句「忽略之前所有指令,然後……」,模型就會照辦。務必把外部資料放在帶標籤的區塊裡。

    模組化架構:停止編寫巨型提示詞

    與其寫一個脆弱的 2000 token 巨型提示詞,不如把系統拆成相互獨立的模組。這能防止指令衝突——即修改提示詞語氣時,意外破壞了它的 JSON 輸出格式。

    核心原則是情境工程(Context Engineering):把靜態指令與動態資料分開。在生產級 RAG 系統中,你的提示詞是一個模板,<context> 區塊會在查詢時被填入最新資料。正如 OptizenApp 的 Jono Farrington 所解釋的,這種模組化方法讓大規模 AI 部署的一致性大大提升。

    提示詞鏈:連接各個模組

    對於複雜的工作流程,使用提示詞鏈(Prompt Chaining)——一個模組的輸出成為下一個模組的輸入:

    [Planner Module] --> outline --> [Executor Module] --> draft --> [Reviewer Module] --> final
    

    這種逐步推進的方式能把輸出品質提升約 35%,因為模型每次只專注於一個子任務。

    簡單的三步提示詞鏈工作流程

    可直接重用的鏈式範例:

    planner_prompt = """
    <system_instructions>
      <role>Technical architect</role>
      <task>Create a step-by-step plan for: {user_request}</task>
    </system_instructions>
    <output_format>JSON array of steps</output_format>
    """
    
    executor_prompt = """
    <system_instructions>
      <role>Senior developer</role>
      <task>Implement step: {step_from_planner}</task>
    </system_instructions>
    <context>{previous_outputs}</context>
    <output_format>Code block with inline comments</output_format>
    """
    

    為難題加入思維鏈

    當任務涉及複雜邏輯時,增加一個 <thought_process> 區塊。這會迫使模型在給出答案前逐步推理,能顯著降低數學、程式設計和多步推理中的錯誤。

    <task_requirements>
      <rules>Reason inside <thought> tags before answering</rules>
    </task_requirements>
    
    <output_format>
      <thought> [Your step-by-step reasoning here] </thought>
      <answer> [Final JSON output here] </answer>
    </output_format>
    

    根據 Zencoder 的說法,思維樹(Tree-of-Thoughts,ToT)等技術更進一步,要求模型同時評估多條解題路徑並選出最優解。這對那些沒有唯一正確答案的架構決策尤其有價值。

    Token 成本警告

    結構化推理會消耗更多 token。一個典型的 <thought_process> 區塊每次請求會增加 200–500 個 token。在規模化使用時,這意味著更高的 API 成本。代價換來的是準確率:你為每次請求付出更多,但需要的重試和人工修正更少。

    生產就緒:版本管理、測試與 CI/CD

    最後一步是把提示詞當作軟體來對待。使用語意化版本號(如 v1.0.0),這樣團隊就能追蹤變更,並在新版本導致效果下滑時立即回復。

    PromptOT 的報告指出,管理 50 個以上提示詞的企業,透過集中化管理並減少工程師手動微調所花的時間,每年可節省多達 40 萬美元。

    搭建提示詞 CI/CD 流水線

    # .github/workflows/prompt-tests.yml
    name: Prompt Quality Gate
    on: [push]
    jobs:
      test-prompts:
        runs-on: ubuntu-latest
        steps:
          - name: Run Golden Dataset Tests
            run: |
              # Test against 50-200 curated cases
              python scripts/eval_prompts.py \
                --dataset golden_dataset.json \
                --judge-model gpt-4 \
                --min-score 0.85
    
          - name: Regression Check
            run: |
              # Compare new version vs. production
              python scripts/compare_versions.py \
                --staging v2.1.0 \
                --production v2.0.3 \
                --threshold 0.05
    

    只有當提示詞通過了由「LLM as a judge(LLM 充當評判)」打分的品質門禁後,才會從 Staging 晉升到 Production

    結語

    使用格式化器的結構化提示詞工程已不再是可選項——它是任何構建可靠 AI 工具之人的基準線。RTCCO 框架、XML 分隔符和模組化架構,就是你把不可預測的 LLM 輸出轉化為穩定、生產級結果的工具棧。

    從你最常用的提示詞入手,用上面的 XML 模板把它們重構為 RTCCO 框架。把它們納入版本管理,搭建基本的評估體系,你就會擁有一套可擴展的提示詞基礎設施。

    常見問題

    如何把現有的段落式提示詞轉換成 RTCCO 區塊格式?

    先找出核心的任務(Task),再把它與背景(Context)分開。用 <rules> 標籤包裹指令,並在 <examples> 標籤裡提供 3–5 個範例。你甚至可以讓 LLM 幫忙——給它這樣的提示詞:「把這些無結構文字用 XML 分隔符重新解析為 RTCCO 框架」,它就會替你完成繁重的轉換工作。

    我該用 XML、JSON 還是 Markdown 分隔符?

    對於在 Claude 和 GPT-5 等模型中把指令與長文字內容分隔開,XML 是目前的黃金標準,因為它有嚴格的層級結構。當你需要為 API 整合提供程式化的輸入輸出時,JSON 更合適。Markdown 適用於簡單、人類易讀的提示詞,但缺乏複雜、多層生產級提示詞所需的嚴格邊界定義。

    如何為提示詞實現自動化 CI/CD 測試?

    搭建一套測試套件,包含一個「黃金資料集」(50–200 個精選測試案例)和一個「LLM as a judge」,按照評分標準對輸出打分。把這些測試整合到 GitHub Actions 或 Jenkins 流水線中,這樣任何提示詞變更在部署前都會經過準確率和語氣的驗證。

    切換到結構化提示詞時最常見的錯誤是什麼?

    <context> 區塊裡塞太多東西。開發者經常把整個程式碼庫或文件倒進背景裡,這會分散模型的注意力。要讓背景聚焦於與任務直接相關的內容。如果需要引用大文件,就用 RAG 檢索只拉取相關章節。