用架構(gòu)設(shè)計(jì)圖解:從模型接入到生產(chǎn)落地的完整指南)
這幾年做AI應(yīng)用落地我見(jiàn)過(guò)太多團(tuán)隊(duì)把大模型接進(jìn)來(lái)卻依然跑不起來(lái)的情況。模型調(diào)用通了問(wèn)答聽(tīng)起來(lái)也沒(méi)問(wèn)題一旦面對(duì)真實(shí)用戶延遲、成本、上下文混亂、工具調(diào)度失控、安全邊界缺失全都浮出來(lái)。問(wèn)題幾乎都出在同一個(gè)地方整個(gè)系統(tǒng)沒(méi)有架構(gòu)可言只有一層直連大模型的膠水代碼。所謂“AI應(yīng)用架構(gòu)設(shè)計(jì)”不是畫(huà)一張漂亮的拓?fù)鋱D而是把交互層、編排層、模型接入層、數(shù)據(jù)記憶層、可觀測(cè)性這堆東西用清晰的邊界和鏈路組織起來(lái)讓每個(gè)環(huán)節(jié)都有擴(kuò)展點(diǎn)每個(gè)失敗都有兜底。這篇文章我準(zhǔn)備用圖解的方式把自己在多個(gè)AI項(xiàng)目中沉淀下來(lái)的拆解思路、參考架構(gòu)、落地步驟和踩坑記錄整個(gè)過(guò)一遍適合后端開(kāi)發(fā)者、全棧工程師、以及正在把AI原型推向生產(chǎn)的架構(gòu)師參考。1. 先把話說(shuō)在前面AI應(yīng)用架構(gòu)到底在解什么題1.1 不是所有“接個(gè)大模型”都叫架構(gòu)設(shè)計(jì)很多團(tuán)隊(duì)的第一步是申請(qǐng)一個(gè)模型API然后把用戶的輸入直接拼到系統(tǒng)提示詞里調(diào)用接口把結(jié)果返給前端。這個(gè)流程在Demo階段沒(méi)有任何問(wèn)題因?yàn)樗?yàn)證的是“模型能不能解決我的業(yè)務(wù)問(wèn)題”。一旦上生產(chǎn)你會(huì)發(fā)現(xiàn)真正需要設(shè)計(jì)的不是模型本身而是模型旁邊那一圈東西。舉個(gè)例子。你做一個(gè)企業(yè)內(nèi)部知識(shí)庫(kù)問(wèn)答助手輸入端可能是Web聊天框也可能是IM機(jī)器人中間要處理權(quán)限普通員工只能檢索公開(kāi)文檔管理層能看戰(zhàn)略材料問(wèn)答過(guò)程可能要調(diào)用內(nèi)部HR系統(tǒng)查請(qǐng)假余額再調(diào)用日歷系統(tǒng)幫你直接發(fā)起一個(gè)會(huì)議邀請(qǐng)最后還得把整個(gè)交互過(guò)程中用了哪些提示詞模板、哪些檢索片段、哪些工具調(diào)用記錄全都留存下來(lái)供質(zhì)量復(fù)盤(pán)用。這些需求沒(méi)有哪一個(gè)是“調(diào)一次大模型”能完成的。所以架構(gòu)設(shè)計(jì)要解的第一個(gè)題是把大模型從“全知全能的回答器”降級(jí)成“一個(gè)可被編排的推理組件”。它負(fù)責(zé)語(yǔ)言理解、邏輯推理、內(nèi)容生成但業(yè)務(wù)狀態(tài)、工具調(diào)用、數(shù)據(jù)權(quán)限、流程控制都應(yīng)該由外部系統(tǒng)接管。這句話聽(tīng)起來(lái)簡(jiǎn)單實(shí)際影響很大它會(huì)決定你后續(xù)的擴(kuò)展模型、替換模型、增加Agent能力時(shí)是改一個(gè)模塊還是推翻重來(lái)。1.2 一張圖先建立整體觀我們常說(shuō)的AI應(yīng)用架構(gòu)從縱向看大致可以分成五層。--------------------------- | 客戶端與產(chǎn)品層 | | Web / 小程序 / App / IM | -------------------------- | -------------v------------- | 應(yīng)用服務(wù)層 | | 業(yè)務(wù)邏輯 / 會(huì)話 / 權(quán)限 / 路由| -------------------------- | -------------v------------- | 編排與Agent層 | | 提示詞 / 上下文 / 工具調(diào)用 | -------------------------- | -------------v------------- | 模型接入層 | | LLM API / 私有化模型 / 多模型| -------------------------- | -------------v------------- | 基礎(chǔ)設(shè)施層 | | 向量庫(kù) / 緩存 / 對(duì)象存儲(chǔ) | | 網(wǎng)關(guān) / 可觀測(cè)性 / 安全 | ---------------------------橫向看一條完整的業(yè)務(wù)請(qǐng)求鏈路會(huì)把這幾層串起來(lái)用戶消息先進(jìn)應(yīng)用服務(wù)層做權(quán)限校驗(yàn)、會(huì)話識(shí)別、敏感信息過(guò)濾然后到編排層由編排器決定這個(gè)問(wèn)題是否需要檢索、需要調(diào)用哪些工具、用哪份提示詞模板接著再把組織好的上下文交給模型接入層模型返回結(jié)果后編排層可能還要執(zhí)行后續(xù)動(dòng)作比如解析結(jié)構(gòu)化輸出、調(diào)用外部系統(tǒng)、再讓模型做一次總結(jié)最后才把響應(yīng)返回到產(chǎn)品層。分層的好處在于每一層只干一件事并且可以被單獨(dú)替換。模型接入層從GPT換成國(guó)產(chǎn)開(kāi)源模型不影響上面三層的邏輯編排層從提示詞拼接演進(jìn)到復(fù)雜Agent循環(huán)也不需要?jiǎng)涌蛻舳藚f(xié)議基礎(chǔ)設(shè)施層的緩存和向量庫(kù)決定性能但它不應(yīng)該跟業(yè)務(wù)代碼耦合在一起。這個(gè)整體觀是我每次開(kāi)始新項(xiàng)目時(shí)即使代碼還沒(méi)寫(xiě)也會(huì)先在文檔里搭起來(lái)的骨架。有了它后面每一步才知道自己動(dòng)的是哪一層。2. 圖解AI應(yīng)用的核心模塊拆解2.1 模型接入層API、私有化還是混合模型接入層是整個(gè)架構(gòu)里最受關(guān)注、也最容易引發(fā)爭(zhēng)論的一層。它要解決三個(gè)問(wèn)題模型從哪來(lái)、如何統(tǒng)一接入、如何做多模型路由。在選擇模型來(lái)源時(shí)我一般會(huì)讓團(tuán)隊(duì)先盤(pán)一下自己的約束條件不搞拍腦袋。API方式優(yōu)勢(shì)是省心——免運(yùn)維、延遲穩(wěn)定、模型升級(jí)立即生效適合快速驗(yàn)證和大多數(shù)SaaS類業(yè)務(wù)但它引入兩個(gè)隱形約束一是數(shù)據(jù)要出外網(wǎng)敏感業(yè)務(wù)必須先過(guò)脫敏和合規(guī)評(píng)審二是單次調(diào)用成本會(huì)隨用量線性上漲。私有化部署適合高隱私、強(qiáng)合規(guī)場(chǎng)景以及希望把單位推理成本壓下來(lái)的中大規(guī)模調(diào)用但GPU資源調(diào)度、模型量化、高并發(fā)推理排隊(duì)都是需要團(tuán)隊(duì)持續(xù)投入的事?;旌辖尤胧悄壳氨容^務(wù)實(shí)的選擇通用對(duì)話走外部API涉及核心數(shù)據(jù)或敏感行業(yè)的推理走內(nèi)網(wǎng)私有化模型再在接入層做透明路由。不管選哪條路徑我都建議在模型接入層定義一個(gè)統(tǒng)一接口而不是讓業(yè)務(wù)代碼直接依賴某個(gè)SDK。這個(gè)接口至少包含這些語(yǔ)義模型名或模型版本標(biāo)識(shí)輸入消息列表角色、內(nèi)容系統(tǒng)提示詞或指令前綴采樣參數(shù)溫度、top_p、最大輸出長(zhǎng)度等結(jié)構(gòu)化輸出要求JSON Schema或函數(shù)定義超時(shí)、重試、失敗回調(diào)定義統(tǒng)一接口的核心價(jià)值是在后面接多模型時(shí)不用改業(yè)務(wù)代碼。我在一個(gè)項(xiàng)目里做過(guò)替換對(duì)外用的模型A內(nèi)部復(fù)盤(pán)和夜間批量任務(wù)用的是更便宜的開(kāi)源模型B兩套模型在接入層只通過(guò)一個(gè)配置項(xiàng)切換上面所有應(yīng)用層完全無(wú)感。這個(gè)設(shè)計(jì)投入不大但后期帶來(lái)的靈活度非常高。2.2 應(yīng)用編排層Prompt、上下文和鏈路控制應(yīng)用編排層是AI應(yīng)用架構(gòu)里最劇變的一層因?yàn)樵缙凇捌碢rompt”的思路已經(jīng)越來(lái)越不夠用?,F(xiàn)在主流的設(shè)計(jì)思路可以分成三種模式。單次調(diào)用模式適合任務(wù)邊界清晰的場(chǎng)景比如內(nèi)容分類、情感分析、標(biāo)題生成。這個(gè)模式下編排層只需要負(fù)責(zé)把系統(tǒng)提示詞、用戶輸入、少量業(yè)務(wù)參數(shù)組裝好然后調(diào)用一次模型拿到結(jié)果返回。簡(jiǎn)單可靠但無(wú)法處理需要多步推理的任務(wù)。鏈?zhǔn)秸{(diào)用模式把你的業(yè)務(wù)流程拆成一串子任務(wù)每個(gè)子任務(wù)調(diào)用一次模型前一個(gè)輸出作為后一個(gè)輸入。典型場(chǎng)景是智能寫(xiě)作助手先讓模型根據(jù)用戶意圖生成大綱再按大綱分段擴(kuò)寫(xiě)最后再讓模型做整體潤(rùn)色。鏈?zhǔn)侥J降膬?yōu)點(diǎn)是可觀測(cè)、每步可控缺點(diǎn)是總延遲是每一步延遲的累加而且一旦某一步輸出質(zhì)量不好后面的步驟都會(huì)受影響。Agent循環(huán)模式是目前最熱門(mén)的架構(gòu)思路它讓模型不是“回答一次就結(jié)束”而是進(jìn)入一個(gè)循環(huán)理解用戶意圖 - 決定要不要調(diào)用工具 - 執(zhí)行工具 - 把工具結(jié)果帶回來(lái) - 繼續(xù)推理直到滿足結(jié)束條件。這個(gè)模式的威力在于模型可以自己規(guī)劃怎么完成任務(wù)而不是每一步都由研發(fā)人員寫(xiě)死。真實(shí)項(xiàng)目的復(fù)雜性在于多數(shù)場(chǎng)景不是單一模式。我的建議是把編排層拆成兩個(gè)子組件一個(gè)是任務(wù)解析器負(fù)責(zé)判斷當(dāng)前輸入適合單次調(diào)用、鏈?zhǔn)竭€是Agent循環(huán)另一個(gè)是執(zhí)行引擎負(fù)責(zé)真正跑對(duì)應(yīng)流程。任務(wù)解析器本身也可以是一個(gè)輕量模型調(diào)用用低溫度參數(shù)保證分類穩(wěn)定性這樣既保留了Agent的靈活性又不會(huì)讓所有請(qǐng)求都陷入不可控的自由發(fā)揮。上下文管理是編排層最容易崩的地方。很多人以為把歷史消息全都塞給模型就完事了實(shí)際上一旦對(duì)話輪數(shù)變多上下文窗口被占滿模型會(huì)開(kāi)始“遺忘”關(guān)鍵指令輸出質(zhì)量快速惡化。實(shí)踐中我會(huì)做三層上下文控制長(zhǎng)期記憶用戶的基本信息和業(yè)務(wù)偏好存數(shù)據(jù)庫(kù)關(guān)鍵節(jié)點(diǎn)注入短期記憶最近N輪對(duì)話摘要可以用單獨(dú)的模型把歷史消息壓縮成結(jié)構(gòu)化摘要工作記憶當(dāng)前任務(wù)正在使用的檢索片段、工具返回結(jié)果、中間推理過(guò)程這是模型真正需要“看到”的內(nèi)容這三層分開(kāi)管理之后模型每次調(diào)用看到的信息總量會(huì)顯著下降質(zhì)量反而提升。上下文不是越多越好而是越精準(zhǔn)越好。這個(gè)認(rèn)知幾乎是所有AI應(yīng)用從Demo走向生產(chǎn)的分水嶺。2.3 能力擴(kuò)展層Function Calling、Agent與工具模型如果只能輸出文本它能解決的業(yè)務(wù)問(wèn)題很有限?,F(xiàn)代AI應(yīng)用架構(gòu)里能力擴(kuò)展層承擔(dān)的是把模型跟真實(shí)世界連接起來(lái)讓它可以查數(shù)據(jù)庫(kù)、發(fā)消息、操作業(yè)務(wù)系統(tǒng)。Function Calling是目前最成熟的機(jī)制你在請(qǐng)求里聲明一組函數(shù)定義描述函數(shù)名、參數(shù)、用途模型通過(guò)推理決定要調(diào)哪個(gè)函數(shù)并輸出結(jié)構(gòu)化的參數(shù)。你收到這個(gè)返回后可以不直接執(zhí)行而是先校驗(yàn)參數(shù)合法性、做權(quán)限檢查再實(shí)際調(diào)用業(yè)務(wù)系統(tǒng)。注意模型不具備真實(shí)執(zhí)行能力它只是“建議”調(diào)用哪個(gè)函數(shù)真正的執(zhí)行權(quán)必須掌握在應(yīng)用層手里。這個(gè)原則能避免一堆安全問(wèn)題比如模型在參數(shù)里填入越權(quán)范圍如果你直接透?jìng)骶统鍪铝?。Agent的興起讓能力擴(kuò)展層面變得復(fù)雜。當(dāng)模型進(jìn)入自主循環(huán)它可能會(huì)連續(xù)調(diào)用多個(gè)工具檢索文檔、查詢庫(kù)存、對(duì)比價(jià)格、生成訂單。這時(shí)候整個(gè)擴(kuò)展層要具備工具注冊(cè)、工具發(fā)現(xiàn)、工具執(zhí)行狀態(tài)管理、以及工具間依賴處理的能力。工具注冊(cè)機(jī)制通常會(huì)維護(hù)一種“工具描述文件”里面包含工具名稱、說(shuō)明、OpenAPI風(fēng)格的入?yún)⒊鰠⒍x、調(diào)用地址、鑒權(quán)方式和重試策略。模型推理時(shí)其實(shí)讀的是這些描述文本所以工具描述寫(xiě)得好不好直接決定模型能不能正確使用工具。我見(jiàn)過(guò)很多團(tuán)隊(duì)在這個(gè)環(huán)節(jié)翻車(chē)工具描述含糊只寫(xiě)“獲取用戶信息”模型根本不知道需要傳什么參數(shù)改成“根據(jù)用戶手機(jī)號(hào)查詢用戶基礎(chǔ)信息手機(jī)號(hào)為11位數(shù)字必須存在且匹配當(dāng)前登錄用戶”之后調(diào)用準(zhǔn)確率立刻上了一個(gè)臺(tái)階。最近比較熱的一個(gè)方向是行業(yè)里開(kāi)始制定標(biāo)準(zhǔn)化工具協(xié)議比如OpenAPI直接轉(zhuǎn)工具定義、MCP協(xié)議把外部能力統(tǒng)一掛進(jìn)來(lái)。圖里畫(huà)的能力擴(kuò)展層不再是一堆散落的函數(shù)而是一個(gè)統(tǒng)一的工具網(wǎng)關(guān)。這個(gè)網(wǎng)關(guān)做三類事情給每個(gè)工具分配唯一標(biāo)識(shí)管理可見(jiàn)范圍對(duì)入?yún)⒆鲂r?yàn)和脫敏對(duì)執(zhí)行結(jié)果做格式化和限流。跟模型相關(guān)的邏輯只發(fā)生在描述文件和工具調(diào)用結(jié)果回填上其余都收斂到網(wǎng)關(guān)側(cè)。2.4 數(shù)據(jù)與記憶層向量庫(kù)、緩存與狀態(tài)很多AI應(yīng)用需要處理私有知識(shí)庫(kù)、歷史會(huì)話、業(yè)務(wù)狀態(tài)這部分是我說(shuō)的數(shù)據(jù)與記憶層。最常被誤解的是向量數(shù)據(jù)庫(kù)的定位。很多人以為只要接了一個(gè)向量庫(kù)就解決了知識(shí)庫(kù)問(wèn)題。實(shí)際上RAG鏈路里數(shù)據(jù)側(cè)要處理的事情遠(yuǎn)比“多存幾個(gè)向量”復(fù)雜。第一文檔入庫(kù)前要做解析PDF、Word、掃描件格式不一表格和圖片還要單獨(dú)走OCR和多模態(tài)處理第二文檔要切分切分策略直接影響檢索質(zhì)量太小則語(yǔ)義不完整太大則噪聲多按標(biāo)題層級(jí)和段落語(yǔ)義切分通常比按固定字符數(shù)切分好用第三每條切片要生成多個(gè)版本的向量以適應(yīng)不同問(wèn)法第四入庫(kù)后還要做去重、權(quán)限標(biāo)記和版本更新舊版本不能繼續(xù)參與檢索。我來(lái)用一個(gè)實(shí)際切分配置舉例。一份企業(yè)制度文檔我先按目錄拆成章節(jié)再按段落和列表項(xiàng)拆分對(duì)于超過(guò)3000字的長(zhǎng)章節(jié)允許單條切片上限800字符左右重疊100到200字符這樣既能保住語(yǔ)義邊界又能覆蓋跨段落提問(wèn)。嵌入模型選擇上如果主要檢索中文內(nèi)容我會(huì)用中文效果好的嵌入模型向量維度視模型而定常見(jiàn)范圍在768到1536之間。向量庫(kù)只是數(shù)據(jù)層的一部分不是全部。業(yè)務(wù)狀態(tài)和會(huì)話狀態(tài)更適合放在傳統(tǒng)SQL或Redis里因?yàn)樗鼈兪菑?qiáng)一致、高可靠的事實(shí)型數(shù)據(jù)比如訂單金額、參數(shù)表不該去走向量召回。RAG擅長(zhǎng)的場(chǎng)景是語(yǔ)義檢索而不是精確計(jì)算。你把訂單號(hào)存進(jìn)向量庫(kù)再問(wèn)“訂單A1234金額多少”純屬繞遠(yuǎn)路正確設(shè)計(jì)應(yīng)該是先讓模型識(shí)別出意圖是查訂單通過(guò)Function Calling去訂單系統(tǒng)精確查詢?cè)侔巡樵兘Y(jié)果拼進(jìn)上下文中去生成回答。緩存是比較容易被忽略的架構(gòu)組件。同一個(gè)問(wèn)題如果答案不依賴當(dāng)前用戶上下文完全可以用語(yǔ)義緩存把用戶輸入做一次向量化如果和近幾天的歷史問(wèn)題相似度超過(guò)閾值直接返回緩存答案。這樣既能大幅降低模型調(diào)用成本也能顯著優(yōu)化響應(yīng)延遲。我在一個(gè)高頻客服系統(tǒng)里這么做過(guò)緩存命中率一度到30%以上線上成本大概省了四分之一。2.5 可觀測(cè)性與安全生產(chǎn)環(huán)境的地基AI應(yīng)用有個(gè)和傳統(tǒng)應(yīng)用很不一樣的地方模型輸出是不確定的同一個(gè)提示詞在不同時(shí)間可能給出不同答案用戶會(huì)拿錯(cuò)誤結(jié)果來(lái)質(zhì)問(wèn)。如果你沒(méi)有完整的調(diào)用記錄排查起來(lái)會(huì)非常痛苦。可觀測(cè)性在AI架構(gòu)里至少要覆蓋四個(gè)維度。第一請(qǐng)求鏈路追蹤一條用戶消息經(jīng)歷了哪些步驟、調(diào)了幾次模型、調(diào)了什么工具每一步耗時(shí)多少第二Token消耗統(tǒng)計(jì)按用戶、按會(huì)話、按功能模塊匯總這是成本分析的原始數(shù)據(jù)第三輸入輸出留存尤其是生產(chǎn)環(huán)境里用戶到底問(wèn)了什么、模型答了什么這個(gè)數(shù)據(jù)是后續(xù)做評(píng)測(cè)集和提示詞調(diào)優(yōu)的基礎(chǔ)第四質(zhì)量監(jiān)控自動(dòng)或半自動(dòng)去評(píng)估模型輸出是否合規(guī)、是否偏離主題。安全方面輸入側(cè)要做兩層過(guò)濾第一層是規(guī)則過(guò)濾攔截明顯異常內(nèi)容第二層可以用一個(gè)輕量分類模型把輸入按安全等級(jí)打標(biāo)高風(fēng)險(xiǎn)內(nèi)容直接不走主鏈路或者走人工審核通道。輸出側(cè)同樣要過(guò)濾防止模型被誘導(dǎo)生成違規(guī)內(nèi)容。此外系統(tǒng)提示詞和工具描述要避免被用戶輸入覆蓋常見(jiàn)的做法是用系統(tǒng)級(jí)指令約束并且在上下文組裝時(shí)把用戶輸入和系統(tǒng)指令分區(qū)做嚴(yán)格的角色隔離。最后是權(quán)限鑒權(quán)模型調(diào)用的工具必須繼承當(dāng)前登錄用戶的權(quán)限不能因?yàn)槟P陀泄ぞ呙枋鼍桶阉?dāng)成超級(jí)管理員對(duì)待。3. 一張可落地的參考架構(gòu)圖以及關(guān)鍵鏈路說(shuō)明前面講的是模塊這里我把它們拼成一張完整參考架構(gòu)圖。這張圖不是擺設(shè)我會(huì)在后面說(shuō)明一條真實(shí)請(qǐng)求是怎么跑通它的。----------------------------- ------------------------- | 客戶端 / 產(chǎn)品層 | | 管理側(cè) | | Web / App / IM / 小程序 | | 運(yùn)營(yíng)監(jiān)控 / 評(píng)測(cè)標(biāo)注 | ---------------------------- ------------------------ | | -------------v-------------------------------------------- | 入口網(wǎng)關(guān)(統(tǒng)一鑒權(quán)/限流/安全過(guò)濾) | ----------------------------------------------------------- | -------------v-------------------------------------------- | 應(yīng)用服務(wù)層 | | 會(huì)話管理 | 用戶權(quán)限 | 意圖分流 | 業(yè)務(wù)API | ----------------------------------------------------------- | -------------v-------------------------------------------- | 編排與Agent層 | | 任務(wù)解析 | 上下文管理 | 工具調(diào)度 | 反饋與重試 | ----------------------------------------------------------- | | | v v v ------------- ----------------- ---------------- | Prompt管理 | | 工具網(wǎng)關(guān) | | RAG檢索服務(wù) | | 模板/版本化 | | Function/API/ | | 向量檢索/重排 | ------------- | MCP能力接入 | ---------------- ----------------- | | | v v v ----------------------------------------------------------- | 模型接入層 | | 統(tǒng)一模型網(wǎng)關(guān)( API / 私有化 / 多模型路由 / 降級(jí)) | ----------------------------------------------------------- | -------------v-------------------------------------------- | 基礎(chǔ)設(shè)施層 | | 向量數(shù)據(jù)庫(kù) | 關(guān)系數(shù)據(jù)庫(kù) | 緩存(Cache) | 對(duì)象存儲(chǔ) | | 可觀測(cè)性 | 日志檢索 | 調(diào)用鏈追蹤 | 成本分析 | -----------------------------------------------------------這條圖里最上層的客戶端只是外殼真正的決策鏈路大多從應(yīng)用服務(wù)層開(kāi)始。拉一條具體請(qǐng)求來(lái)看。用戶在Web端問(wèn)“幫我查一下張三這個(gè)月還剩幾天年假?!闭?qǐng)求先進(jìn)入口網(wǎng)關(guān)完成登錄鑒權(quán)、基礎(chǔ)限流、敏感輸入過(guò)濾。應(yīng)用服務(wù)層拿到請(qǐng)求后會(huì)先判斷當(dāng)前用戶在組織架構(gòu)里的身份發(fā)現(xiàn)他只能查自己的年假于是給編排層注入一個(gè)約束只允許查詢當(dāng)前用戶自己的數(shù)據(jù)。編排層的任務(wù)解析器判斷這個(gè)問(wèn)題需要兩步完成先調(diào)用休假系統(tǒng)的查詢函數(shù)再讓模型基于返回結(jié)果組織回答。于是執(zhí)行引擎開(kāi)始循環(huán)第一輪調(diào)用模型模型輸出一個(gè)Function Calling請(qǐng)求參數(shù)是當(dāng)前用戶ID和月份范圍工具網(wǎng)關(guān)收到請(qǐng)求后先按工具入?yún)chema校驗(yàn)再執(zhí)行真正的查詢把返回結(jié)果回填給編排層第二輪編排層把“張三本月剩余年假5天”拼進(jìn)上下文再次調(diào)用模型模型輸出最終回答?;卮鸾?jīng)過(guò)輸出過(guò)濾由應(yīng)用服務(wù)層組裝成客戶端需要的格式最后展示給用戶。整個(gè)過(guò)程還有一個(gè)并行動(dòng)作是記錄可觀測(cè)性數(shù)據(jù)兩輪模型調(diào)用的Token數(shù)、工具執(zhí)行耗時(shí)、完整輸入輸出、命中緩存還是走了模型統(tǒng)一寫(xiě)入日志系統(tǒng)。如果用戶覺(jué)得回答不準(zhǔn)你要復(fù)現(xiàn)時(shí)直接按會(huì)話ID拉出這條鏈路的所有記錄。這張架構(gòu)圖相比“直接調(diào)API”的寫(xiě)法多出來(lái)的這些層不是復(fù)雜度而是控制點(diǎn)。每一步都有關(guān)卡每一步都可觀測(cè)每一步都有回退方案。這就是架構(gòu)設(shè)計(jì)的本質(zhì)。4. 從圖到落地最小可用架構(gòu)的實(shí)操拆解4.1 先定義邊界再畫(huà)圖拿到一個(gè)AI項(xiàng)目需求時(shí)我不會(huì)立刻去選型大模型而是先跟業(yè)務(wù)方一起把邊界定清楚。一般我會(huì)問(wèn)四個(gè)問(wèn)題用戶是誰(shuí)輸入是什么形式文本、語(yǔ)音、圖片輸出是什么形式這個(gè)場(chǎng)景是一次性問(wèn)答還是多輪對(duì)話要不要調(diào)用外部系統(tǒng)要調(diào)用哪些能不能接受最多多長(zhǎng)的響應(yīng)時(shí)間成本有沒(méi)有硬上限以“企業(yè)智能客服”為例輸入是文本或語(yǔ)音轉(zhuǎn)寫(xiě)輸出是文本大部分場(chǎng)景多輪對(duì)話要調(diào)用訂單系統(tǒng)、退款系統(tǒng)響應(yīng)時(shí)間要求首字不超過(guò)2秒單次回答成本上限幾分錢(qián)。這幾個(gè)問(wèn)題回答完整個(gè)架構(gòu)的輪廓基本就定出來(lái)了。接下來(lái)才是畫(huà)架構(gòu)圖。畫(huà)圖的時(shí)候不要一上來(lái)就考慮微服務(wù)、K8s先用前面那張參考架構(gòu)圖當(dāng)?shù)赘逡粚右粚訂?wèn)自己這一層在當(dāng)前場(chǎng)景里要不要單獨(dú)存在多數(shù)時(shí)候早期項(xiàng)目可以把編排層和應(yīng)用服務(wù)層合并成一坨代碼把模型接入層做成一個(gè)函數(shù)基礎(chǔ)設(shè)施只保留一個(gè)向量庫(kù)和日志表。架構(gòu)的分層思維要保留物理部署可以先用單體。4.2 技術(shù)棧選擇和關(guān)鍵參數(shù)技術(shù)棧這塊我給出的是目前行業(yè)實(shí)踐里比較穩(wěn)的組合你可以根據(jù)團(tuán)隊(duì)情況調(diào)整。模型選擇上如果一個(gè)團(tuán)隊(duì)沒(méi)有專門(mén)的推理優(yōu)化團(tuán)隊(duì)我建議優(yōu)先走成熟API不要自己部署大模型。API的好處是開(kāi)箱即用RLHF對(duì)齊做得好輸出穩(wěn)定性高。開(kāi)源模型適合數(shù)據(jù)敏感或成本敏感的團(tuán)隊(duì)但要能接受性能調(diào)優(yōu)和運(yùn)維的投入。不要只看榜單分?jǐn)?shù)落地時(shí)要測(cè)你場(chǎng)景里的真實(shí)數(shù)據(jù)反復(fù)測(cè)200條以上再做決定。編排框架方面團(tuán)隊(duì)熟悉Python就考慮LangChain生態(tài)但我們自己內(nèi)部現(xiàn)在會(huì)刻意把框架承擔(dān)的責(zé)任控制在“標(biāo)準(zhǔn)化調(diào)用”這個(gè)層面框架負(fù)責(zé)工具調(diào)用、上下文包裝、重試機(jī)制復(fù)雜的業(yè)務(wù)狀態(tài)流轉(zhuǎn)自己寫(xiě)。最近行業(yè)里也很流行Graph方式的工作流編排這個(gè)適合任務(wù)鏈路復(fù)雜、并行分支多的場(chǎng)景。小團(tuán)隊(duì)或產(chǎn)品型團(tuán)隊(duì)也可以直接上一個(gè)開(kāi)源的應(yīng)用平臺(tái)來(lái)縮短開(kāi)發(fā)周期但對(duì)底層細(xì)節(jié)的掌控會(huì)弱一些。性能相關(guān)的關(guān)鍵參數(shù)我的默認(rèn)值是溫度分類和抽取任務(wù)用0到0.2生成和創(chuàng)意類用0.7左右top_p一般跟溫度配合不單獨(dú)調(diào)保持0.9到1max_tokens按任務(wù)類型控制生成類給足分類類給短上下文上限設(shè)一個(gè)低于模型硬上限的軟上限比如模型支持32K我會(huì)控制在線請(qǐng)求不超過(guò)16K留一半空間給工具結(jié)果和檢索片段超時(shí)與重試單次模型調(diào)用超時(shí)設(shè)置30秒重試2次重試間隔遞增這些參數(shù)不是拍腦袋定的而是經(jīng)過(guò)真實(shí)壓測(cè)后調(diào)出來(lái)的。注意一點(diǎn)溫度調(diào)高不意味著“更聰明”它只表示采樣時(shí)更多樣化、更隨機(jī)。想讓它遵守你的輸出格式溫度越低越穩(wěn)。4.3 從零到一的最小閉環(huán)示例這里用“企業(yè)知識(shí)庫(kù)問(wèn)答助手”做一個(gè)最小閉環(huán)。第一步建一個(gè)FastAPI應(yīng)用暴露一個(gè)/chat接口這個(gè)接口做三件事接收用戶消息、調(diào)用后端的問(wèn)答函數(shù)、返回回答。這個(gè)階段不用考慮權(quán)限不用考慮多租戶只要鏈路通。第二步用向量庫(kù)存知識(shí)庫(kù)。做一個(gè)文檔導(dǎo)入腳本把公司的操作手冊(cè)、FAQ、產(chǎn)品文檔解析后切分逐塊生成向量并寫(xiě)入向量數(shù)據(jù)庫(kù)。切分和嵌入的具體參數(shù)按前面說(shuō)的方法設(shè)。第三步寫(xiě)RAG查詢函數(shù)。用戶問(wèn)問(wèn)題時(shí)先用同款嵌入模型把問(wèn)題向量化到向量庫(kù)檢索TopK個(gè)相關(guān)片段TopK默認(rèn)設(shè)8檢索回來(lái)之后過(guò)濾掉相關(guān)度太低的片段剩下的拼進(jìn)上下文。第四步組裝Prompt。系統(tǒng)提示詞里寫(xiě)清楚你是企業(yè)助手、只能基于給定的資料回答、不知道就說(shuō)不確定。然后把檢索片段放在用戶問(wèn)題之前用明確的標(biāo)記區(qū)分“資料區(qū)”和“用戶問(wèn)題區(qū)”。第五步加輸出約束。讓模型輸出JSON里面包含回答內(nèi)容、引用資料編號(hào)、置信度。這一步可以用結(jié)構(gòu)化輸出的方法也可以讓模型在回答末尾附上結(jié)論依據(jù)。第六步接入工具調(diào)用。當(dāng)用戶問(wèn)“我之前提交的工單處理到哪一步了”時(shí)讓模型識(shí)別出意圖調(diào)用工單查詢函數(shù)函數(shù)返回結(jié)果后再生成回答。工具函數(shù)本身先寫(xiě)死返回測(cè)試數(shù)據(jù)后面再接入真實(shí)系統(tǒng)。第七步加日志。把每一次用戶輸入、檢索到的片段、拼出來(lái)的Prompt、模型輸出、耗時(shí)、Token用量全量記錄下來(lái)。沒(méi)有日志之前你很難知道Prompt哪一步寫(xiě)錯(cuò)了有了日志你就能對(duì)著實(shí)際數(shù)據(jù)做優(yōu)化。當(dāng)這個(gè)最小閉環(huán)跑通之后你再去補(bǔ)生產(chǎn)化的能力緩存、降級(jí)、權(quán)限、自動(dòng)化評(píng)測(cè)。這樣做的順序保證你每一步的復(fù)雜度都是因?yàn)檎鎸?shí)需求而引入的不是為了架構(gòu)而架構(gòu)。4.4 生產(chǎn)環(huán)境專屬注意事項(xiàng)從小閉環(huán)到生產(chǎn)環(huán)境有幾個(gè)容易忽略的細(xì)節(jié)最值得記住。第一模型調(diào)用不能當(dāng)同步阻塞接口寫(xiě)死。你要在生產(chǎn)代碼里加熔斷和降級(jí)模型服務(wù)返回超時(shí)或錯(cuò)誤時(shí)可以先返回友好兜底話術(shù)而不是讓用戶看到一片空白的異常頁(yè)。某些場(chǎng)景里次級(jí)模型降級(jí)比如主模型失敗后用更小的模型先頂上也比完全不可用強(qiáng)。第二Token成本必須按“業(yè)務(wù)路徑”來(lái)做預(yù)算。有的場(chǎng)景一次回答可能要調(diào)用3次以上模型每次都是幾千Token疊加檢索、工具返回單次成本會(huì)是純問(wèn)答的好幾倍。前期要畫(huà)一個(gè)成本表格按用戶量、平均調(diào)用輪數(shù)、平均Token數(shù)去估算月度成本。第三緩存不是簡(jiǎn)單加一層Redis就行。緩存鍵要考慮用戶權(quán)限否則A用戶通過(guò)緩存拿到了B用戶專屬的知識(shí)庫(kù)回答。語(yǔ)義緩存命中時(shí)要重新檢查權(quán)限標(biāo)記因?yàn)榈讓訑?shù)據(jù)可能已經(jīng)變更。第四向量庫(kù)的檢索結(jié)果版本問(wèn)題。知識(shí)庫(kù)文檔更新后舊切片的向量可能還在庫(kù)里檢索時(shí)如果排到了最前面回答就會(huì)過(guò)時(shí)。生產(chǎn)環(huán)境里要維護(hù)一個(gè)文檔版本表和切片狀態(tài)字段增量更新時(shí)把舊切片標(biāo)記為失效。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄AI應(yīng)用架構(gòu)的坑不同項(xiàng)目踩出來(lái)有共性。我把在項(xiàng)目里遇見(jiàn)頻率最高的問(wèn)題整理成一個(gè)速查表附帶排查套路和解決方案。這一節(jié)每個(gè)問(wèn)題背后都有真實(shí)的排障過(guò)程不是紙面結(jié)論。常見(jiàn)現(xiàn)象真正原因排查套路解決方案多輪對(duì)話后回答質(zhì)量驟降甚至“忘掉”系統(tǒng)指令上下文窗口被歷史消息占滿關(guān)鍵指令被擠出注意力范圍在日志里查看每次請(qǐng)求實(shí)際填入的Prompt長(zhǎng)度對(duì)比上下文軟上限啟用歷史摘要壓縮設(shè)置明確的上下文保留策略把工具返回和檢索片段放在消息中部而非尾部Agent經(jīng)常循環(huán)空轉(zhuǎn)不停調(diào)用同一個(gè)工具工具返回結(jié)果沒(méi)有被正確回填模型看不到執(zhí)行后的狀態(tài)檢查工具網(wǎng)關(guān)日志看返回結(jié)果格式和長(zhǎng)度格式過(guò)長(zhǎng)時(shí)模型注意力被稀釋工具結(jié)果做截?cái)嗪徒Y(jié)構(gòu)化摘要超過(guò)800字符先壓縮給工具執(zhí)行結(jié)果增加完成標(biāo)志檢索不到相關(guān)內(nèi)容回答“不知道”文檔切分不合理或嵌入模型對(duì)領(lǐng)域詞匯理解弱也可能TopK設(shè)置過(guò)低單獨(dú)抽一條問(wèn)題做檢索測(cè)試直接看向量庫(kù)返回TopK片段的得分和內(nèi)容優(yōu)化切分策略增加領(lǐng)域同義詞擴(kuò)展引入重排模型調(diào)高TopK后再過(guò)濾回答很慢首字延遲超過(guò)預(yù)期模型輸入Token過(guò)長(zhǎng)或鏈路里串行步驟太多用鏈路追蹤看每步耗時(shí)定位是檢索慢、模型慢還是工具慢輸入提示詞前做壓縮檢索和工具調(diào)用做并行化增加流式輸出Token成本遠(yuǎn)超預(yù)算每輪請(qǐng)求把大量歷史消息和完整工具文檔重復(fù)傳給模型按會(huì)話統(tǒng)計(jì)每次調(diào)用Token數(shù)找最大消耗點(diǎn)共用Prompt做緩存工具描述按需加載歷史消息改摘要加入語(yǔ)義緩存提示詞被用戶輸入“注入”模型不按指令走用戶輸入和系統(tǒng)提示詞在同一個(gè)消息里模型邊界感失效查看Prompt組裝源碼確認(rèn)角色隔離是否生效復(fù)現(xiàn)惡意輸入嚴(yán)格區(qū)分system/user消息對(duì)用戶輸入做前置檢測(cè)必要時(shí)用輸入分類模型過(guò)濾除開(kāi)表格里的問(wèn)題我再單獨(dú)講一個(gè)團(tuán)隊(duì)經(jīng)常忽略的點(diǎn)評(píng)測(cè)機(jī)制的缺失。很多AI應(yīng)用上線后改動(dòng)提示詞或調(diào)整檢索參數(shù)沒(méi)人知道是變好了還是變壞了。我們?cè)趯?shí)際項(xiàng)目里維護(hù)了一個(gè)評(píng)測(cè)集大概一兩百條覆蓋典型用戶任務(wù)的樣例每次調(diào)整架構(gòu)或者改提示詞就用這個(gè)評(píng)測(cè)集批量跑一遍人工打分對(duì)比。別看它初期要花時(shí)間后面所有優(yōu)化工作都依賴這個(gè)基線否則你對(duì)“架構(gòu)改得好不好”沒(méi)有任何判斷依據(jù)。還有一個(gè)和“多AI協(xié)作”相關(guān)的排查經(jīng)驗(yàn)也能分享。當(dāng)你把多個(gè)模型放進(jìn)一條工作流里比如一個(gè)模型做意圖解析另一個(gè)模型做內(nèi)容生成結(jié)果經(jīng)常出現(xiàn)后一個(gè)模型不滿意前一個(gè)模型的輸出格式。問(wèn)題不一定出在模型能力上而是你沒(méi)有在兩步之間做“契約約束”。我現(xiàn)在會(huì)在每個(gè)模型調(diào)用的邊界上清確定義輸入輸出的Schema前置模型輸出先經(jīng)過(guò)一次格式校正和提取再傳給下一個(gè)模型。這個(gè)中間適配層比讓模型自己去理解上一個(gè)模型的輸出要穩(wěn)定得多。個(gè)人落地感受和一個(gè)小技巧我自己把AI應(yīng)用架構(gòu)這套思路在不同項(xiàng)目里反復(fù)用了很多遍以后最大的感受是架構(gòu)從來(lái)不是一次畫(huà)出來(lái)的巨型藍(lán)圖而是一層層長(zhǎng)出來(lái)的。最開(kāi)始可能就是一個(gè)模型接入函數(shù)加一個(gè)RAG查詢跑通之后你發(fā)現(xiàn)需要權(quán)限控制再加應(yīng)用服務(wù)層的校驗(yàn)然后你發(fā)現(xiàn)Agent在工具調(diào)用里失控再補(bǔ)工具網(wǎng)關(guān)的統(tǒng)一描述和校驗(yàn)再之后你會(huì)發(fā)現(xiàn)同樣的模型被好幾個(gè)模塊調(diào)用再加一個(gè)模型接入層做統(tǒng)一管理。每一步都是因?yàn)檎鎸?shí)的痛點(diǎn)和真實(shí)的數(shù)據(jù)才把架構(gòu)的某一塊補(bǔ)齊。如果只能給一個(gè)建議我會(huì)說(shuō)先把“上下文管理”這件事做好。我踩過(guò)最大的坑就是在Agent應(yīng)用里無(wú)腦堆歷史消息和檢索片段導(dǎo)致模型輸出幻覺(jué)嚴(yán)重、指令不穩(wěn)定表面看是大模型選錯(cuò)了實(shí)際上我根本沒(méi)做好提示詞邊界和上下文精準(zhǔn)度。后面我把短期記憶、長(zhǎng)期記憶、工作記憶拆開(kāi)把每個(gè)模型調(diào)用限制在一個(gè)“精準(zhǔn)上下文”的范圍內(nèi)之后整個(gè)系統(tǒng)的穩(wěn)定性一下就上來(lái)了。架構(gòu)圖再?gòu)?fù)雜它最終服務(wù)的還是“讓模型在合適的時(shí)間看到合適的信息”。這句話建議你每畫(huà)一層架構(gòu)設(shè)計(jì)都默念一遍。