![]()
2024年Q3,我的翻譯功能日活剛破2萬(wàn),系統(tǒng)就開始在凌晨三點(diǎn)報(bào)警。不是翻譯質(zhì)量下滑,是整段JSON直接解析失敗——用戶看到的不是蹩腳英文,是空白。
罪魁禍?zhǔn)资侨蟹匆?hào)。
模型突然開始"貼心"地用Markdown代碼塊包裹JSON響應(yīng),JSON.parse()當(dāng)場(chǎng)窒息。沒(méi)有預(yù)警,沒(méi)有版本說(shuō)明,OpenRouter的某個(gè)上游模型在負(fù)載高峰時(shí)改變了行為模式。我花了72小時(shí)搭建的三層防御系統(tǒng),全部源于這次生產(chǎn)事故。
第一層:JSON模式是底線,不是選項(xiàng)
最初的實(shí)現(xiàn)堪稱裸奔:系統(tǒng)提示詞寫"請(qǐng)返回JSON",response_format字段空著。這在原型階段跑了三個(gè)月沒(méi)出問(wèn)題,直到那個(gè)凌晨。
修復(fù)方案看起來(lái)簡(jiǎn)單——加上response_format: { type: 'json_object' }。但OpenRouter的文檔埋了個(gè)細(xì)節(jié):結(jié)構(gòu)化輸出并非全模型支持,得逐頁(yè)檢查兼容性列表。我用的Claude 3.5 Sonnet當(dāng)時(shí)剛更新支持,而部分Gemini模型至今沒(méi)有。
這層防御解決的是"模型故意輸出合法JSON"的場(chǎng)景。但LLM的"故意"和人類的理解常有偏差,比如它可能認(rèn)為在JSON外面套個(gè)代碼塊是"幫助用戶閱讀"。
第二層:OpenRouter的隱藏插件
JSON模式能約束格式,卻修不了語(yǔ)法錯(cuò)誤。模型可能在超長(zhǎng)輸出時(shí)截?cái)啵赡馨裊nicode轉(zhuǎn)義寫成亂碼,可能在嵌套對(duì)象里漏掉閉合括號(hào)。
OpenRouter有個(gè)幾乎沒(méi)宣傳的response-healing插件,啟用方式是在請(qǐng)求體里加一行:
plugins: [{ id: 'response-healing' }]
它會(huì)在服務(wù)端嘗試自動(dòng)修復(fù)常見JSON缺陷,比如補(bǔ)全截?cái)嗟淖址⑿拚D(zhuǎn)義序列。但有兩個(gè)硬限制:僅支持非流式響應(yīng),且對(duì)max_tokens導(dǎo)致的截?cái)酂o(wú)能為力——如果模型被令牌上限硬生生切斷,healing插件也拼不回完整的JSON結(jié)構(gòu)。
這層防御讓我扛過(guò)了兩次小規(guī)模故障,但第三次崩潰來(lái)自更隱蔽的角落:模型開始在中文字符里混用全角半角引號(hào),healing插件識(shí)別為合法JSON,我的下游解析器卻爆了。
第三層:客戶端的"不信任"解析器
前兩層都是上游防護(hù),第三層必須握在自己手里。我寫的防御性解析器只做一件事:拒絕任何"看起來(lái)不對(duì)"的數(shù)據(jù),而不是試圖修復(fù)。
具體策略包括:預(yù)檢響應(yīng)體是否以{或[開頭(過(guò)濾掉代碼塊包裝);用zod或類似庫(kù)做運(yùn)行時(shí)schema驗(yàn)證;對(duì)解析失敗返回明確的錯(cuò)誤碼,觸發(fā)降級(jí)流程而非靜默崩潰。
這套邏輯多攔截了17%的"邊緣合法"響應(yīng)——比如模型在JSON末尾加了換行和注釋,或者把數(shù)字鍵名不加引號(hào)地返回。這些在寬松解析器里能過(guò),在我的生產(chǎn)環(huán)境里會(huì)被拒掉。
被忽略的周邊:重試與語(yǔ)言檢測(cè)
JSON處理占了80%的工時(shí),但另外兩層也 worth 提。
重試策略我設(shè)了三檔:首次失敗立即重試(可能是瞬時(shí)網(wǎng)絡(luò)抖動(dòng));第二次失敗切換備用模型(OpenRouter的model字段支持按優(yōu)先級(jí)數(shù)組傳入);第三次失敗返回原文并標(biāo)記待人工審核。沒(méi)有無(wú)限重試,沒(méi)有指數(shù)退避到地老天荒。
語(yǔ)言檢測(cè)則是前置過(guò)濾。用戶生成的日文內(nèi)容里混著英文配料名、片假名外來(lái)語(yǔ)、甚至顏文字,直接扔給翻譯模型會(huì)浪費(fèi)令牌。我用fast-text做初篩,置信度低于0.85的段落跳過(guò)翻譯,原樣展示。
這套組合拳跑下來(lái),翻譯功能的可用性從事故后的94.3%爬回99.6%。但數(shù)字背后有個(gè)更硬的認(rèn)知:LLM API的"穩(wěn)定性"是工程堆出來(lái)的,不是供應(yīng)商承諾出來(lái)的。
OpenRouter的文檔里至今沒(méi)提response-healing的完整故障模式列表,JSON Mode的兼容性矩陣更新滯后于實(shí)際上線時(shí)間。生產(chǎn)環(huán)境的防御深度,取決于你愿意為"模型可能變卦"這個(gè)假設(shè)寫多少代碼。
上周我在日志里又發(fā)現(xiàn)一批異常:某個(gè)模型的響應(yīng)開始隨機(jī)包含BOM頭(字節(jié)順序標(biāo)記),JSON.parse()不報(bào)錯(cuò),但我的schema驗(yàn)證會(huì)掛。第四層防火墻已經(jīng)在寫了。
你的LLM生產(chǎn)環(huán)境里,最近一次"不是bug是特性"的模型行為變更是什么?
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.