定方案:自建網(wǎng)關(guān)與多供應(yīng)商降級(jí)實(shí)戰(zhàn))
做服務(wù)端這塊以來(lái)最讓我頭疼的采購(gòu)單不是服務(wù)器而是大模型 API 的賬單。官方接口質(zhì)量確實(shí)有保證可價(jià)格明明白白放在那里按 Token 計(jì)費(fèi)量一上來(lái)就肉疼直接連官方接口又經(jīng)常遇上限流和超時(shí)尤其業(yè)務(wù)高峰期429 和 504 交替出現(xiàn)用戶那邊直接看到白屏。這個(gè)問(wèn)題說(shuō)白了就是官方 API 太貴、直連又不穩(wěn)而我最后是用“自建接入網(wǎng)關(guān) 多供應(yīng)商降級(jí)梯隊(duì) 用量治理”這套組合解決的。這篇文章不繞彎子直接講我踩過(guò)的坑、算過(guò)的賬以及現(xiàn)在線上跑的方案適合預(yù)算有限的個(gè)人開發(fā)者和三五十人團(tuán)隊(duì)參考。1. 先摸清癥結(jié)官方 API 貴在哪里直連不穩(wěn)又卡在哪里1.1 Token 計(jì)費(fèi)里的三個(gè)隱形漏斗很多人只看模型單價(jià)覺(jué)得“價(jià)格表這么低怎么可能超預(yù)算”。真正的賬單爆炸通常來(lái)自三個(gè)不容易察覺(jué)的環(huán)節(jié)。第一個(gè)是上下文膨脹。我接手過(guò)一個(gè)客服機(jī)器人最初 Prompt 只有兩百字后來(lái)運(yùn)營(yíng)同學(xué)不斷在系統(tǒng)提示里補(bǔ)充規(guī)則不知不覺(jué)膨脹到了四千字。用戶每次對(duì)話都要攜帶這段超長(zhǎng)前綴而輸入 Token 是按人頭重新計(jì)費(fèi)的。假設(shè)一天一萬(wàn)次請(qǐng)求兩百字變四千字輸入成本直接翻二十倍。這個(gè)成本增長(zhǎng)不體現(xiàn)在單次體驗(yàn)上只體現(xiàn)在月底賬單里。第二個(gè)是重試重復(fù)計(jì)費(fèi)。官方 API 偶發(fā)超時(shí)很正常最初客戶端邏輯是“超時(shí)就重新請(qǐng)求”但事前沒(méi)有排查上一個(gè)請(qǐng)求是否已經(jīng)被服務(wù)端接收。結(jié)果高峰期經(jīng)常出現(xiàn)同一個(gè)請(qǐng)求被重復(fù)處理用戶只看到一次回答賬單上卻計(jì)了兩次費(fèi)。這個(gè)坑在高并發(fā)場(chǎng)景下尤其明顯因?yàn)槌瑫r(shí)集中在流量高峰一次雪崩可能帶來(lái)成倍的重試。第三個(gè)是無(wú)腦重復(fù)調(diào)用。同一個(gè)問(wèn)題在不同會(huì)話里問(wèn)了很多遍每次都走完整推理鏈路完全沒(méi)考慮緩存。哪怕系統(tǒng)提示詞優(yōu)化得再好高頻重復(fù)問(wèn)題依然在燒錢。后來(lái)我加了語(yǔ)義緩存之后類似“怎么退款”“人工客服幾點(diǎn)上班”這類重復(fù)問(wèn)題大概有三分之一被直接命中攔截沒(méi)有進(jìn)模型。為了看清“貴”到底貴在哪我算過(guò)一筆簡(jiǎn)單的賬。假設(shè)某主流模型輸入價(jià)格是 0.5 元/百萬(wàn) Token輸出價(jià)格是 2 元/百萬(wàn) Token每天一萬(wàn)次調(diào)用平均每次輸入 2000 Token、輸出 500 Token輸入日成本 10000 × 2000 × 0.5 / 1000000 10 元輸出日成本 10000 × 500 × 2 / 1000000 10 元月成本大約 600 元。如果上下文膨脹到 8000 Token輸入日成本會(huì)變成 40 元月成本直接變成一千五以上。再加上重試重復(fù)計(jì)費(fèi)實(shí)際可能到兩千元。所以說(shuō)“貴”不完全是因?yàn)閱蝺r(jià)更多是用量習(xí)慣和接入方式造成的浪費(fèi)。1.2 直連不穩(wěn)定缺的其實(shí)不是網(wǎng)絡(luò)而是治理層先定義一下這里說(shuō)的“直連”客戶端把請(qǐng)求直接發(fā)到官方 API Endpoint不經(jīng)過(guò)任何中間層。這種方式在開發(fā)階段完全沒(méi)問(wèn)題但放到生產(chǎn)環(huán)境就暴露出四個(gè)缺口。第一是并發(fā)與限流。官方網(wǎng)關(guān)對(duì)單個(gè) Key 的每分鐘請(qǐng)求數(shù)、每分鐘 Token 數(shù)都有硬限制。業(yè)務(wù)秒級(jí)并發(fā)一上來(lái)429 就滿天飛。429 一旦出現(xiàn)如果客戶端沒(méi)有做指數(shù)退避只會(huì)加劇限流陷入“越急越失敗越失敗越重試”的惡性循環(huán)。第二是連接復(fù)用。官方接口走 HTTPS每次新建連接都要完成 TCP 握手和 TLS 握手。連接池配置不當(dāng)或者長(zhǎng)連接被服務(wù)端斷開后沒(méi)有及時(shí)重連P99 延遲會(huì)被拉得很高。很多團(tuán)隊(duì)只盯著模型推理時(shí)間卻忽略了握手開銷占了總耗時(shí)的大半。第三是超時(shí)與重試規(guī)范。超時(shí)值設(shè)得太短正常的慢請(qǐng)求被誤殺設(shè)得太長(zhǎng)故障時(shí)用戶要等很久。更麻煩的是重試沒(méi)有冪等標(biāo)識(shí)失敗后重新發(fā)送服務(wù)端可能已經(jīng)處理過(guò)了于是用戶得到一次回復(fù)賬單卻記了兩次費(fèi)用。第四是鏈路波動(dòng)。不同地區(qū)訪問(wèn)同一 APIDNS 解析可能落到不同的集群節(jié)點(diǎn)時(shí)延方差巨大。業(yè)務(wù)高峰期官方網(wǎng)關(guān)本身也會(huì)出現(xiàn)負(fù)載不均表現(xiàn)為時(shí)好時(shí)壞。這些問(wèn)題都不是改一個(gè)“超時(shí)時(shí)間”能解決的它們屬于接入層治理的范疇。想解決“直連不穩(wěn)”不能只盯著網(wǎng)絡(luò)而是要在應(yīng)用和上游之間補(bǔ)一層統(tǒng)一處理限流、超時(shí)、重試、緩存和故障切換。這正好引出后面要展開的方案。2. 方案權(quán)衡官方企業(yè)版、第三方 API 服務(wù)商、自建網(wǎng)關(guān)到底怎么選2.1 先算成本賬再談選型在動(dòng)手接第三方之前我建議所有人都先做一次成本測(cè)算。因?yàn)楹芏鄷r(shí)候不是平臺(tái)貴而是你選錯(cuò)了購(gòu)買方式。官方公開價(jià)適合開發(fā)調(diào)試、低頻率生產(chǎn)調(diào)用。優(yōu)點(diǎn)是沒(méi)有中間商缺點(diǎn)是沒(méi)有折扣也沒(méi)有流量治理能力。官方企業(yè)版適合月度調(diào)用量穩(wěn)定且高的團(tuán)隊(duì)。銷售可以談?wù)劭弁ǔ1裙_價(jià)低 10% 到 40%。缺點(diǎn)是要求一定消費(fèi)量流程偏重對(duì)個(gè)人開發(fā)者基本談不下來(lái)。第三方 API 服務(wù)商這些廠商向上游批量采購(gòu)再把能力以兼容 OpenAI SDK 的方式開放給開發(fā)者。對(duì)散戶來(lái)說(shuō)它解決的是兩件事用批發(fā)價(jià)買到更多調(diào)用量以及獲得多線路容災(zāi)能力。缺點(diǎn)是需要在第三方平臺(tái)充值存在平臺(tái)穩(wěn)定性和數(shù)據(jù)合規(guī)風(fēng)險(xiǎn)。自建網(wǎng)關(guān)它不替代供應(yīng)商而是在你的應(yīng)用和多個(gè)上游之間加一層統(tǒng)一做緩存、重試、熔斷和計(jì)費(fèi)。自建網(wǎng)關(guān)解決的是以后每次調(diào)整供應(yīng)商不需要?jiǎng)訕I(yè)務(wù)代碼只需要改配置。我把四個(gè)方案做了對(duì)比方案準(zhǔn)入門檻成本水平穩(wěn)定性適合場(chǎng)景官方公開價(jià)低基準(zhǔn)價(jià)一般取決于鏈路開發(fā)測(cè)試、低頻生產(chǎn)官方企業(yè)折扣高基準(zhǔn)價(jià) 70%-90%較高用量大的正規(guī)業(yè)務(wù)第三方 API 服務(wù)商低基準(zhǔn)價(jià) 50%-85%中高個(gè)人開發(fā)者、小團(tuán)隊(duì)自建網(wǎng)關(guān)中增加少量開發(fā)成本高需要長(zhǎng)期精細(xì)治理的業(yè)務(wù)實(shí)際選型時(shí)不一定只選一個(gè)。我最后是把“官方 Key 第三方服務(wù)商”都作為上游外面再包一層自建網(wǎng)關(guān)做治理組合起來(lái)用。2.2 第三方 API 服務(wù)商為什么能“便宜又穩(wěn)”很多人第一次接觸第三方 API 服務(wù)商會(huì)懷疑它是不是藏著什么貓膩為什么上游官方價(jià)格那么貴它卻能便宜 20% 甚至 50%原因主要有三個(gè)。第一是折扣差。他們和上游簽的是預(yù)付包量協(xié)議或者享受階梯折扣采購(gòu)價(jià)低于公開價(jià)。平臺(tái)再把能力轉(zhuǎn)售給大量開發(fā)者從中賺取合理差價(jià)。只要用量足夠大差價(jià)空間是真實(shí)存在的。第二是網(wǎng)絡(luò)復(fù)用。這些平臺(tái)有自己的機(jī)房和網(wǎng)絡(luò)資源能把官方接口放到更優(yōu)鏈路上并提供統(tǒng)一的接入入口。對(duì)個(gè)人開發(fā)者來(lái)說(shuō)省去了自己優(yōu)化網(wǎng)絡(luò)的成本。第三是多上游容災(zāi)。成熟的平臺(tái)通常同時(shí)接多個(gè)上游供應(yīng)商某一個(gè)源出了問(wèn)題能自動(dòng)切換。這是散戶自己很難做到的。但選擇平臺(tái)時(shí)一定要謹(jǐn)慎。我自己的篩選標(biāo)準(zhǔn)是支持 OpenAI 兼容格式、計(jì)價(jià)透明、有請(qǐng)求級(jí)賬單、提供小額測(cè)試額度、明確說(shuō)明數(shù)據(jù)不留存、工單響應(yīng)及時(shí)。決定長(zhǎng)期使用前先充一個(gè)最低檔用三天小流量灰度重點(diǎn)看 P99 耗時(shí)、429 限流頻率和錯(cuò)誤返回結(jié)構(gòu)。這里必須提醒一句遇到那些聲稱“無(wú)限調(diào)用”“無(wú)視限流”“永久免費(fèi)”的渠道盡量遠(yuǎn)離。大概率有違規(guī)風(fēng)險(xiǎn)數(shù)據(jù)安全也完全沒(méi)有保障。2.3 自建網(wǎng)關(guān)把主控權(quán)拿回自己手里自建網(wǎng)關(guān)聽起來(lái)工程量大其實(shí)對(duì)一個(gè)十人左右的技術(shù)團(tuán)隊(duì)來(lái)說(shuō)用 FastAPI Redis 就能實(shí)現(xiàn)一個(gè)最小可用版本。它不需要很強(qiáng)的造輪子能力核心是這五個(gè)模塊配置中心用來(lái)維護(hù)模型列表、供應(yīng)商優(yōu)先級(jí)、成本權(quán)重路由層按業(yè)務(wù)場(chǎng)景把請(qǐng)求分到不同上游緩存層攔截高頻重復(fù)問(wèn)題可靠性層負(fù)責(zé)超時(shí)、重試、熔斷和退避可觀測(cè)層記錄每一次調(diào)用的 Token、費(fèi)用、延遲和狀態(tài)碼。網(wǎng)關(guān)的另一層價(jià)值在于它可以承載“灰度切換”。以前想從一個(gè)供應(yīng)商切到另一個(gè)要改代碼發(fā)版有了網(wǎng)關(guān)只需要在配置中心調(diào)整分流比例比如官方 20%、第三方 A 平臺(tái) 70%、第三方 B 平臺(tái) 10%改完立即生效。供應(yīng)商故障時(shí)可以把對(duì)應(yīng)權(quán)重直接改成 0其他流量自動(dòng)走剩余通道。第三章我會(huì)給出一個(gè)最小可用的實(shí)現(xiàn)它不需要復(fù)雜框架一個(gè) Python 封裝類就夠了。3. 實(shí)操?gòu)牧愦钇鹨惶资″X又不飄的 API 接入層3.1 第一步盤點(diǎn)業(yè)務(wù)調(diào)用畫像任何改動(dòng)之前先回答幾個(gè)問(wèn)題日均調(diào)用量是多少高峰期 QPS 是多少平均輸入 Token、輸出 Token 分別是多少上下文有沒(méi)有過(guò)度膨脹P99 延遲、429 和 5xx 錯(cuò)誤率是多少每月實(shí)際出賬費(fèi)用是多少哪些功能模塊消耗最大我當(dāng)時(shí)把所有調(diào)用場(chǎng)景列了個(gè)表客服、摘要、分類、寫作。每個(gè)場(chǎng)景標(biāo)注“高價(jià)值/低成本”。比如用戶直接操作的對(duì)話屬于高價(jià)值后臺(tái)批量摘要屬于低成本。這個(gè)標(biāo)記決定了后續(xù)的路由策略高價(jià)值場(chǎng)景優(yōu)先保證質(zhì)量低成本場(chǎng)景優(yōu)先用廉價(jià)供應(yīng)商。同時(shí)還要統(tǒng)計(jì)上下文長(zhǎng)度分布。有些場(chǎng)景明明只是分類任務(wù)卻把整篇長(zhǎng)文都塞進(jìn)去輸入成本被拉得很高。后來(lái)我加了前置截?cái)嗪完P(guān)鍵信息抽取平均輸入 Token 從五千降到了一千二成本直接降了一截。3.2 第二步配置上游供應(yīng)商與降級(jí)梯隊(duì)網(wǎng)關(guān)的第一步是定義供應(yīng)商。我用 Python 字典維護(hù)了一個(gè)全局配置示例結(jié)構(gòu)如下import os PROVIDERS { official: { api_key: os.environ[OFFICIAL_API_KEY], base_url: https://api.official.com/v1, models: [main-model], priority: 1, max_retries: 2, }, third_party: { api_key: os.environ[THIRD_PARTY_API_KEY], base_url: https://api.third-party.com/v1, models: [cheap-model], priority: 2, max_retries: 3, }, third_party_b: { api_key: os.environ[THIRD_PARTY_B_API_KEY], base_url: https://api.third-party-b.com/v1, models: [backup-model], priority: 3, max_retries: 3, }, }優(yōu)先級(jí)的含義是正常情況下優(yōu)先嘗試 priority 小的供應(yīng)商失敗后依次向后降級(jí)。但這里有一個(gè)很關(guān)鍵的經(jīng)驗(yàn)不要把所有流量都?jí)涸谕粋€(gè)優(yōu)先級(jí)上尤其是不要把便宜供應(yīng)商設(shè)為唯一首選。因?yàn)榈谌狡脚_(tái)便宜往往伴隨更嚴(yán)格的并發(fā)限制一旦 QPS 起來(lái)限流會(huì)遠(yuǎn)比官方更猛。我的做法是核心實(shí)時(shí)請(qǐng)求先走官方或質(zhì)量最高的供應(yīng)商非核心批量任務(wù)走便宜供應(yīng)商這樣能拉平整體成本同時(shí)保住核心體驗(yàn)。還有一點(diǎn)Key 一定通過(guò)環(huán)境變量注入不要寫死在代碼里。后面避坑環(huán)節(jié)我會(huì)詳細(xì)講原因。3.3 第三步實(shí)現(xiàn)帶重試、退避和降級(jí)的調(diào)用封裝網(wǎng)關(guān)最核心的代碼是一個(gè)調(diào)用封裝。先用 OpenAI SDK 創(chuàng)建多個(gè)客戶端再按優(yōu)先級(jí)逐個(gè)嘗試配合指數(shù)退避和隨機(jī)抖動(dòng)。示例實(shí)現(xiàn)如下import os import random import time from openai import OpenAI class LLMGateway: def __init__(self, providers): self.clients {} self.providers providers for name, cfg in providers.items(): self.clients[name] OpenAI( api_keycfg[api_key], base_urlcfg[base_url] ) def chat(self, messages, temperature0.7, max_attempts5): attempts 0 while attempts max_attempts: for name, cfg in sorted( self.providers.items(), keylambda item: item[1][priority] ): try: resp self.clients[name].chat.completions.create( modelcfg[models][0], messagesmessages, temperaturetemperature, timeout30, ) self._record(name, resp) return resp except Exception as e: self._log_error(name, e) # 指數(shù)退避 隨機(jī)抖動(dòng) sleep_time 0.5 * (2 ** attempts) random.uniform(0, 0.5) time.sleep(sleep_time) attempts 1 raise RuntimeError(all providers failed)這段代碼有兩個(gè)細(xì)節(jié)值得說(shuō)。第一重試不能立刻重試。立刻重試往往還是失敗而且會(huì)加重上游壓力。指數(shù)退避加隨機(jī)抖動(dòng)是為了避免多個(gè)請(qǐng)求在同一時(shí)刻集體重試形成二次壓垮。第二每次失敗后都要記錄供應(yīng)商名和異常類型否則到時(shí)候只知道“調(diào)不通”不知道是哪條鏈路先掛的。如果業(yè)務(wù)對(duì)冪等有要求我建議在請(qǐng)求參數(shù)里帶上自定義 request_id傳給上游并在日志里記錄。這樣即使發(fā)生重復(fù)請(qǐng)求對(duì)賬時(shí)也能查出來(lái)避免重復(fù)計(jì)費(fèi)說(shuō)不清。3.4 第四步語(yǔ)義緩存把高頻重復(fù)問(wèn)題攔在網(wǎng)關(guān)外成本優(yōu)化的另一個(gè)大頭是緩存。最簡(jiǎn)單的是精確匹配把用戶輸入做哈希查 Redis命中直接返回上次結(jié)果。import hashlib import redis cache redis.Redis(hostlocalhost, port6379, decode_responsesTrue) def chat_with_cache(gateway, messages): text .join(msg[content] for msg in messages) key fllm_cache:{hashlib.sha256(text.encode()).hexdigest()} cached cache.get(key) if cached: return cached resp gateway.chat(messages) content resp.choices[0].message.content cache.setex(key, 600, content) # 10 分鐘過(guò)期 return content精確匹配能解決“一模一樣的重復(fù)問(wèn)題”但解決不了“說(shuō)法不同但意圖相同”的問(wèn)題比如“怎么退款”和“退款流程是什么”。想攔這部分就要上語(yǔ)義緩存先用 embedding 接口把輸入向量化再和緩存中的歷史向量算相似度閾值高于 0.92 就認(rèn)為語(yǔ)義重復(fù)直接返回緩存結(jié)果。不過(guò)語(yǔ)義緩存建議謹(jǐn)慎放開原因有兩點(diǎn)一是相似不等于相同可能誤導(dǎo)用戶二是隱私敏感內(nèi)容不該被緩存。我的經(jīng)驗(yàn)是先只對(duì)客服場(chǎng)景開放精確匹配語(yǔ)義匹配在小流量下驗(yàn)證效果之后再逐步放大。緩存命中時(shí)我會(huì)在響應(yīng)頭加一個(gè) X-Cache: HIT 標(biāo)記方便后續(xù)和日志對(duì)應(yīng)排查。4. 把“省下來(lái)的錢”變成可觀測(cè)的數(shù)字4.1 設(shè)計(jì)費(fèi)用日志與日結(jié)報(bào)表很多團(tuán)隊(duì)省錢靠月底看賬單問(wèn)題賬單出來(lái)已經(jīng)晚了根本不知道是哪天的哪個(gè)功能燒掉了預(yù)算。我在網(wǎng)關(guān)里加了結(jié)構(gòu)化日志要求每次調(diào)用都至少記錄以下字段時(shí)間戳、trace_id、業(yè)務(wù)場(chǎng)景標(biāo)簽、供應(yīng)商名、模型名、輸入 Token、輸出 Token、估算費(fèi)用、延遲、HTTP 狀態(tài)碼、是否緩存命中。費(fèi)用估算可以簡(jiǎn)單用一個(gè)函數(shù)def estimate_cost(input_tokens, output_tokens, price_map): return ( input_tokens * price_map[input] output_tokens * price_map[output] )price_map 來(lái)自統(tǒng)一配置每個(gè)供應(yīng)商每種模型單獨(dú)維護(hù)。日志落盤后每天跑一次聚合腳本按場(chǎng)景和供應(yīng)商兩個(gè)維度做統(tǒng)計(jì)。這樣我能立刻回答三個(gè)問(wèn)題今天花了多少錢哪個(gè)場(chǎng)景花得最多哪個(gè)供應(yīng)商實(shí)際最便宜這套報(bào)表上線第一周就發(fā)現(xiàn)了問(wèn)題某個(gè)后臺(tái)批處理任務(wù)占了 40% 的費(fèi)用而它的業(yè)務(wù)價(jià)值很低只是因?yàn)橹卦囘壿媽懙貌缓侠砻看问《及颜蝿?wù)重新跑一遍。后來(lái)把重試粒度從批改成單條費(fèi)用直接腰斬。4.2 設(shè)置成本與穩(wěn)定性告警有了數(shù)據(jù)之后接下來(lái)就是設(shè)閾值。我目前的告警規(guī)則如下日成本環(huán)比增長(zhǎng)超過(guò) 50% 時(shí)告警單個(gè)供應(yīng)商 5 分鐘錯(cuò)誤率超過(guò) 5% 時(shí)告警P99 延遲超過(guò) 5 秒時(shí)告警賬戶余額低于預(yù)期三天用量時(shí)告警。告警渠道直接用企業(yè)微信或釘釘機(jī)器人本質(zhì)就是往 Webhook 推一條 JSON。重點(diǎn)不是怎么推而是閾值怎么定。第一次我把錯(cuò)誤率閾值設(shè)成了 0結(jié)果一天收到幾百條告警徹底疲勞。后來(lái)改成“連續(xù)兩個(gè)統(tǒng)計(jì)周期超過(guò)閾值才告警”準(zhǔn)確率高了很多。穩(wěn)定性告警的下一步是自動(dòng)切換。當(dāng)?shù)谌焦?yīng)商連續(xù)錯(cuò)誤率升高時(shí)網(wǎng)關(guān)可以把它的權(quán)重臨時(shí)降為 0把流量切到官方 Key 或其他備用通道。同時(shí)保留人工確認(rèn)機(jī)制避免自動(dòng)切換引發(fā)的誤判。4.3 每周復(fù)盤動(dòng)態(tài)調(diào)整分流比例我固定每周五做一次成本復(fù)盤數(shù)據(jù)表格很簡(jiǎn)單各供應(yīng)商的實(shí)際到賬費(fèi)用、成功率、P99 延遲、重試率。如果某個(gè)平臺(tái)聲稱便宜 10%但限流導(dǎo)致重試率高達(dá) 25%實(shí)際算下來(lái)比官方還貴這種表面便宜就沒(méi)有意義。調(diào)整方式很直接在配置中心改分流比例。比如這周官方折扣力度大核心請(qǐng)求比例可以從 20% 提到 40%下周某個(gè)第三方平臺(tái)服務(wù)不穩(wěn)定權(quán)重直接降到 0。整個(gè)過(guò)程不需要重新發(fā)版網(wǎng)關(guān)讀到新配置后自動(dòng)生效。這里有一個(gè)值得強(qiáng)調(diào)的思路成本優(yōu)化不是一次性動(dòng)作而是一個(gè)持續(xù)調(diào)參的過(guò)程。模型價(jià)格會(huì)變、供應(yīng)商政策會(huì)變、業(yè)務(wù)流量也會(huì)變只有通過(guò)數(shù)據(jù)驅(qū)動(dòng)才能長(zhǎng)期維持合理的成本水平。5. 避坑實(shí)錄這些問(wèn)題我花了真金白銀才學(xué)會(huì)5.1 API Key 硬編碼是全劇最蠢的錯(cuò)誤我見過(guò)不少項(xiàng)目為了圖省事把 API Key 直接寫在代碼里甚至寫在前端的靜態(tài)資源里。這種操作一旦被爬走后果就是被刷量扣費(fèi)。我自己早期就吃過(guò)一次虧因?yàn)榧敝暇€把 Key 放到了前端配置里當(dāng)天夜里被刷掉一千多塊。第三方平臺(tái)的 Key 泄露比官方 Key 更肉疼因?yàn)楹芏嗟谌桨从囝~實(shí)時(shí)扣費(fèi)濫用速度極快?,F(xiàn)在我的所有 Key 一律從環(huán)境變量讀取配置文件中只保留鍵名不留值。另外每個(gè)環(huán)境用獨(dú)立的 Key方便出問(wèn)題時(shí)單獨(dú)輪換不用全量重發(fā)。5.2 廉價(jià)平臺(tái)偷偷混用小模型有一段時(shí)間我發(fā)現(xiàn)輸出質(zhì)量時(shí)好時(shí)壞同一個(gè)問(wèn)題有時(shí)候回答很深入有時(shí)候明顯淺薄。查日志發(fā)現(xiàn)請(qǐng)求日志里 model 字段完全一致但返回內(nèi)容的 Token 分布和推理風(fēng)格差異很大。后來(lái)我懷疑平臺(tái)在低峰期用小模型頂替了大模型來(lái)控制成本。為了驗(yàn)證我準(zhǔn)備了一組“金絲雀問(wèn)題”專門問(wèn)那些只有高版本模型才答得出來(lái)、低版本模型大概率會(huì)答錯(cuò)的知識(shí)點(diǎn)。每隔一小時(shí)跑一次結(jié)果果然抓到了問(wèn)題。這樣的平臺(tái)我直接拉黑因?yàn)樗茐牡氖怯脩粜湃尾皇清X的問(wèn)題。5.3 沒(méi)有熔斷被上游故障拖垮某次第三方平臺(tái)整體故障我們這邊所有請(qǐng)求都在超時(shí)重試線程池很快被打滿連健康檢查都開始失敗。問(wèn)題根本不在于那一次上游抖動(dòng)而在于我們沒(méi)有做熔斷。如果一個(gè)請(qǐng)求連續(xù)失敗 20 次網(wǎng)關(guān)應(yīng)該主動(dòng)打開熔斷開關(guān)直接拒絕新請(qǐng)求 10 秒讓積壓流量快速消化。熔斷恢復(fù)也要講究不能時(shí)間一到就立刻全量放流量而應(yīng)該先用小流量試探等成功率回升后再逐步放開。這一套邏輯雖然簡(jiǎn)單但關(guān)鍵時(shí)候能保住整套服務(wù)的命。5.4 長(zhǎng)上下文請(qǐng)求最容易預(yù)算超標(biāo)有些模型單價(jià)并不高但如果業(yè)務(wù)不控制上下文長(zhǎng)度一次請(qǐng)求塞幾十萬(wàn) Token照樣能把預(yù)算燒穿。我現(xiàn)在對(duì)用戶輸入長(zhǎng)度做前置限制超過(guò)閾值就截?cái)嘣倥浜详P(guān)鍵信息抽取。對(duì)于長(zhǎng)文檔場(chǎng)景先做分段摘要再把摘要喂給模型而不是讓模型直接閱讀全文。同樣重要的還有系統(tǒng)提示詞。不要覺(jué)得提示詞寫得越長(zhǎng)模型越聰明它每多一個(gè) Token 都會(huì)進(jìn)入每次調(diào)用的計(jì)費(fèi)基數(shù)。我現(xiàn)在的建議是提示詞只保留必要規(guī)則把不影響正確性的歷史包袱全部清掉。5.5 免費(fèi)額度只適合測(cè)試不適合生產(chǎn)不少平臺(tái)會(huì)送免費(fèi)額度用來(lái)跑通流程沒(méi)有問(wèn)題。但生產(chǎn)鏈路對(duì)可靠性、售后、并發(fā)能力的要求完全不同。如果只是因?yàn)槊赓M(fèi)省下了費(fèi)用卻扛不住限流得不償失。我見過(guò)有人把免費(fèi)額度用進(jìn)生產(chǎn)結(jié)果平臺(tái)因?yàn)轱L(fēng)控收緊直接封號(hào)臨時(shí)找不到替代供應(yīng)商業(yè)務(wù)停了半天。我現(xiàn)在的策略是免費(fèi)額度只用來(lái)做模型效果測(cè)評(píng)和連通性測(cè)試正式生產(chǎn)至少準(zhǔn)備一個(gè)付費(fèi)供應(yīng)商和一個(gè)官方兜底通道。穩(wěn)定優(yōu)先省錢在后。這套組合方案線上跑了一段時(shí)間之后效果確實(shí)符合預(yù)期。月度 API 成本從原來(lái)的兩千四降到了一千出頭接口的 P99 延遲從動(dòng)輒七八秒降到兩秒以內(nèi)更重要的是上游故障時(shí)基本做到了無(wú)感切換。整個(gè)過(guò)程中最大的體會(huì)是省錢不能靠單一技巧而是要把用量治理嵌入到開發(fā)的日常流程里。如果你正準(zhǔn)備接大模型 API我的建議是先花一天時(shí)間優(yōu)化提示詞和加緩存再選一兩家正規(guī)服務(wù)商做小流量灰度同時(shí)保留官方 Key 做兜底。很多細(xì)節(jié)不親自踩一遍看再多文章也體會(huì)不到。