跳到主要內容
maxstudioNews
AI 自動化n8n Community約 3 分鐘

讓 n8n 穩定解析 LLM JSON:防範程式碼區塊導致的靜默錯誤

許多在 n8n 中整合 AI 的工作流,常因大型語言模型(LLM)將 JSON 輸出包裹在 Markdown 程式碼區塊中,導致解析失敗。這篇文章介紹一個簡單的 Code 節點解決方案,它能自動移除程式碼區塊、安全解析 JSON,並在失敗時保留原始文本,避免靜默錯誤並提升工作流的穩定性。

讓 n8n 穩定解析 LLM JSON:防範程式碼區塊導致的靜默錯誤
圖片來源:n8n Community

大多數在 n8n 中整合 AI 的工作流,雖然在測試階段能順利通過,卻常因一個常見原因在實際運行時出錯:模型將其 JSON 輸出包裹在 Markdown 程式碼區塊中。例如,當你要求 { "score": 7 } 時,模型可能會回傳 ``json { "score": 7 } ``。

這會導致 JSON.parse($json.message.content) 拋出錯誤。更糟的是,像 {{ $json.score }} 這樣的表達式可能會靜默地解析為 undefined,讓工作流在空資料上繼續運行。這種靜默失敗是最危險的。

解決方案是在 LLM 節點和所有下游節點之間加入一個 Code 節點。這個節點會執行三件事:首先,它會移除開頭和結尾的程式碼區塊。其次,它會在 try/catch 區塊內執行 JSON.parse。

最重要的是,如果解析失敗,它不會拋出錯誤,而是以已知格式回傳原始文本。這樣一來,你就可以將其導向審核分支,實際查看模型回傳了什麼內容。以下是該 Code 節點的程式碼範例:

const raw = $input.first().json.message?.content ?? '';

const cleaned = String(raw).trim()

.replace(/^```(?:json)?/i, '')

.replace(/```$/, '')

.trim();

let parsed = {};

let parse_ok = true;

try {

parsed = JSON.parse(cleaned);

} catch (e) {

parse_ok = false; // do not throw: keep the item alive

}

return [{ json: { parse_ok, ...parsed, _raw: parse_ok ? undefined : cleaned } }];

接著,你可以使用一個 IF 節點來判斷 parse_ok 的值:如果為 true,則工作流正常繼續;如果為 false,則記錄 _raw 內容,或者發送通知提醒你處理這個錯誤的輸出。

有三種常見的錯誤我一直看到:第一,沒有處理程式碼區塊,即使是強大的模型,尤其是在長輸出時,也會這樣做。第二,在表達式內部呼叫 JSON.parse,因為表達式拋出錯誤會終止項目,讓你無法取得除錯所需的原始回覆。

第三,過度信任模型回傳的 schema。即使是有效的 JSON,也可能出現 action_items: null 的情況。在對陣列進行 .map() 操作之前,務必使用 Array.isArray(x) ? x : [] 進行防護。

一個非常實用的提示詞技巧是:要求嚴格的格式,並指定預設值。例如,你可以寫「如果備註中沒有提及所有者,請寫『未提及』」。這幾乎可以消除所有模型憑空捏造的所有者。

我將這個防護機制應用在一個小型「會議記錄轉待辦事項」的工作流中:手動觸發 → 設定(筆記)→ OpenAI(嚴格 JSON)→ 這個解析加防護 Code 節點 → 設定輸出。這個工作流會回傳摘要、決策、一個包含所有者和截止日期的待辦事項 Markdown 表格,以及一封後續追蹤的草稿電子郵件。

它還會計算未完成的待辦事項數量以供分支判斷,並且從未因錯誤的完成內容而中斷。你如何處理模型回傳的無效 JSON 呢?是使用像這樣的防護機制、自動重試一次,還是依賴 AI Agent 的結構化輸出?我一直在「防護加警報」和「防護加重試一次」之間猶豫不決,所以很想聽聽大家在實際生產環境中,哪種方法更有效。

Share

覺得值得一看?分享給朋友。

以上為 AI 自動翻譯導讀。原文版權歸 n8n Community 所有, 建議透過「閱讀原文」前往原始網站,以取得最完整資訊並支持原作者。

Newsletter

不用每天追,AI 重點每週寄給你

43 個來源、每 2 小時更新,太多看不完。電子報每週挑最值得看的幾則,附上 Max 的看法。

每週一封。Email 只用來寄電子報,每封信都能一鍵退訂。