實(shí)戰(zhàn):從零構(gòu)建AI工具調(diào)用與部署指南)
MCP 這個(gè)縮寫最近在 AI 工具鏈的圈子里幾乎天天被提起如果你翻過(guò)一些相關(guān)技術(shù)帖應(yīng)該對(duì) Model Context Protocol模型上下文協(xié)議有印象。我自己的感覺(jué)是MCP 正在把AI 接入外部工具這件事從手工作坊推進(jìn)到標(biāo)準(zhǔn)件時(shí)代。以前接一個(gè)工具要寫一堆膠水代碼現(xiàn)在大家照著協(xié)議來(lái)就行。這篇文章不聊概念史直接聊開發(fā)——怎么從零開始寫一個(gè)真正的 MCP Server 和 Tool順便把我自己踩過(guò)的坑、測(cè)試下來(lái)好用的調(diào)試方式、以及上線部署前那些容易忽略的細(xì)節(jié)都梳理一遍。如果你正準(zhǔn)備用 MCP 把自家業(yè)務(wù)能力開放給 AI 客戶端或者想讓本地 Agent 能調(diào)用幾個(gè)內(nèi)部工具這篇文章應(yīng)該能讓你少走不少?gòu)澛贰?. 為什么是 MCP以及它的核心運(yùn)行邏輯1.1 從集成地獄到統(tǒng)一協(xié)議在 MCP 出現(xiàn)之前AI 應(yīng)用要接一個(gè)外部工具基本是每條鏈路單獨(dú)對(duì)接。比如你的 AI 助手要查數(shù)據(jù)庫(kù)、查工單系統(tǒng)、查內(nèi)部文檔那就得給每個(gè)系統(tǒng)各寫一套函數(shù)調(diào)用邏輯還要處理認(rèn)證、輸入輸出格式、錯(cuò)誤重試這些重復(fù)工作。我見過(guò)不少團(tuán)隊(duì)維護(hù)著四五套互不兼容的工具適配層純粹是為了讓 LLM 能調(diào)用不同后端。MCP 的思路很樸素把AI 應(yīng)用和外部工具/數(shù)據(jù)源之間的一致性接口抽出來(lái)做成一個(gè)標(biāo)準(zhǔn)協(xié)議。所有工具統(tǒng)一暴露成 MCP Server所有 AI 應(yīng)用統(tǒng)一通過(guò) MCP Client 去調(diào)用。這樣工具只承擔(dān)實(shí)現(xiàn)協(xié)議的成本AI 應(yīng)用只承擔(dān)連接協(xié)議的成本兩邊解耦。1.2 三個(gè)核心角色一次完整的 MCP 調(diào)用涉及三個(gè)角色Host承載 AI 應(yīng)用的主體比如桌面端 AI 助手、IDE 插件、網(wǎng)關(guān)服務(wù)。它負(fù)責(zé)把用戶意圖交給模型再把模型想調(diào)用工具的意圖轉(zhuǎn)給 Client。Client就是 Host 內(nèi)部集成的一個(gè)庫(kù)負(fù)責(zé)和 Server 建立連接、發(fā)請(qǐng)求、收結(jié)果。Client 通常不需要你手寫用官方 SDK 即可。Server真正干活的進(jìn)程暴露出 tools、resources、prompts 三類能力核心是 tools。打個(gè)比方Host 是餐廳顧客Client 是服務(wù)員Server 是后廚。顧客說(shuō)來(lái)一份少鹽的番茄炒蛋服務(wù)員把需求轉(zhuǎn)述給后廚后廚按標(biāo)準(zhǔn)流程做菜并端回來(lái)。這個(gè)標(biāo)準(zhǔn)流程就是 MCP 要定義的東西。1.3 通信機(jī)制JSON-RPC 2.0 與兩種傳輸方式MCP 的通信協(xié)議基于 JSON-RPC 2.0這個(gè)消息格式本身不復(fù)雜——method、params、result、error 四個(gè)字段打天下。但真正影響開發(fā)體驗(yàn)的是傳輸層目前主流有兩條路stdioServer 以子進(jìn)程方式啟動(dòng)Host 通過(guò)標(biāo)準(zhǔn)輸入輸出跟它通信。好處是零網(wǎng)絡(luò)配置、天然安全適合本地個(gè)人工具。HTTP SSEServer-Sent EventsServer 作為一個(gè)遠(yuǎn)程服務(wù)客戶端通過(guò) HTTP 發(fā)請(qǐng)求、通過(guò) SSE 收推送。適合多客戶端同時(shí)訪問(wèn)、需要鑒權(quán)、需要跨機(jī)器部署的生產(chǎn)場(chǎng)景。開發(fā)初期先用 stdio 跑通邏輯再遷移到 HTTP這是最穩(wěn)妥的路徑。直接上 HTTP 容易把協(xié)議實(shí)現(xiàn)和網(wǎng)絡(luò)問(wèn)題兩個(gè)變量攪在一起排查起來(lái)頭疼。2. 動(dòng)手選型語(yǔ)言與 SDK 的取舍2.1 語(yǔ)言怎么選MCP 目前最成熟的官方 SDK 是 Python 和 TypeScript。Python 生態(tài)在 AI 領(lǐng)域積累深FastMCP 這類封裝可以讓你用更少的樣板代碼做更多事適合內(nèi)部工具或快速原型。TypeScript 在前端和后端領(lǐng)域滲透率高如果團(tuán)隊(duì)已有 Node.js 基礎(chǔ)設(shè)施那選 TypeScript 能更好地復(fù)用現(xiàn)有工程體系。其他語(yǔ)言比如 Java、Go、Ruby、PHP 也有社區(qū)版或官方出品的 SDK但是成熟度和文檔完整度參差不齊。我的觀點(diǎn)是第一優(yōu)先選 Python 或 TS除非你的服務(wù)端基建非常單一比如全公司只有 Go那再用 Go 的 MCP 庫(kù)。2.2 一個(gè) Server 可以掛多種能力的組合不要把 Server 理解成一個(gè)工具它是一個(gè)能力容器。你可以把一個(gè) Server 設(shè)計(jì)成統(tǒng)一的內(nèi)部數(shù)據(jù)查詢臺(tái)里面同時(shí)注冊(cè)數(shù)據(jù)查詢 Tool、指標(biāo)字典 Resource、對(duì)話排障 Prompt。這樣客戶端只需要連一個(gè) Server就能得到一整組能力。開發(fā)時(shí)也可以按域拆多個(gè) Server比如訂單域庫(kù)存域按需連接。2.3 選 FastMCP 還是底層 SDKPython 生態(tài)里直接用官方 SDK 寫一個(gè) MCP Server 會(huì)有不少模板代碼比如初始化 Server 對(duì)象、注冊(cè) handler、做生命周期管理。而 FastMCP 這個(gè)庫(kù)把注冊(cè)工具的方式簡(jiǎn)化到一個(gè)裝飾器幾乎就是寫普通函數(shù)。我用下來(lái)更推薦 FastMCP它把樣板代碼壓得很低核心邏輯的辨識(shí)度很高后面接 HTTP 傳輸也只需要改一行。TypeScript 官方 SDK 目前做得也不錯(cuò)默認(rèn)提供清晰的 Transport 抽象底層控制力更強(qiáng)。如果你對(duì)協(xié)議本身有定制需求用底層 SDK 會(huì)更順手。3. 用一個(gè) QueryTool 講透 Server 開發(fā)全過(guò)程3.1 場(chǎng)景與目標(biāo)我拿一個(gè)模擬場(chǎng)景來(lái)演示開發(fā)一個(gè)訂單查詢工具 MCP Server接收一個(gè)訂單號(hào)返回訂單狀態(tài)、金額、下單時(shí)間。這個(gè)工具如果接入到 AI 客服系統(tǒng)里用戶一句幫我看看我 20240401 的訂單AI 就會(huì)自動(dòng)查出來(lái)。放棄暴力的把數(shù)據(jù)庫(kù)接入給 AI方案采用 QueryTool 方案的原因是數(shù)據(jù)庫(kù)直接暴露給 LLM 風(fēng)險(xiǎn)極大表結(jié)構(gòu)容易泄漏、SQL 容易被亂寫、生產(chǎn)庫(kù)有被拖垮的風(fēng)險(xiǎn)。而 Tool 方案有完全可控的入?yún)?、可限制的查詢邏輯、可追加的?quán)限校驗(yàn)。3.2 項(xiàng)目初始化和依賴安裝先建一個(gè)干凈的虛擬環(huán)境mkdir mcp-order-server cd mcp-order-server python -m venv .venv source .venv/bin/activate pip install mcp[cli]1.2.0 fastmcp裝完確認(rèn)版本python -c import fastmcp; print(fastmcp.__version__)如果啟用了其他集成 Sdk比如生態(tài)工具包也一并裝好。這是標(biāo)準(zhǔn)前置步驟。3.3 核心代碼三層結(jié)構(gòu)一次寫清下面是一個(gè)結(jié)構(gòu)清晰的最小實(shí)現(xiàn)代碼可以直接復(fù)用骨架# server.py from fastmcp import FastMCP mcp FastMCP(訂單查詢服務(wù)) def _get_order_from_db(order_id: str) - dict: # 真實(shí)項(xiàng)目這里會(huì)走數(shù)據(jù)訪問(wèn)層控權(quán)限、加監(jiān)控 # 示例中返回模擬數(shù)據(jù) return { order_id: order_id, status: 已發(fā)貨, amount: 299.00, created_at: 2024-04-01 10:22:00 } mcp.tool() def query_order(order_id: str) - dict: 根據(jù)訂單號(hào)查詢訂單狀態(tài)、金額和創(chuàng)建時(shí)間。 Args: order_id: 完整的訂單號(hào)例如 2024040112034567。 if not order_id or len(order_id) 10: return {error: 訂單號(hào)格式不正確} return _get_order_from_db(order_id) mcp.resource(order://{order_id}) def order_resource(order_id: str) - dict: 以 Resource 方式暴露只讀數(shù)據(jù)便于描述性引用。 return _get_order_from_db(order_id) if __name__ __main__: mcp.run(transportstdio)這段代碼里最需要注意的是mcp.tool()下面的函數(shù)注釋。MCP 對(duì)工具的 JSON Schema 是根據(jù)函數(shù)的簽名和注釋自動(dòng)生成的。docstring 里對(duì)參數(shù)的說(shuō)明寫得多清楚AI 調(diào)用工具時(shí)就有多明白。不少人圖省事不寫參數(shù)說(shuō)明結(jié)果 AI 調(diào)用時(shí)總是把字段名猜錯(cuò)這就是常見的工具在模型眼里是黑盒問(wèn)題。mcp.run(transportstdio)這行是入口告訴 FastMCP 用 stdio 模式啟動(dòng)。等代碼跑通后把 transport 改成http即可切到遠(yuǎn)程模式我后面第 5 章會(huì)專門討論部署切換的細(xì)節(jié)。3.4 啟動(dòng)并接入客戶端本地驗(yàn)證最簡(jiǎn)單的辦法是用 MCP Inspector 這個(gè)官方的調(diào)試界面。命令行執(zhí)行mcp dev server.py這個(gè)命令會(huì)把服務(wù)啟動(dòng)到調(diào)試模式然后自動(dòng)打開一個(gè)本地的 Inspector 頁(yè)面。在頁(yè)面里你可以直觀地看到 Server 暴露出的工具名、工具描述、JSON Schema以及你直接模擬調(diào)用之后返回的結(jié)果。我自己的習(xí)慣是先在這里把函數(shù)調(diào)用通了再接到任何上層客戶端。如果接到支持 MCP 的桌面端 AI 客戶端在配置里填入命令python /path/to/server.pySSE 遠(yuǎn)程模式則填https://your-domain.com/mcp第一次接桌面端時(shí)注意看客戶端有沒(méi)有在工具列表里掃到query_order。如果遲遲掃不到優(yōu)先懷疑 Server 啟動(dòng)時(shí)報(bào)錯(cuò)了正常啟動(dòng)的進(jìn)程會(huì)有握手日志建議先用 Inspector 確認(rèn)端口。3.5 一個(gè)突發(fā)的邊界問(wèn)題參數(shù)格式校驗(yàn)我實(shí)際測(cè)試這個(gè) QueryTool 時(shí)遇到一個(gè)很有意思的情況AI 在調(diào)用query_order時(shí)傳入的order_id是202404011203465這種長(zhǎng)度但字段本身被偷偷加了空格或者帶了前綴#ORD-。如果你不做入?yún)⑶逑凑?qǐng)求會(huì)打進(jìn)數(shù)據(jù)庫(kù)層才失敗錯(cuò)誤信息又長(zhǎng)又難看。所以我在工具里加了一個(gè)顯式的 clean 和校驗(yàn)邏輯mcp.tool() def query_order(order_id: str) - dict: 根據(jù)訂單號(hào)查詢訂單狀態(tài)、金額和創(chuàng)建時(shí)間。 Args: order_id: 訂單號(hào)需要是純數(shù)字字符串。 order_id order_id.strip().removeprefix(ORD-) if not order_id.isdigit() or len(order_id) ! 16: return {error: 訂單號(hào)格式不正確應(yīng)為16位純數(shù)字} return _get_order_from_db(order_id)不要迷信AI 一定會(huì)傳干凈的參數(shù)LLM 的輸出在格式上天然具有不確定性。一個(gè) Tool 除了核心邏輯必須自己兜住入?yún)⑿r?yàn)。這個(gè)習(xí)慣能省掉大量下游異常排查。4. 調(diào)試、測(cè)試與為什么工具調(diào)用總是失敗4.1 日志與輸出的隔離陷阱開發(fā) MCP Server 時(shí)最容易被表象迷惑的就是日志。你如果在代碼里用了print()來(lái)調(diào)試在 stdio 模式下這些 print 內(nèi)容會(huì)直接打到 stdout 上而 stdout 正是 MCP 協(xié)議通信的通道。這樣會(huì)直接污染協(xié)議流導(dǎo)致客戶端解析失敗表現(xiàn)為連接成功但收不到工具列表或調(diào)用時(shí)超時(shí)。正確的做法是全部用logging模塊并把日志打到 stderrimport logging logging.basicConfig(levellogging.DEBUG) logger logging.getLogger(mcp-order-server) logger.info(query_order called with %s, order_id)本地排查協(xié)議問(wèn)題先分清三層第一層Server 有沒(méi)有正常啟動(dòng)看進(jìn)程日志。第二層工具的 JSON Schema 有沒(méi)有生成看 Inspector。第三層工具調(diào)用結(jié)果是否正常返回看 Inspector 模擬調(diào)用。多數(shù)工具失效問(wèn)題都卡在第二三層很少需要抓原始 TCP 包。4.2 測(cè)試策略單測(cè)之外補(bǔ)一輪帶 LLM 的端到端測(cè)試傳統(tǒng)的工具開發(fā)者容易犯的毛病是只做單元測(cè)試把函數(shù)邏輯測(cè)通了就以為大功告成。但 MCP 工具層的特殊性在于真正調(diào)用它的是 LLMLLM 對(duì)工具的理解與你代碼里的 docstring 直接相關(guān)。你注釋里寫訂單號(hào)需要是16位純數(shù)字AI 如果是先脫敏后傳參大概率是對(duì)的但如果文檔描述模糊AI 可能會(huì)傳余額字段來(lái)查訂單或者把order_id寫成了orderNumber。我的經(jīng)驗(yàn)是加一層端到端測(cè)試準(zhǔn)備 5-10 個(gè)真實(shí)風(fēng)格的自然語(yǔ)言問(wèn)句。跑一個(gè)帶工具的客戶端會(huì)話讓它依次回答這些問(wèn)題。人工檢查 AI 每次調(diào)用工具時(shí)的參數(shù)是否如預(yù)期。這種做法能提前發(fā)現(xiàn)大量看起來(lái)工具能用、接上 AI 就不能用的問(wèn)題。4.3 命名的坑use tool 名的語(yǔ)義要收斂工具命名直接影響 LLM 的識(shí)別準(zhǔn)確率。比如你把一個(gè)查訂單狀態(tài)的工具命名為get_dataLLM 可能分不清它到底是查訂單、查庫(kù)存還是查物流調(diào)用成功率會(huì)明顯下降。更推薦的做法是把工具名設(shè)計(jì)成動(dòng)詞業(yè)務(wù)對(duì)象如query_order_status、query_inventory_quantity。工具的 description 也可以寫得像一句明確的能力聲明比如查詢訂單的實(shí)時(shí)狀態(tài)和配送進(jìn)度輸入訂單號(hào)即可。我在多個(gè)命名實(shí)驗(yàn)中發(fā)現(xiàn)描述里把不支持的能力也順帶寫進(jìn)去如不包含物流軌跡物流軌跡另查 trade_logistics可以顯著減少錯(cuò)誤調(diào)用。5. 遠(yuǎn)程化部署stdio 轉(zhuǎn) HTTP 的完整過(guò)渡5.1 生命周期管理的變化本地 stdio 模式下Server 的生命周期跟客戶端進(jìn)程一致——客戶端啟動(dòng)它啟動(dòng)客戶端退出它退出。轉(zhuǎn)成 HTTP 模式后Server 變成常駐服務(wù)需要考慮四個(gè)原來(lái)沒(méi)有的問(wèn)題并發(fā)多個(gè)客戶端同時(shí)連上每個(gè)請(qǐng)求是否安全隔離。鑒權(quán)誰(shuí)有權(quán)限調(diào)用工具。超時(shí)與重試網(wǎng)絡(luò)請(qǐng)求什么時(shí)候算失敗。審計(jì)工具被誰(shuí)調(diào)用、每次傳了什么參數(shù)。FastMCP 如果需要開啟 HTTP 模式需要加一個(gè)額外的異步服務(wù)器入口from fastmcp import FastMCP mcp FastMCP(訂單查詢服務(wù)) # ... 工具定義 ... if __name__ __main__: mcp.run(transporthttp, host0.0.0.0, port8080)啟動(dòng)后HTTP 服務(wù)提供一個(gè)端點(diǎn)客戶端通過(guò)配置這個(gè) URL 建立 SSE 流式連接。注意這里跟普通 REST API 的區(qū)別MCP 的 HTTP 傳輸并不是每次請(qǐng)求打一次接口這么簡(jiǎn)單它需要建立一個(gè)持久化的 SSE 通道讓服務(wù)端可以主動(dòng)給客戶端推送事件。這個(gè)語(yǔ)義的轉(zhuǎn)變意味著你的負(fù)載均衡、健康檢查配置也要跟著調(diào)整不能簡(jiǎn)單按 HTTP 請(qǐng)求數(shù)來(lái)壓測(cè)。5.2 鑒權(quán)與多租戶隔離遠(yuǎn)程化之后第一個(gè)要解決的問(wèn)題是鑒權(quán)。MCP 官方協(xié)議目前提供的鑒權(quán)方案可以內(nèi)嵌 OAuth 2.1 流程也可以直接加在反向代理層。我實(shí)際部署時(shí)的做法是統(tǒng)一走公司內(nèi)部網(wǎng)關(guān)網(wǎng)關(guān)層完成單點(diǎn)登錄認(rèn)證生成短期 token。MCP Server 每次收到請(qǐng)求都驗(yàn)證 token并從 token 里解析出用戶身份和角色。在 Tool 函數(shù)內(nèi)部根據(jù)身份做數(shù)據(jù)權(quán)限過(guò)濾。舉個(gè)具體場(chǎng)景同樣是query_order普通客服角色只能查自己團(tuán)隊(duì)負(fù)責(zé)的訂單而大區(qū)總監(jiān)可以查整個(gè)大區(qū)訂單。這一切不能靠 LLM 自覺(jué)必須在 Server 里硬編碼權(quán)限邊界。你要清楚一個(gè)事實(shí)LLM 可以騙一個(gè)沒(méi)有鑒權(quán)的工具所以所有危險(xiǎn)操作都必須有一層硬校驗(yàn)——比如只允許 SELECT、不允許 UPDATE。5.3 日志、監(jiān)控、限流生產(chǎn)級(jí)部署別忘了打日志。我的建議是從第一版上線就只有意識(shí)地記錄三個(gè)信息時(shí)間戳與唯一請(qǐng)求 ID。入?yún)⒄⒁饷撁羟f(wàn)別整單號(hào)全量打進(jìn)去。響應(yīng)狀態(tài)、耗時(shí)、最終用戶身份。限流層面面向內(nèi)部使用可以先做全局限流比如每客戶端每分鐘最多 60 次調(diào)用。如果工具推動(dòng)的是 LLM 調(diào)用LLM 的循環(huán)調(diào)用有時(shí)會(huì)產(chǎn)生突發(fā)流量不加限流底層數(shù)據(jù)庫(kù)或第三方依賴很容易被打滿。我在一臺(tái)測(cè)試機(jī)上曾見過(guò)循環(huán)調(diào)用把第三方查詢接口打到超時(shí)就是因?yàn)闆](méi)有給工具加流量閘門。5.4 一個(gè)常見誤區(qū)和進(jìn)階方向遠(yuǎn)程化還有一個(gè)常見誤區(qū)以為 MCP Client 只能由一個(gè) AI 應(yīng)用來(lái)連。實(shí)際上你完全可以直接用 MCP Client SDK 把 Server 包一層做成一個(gè)內(nèi)部命令行工具、一個(gè)定時(shí)任務(wù)甚至一個(gè)異步 Worker。MCP Tool 的本質(zhì)是能力封裝不是 AI 專屬 API。這個(gè)點(diǎn)想通之后同一個(gè) Server 可以復(fù)用在多個(gè)業(yè)務(wù)鏈路里工具函數(shù)變成一套可復(fù)用的中間層能力跨業(yè)務(wù)暴露價(jià)值。6. 進(jìn)階設(shè)計(jì)資源、提示詞與復(fù)雜工具模式6.1 Resource 不只是數(shù)據(jù)還是上下文的引子Resource 在 MCP 里可以理解為只讀數(shù)據(jù)的描述性入口。它和 Tool 最大的區(qū)別是Tool 是一次動(dòng)作Resource 是一個(gè)可被引用的數(shù)據(jù)對(duì)象。比如我在 Server 里注冊(cè)了一個(gè)order://{order_id}的 ResourceAI 在回答用戶時(shí)可以在上下文里引用關(guān)于訂單的資源然后讓工具去查更多。Resource 很適合把數(shù)據(jù)模型、元數(shù)據(jù)、配置項(xiàng)這些內(nèi)容暴露給模型讓模型在交互時(shí)擁有足夠的背景知識(shí)。6.2 Prompt 模塊化沉淀調(diào)用經(jīng)驗(yàn)MCP 的 Prompt 能力也值得善用。你可以把客服對(duì)話時(shí)如何查詢訂單的提示模板做到 Server 里客戶端連接后自動(dòng)拿到這些模板。每次接新客戶端時(shí)不用重新從零調(diào)提示詞直接在客戶端側(cè)選一個(gè)模板就能獲得不錯(cuò)的效果。這對(duì)團(tuán)隊(duì)合作的價(jià)值很高相當(dāng)于把怎么用這套工具最順的經(jīng)驗(yàn)沉淀成配置。6.3 復(fù)雜工具多輸入?yún)?shù)的組合查詢當(dāng)工具的參數(shù)超過(guò)三個(gè)就要考慮設(shè)計(jì)成結(jié)構(gòu)化的組合查詢了。比如企業(yè)內(nèi)部的訂單查詢工具除了訂單號(hào)還支持客戶名稱時(shí)間范圍狀態(tài)的組合過(guò)濾。這種工具的輸入要用 JSON 對(duì)象而不是平鋪參數(shù)。我的實(shí)現(xiàn)方式from pydantic import BaseModel class OrderQueryParams(BaseModel): order_id: str | None None customer_name: str | None None date_from: str | None None date_to: str | None None status: str | None None mcp.tool() def query_orders_advanced(params: OrderQueryParams) - list[dict]: 按組合條件查詢訂單列表?xiàng)l件可任意組合至少需要提供一個(gè)字段。 return _query_orders(params)把它設(shè)置成 Pydantic Model 有兩個(gè)好處FastMCP 能直接把 Model 轉(zhuǎn)成結(jié)構(gòu)良好的 JSON Schema 給 LLM。字段級(jí)校驗(yàn)在入口處就完成了非法值不會(huì)泄漏進(jìn)下層。6.4 長(zhǎng)耗時(shí)任務(wù)的模式選擇MCP 工具是同步調(diào)用還是異步結(jié)果回傳取決于傳輸方式。HTTP SSE 模式下可以采用立即返回一個(gè)任務(wù) ID后續(xù)通過(guò) Resource 或事件通道查詢進(jìn)度的方式stdio 模式下則建議保持同步調(diào)用設(shè)定合理的超時(shí)上限。我自己做數(shù)據(jù)重算類工具時(shí)傾向于異步任務(wù)模式——先讓工具回一個(gè)任務(wù)已提交然后單獨(dú)做一個(gè)查詢進(jìn)度的工具這樣 LLM 不會(huì)因?yàn)殚L(zhǎng)時(shí)間等待而誤判調(diào)用失敗。7. 上線前后一定要檢查的十項(xiàng)清單開發(fā)接近尾聲很多問(wèn)題不是代碼邏輯錯(cuò)而是部署形態(tài)沒(méi)想全。下面這十項(xiàng)是我自己在每次部署之前都會(huì)過(guò)的清單也分享給你們照著檢查基本能規(guī)避絕大部分上線事故Server 啟動(dòng)方式是否可被進(jìn)程管理工具托管sudo systemd 或容器平臺(tái)沒(méi)有守護(hù)進(jìn)程的話掛了沒(méi)人拉。日志是否全量走 stderr 或獨(dú)立文件沒(méi)有污染 stdio 通道。Token 和密鑰是否通過(guò)環(huán)境變量或密鑰管理服務(wù)注入有沒(méi)有硬編碼進(jìn)代碼。工具入?yún)⑹欠褡隽嘶拘r?yàn)尤其針對(duì) LLM 輸入的不確定性。數(shù)據(jù)庫(kù)訪問(wèn)是否限定了最小權(quán)限集有沒(méi)有按用戶隔離數(shù)據(jù)范圍。是否有審計(jì)字段可以追溯某次查詢是哪個(gè)用戶、哪個(gè)客戶端觸發(fā)的。超時(shí)時(shí)間是否合理過(guò)長(zhǎng)會(huì)積累請(qǐng)求積壓過(guò)短會(huì)誤殺依賴的慢請(qǐng)求。并發(fā)數(shù)是否有壓測(cè)數(shù)據(jù)支撐避免突發(fā)流量打滿依賴。API 網(wǎng)關(guān)或負(fù)載均衡的會(huì)話保持是否適配 SSE 連接不然長(zhǎng)連接容易被切斷。配置文件是否有版本管理避免上線后改不回滾。其中第九條曾經(jīng)讓我費(fèi)了不少時(shí)間。之前我把 MCP HTTP 服務(wù)部署到負(fù)載均衡后面結(jié)果發(fā)現(xiàn)客戶端每隔幾十秒就斷連一次排查了很久才發(fā)現(xiàn)是網(wǎng)關(guān)的默認(rèn)空閑超時(shí)時(shí)間太短把 SSE 長(zhǎng)連接給掐了。這種問(wèn)題在日志里特別隱蔽因?yàn)樗皇菆?bào)錯(cuò)只是連接被重置。如果你的網(wǎng)絡(luò)拓?fù)淅飵в芯W(wǎng)關(guān)請(qǐng)務(wù)必檢查空閑連接超時(shí)。8. 做 Tool 和做平臺(tái)更長(zhǎng)期的視角當(dāng)你把第一個(gè) Server 跑通之后建議退一步問(wèn)自己一個(gè)問(wèn)題團(tuán)隊(duì)里有多少場(chǎng)景其實(shí)可以抽象成同一種公共能力我的經(jīng)驗(yàn)是與其給每個(gè) AI 應(yīng)用各自連一套獨(dú)立 Server不如先梳理一下內(nèi)部公共數(shù)據(jù)接口按業(yè)務(wù)域做成統(tǒng)一的 MCP Server 組。比如訂單域、商品域、庫(kù)存域、用戶域每個(gè)域一個(gè) Server所有上層應(yīng)用按需連接。這能讓團(tuán)隊(duì)沉淀出一層穩(wěn)定的AI 可調(diào)用中間層后續(xù)做新的 AI 功能成本會(huì)肉眼可見地下降。從工程角度講MCP 的標(biāo)準(zhǔn)化還帶來(lái)一個(gè)隱性收益新員工入職后學(xué)習(xí)如何提供工具能力不再需要翻舊項(xiàng)目的膠水代碼只需要看協(xié)議和 SDK 文檔。這對(duì)團(tuán)隊(duì)長(zhǎng)期維護(hù)的成本是很大的改善。如果你現(xiàn)在正處在要不要上車 MCP的觀望期我的建議是先拿一個(gè)低頻、只讀、不敏感的工具跑通全鏈路比如查應(yīng)用版本信息或者查配置字典。這個(gè)周期一般不會(huì)超過(guò)半天卻能完整經(jīng)歷從開發(fā)、調(diào)試到接入客戶端的全部過(guò)程比看十篇文章都有用。跑通之后再逐步擴(kuò)大工具覆蓋范圍步步為營(yíng)風(fēng)險(xiǎn)完全可控。